TIMER avec Arduino Leonardo

Bonjour,
J’ai un programme que je récupère et je que je souhaiterai faire marcher uniquement ISR(TIMER1_COMPA_vect) mais cela ne fonctionne pas. Le programme fonctionne uniquement avec ISR(TIMER1_COMPB_vect). Savez vous pour quelle raison. Merci d’avance de votre réponse.

volatile byte compteur=0;
void setup()
{
Serial.begin(115200);
startTimer1();
}

void loop()
{
}

void startTimer1()
{
const unsigned periodeA = 1000; // ms OCR1A doit etre sup à OCR1B
const unsigned periodeB = 1000; // ms OCR1B doit etre inf à OCR1A
cli();
TCCR1A = 0;
TCCR1B = _BV(WGM12) | _BV(CS12) | _BV(CS10);
TIMSK1 = _BV(OCIE1A) | _BV(OCIE1B);
TCNT1 = 0;
OCR1A = (((F_CPU / 1000 / 1024)) * periodeA);
OCR1B = ((F_CPU / 1000 / 1024) * periodeB);
sei();
}

ISR(TIMER1_COMPA_vect)
{
Serial.println(“A”);
}

ISR(TIMER1_COMPB_vect)
{
if (compteur++%2){Serial.println(“B”);compteur=0;}
}

Bonjour,
Serial.println(“A”);
Avec des guillemets inversés ça ne devrait pas compiler.

Je ne comprend pas ton problème, ISR(TIMER1_COMPA_vect) fonctionne sans problème.

Bonjour Kamil,
Oui cela fonctionne sans problème mais je voudrai comprendre un peu le code par curiosité. Le Timer 1 est sur 16 bits et il fonctionne en comparateur (si je ne me trompe pas), on charge la valeur OCR1A = (((F_CPU / 1000 / 1024)) * periodeA); soit 15625 soit 64µs. Du coup toutes les 64µs on a une interruption ? Est ce bien cela ?

15625 c’est le nombre de fois 1024 périodes horloge entre deux interruptions.
Donc la période est 15625/16000000*1024=1 seconde

Merci Kamill,
Dans un premier temps, je voudrai isoler le fonctionnement de OCR1A pour bien comprendre son fonctionnement (peut-être que je me trompe ? ou bien OCR1A est lié avec OCR1B ?)
TCCR1B = _BV(WGM12) | _BV(CS12) | _BV(CS10); Diviser par 1024 = CS12=1; CS11=0; CS10=1.
Fonctionnement en CTC : WGM12 = 1; WGM13 = 0
Est ce bien cela ou je me trompe ?

C’est OCRB qui est lié à OCRA. Les deux its ont la même période définie par OCRA (et le prédiviseur) et OCRB est le retard de l’it B par rapport à l’it A.

Dans ce cas je peux très bien raisonner uniquement sur OCRA et j’obtiens :

16:35:36.228 → A
16:35:37.181 → A
16:35:37.181 → B
16:35:38.130 → A
16:35:39.115 → A

La période de A n’est pas tout à fait 1seconde. Je suis un peu lent et je ne comprends pas très bien ton expression :
OCR1A = (((F_CPU / 1000 / 1024)) * periodeA); F_CPU = 16 Mhz et priodeA=1000 dont tu charges bien la valeur 15625 dans le OCR1A non ?
du coup le Timer 1 comptes avec la nouvelle période 64µs (16Mhz/1024). Dont pour aller jusqu’à 15625 avec la nouvelle période de l’horloge à 64µs il faut 1seconde ? Je ne me trompe pas dans le raisonnement ?

Parce que tu fais une division avec des entiers (long). La division par 1024 laisse un reste non négligeable. Faire la division par 1024 en dernier.
Pour minimiser l’erreur il faudrait faire
OCR1A = F_CPU / 1000 * periodeA / 1024;

C’est pour cette raison que je voulais enlever le OCR1B pour ne voir uniquement le fonctionnement de l’interruption OCR1A ci dessous le fonctionnement de ISR(TIMER1_COMPA_vect) :
18:38:11.731 → A
18:38:12.708 → A
18:38:13.666 → A
18:38:14.616 → A
18:38:15.569 → A
18:38:16.527 → A
18:38:17.513 → A
18:38:18.466 → A
18:38:19.421 → A
18:38:20.376 → A
18:38:21.328 → A
18:38:22.314 → A
18:38:23.269 → A
18:38:24.226 → A
18:38:25.178 → A
18:38:26.127 → A
C’est un peu plus juste, je pense que le faîte d’envoyer une valeur via le PORT série USB fait perdre un peu de temps.
En revanche je n’ai pas compris l’astuce de terminer par une division au lieu d’une multiplication nous fait minimiser l’erreur ?
OCR1A = F_CPU / 1000 * periodeA / 1024;
Pourras-tu détailler ta réponse ? Merci Kamill.

Il suffit d’essayer. Tu fais

  Serial.println (((F_CPU / 1000 / 1024)) * periodeA);
  Serial.println(F_CPU / 1000 * periodeA / 1024);

et tu vois la différence

Effectivement cela ne donne pas le même résultat :
09:14:09.151 → 15000
09:14:09.151 → 15625
Serial.println(((F_CPU / 1000 / 1024)) * periodeA); donne 15000 et
Serial.println(F_CPU / 1000 * periodeA / 1024); donne 15625
Je ne sais pas pour quelle raison ? Il a probablement arrondi le résultat en divisant ? Ou je me trompe ?

Oui il y a une troncature quand tu fais F_CPU / 1000 / 1024
Il y a aussi une troncature lorsqu’on fait F_CPU / 1000 * periodeA / 1024 mais le dividende est 1000 fois plus grand donc la troncature est plus faible.

09:49:13.418 → A
09:49:14.431 → A
09:49:15.421 → A
09:49:16.402 → A
09:49:17.411 → A
09:49:18.405 → A
09:49:19.426 → A
09:49:20.424 → A
09:49:21.429 → A
09:49:22.403 → A
09:49:23.405 → A
09:49:24.407 → A
09:49:25.409 → A
09:49:26.413 → A
09:49:27.411 → A

Effectivement avec cette modification, on est au 1/100 de précision et je pense que dans la routine interruption :
ISR(TIMER1_COMPA_vect)
{ Serial.println(“A”);}
Il faut aller très vite si je me trompe du coup le faite d’envoyer sur le port série et afficher les valeurs nous fait perdre pas mal de temps.
Je ne sais pas si on peut mettre une sonde directement dans l’environnement de développement Arduino (IDE Arduino) pour regarder l’incrémentation d’une variable ? Je ne connais pas très bien l’environnement de développement Arduino mais j’avais travaillé (il y a très longtemps) sur IAR Embedded Workbench pour les microprocesseurs Motorola et on peut pratiquement faire du Debug en temps réel ce qui aide beaucoup dans la phase de développement.

Effectivement le traitement d’interruption doit être le plus court possible et en principe on ne met pas de Serial.print() dans l’interruption, sauf besoin de debug.
Cependant l’envoi sur la liaison série est bufferisé et tant que le buffer n’est pas plein Serial.print() est rapide puisque il se résume à formater le message et à le ranger dans le buffer. C’est le cas ici, comme l’interruption a lieu toutes les secondes le buffer a le temps de se vider.
A ma connaissance, il n’y a pas moyen d’utiliser un debugger sous l’IDE.

Merci pour les renseignements. Je me demande s’il existe des compilateurs autre que sur ce site qui nous permet d’avoir la possibilité de visualiser les registres, les variables, les interruptions etc…

Je suppose qu’on doit pouvoir le faire avec Atmel Studio et le hard qui va bien.

Merci Kamill, je vais regarder un peu ce qui existe sur le marché et combien ça coute.