Problème de mesure d'un temps sur arduino uno

Bonjour, le problème est un peu complexe et je ne sais pas si il a déjà été posté sur le forum.

J'essaies de faire un détecteur d'ondes sismiques pour des tp de lycées. L'idée est d'avoir une barre d'une roche, placer deux capteurs piézoélectrique, un à la fin et l'autre au début de la barre, puis de donner un coup sur l'une des extrémités et mesurer le temps de propagation de l'onde pour calculer la vitesse de propagation de l'onde.

Seulement voilà, je débute avec l'arduino et je n'ai pas encore tout bien acquis par rapport à la gestion du temps dans les programmes.

Voici mon code : (ne faites pas attention aux commentaires, ils sont juste là pour faire des mesures si besoin)

#define piezo1 3
#define piezo2 0
int value1 =0;
int value2 = 0;
int max1 = 0;
int max2 = 0;
int seuil = 10;
long t1=0;
long t2=0;
long tf=0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  value1=analogRead(piezo1);
  value2=analogRead(piezo2);
  
  
  //Serial.println(value1,DEC);
  if (value1>seuil)
  {t1=micros();
  //Serial.print("capteur 1 : ");Serial.println(value1,DEC);
  }
  if (value2>seuil)
  {t2=micros();
  //Serial.print("capteur 2 : ");Serial.println(value2,DEC);
  }
  if(t2>0 and t1>0)
  {tf=t1-t2;tf=abs(tf);Serial.print("temps écoulé entre les deux détections (en microsecondes) : ");Serial.println(tf,DEC);tf=0;t1=0;t2=0;}
}

Quand je l'éxecute sur l'arduino (arduino uno, clock interne de 16MHz), les valeurs obtenus ne sont pas les bonnes. J'obtiens presque toujours des multiples de 224, peu importe la position des capteurs sur la roche, le problème ne peut donc pas venir du dispositif expérimental (j'ai déjà changé la roche et la position des capteurs sur celle ci), il vient donc du code.

Je voudrais donc savoir d'où le problème pourrait venir, mes pistes pour l'instant sont :

  • le code, comme je l'ai dit je débute, la gestion du temps dans le programme n'est certainement pas la meilleure.

  • le matériel, les temps à mesurer tourne dans les 17 microsecondes et je me dis que le problème vient peut être de la fréquence de l'arduino.

Voilà, désolé du pavé et merci d'avance de l'aide que vous pourrez m'apporter.

utilisez des unsigned long pour stocker le temps

ensuite le piezo 1 risque de continuer à déclencher pendant un petit moment. Il ne faudrait plus le lire tant que vous n'avez pas reçu le signal sur le piezo2

enfin, et c'est un gros problème, chaque analogRead() prend longtemps... 100 microsecondes donc c'est un souci si vous voulez en mesurer 17...

en 17 micro-secondes votre arduino ne peut faire que 272 instruction de base.. c'est peu pour faire du monitoring. il faudrait que l'impulsion initiale soit déclenchée par l'Arduino (par exemple c'est vous qui activez électriquement le premier piezo) et ensuite il faudrait que le captage du signal de l'autre côté déclenche une interruption sur un front rapide et utiliser les timers...

ça me semble complexe surtout pour la partie réception du signal et déclenchement.

hello, une idée:
D2 et D3 declarées en interruptions
piezzo 1 sur D2
piezzo 2 sur D3
D2 declenche le timer 1 TCCRB1 =0b00000001 (en one shoot ( par flag))
D3 le stoppe TCCRB1=0b00000000 (en one shoot (par flag))
ensuite, tu fais la conversion de TCNT1 en micros . TCNT1*0.0625

juste une idée, pas testé

EDIT: après tests, c'est OK

Cela devrait pouvoir fonctionner. Il faut aussi savoir qu'une fonction d'interruption dure au moins 4µs (le temps de sauvegarder les registres et de les restituer), mais avec deux appels, cela doit se compenser. Il faut aussi pour faire la mesure arrêter le timer 1 qui de temps en temps bloque tout pendant 6µs.Il faut aussi savoir que lorsqu'une interruption se présente, il faut finir l'instruction en cours avant de la traiter. Une instruction dure de 1 à 3 cycles d'horloge (1 cycle dure 0,0625µs). Il peut donc y avoir une différence jusqu'à 6 cycles entre deux mesures suivant où ont lieu les interruptions.

Tout dépend de le précision qui est voulue.

Une recherche basique avec Duck Duck Go donne plusieurs liens qui délivrent l'information pour ce type d'exercice qui semblent fréquents dans les Lycées.

La plupart proviennent de site de l'éducation nationale et parlent de cours de SVT niveau classe de première.

Merci de ta réponse, je suis entrain d'essayer de l'appliquer mais je dois déjà comprendre ce à quoi les interruptions correspondent et comment déclencher les timers mais je devrai m'en sortir.

parfait si tu t'en sors
en cas contraire, n'hésites pas à revenir, nous t'aiderons avec plaisir

Bon, j'ai manipulé un peu les interruptions, je pense tenir quelque chose mais quand j'exécute le programme sur mon arduino je n'ai aucune réponse, le temps souhaité ne s'affiche pas, voici le nouveau code :

const byte PIEZO1 = 2;
const byte PIEZO2 = 4;
long time1 = 0;
long time2 = 0;
long elapsed_time = 0;
//volatile TYPE time = null; 
void setup() {
  // put your setup code here, to run once:
  // setup PIEZO1 pin to interrupt on falling edge
  Serial.begin(9600);
  pinMode (PIEZO1,INPUT);
  attachInterrupt(digitalPinToInterrupt(PIEZO1), interruptpiezo1, FALLING);
  // setup PIEZO2 pin to interrupt on falling edge
  pinMode (PIEZO2,INPUT);
  attachInterrupt(digitalPinToInterrupt(PIEZO2), interruptpiezo2, FALLING);
 /* bitClear (TCCR2A,WGM20);
  bitClear (TCCR2A,WGM21);
  TCCR2B = 0b00000110;
  TIMSK2 = 0b00000001;
  TCNT2 = 256 - 250;*/
  }
// byte varCompteur = 0;

// function to call in attachInterrupt, must not take any params and return void
void interruptpiezo1() {
  // pseudo code to take time
  time1 = micros();
}

// function to call in attachInterrupt, must not take any params and return void
void interruptpiezo2() {
  // pseudo code to calculate elapsed time between the 2 interrupt
  time2 = micros();
  elapsed_time = time2 - time1;
  Serial.print(elapsed_time);
  time1 = 0; time2 = 0; elapsed_time=0;
}
void loop() {
  // put your main code here, to run repeatedly:
}

J'ai aussi essayé un peu les timers mais je me suis dit qu'avec micros() je pourrai peut être y arriver. Ducoup je me demandais d'où pouvait venir le problème qui m'empêche d'avoir un résultat, si j'avais bien utilisé les interruptions et si je peux m'en sortir sans les timers :slight_smile: Merci de vos réponses.

Bonjour
je vais lire mieux plus tard
Mais attention à une chose : la vitesse du son selon les milieux traversés n'est pas homogénes et en tous cas différentes de celle de l'air.

un defenseur du clacos de tradition :innocent:

Oui je sais, dans la barre testé je dois trouver une vitesse de 3.1 km/s, dans mon cas un temps de 38 microsecondes. Et ce n'est pas la vitesse de son mais de propagation, mais c'est du détail ça :slight_smile: . Le problème c'est qu'en l'état, l'arduino ne me renvoies rien, pas de temps écoulé.

hello
_est tu sur de déclencher tes interruptions?
_quel signal sort des piezzos?
_quelle est l'amplitude de ces signaux?
_tes interruptions déclenchent sur flancs descendants(est ce le bon choix). donc tu pouvais valider les résistances de pull up.
_dans isr1 tu devrais déclencher le TIMER1 et le stopper dans isr2. puis tu fais les comptes

Après 2/3 tests, le signal des deux piezo est capté, mais la 2ème interruption (celle lié au capteur 2) ne se déclenche pas. La première interruption se fait sans problème. Je ne vois pas la différence entre le lancer sur le front descentant ou ascendant du signal tant que les 2 ont le même déclencheur, mais je ne sais pas non plus ce que tu veux dire pas les résistances pull up, c'est peut être pour ça.
Enfin, je n'ai pas réussi à trouver comment tu enclenches le début d'un timer dans une interruption, j'ai trouvé comment les initialiser mais pas comment les déclencher, si tu as un exemple ou un lien je suis preneur.

hello
voici le prg avec lequel j'ai testé ( avec un generateur de fréquences à la place des piezzos

#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 unsigned long duree_propagation = 0;//

void setup() {
  Serial.begin(115200);
  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 = 0b00000001;//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;}}
void ISR_piezzo_2(){if (flag_2){TCCR1B = 0b00000000;flag_2=false;}}
void loop() {
  //Serial.println (TCNT1);
  if ((!flag_1)&&(flag_impression)){flag_impression=false;Serial.print("falg_1 = false ");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); 
  duree_propagation = (nombreCycles * 4096) + (ICR1 * 0.0625) +((nombreCycles*96)*0.0625);//resultat en micro secondes
  Serial.print(duree_propagation);Serial.print("µ 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
  
  nombreCycles=0;TCNT1=0;flag_impression=true;flag_1=true;flag_2=true;
  
  sei();
  }
}

Bonjour,

Avant de vouloir mesurer le temps entre deux signaux, il faudrait commencer à voir à quoi ressemblent ces signaux.
Est ce que tu les as regardé à l'oscillo? Est ce que le signal est suffisant pour déclencher l'interruption (mais pas trop fort pour ne pas détruire les entrées)?

Je viens de l'essayer, et à chaque fois que je le lance, et que je fais la manip, il me renvoie toujours un temps de 0 micros, pour être plus précis :
falg_1 = false 304
nb cycles overflow timer1 = 0
TCNT1 de timer1 = 304
Il me renvoie ceci (puis la requête du bouton poussoir).
J'ai essayé avec les deux interruptions (rising et falling) mais ça ne change pas le problème :confused: Mais ducoup je comprends mieux les timers c'est déjà ça :smiley:

Bonjour, je n'ai pas d'oscillos que je peux utiliser pour vérifier ça. J'ai cependant pu vérifier que les 2 interruptions pouvaient être enclenché. pour ce qui est de la sécurité des entrées, j'ai placé deux résistances (une sur chaque piezo) d'1MOhm pour ne pas griller les entrées.
Je suis pas sûr d'avoir répondu à ce que tu me disais, mes connaissances en électronique datent un peu.

Ils sont fixés et connectés comment ces piezos il y a une R d'amortissement ? (ref des piezo) ? ?

Que donne un test simple consistant simplement à logger en Int la valeur de micros() au moment des interruptions 0 et 1 piezo A et B en frappant la "pierre" avec un marteau ?
Il faut prendre en compte le temps de conversion AD qui est trés long devant la resolution demandée

Les piezos sont branchés en parallèle de la résistance, pour la ref je n'ai que le sachet, il est écrit 724-3162, Piezo 15 Vac.
Je n'ai pas été amené à faire ce test, mais le temps de conversion ne peut il pas être ignoré vu qu'il est utilisé deux fois de suite ?
Dis moi si je n'ai pas été clair.

un piezo va produire lorsqu'il est sollicité plusieurs "pics" de déclenchements

essaie de faire un petit programme test prenant simplement en compte sur IT la valeur de micros() pour INT0 et INT1 et sort les valeurs sur un timeout de l'ordre de 5 secondes , ce qui te laisse le temps de frapper la "pierre"

Piezo solidarisé comment sur la pierre ?

Comme je suis actuellement en train de jouer avec avec des micros mems et des equipements US
Jj'ai fais une rapide manip avec un petit analyseur logique Saleae clone

Pour (dé)passer la barrière du trigger High, il faut vraiment solliciter l'element piezo :
exemple de "tapotage" du piezo avec un marqueur.

Il ne faut pas oublier que ces composants sont trés selectifs en fréquence/résonance