« Comparateur Numérique » : différence entre les versions
m (Le code) |
m (Explications) |
||
Ligne 240 : | Ligne 240 : | ||
Logic 3 = Lecture de la valeur "data" sur chaque front montant de la clock (le front descendant de la clock à travers le NPN) <syntaxhighlight lang="c++" line="1"> | Logic 3 = Lecture de la valeur "data" sur chaque front montant de la clock (le front descendant de la clock à travers le NPN) <syntaxhighlight lang="c++" line="1"> | ||
// Analyse comparator signal | |||
// processing in µs on uint32_t integer | |||
// 4 294 967 296 µs | |||
// 4 294.967296 sec | |||
// 1:11:34 so after 1 hour needs to reboot | |||
// Related to https://knowledge.pinon-hebert.fr/index.php/Comparateur_Num%C3%A9rique | // Related to https://knowledge.pinon-hebert.fr/index.php/Comparateur_Num%C3%A9rique | ||
const int clk = 32; | const int clk = 32;//32; | ||
const int dat = 33; | const int dat = 33; | ||
const int clk_out = 23; // to monitor clock signal | //const int clk_out = 23; // to monitor clock signal | ||
const int frame_out = 22; /// frame detection | const int frame_out = 22; /// frame detection | ||
const int dat_out=21; // data decode | const int dat_out=21; // data decode | ||
Ligne 318 : | Ligne 323 : | ||
event_change=ti; | event_change=ti; | ||
if(getClkState()){ | if(getClkState()){ | ||
return clk_rise(); | return clk_rise(); | ||
}else{ | }else{ | ||
return clk_fall(); | return clk_fall(); | ||
} | } | ||
Ligne 353 : | Ligne 356 : | ||
pinMode(clk, INPUT_PULLUP); | pinMode(clk, INPUT_PULLUP); | ||
pinMode(dat,INPUT_PULLUP); | pinMode(dat,INPUT_PULLUP); | ||
pinMode(frame_out,OUTPUT); | pinMode(frame_out,OUTPUT); | ||
pinMode(dat_out,OUTPUT); | pinMode(dat_out,OUTPUT); | ||
Ligne 376 : | Ligne 378 : | ||
printMeasure(); | printMeasure(); | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight>Explication : | ||
''Les constantes'' | |||
* Lignes 5 à 10 définitions des broches GPIO | |||
* Ligne 14 on défini REVERSE si le signal est inversé en entrée ce qui est la cas avec notre montage à transistors NPN. | |||
''Les variables'' | |||
* Lignes 18 à 25 des entiers non signés sur 32 bits qui servent a mémoriser les "timestamps en microsecondes" des derniers événements (rise, fall, change) et la durée des états HAUTS BAS et la dernière période. | |||
{| class="wikitable" | |||
|+ | |||
|[[Fichier:Attention.png|sans_cadre|47x47px]] | |||
|Attention dans ce code on ne gère pas le cas ou la valeur du timestamp en microsecondes va repasser à zéro. Apres 4 294 967 296 µs soit 1h11 notre programme va planter! | |||
|} | |||
* Ligne 29 et 30 le cadre de décodage (buffer et pointeur) | |||
* Ligne 31 la variable décodée (double buffering) | |||
* Ligne 33 l'état de la ligne à un instant donné. | |||
''Le code'' | |||
* Lignes 35 à 49 gestion de la lecture de la valeur des deux lignes. Prends en compte la constante REVERSE (gestion du transistor NPN) | |||
* '''Lignes 51 à 66 : C'est l'une des deux fonctions primordiales.''' C'est une interruption matérielle appelée à chaque changement d'état de CLK. | |||
** Elle "remplis" le buffer bit après bit à chaque front montant du signal du comparateur (attention NPN) | |||
** Lorsque une "frame" est pleine on la transfère dans le buffer de lecture | |||
** Accessoirement (lignes 64 et 65) on mets a disposition les signaux décodés sur des deux GPIO | |||
== Les étapes suivantes... == | == Les étapes suivantes... == |
Version du 17 juin 2024 à 17:02
Analyse hardware
J'ai acheté un comparateur numérique sur Amazon. Il est donné pour avoir une sortie RS232.
En revanche la connectique est "exotique" (un trou dans le boitier et 4 traces sur le PCB de l'appareil) et aucune explication dans la doc. La majorité des vendeurs disent que le "kit connectique" est disponible séparément mais aucun de mes messages aux distributeurs ni question sur le site Amazon ne m'a donné de réponses.
Il n'y a pas de marque sur ce modèle donc pas de fabricant à contacter. Alors je sors mon oscilloscope, mon multimètre et mes pointes de touches maisons pour comprendre de quoi il en retourne "à la main".
Si on ouvre le cache du connecteur (le petit, le grand c'est celui de la pile) on voit qu'on a accès directement au PCB de la carte et que 4 conducteurs sont présents.
On nommera ces broches de 1 à 4 de gauche à droite. Les couleurs donnent déjà un indication de ce que j'ai déduit de mes mesures.
A priori la broche 4 est la masse et la 1 est la tension d'alim de la pile (1,17V avec une pile... pas toute neuve mais 1.6 avec une pile neuve).
En 2 et en 3 on voit passer des données.
En 2 on voit passer un signal qui ne ressemble pas à un signal UART!
Mon "GND" était pas parfait mais ce ressemble a un message aussi et c'est moins régulier.
Définitivement, avec mes pointes de touches je n'arrive à rien de propre. Je décide d'ouvrir la bête. Je soude trois fils sur les broches 2, 3 et 4 et je rebranche mon oscilloscope.
Il faut être très prudent lors de cette opération. L'écran LCD est relié au circuit imprimé par un connecteur qui est un sandwich de couches conductrices et isolantes en plastique souple. C'est impossible à remettre en place correctement. Au bout de 50 essais j'ai un affichage "a peu près" correct. Faut se mettre bien en face!. Quand j'aurais terminé je penses que j'en achèterais un neuf!
Analyse du signal de sortie
Voie 1 (rouge) sur 3
Voie 2 (jaune) sur 2
Les deux masses à 4
On visualise:
Je n'ai pas mis d'échelle mais mes mesures donnent :
- Un message toutes les 110 ms
- Le message lui même dure 8ms
Regardons de près le signal pour une mesure à 0mm:
Intuitivement :
- La voie 1 (broche 3) semble être un horloge (elle ne change jamais quel que soit la mesure)
- La voie 2 (broche 2) semble être la mesure dans un format étrange.
Après une après midi de creusage de tête j'ai compris plusieurs choses:
- Le signal de la voie 2 est un signal logique dont il faut lire l'état à chaque front montant de l'horloge.
- Le message contient 6 groupes de 4 bits. (24 bits)
- Le bit 23 indique l'unité (0="mm" et 1="in")
- Le bit 20 c'est le signe (0="+" et 1="-")
- Seul les 3 premiers quartets (12 premiers bits) semblent significatifs les 2 suivants sont toujours à zéro
- Pour le reste la seule chose que je vois c'est que le bit 0 est l'unité car il est à 0 pour les nombres paire et à 1 pour les impairs.
Décodage en mode métrique (unité ="mm")
Signal décodé | Mesure affichée | Valeur binaire
12 premiers bits |
Valeur décimale
bit0 = lsb |
---|---|---|---|
0000 0000 0000 0000 0000 0000 | 0mm | 000000000000 | 0 |
0100 0000 0000 0000 0000 0000 | 0,02mm | 010000000000 | 2 |
0111 0100 1000 0000 0000 0000 | 3.02mm | 011101001000 | 302 |
0101 0111 1100 0000 0000 0000 | 10,02mm | 010101111100 | 1002 |
1111 0110 1000 0000 0000 0000 | 3,67mm | 111101101000 | 367 |
0111 1110 1010 0000 0000 0000 | 14,06mm | 011111101010 | 1406 |
1010 0100 0100 0000 0000 1000 | -05,59mm | 101001000100 | 549 |
1110 0101 0010 0000 0000 1000 | -11,91mm | 111001010010 | 1191 |
On voit rapidement que la valeur binaire correspond à la mesure *100. On à le nombre de centièmes de mm.
On est donc précis à 0.01 mm près soit 10µm.
Décodage en mode impérial (US ?)
Le décodage est acquis je me focalise sur les correspondance entre l'entier transmis et la valeur affichée.
Mesure affichée | Valeur binaire
12 premiers bits |
---|---|
0 in | 0 |
0.1445 in | 289 |
0.0025 in | 5 |
0.1715 in | 343 |
0.277 in | 554 |
0.0245 in | 49 |
0.267 in | 534 |
C'est moins évidant (c'est toujours bizarre avec les unités impériales).
La représentation "XY" nous donne l'équation : mesure=valeur*0,0005
En gros on divise par 2000. on a le nombre de 1/2000 de pouces de la mesure. Quand je vous disais que les anglais étaient bizarres dans leurs unités.
On est précis à 1/2000 de pouces soit 25,4/2000 soit 0.0127 mm ou 12.7 µm. Il vaut mieux travailler en mm car les unités impériales semblent être des interpolations!
Conclusion
Dans la doc sur Amazon on a :
Déjà "Porta A" je ne comprends pas bien ce que ça veut dire mais RS232 c'est archi faux. Les signal est pas du tout compatible UART et pas non plus en niveaux -12/+12V (ni 0/5V).
En revanche "Porta B" c'est bien un emplacement pour une pile LR44 !
Le hardware nécessaire
Les niveaux
On a vu que les signaux si=ont entre 0 et1.6 V max (si le pile est neuve mais à 1.2V le comparateur marche encore).
Pour un microcontrôleur classique (ex ESP32) on a les valeurs limites haut bas suivantes:
Si on compare ça avec le signal issue du comparateur on à
On voit bien que le niveau "haut" du signal reste bien en dessous du minimum du niveau bas de l'ESP 32. (1.6 < 2.4).
Il faut donc amplifier ce signal. Certains utiliseraient des transistor MOSFET mais, je maitrise mal le sujet, je n'en ai pas en stock. En revanche j'ai des transistors bipolaires et c'est assez facile a gérer.
L'électronique
J'ai fait le petit schéma :
Riens de complexe, deux transistors NPN montés utilisé en mode saturé/bloqué.
On fait un PCB:
J'ai fais des grosses traces et des pads éloignés car je veux utiliser ma CNC pour faire le travail.
Le PCB usiné (il faudrait que j'affine mes paramètres de coupe car c'est un peu brutal)
Avec les composants.
Les mesures
Si on compare l'entrée à la sortie
Le signal d'entrée (0-1,6V) est bien transformé en signal entre 0 et 3.3V.
Attention cependant on a utilisé un transistor NPN le signal est inversé. Il faudra en tenir compte dans le logiciel!
Visualisation clock + data
En entrée
En sortie
On a bien une mise à niveau et une inversion du signal.
Logiciel
J'ai choisi de développer une application simple pour ESP32 (avec l'IDE Arduino).
On à trois tâches à réaliser :
- Détecter le début d'une "frame" sur la "clock"
- Lire la valeur de la broche "data" pour chaque front montant de clock.
- Décodage des bits acquis en en données réelles.
Logic 1 = clock inversée par un transistor NPN
Logic 0 = data inversée par un transistor NPN
Logic 2 = Décodage de la "frame"
Logic 3 = Lecture de la valeur "data" sur chaque front montant de la clock (le front descendant de la clock à travers le NPN)
// Analyse comparator signal
// processing in µs on uint32_t integer
// 4 294 967 296 µs
// 4 294.967296 sec
// 1:11:34 so after 1 hour needs to reboot
// Related to https://knowledge.pinon-hebert.fr/index.php/Comparateur_Num%C3%A9rique
const int clk = 32;//32;
const int dat = 33;
//const int clk_out = 23; // to monitor clock signal
const int frame_out = 22; /// frame detection
const int dat_out=21; // data decode
#define TRUE 1
#define FALSE 0
#define REVERSE // Defined if input signal needs to be inverted (needed if level adaptation done with NPN)
// ANALYSE THE CLOCK SIGNAL
uint32_t event_fall; // timestamp of the last falling edge
uint32_t time_low; // duration of last low level (between falling and rising edge)
uint32_t event_rise; // tlmestamp of the last rising edge
uint32_t time_high; // duration of the last high levet (between rising and fallin edge)
uint32_t event_change;
uint32_t period;
int bit=-1;
uint8_t bitFrame[24];
uint8_t measure[24];
int state;
inline int getClkState(){
#ifdef REVERSE
return (!digitalRead(clk));
#else
return (digitalRead(clk));
#endif
}
inline int getDatState(){
#ifdef REVERSE
return (!digitalRead(dat));
#else
return (digitalRead(dat));
#endif
}
void IRAM_ATTR clk_rise(){
state=HIGH;
event_rise=micros();
int value=getDatState();
time_low=event_rise-event_fall;
if (bit>=0){
bitFrame[bit]=value;
bit++;
bit%=24;
}
if (bit==0){
memcpy(measure,bitFrame,24);
}
digitalWrite(frame_out,(bit==0));
digitalWrite(dat_out,value);
}
void IRAM_ATTR clk_fall(){
state=LOW;
event_fall=micros();
time_high=event_fall-event_rise;
}
void IRAM_ATTR clk_CHANGE() {
uint32_t ti=micros();
period=ti-event_change;
event_change=ti;
if(getClkState()){
return clk_rise();
}else{
return clk_fall();
}
}
void printMeasure(){
int i;
// Décode mesured value
int val=0;
for (i=11; i>=0; i--){
val<<=1;
val+=measure[i];
}
if (measure[20]==HIGH){
val=-val;
}
// convert regarding the system (metric vs US)
float fval;
if (measure[23]==HIGH){
fval=float(val)/2000.0;
Serial.println(fval,4);
}else{
fval=float(val)/100.0;
Serial.println(fval,2);
}
}
void setup() {
Serial.begin(115200);
pinMode(clk, INPUT_PULLUP);
pinMode(dat,INPUT_PULLUP);
pinMode(frame_out,OUTPUT);
pinMode(dat_out,OUTPUT);
digitalWrite(frame_out,LOW);
digitalWrite(dat_out,HIGH);
Serial.println("\nInit interuption");
state=getClkState();
attachInterrupt(clk,clk_CHANGE,CHANGE);
Serial.println("Sync");
while (time_high<100000){
}
bit=0;
Serial.println(getClkState());
Serial.println("Ready");
}
void loop() {
delay(100);
printMeasure();
}
Explication :
Les constantes
- Lignes 5 à 10 définitions des broches GPIO
- Ligne 14 on défini REVERSE si le signal est inversé en entrée ce qui est la cas avec notre montage à transistors NPN.
Les variables
- Lignes 18 à 25 des entiers non signés sur 32 bits qui servent a mémoriser les "timestamps en microsecondes" des derniers événements (rise, fall, change) et la durée des états HAUTS BAS et la dernière période.
Attention dans ce code on ne gère pas le cas ou la valeur du timestamp en microsecondes va repasser à zéro. Apres 4 294 967 296 µs soit 1h11 notre programme va planter! |
- Ligne 29 et 30 le cadre de décodage (buffer et pointeur)
- Ligne 31 la variable décodée (double buffering)
- Ligne 33 l'état de la ligne à un instant donné.
Le code
- Lignes 35 à 49 gestion de la lecture de la valeur des deux lignes. Prends en compte la constante REVERSE (gestion du transistor NPN)
- Lignes 51 à 66 : C'est l'une des deux fonctions primordiales. C'est une interruption matérielle appelée à chaque changement d'état de CLK.
- Elle "remplis" le buffer bit après bit à chaque front montant du signal du comparateur (attention NPN)
- Lorsque une "frame" est pleine on la transfère dans le buffer de lecture
- Accessoirement (lignes 64 et 65) on mets a disposition les signaux décodés sur des deux GPIO
Les étapes suivantes...
Maintenant il faut écrire un programme pour un microcontrôleur quelconque (Arduino, ESP32... je ne sais pas encore) pour décoder ce signal et l'envoyer sur un écran et surtout sur l'UART.
Ensuite il faudra usiner un connecteur "maison" pour pas être obligé de démonter un comparateur à chaque fois.
Et... le top du top, écrire une programme pour piloter une CNC 3018 et sortie un fichier "heigth" pour corriger les erreurs de planéité.