micros() dans un intterupt (ISR)

Bonjour,

J'a un bont qui est connectée a une pin de mon microprocesseur.

J'utilise ceci pour que d'est que mon bouton est pressé,

attachInterrupt(MO_BTN_INTERRUPT, sosBtnIinterrupt, FALLING); // TRY LOW or FALLING

la fonction sosBtnInterrupt() soit appelée.

Le premier problème, la fonction ISR sosBtnInterrupt() est très souvent appelée sans que j'aie appuyé sur le bouton. Je pense que c'est le cas du Bouncing car je n'ai pas encore mis de condensateut en paralélle avec le bouton poussoir.

A la limite ca c'est pas encore grave.

Voici mon code (c'est du debugage pour comprendre)

void sosBtnIinterrupt() //attachInterrupt
{
  unsigned long last_time_btn = micros();
  unsigned long time_micro;
 
  sprintln(F("\n** btn Bounce **"),0);

  time_micro = (long)(micros() - last_time_btn);

  Serial.print(F("Con tim 1: "));
  Serial.println(time_micro);

    do
    {

        time_micro = (long)(micros() - last_time_btn);
        Serial.print(F("Con tim 2: "));
        Serial.println(time_micro);
      
      
      
     }while(digitalRead(PIN_BTN) == 0 && time_micro < 1500);
     
     Serial.print(F("Con tim 3: "));
     Serial.println(time_micro);
     
     
  if(times > 1000)
  {
    interrupt(); 
  }
      sprintln(F("===================\n"),0);
};

void interrupt(){
  sprintln(F("Do somthing"),0);
}

quand je n'appuye pas sur le bouton, j'ai ceci:

** btn Bounce **
Con tim 1: 99
Con tim 2: 217
Con tim 3: 217

Si j'appuye sur le bonton j'ai ceci

** btn Bounce **
Con tim 1: 84
Con tim 2: 205
Con tim 2: 323
Con tim 2: 439
Con tim 2: 619
Con tim 2: 741
Con tim 2: 859
Con tim 2: 977
Con tim 2: 1100
Con tim 2: 1217
Con tim 2: 1334
Con tim 2: 1453
Con tim 2: 618
Con tim 2: 738
Con tim 2: 855
Con tim 2: 974
Con tim 2: 1097
Con tim 2: 1220
Con tim 2: 1338
Con tim 2: 1456
Con tim 2: 622
Con tim 2: 739
Con tim 2: 854
Con tim 2: 973
Con tim 2: 1090
Con tim 2: 1207
Con tim 2: 1323
Con tim 2: 1438
Con tim 2: 617
Con tim 2: 734
Con tim 2: 852
Con tim 2: 972
Con tim 2: 1093
Con tim 2: 1211
Con tim 2: 1328
Con tim 2: 1445
Con tim 2: 616
Con tim 2: 732
Con tim 2: 849
Con tim 2: 966
Con tim 2: 1081
Con tim 2: 1196
Con tim 2: 1314
Con tim 2: 1435
Con tim 2: 616
Con tim 2: 732
Con tim 2: 850
Con tim 2: 965
Con tim 3: 1082

Premièrement, je ne comprends pas pourquoi, il n'incrémente pas correctement et il n'atteind jamais le seuil de 1500.

Le but de l'exercie est que si le bouton est appayé entre 1seconde il affiche

Do something

Donc pour éviter le Bouncing, je devrais mettre un condensateur, mais j'aimerais bien comprendre pourquoi, je n'arrive pas à incémenter 0Con tim 2:' pour que si le bouton est appuyé 1 seconde, il affiche une action à faire.

Voyez-vous?

Pierre

pierrot10:
Le premier problème, la fonction ISR sosBtnInterrupt() est très souvent appelée sans que j'aie appuyé sur le bouton. Je pense que c'est le cas du Bouncing car je n'ai pas encore mis de condensateut en paralélle avec le bouton poussoir.

Bonjour,

Il n'y a pas de rebonds spontanés. Les rebonds se produisent lorsqu'on appuie ou relache le bouton poussoir.
Il y a bien une résistance de pullup ou pulldown?

Hello, alors je dois avoir un petit problème :confused:

Il n'y a pas de rebonds spontanés. Les rebonds se produisent lorsqu'on appuie ou relache le bouton poussoir.

Oui c'est bien ce qu'il me semblait

Oui il y a bien une resistence de 10k qui met la pin à 1

Voici le schema. Regarde uniquement les fils oranges (pin 2 (3)). La pin 1 de la résistence est elle connectée à de 3.3V. Attention, le concensateur C3, n'est pas sur le circuit. Je l'ai ajouté au schema après l'impression du PCB. Il y sera sur le prochain PCB.

Aussi, ce matin, je pensais à un truc. J'aimerais pouvoir savoir le temps que le bouton est pressé.
Il semble que millis() et micros() n'aime pas trop les interrupt. Je me demandais si je pouvais calculer le temps avec une variable qui incrémente (int inc=0; inc++) le temps que le bouton est pressé. OK, ca ne me retournra pas une valeur de temps (sec, mn.), mais si je sais à quelle vitesse tourne mon MicroControlleur (ATSAMD21G18 @ 48MHz with 3.3V logic/power), es-ce que je peux savoir combien d'incrémentation, il y a en 1 sec? (sachant que c'est une loop qui tourne et qu'il y a aucun code dans la loop, sauf le inc++)

C'est bizarre qu'il y ait des interruptions parasites avec un pullup de 10k. Le bouton est cablé loin du connecteur?

Il n'y a pas de problème pour utiliser millis() ou micros() pour mesurer le temps; Par contre bien sur il ne faut pas boucler dans l'interruption.

Il faut que je vérifie mon code et mes connections. C'est en effet bizzrad car je n'avais pas ces interruptions sans que j'appuye sur le bouton.
Il faut que je vérifie avant. Merci pour ton aide, je regarderai ce soir ou demain.

Il n'y a pas de problème pour utiliser millis() ou micros() pour mesurer le temps; Par contre bien sur il ne faut pas boucler dans l'interruption.

Question :
Comment sont gérés les débordements du compteur du timer ?

Je n'ai pas la réponse, je soulève seulement le point.

Comme on va faire une différence d'unsigned long, même s'il y a débordement le résultat sera juste.
Bien sur il ne faut pas qu'il y ait eu 2 débordements.
Comme micros() déborde au bout de 1h11mn et qu'il s'agit de mesurer le temps d'appui sur un bouton, on peut penser que l'opérateur aura eu une crampe avant le 2eme débordement. :slight_smile:
Si on utilise millis(), alors il faut attendre 49 jours en appuyant sur le bouton.

Comme micros() déborde au bout de 1h11mn et qu'il s'agit de mesurer le temps d'appui sur un bouton, on peut penser que l'opérateur aura eu une crampe avant le 2eme débordement

:smiley: :wink: :grinning: :grin:

J'aimerais juste encore ajouté que millis() n'incrémente pas dans une fonction ISR.

Generally, an ISR should be as short and fast as possible. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be executed after the current one finishes in an order that depends on the priority they have. millis() relies on interrupts to count, so it will never increment inside an ISR. Since delay() requires interrupts to work, it will not work if called inside an ISR. micros() works initially, but will start behaving erratically after 1-2 ms. delayMicroseconds() does not use any counter, so it will work as normal.

UNE ISR DOIT ETRE LE PLUS COURTE POSSIBLE.
Mills() s'incrémente correctement pour peu que l'isr ne dure pas trop longtemps (temps inférieur au temps de débordement du timer utilisé par millis (1ms environ)).
On n'utilise pas millis() pour mesurer le temps dans l'interruption, mais entre deux interruptions.

D'accord, c'est très intéressant, ta remarque.

En fait je devrait faire comme ceci

attachInterrupt(MO_BTN_INTERRUPT, sosBtnIinterruptF, FALLING); // TRY LOW or FALLING
attachInterrupt(MO_BTN_INTERRUPT, sosBtnIinterruptR, RISNG); // TRY LOW or FALLING

(Pour autant qu'il y a un deboncing sur le bouton)

volatile int btnPressed;
volatile int btnTime;
sosBtnInterruptF()
{
btnPressed = millis();
}

sosBtnInterruptR()
{
int btnReleased = millis();
btnTime = btnReleased - btnPressed;

}
Et là, j'ai mon temps!
N'es-ce pas.

(J'ai pas mon module avec moi, je ne peux pas tester...)

Oui, sauf que je ne pense pas qu'on puisse mettre deux routines d'interruption sur la même entrée.
Il faut faire un attachInterrupt(...,...,CHANGE);
Puis dans l'interruption on teste l'entrée
Si elle est à 1 on mémorise de debut,
Si elle est à 0 on calcule la durée (inverse si logique négative)

D'accord, je vois. Merci, je vais essayer tout ca!!! Milles mercis!

kamill:
Comme on va faire une différence d'unsigned long, même s'il y a débordement le résultat sera juste.
Bien sur il ne faut pas qu'il y ait eu 2 débordements.

Je pense qu'on ne s'est pas compris :
Ce que j'ai dans la tête :
Quand il y a débordement il y incrémentation d'une ou plusieurs variables pour qu'avec un simple timer 8 bits on puisse compter jusqu'à plusieurs dizaines de jours.

Est-ce que cette incrémentation n'est pas déclenchée par une interruption interne au timer ?

Bien sûr il y a des ordres de priorité dans les interruptions.
Sûrement les interruptions timer sont bloquées par une interruption intx mais dans ce cas la valeur renvoyée par milli est fausse d'un point de vue "mathématique" mais peut-être suffisante d'un point de vue "physique".

Et peut-être que je me fais des nœuds au cerveau pour rien.

Si on parle de millis() c'est géré par un compteur soft qui est incrémenté toutes les mS (environ) sur interruption timer. Donc si le traitement de l'interruption dure plus de 1ms, on a des (mal)chances de perdre des ms dans millis (si le traitement de l'it dure plus de 2ms on est sur d'en perdre).
C'est pour ça (entre autres) que le traitement d'interruption doit être le plus court possible.
On peut aussi reautoriser les interruptions dans l'interruption, mais la il faut bien faire attention à ce qu'on fait et aux effets de bord.

Donc si le traitement de l'interruption dure plus de 1ms, on a des (mal)chances de perdre des ms dans millis (si le traitement de l'it dure plus de 2ms on est sur d'en perdre).

Ou si on tombe pile au mauvais moment pas besoin que l'interruption dure plus de 1 ms.
Le pas avec 16 MHz système est de 62,5 ns.

Ce n'est pas la peine de se mettre martel en tête mais pour des temps à connaître avec précision autant ne pas avoir une confiance aveugle.

Si l'interruption dure moins que 1ms, on est sur que l'interruption timer ne sera pas perdue, car même si elle n'est pas traitée immédiatement elle est mémorisée et sera bien traitée dès que les it seront réautorisées.

car même si elle n'est pas traitée immédiatement elle est mémorisée

C'est une information que je ne connaissait pas.