Bonjour a tous, je travailles actuellement sur mon TIPE, celui-ci porte sur la conception d'un anémomètre à ultrasons. Pour cela je dois déterminer des intervalles de temps très courts pour en déduire la vitesse du vent. (<4microsecondes).
J'utilise actuellement la fonction micro() mais ça précision n'est pas suffisante (+/- 10m/s pour le calcul final). Je voudrais donc savoir s'il existe une fonction encore plus précise qui me permettrait d'améliorer cela. J'utilise une carte arduino UNO.
J'ai la possibilité de changer carte (achat par le lycée) mais je veux être sûr que cela fonctionne avant de commander.
Merci d'avance pour vos réponses
hello
je viens de tester avec une UNO et l'entrée de capture d'évenement.
le mieux que je réussi à faire, d'une façon fiable, c'est à une fréquence de 100KHz
et le micro ne fait rien d'autre pendant l'acquisition.
peut etre avec deux interruptions, une en RISING et l"autre en FALLING et celle en FALLING n'étant autorisée que si celle en RISING à été déclenchée, à voir...........
je ne connais pas assez les esp32 pour te dire s'ils peuvent le faire, ils sont cadencés plus vite qu'une UNO.
attendons de voir ce que les copains vont dire.
tests fais avec un générateur de fonctions en signal carré à 100.0 KHz
raccordé sur D8 du uno et les masses ensemble.
le code: tu téléverses et tu ouvres le moniteur. et tu attends......
//mesure la période d'un signal sur l'entrée D8
//143KHz maxi. periode mesurée = 7µS
#define debut_evenement 8//entree pour debut et fin evenement à chronometrer
byte flag_impression = true; //pour un seul serial print
volatile unsigned long nombre_cycles = 0;//avec le prescaler du timer1 à 1, un cycle dure 4096 µ
//volatile float duree_propagation = 0.0;//
volatile byte compteur = 0;
//volatile float date_evenement = 0.0;
//volatile float memo_evenement = 0.0;
int seuil = 10;
unsigned long chrono[100][2];
unsigned long duree_[100];
void setup() {
pinMode(debut_evenement, INPUT_PULLUP);
// pinMode(fin_evenement, INPUT_PULLUP);
Serial.begin(500000);
Serial.println(__FILE__); Serial.println("");// chemin
Serial.println("systeme acquisition en one shoot par arret sur while(1)");
cli();
TCCR1A = 0;
TCCR1B = 0b00000001;//le timer1 démarre, il sera lu à la volée. prescaler 1, ICES1 bit6 evenement falling sur D8
TIMSK1 = 0b00100001;//autorise l'interruption de capture sur ICP1 (PB0 soit D8)sur flanc descendant
TCNT1 = 0; //tampon de comptage est razé
ICR1 = 0; //valeur du tampon de comptage sur arret du timer1
sei();
}
ISR(TIMER1_OVF_vect)//à chaque debordement du timer1
{
nombre_cycles++;
}
ISR(TIMER1_CAPT_vect) // capture ( recopie) TCNT1 dans ICR1 sur evenement en PB0 ( D8)
{
chrono[++compteur][0] = ICR1;
chrono[compteur][1] = nombre_cycles;
//TCCR1B = 0b01000001; //declenchera sur flanc montant
}
void loop()
{
if ((compteur >= seuil) && (flag_impression))
{ TCCR1B = 0b00000000;//arret du timer
// for (int f = 0; f <=seuil; f++)
// { Serial.print((chrono[f][0]));Serial.print("\t");Serial.print((chrono[f][1]));
Serial.println("");//}
for (int f = seuil - 1; f > 1; f--)
{
double millis_=(((chrono[f + 1][0] * 62.5 + chrono[f + 1][1] * 4096000) - (chrono[f ][0] * 62.5 + chrono[f][1] * 4096000)) / 1000000);
Serial.print(millis_);Serial.print(" milli secondes");Serial.println("\t");
double micro=(((chrono[f + 1][0] * 62.5 + chrono[f + 1][1] * 4096000) - (chrono[f ][0] * 62.5 + chrono[f][1] * 4096000)) / 1000);
Serial.print(micro);Serial.print(" micro secondes");Serial.println("\t");
double nano=(1*(((chrono[f + 1][0] * 62.5 + chrono[f + 1][1] * 4096000) - (chrono[f ][0] * 62.5 + chrono[f][1] * 4096000)) ));
Serial.print(nano);Serial.println(" nano secondes");
Serial.print(F("frequence = "));Serial.print(1000000000/nano);Serial.println(" Hertz");
Serial.flush();
//while(1);
flag_impression = false; //flag1 = false;
}while(1);
}
}
voici le deuxième code dont je te parlais plus haut.
deux générateurs qui ne sont pas synchronisés...
1 à 10 KHz, l'autre à 100KHz les deux en signal carré.
le programme à capturé 6.5µs, mais bien évidement, c'est du hasard, puisque les générateurs ne sont pas synchro. mais ça prouve que le principe est capable de capturer 6.5µS.
#define piezzo_1 2//INT0
#define piezzo_2 3//INT1
byte flag_1 = true;//un seul passage en INT0 sert de filtrage, déclenchera sur le 1er signal d'une onde
byte flag_2 = true;//un seul passage en INT1 sert de filtrage, déclenchera sur le 1er signal d'une onde
byte flag_impression=true; //pour un seul serial print
volatile unsigned long nombreCycles = 0;//avec le prescaler du timer1 à 1, un cycle dure 4096 µ
volatile float duree_propagation = 0;//
void setup() {
Serial.begin(500000);
Serial.println(__FILE__); Serial.println("");// chemin
Serial.println("systeme acquisition en one shoot par arret sur while(1)");
cli();
TCCR1A = 0;
TCCR1B = 0b00000000;//le timer1 est à l'arret
TIMSK1 = 0b00100001;//autorise l'interruption de dépassement
TCNT1 = 0; //tampon de comptage est razé
ICR1 = 0; //valeur du tampon de comptage sur arret du timer1
pinMode(piezzo_1,INPUT_PULLUP);//en fonction du signal
pinMode(piezzo_2,INPUT_PULLUP);//en fonction du signal
attachInterrupt(0,ISR_piezzo_1,FALLING);//declenchera sur flanc descendant
attachInterrupt(1,ISR_piezzo_2,FALLING);//declenchera sur flanc descendant
//pinMode(piezzo_1,INPUT);//en fonction du signal
//pinMode(piezzo_2,INPUT);//en fonction du signal
//attachInterrupt(0,ISR_piezzo_1,RISING);//declenchera sur flanc montant
//attachInterrupt(1,ISR_piezzo_2,RISING);//declenchera sur flanc montant
sei();
}
ISR(TIMER1_OVF_vect)//à chaque debordement du timer1
{
nombreCycles++;
}
void ISR_piezzo_1(){if (flag_1){TCCR1B = 0b00000001;flag_1=false;}}//prescaler /8 ==> 500 nano
void ISR_piezzo_2(){if ((flag_2)&(!flag_1)){TCCR1B = 0b00000000;Serial.print("ICR1 de timer1 = ");Serial.println(ICR1); flag_2=false;}}
void loop() {
//Serial.println (TCNT1);
if ((!flag_1)&&(flag_impression)){flag_impression=false;Serial.print("falg_1 = false, tcnt1 = ");Serial.println(TCNT1);}
if ((!flag_1)&&(!flag_2))
{cli();
Serial.print("nb cycles overflow timer1 = ");Serial.println(nombreCycles);
Serial.print("TCNT1 de timer1 = ");Serial.println(TCNT1);
Serial.print("ICR1 de timer1 = ");Serial.println(ICR1);
duree_propagation = (nombreCycles * 4096000) + (TCNT1 * 62.5) ;//+((nombreCycles*96)*0.0625);//resultat en micro secondes
Serial.print((duree_propagation/1000),3);Serial.println("µ Secondes");Serial.flush();
sei();
//while(1){Serial.println("attente appui BP (non programmé)");delay(10000);}//pour debug//attente appui sur un BP pour remttre flag_1 et flag_2 à true
delay(1000);
nombreCycles=0;TCNT1=0;flag_impression=true;flag_1=true;flag_2=true;
sei();
}
}
Sur un micro "rudimentaire" comme celui de la carte UNO la fréquence d'horloge veut dire quelque chose.
Sur les micros "modernes" 32 bits ARM ou Espressif c'est beaucoup moins simple.
Par exemple avec celui que j'utilise actuellement ESP32-C3 la vitesse d'horloge est 160 MHz : potentiellement 10 fois plus rapide que les 16 MHz de la Uno.
Sauf qu'à l'intérieur, il y a des diviseurs et les gpio sont pilotés par une horloge à 40 MHz.
Et c'est la même chose pour les fonctions périphériques.
Pour revenir au micro de la UNO l'atmega328p, les 4 microsecondes de pas de mesure ne sont pas une fatalité : c'est un choix fait par Arduino => compromis entre PWM, amplitude de comptage de micro et delay
Le diviseur (prescaler) du timer 0 a été réglé pour.
Si on lit le compteur d'un timer dont le diviseur (prescaler) à été réglé sur 1, il est possible de mesurer des temps de 62,5 ns (T = 1/F = 1/(16 MHz) ).
Je ne peux pas en dire plus. Je ne comprends pas suffisamment les mécanismes internes aux microcontrôleurs.
Méfis toi des délais de commande et de livraison.
hello
merci de la précision ![]()
On va bien être en dessous des 4µs, mais une interruption ne peut intervenir qu'à la fin d'une instruction. Et ces dernières durent 1 ou 2 périodes d'horloge. En conséquence la résolution est de 2 périodes d'horloge, soit 125ns.
Dans la question, il manque des données essentielles, si on mesure des impulsions:
- Combien de temps dure ces impulsions? si les impulsion sont courtes, on ne pourra pas armer le compteur de temps du dessus. Par contre c'est une méthode pour mesurer par exemple une impulsion qui dure entre 100µs et 200µs avec une résolution de 125ns
- Que mesure-t-on?
− une impulsion qui vient de l'extérieur
− la Uno délivre un signal de début et l'extérieur donne la fin (nettement plus facile)
Dans tous les cas, il faut éventuellement penser à arrêter l'horloge système pendant l'acquisition, l'interruption système peut rajouter des temps aléatoirement de l'ordre de 6µs
Hello
Merci de ces précisions ![]()
Il manque aussi la dynamique de la mesure, sa résolution et sa précision.
Je suis curieux de savoir quel calcul te porte à conclure que tu dois avoir une précision de 4 µs. Ca me semble vraiment très peu.
Principe de fonctionnement de l'anémomètre à ultrason
Avec un anémomètre à ultrason, la mesure du vent est basée sur la durée de déplacement d'une onde ultrasonore. Deux couples de transducteurs ultrasonores sont alternativement émetteurs et récepteurs d'un train d'onde ultrasonore. L'anémomètre à ultrason mesure les temps de transit aller et retour, et par déduction l'écart entre les vitesses aller et retour, la vitesse du vent le long de l'axe formé par les deux transducteurs. Pour affiner le résultat, l'anémomètre à ultrason mesure aussi la température ambiante.
Pendant 4 µs, un son se déplace de 1.2 mm (à 300m/s).
Le principe de mesure est décrit ici : https://www.rainbow.c2ai.com/uploads/catalogue/documents/produits/DeltaOhm/HD/MN/HD2003_1.0_En.pdf
Un calcul rapide (et peut-être complètement faux
) pour un écart de 10 cm fait qu'une mesure précise à 4µs permet de mesurer des vitesses proches de 3000 m/s !!!
hello lesept, notre ami parle d'ultrasons sans nous en donner la fréquence.
Rebonjour a tous, merci de vos réponse. J'apporte quelques précision en plus. Tout d'abord on émet un ultrason à une fréquence de 40 Khz, ce sont des salves de 0.5 ms, chaque fois qu'on émet une salve, on regarde la temps qui s'est écoulé entre l'émission et la réception de la salve (on a un émetteur et un récepteur qui se font face, l'émetteur est piloté par arduino et le récepteur envoie le signal sur l'arduino). comme on connait le temps de parcours de l'onde, on peut le comparer au temps de parcours qu'elle aurait du avoir s'il n'y avait pas eu de vent. [Vvent = (deltaTVson**2)/(distanceER-deltaTVson)]. avec cette formule, une distance de 20 cm entre l'émetteur et le récepteur, et une résolution de 4microsecondes, on a une résolution de 1,8 m/s et avec les fluctuations du à l'environnement, on a une mesure qui se trouve dans +/- 5*1,8m/s ce qui n'est vraiment pas très concluant pour notre projet, le seul moyen qu'on a trouvé pour l'instant pour améliorer la précision est d'espacer l'émetteur et le récepteur, ou de réduire la résolution du temps
avec un ESP32 , ça va pas être évident , mieux vaut un UNO pour faire ça
l'ESP32 , c'est de la merdre si on veut traiter du signal : la latence entre le déclenchement et le traitement des interruptions est longue et variable , entre 4 et 7us , voire + , et même beaucoup + si le RTOS en décide ainsi , ou si les lacunes de conception de l'interface wifi s'y mettent
la solution idiomatique pour ce type de mesure , c'est une entrée ICP , agrémentée d'un filtre digital ; l'ESP32 , n'en a pas (ni le Pi Pico)
maintenant , si ton anémomètre met 4us pour faire un tour , dis-moi dans quelle région tu vis , que je n'y vienne pas
Bonsoir,
Sauf erreur de ma part, mesurer des temps de commutation < 4µS est une hérésie sur un Arduino UNO qui plus est, écrit en Langage C et même en assembleur...
A voir tout de même avec un ESP32 cadencé à 240 Mhz, mais je préconiserais une acquisition en assembleur - cf. Optimisation d'une routine d'interruption AVR pour l'émulation d'une manette Genesis sur un Atmega8 cadencé à 16 MHz - très en dessous en terme de rapidité de l'ESP32 sus-cité ![]()
Une autre solution est de faire l'acquisition au travers d'un ou plusieurs registres à décalage comme le font les analyseurs logiques mais cela nécessite des compétences matérielles
A suivre...
Peut-être des pistes ici :
Nous sommes plusieurs à mesurer le temps des instructions sur Uno, donc avec une résolution de 62.5ns. Et je ne vois pas pourquoi une horloge à 8MHz ne mesurerait pas des temps à 62,5ns près, vue qu'elle est faite pour.
Dans le cas de notre ami @aweisse, C'est possible, vu que c'est l'Arduino qui donne l'ordre de départ. Et le langage n'a rien à voir la dedans car ce n'est pas le programme qui fait le comptage du temps, mais le hard spécifique.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.

