Auteur Sujet: Programmer le timer0 pour faire clignoter une led  (Lu 22410 fois)

jowell88

  • Newbie
  • *
  • Messages: 2
    • Voir le profil
Programmer le timer0 pour faire clignoter une led
« le: janvier 30, 2018, 06:37:15 pm »
Bonjour,
Suite à ma lecture de cet article http://www.locoduino.org/spip.php?article84 où il est expliqué comment faire clignoter une LED tous les 500ms en programmant le TIMER2 de l'Arduino Uno, j'ai essayé de reproduire la même chose mais avec le TIMER0. Le problème c'est que la LED clignote environ toutes les 3 secondes et pas tous les 500 ms. J'ai essayé avec le TIMER1 qui fait 16 bits et j'ai réussi. Voici mon code pour le TIMER0:

const byte RED = 5;
#define LedToggleRed digitalWrite (RED, !digitalRead(RED))
 
void setup() {
  pinMode (RED, OUTPUT);
  bitClear (TCCR0A, WGM00); // WGM00 = 0;
  bitClear (TCCR0A, WGM01); // WGM01 = 0;
  TCCR0B = 0b00000100; // Clock / 256 soit 16 micro-s et WGM02 = 0;
  TIFR0 = 0b00000001; // Réinitialisation du flag TOV0
  TCNT0 = 256 - 250; // Chargement du timer à 6
}
 
byte varCompteurRed = 0; // La variable compteur
 
void loop() {
  if (bitRead (TIFR0, 0) == 1) { // Flag TOV mis à 1 ?
    TCNT0 = 256 - 250; // Rechargement du timer à 6
    bitSet(TIFR0, TOV0); // Remise à 0 du flag TOV0
    if (varCompteurRed++ > 125){ // Incrémentation et a atteint 125 ?
      varCompteurRed = 0; // On recommence un nouveau cycle
      LedToggleRed; // Inversion de la Led rouge
    }
  }
}

Je vois pas ce qui cloche  :(

« Modifié: janvier 30, 2018, 11:18:26 pm par Dominique »

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 3045
  • 100% Arduino et N
    • Voir le profil
Re : Programmer le timer0 pour faire clignoter une led
« Réponse #1 le: janvier 30, 2018, 11:20:44 pm »
C’est mieux d’utiliser la balise « code » (le bouton marqué « # »)
Cordialement,
Dominique

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1716
    • Voir le profil
Re : Programmer le timer0 pour faire clignoter une led
« Réponse #2 le: janvier 31, 2018, 08:38:34 am »
Le Timer 0 est utilisé pour compter le temps. Il est donc programmé pour déclencher une interruption toutes les 1,024 ms. Ici le diviseur et la valeur initiale du timer sont changés et l’interruption se produira donc toutes les 4ms.

Mon intuition est que lorsque l’interruption survient alors que la lecture du TOV est en court, le TOV est vu à 1 et le code de la branche if s’exécute. Lorsque l’interruption survient entre deux lectures du TOV, le TOV est remis à 0 par l’exécution de la routine d’interruption et il est vu a 0 par le programme principal.

Ça serait donc dû, en quelque sorte à un problème d’interférence entre le programme principal et l’interruption.

Ce qui est rigolo à tester : l’ajout d’instructions dans loop en dehors du if devrait ralentir encore le clignotement en diminuant la probabilité que l’interruption survienne au moment de la lecture du TOV et donc diminuer la probabilité de voir le TOV à 1.

Pour que ça fonctionne correctement, il faudrait ne plus autoriser les interruptions du Timer 0.

Mais c’est une intuition, je n’ai rien testé :)
Cordialement

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1716
    • Voir le profil
Re : Programmer le timer0 pour faire clignoter une led
« Réponse #3 le: janvier 31, 2018, 12:40:25 pm »
J'ai pu vérifier que

1 - coupez les interruptions du Timer 0 (TIMSK0 = 0;) conduit à un clignotement à le demi seconde comme prévu

2 - ne pas les couper et ajouter des instructions dans loop, par exemple :

volatile int a;

void loop() {
  a = 0;
  if (bitRead (TIFR0, 0) == 1) { // Flag TOV mis à 1 ?
    TCNT0 = 256 - 250; // Rechargement du timer à 6
    bitSet(TIFR0, TOV0); // Remise à 0 du flag TOV0
    if (varCompteurRed++ > 125){ // Incrémentation et a atteint 125 ?
      varCompteurRed = 0; // On recommence un nouveau cycle
      LedToggleRed; // Inversion de la Led rouge
    }
  }
}

produit d'autres jeux de lumière rigolos. Ce qui confirme mon intuition ;D
Cordialement

chris_bzg

  • Sr. Member
  • ****
  • Messages: 319
    • Voir le profil
Re : Programmer le timer0 pour faire clignoter une led
« Réponse #4 le: janvier 31, 2018, 12:43:08 pm »
Suite au problème qui m'avait été remonté, j'ai consulté la doc Atmel de l'ATMega328P.
Pour moi jowell88 a fait tout ce qu'il faut, notamment en positionnant les bits CS02:0 à 100 comme l'indique bien la doc.
Donc j'étais un peu perdu, ne comprenant pas pourquoi on obtenait une période si longue et j'ai donc appelé mon ami Jean-Luc à l'aide !
Et comme d'habitude, il a trouvé (un grand merci à lui  ;))
J'ai repris mon programme d'hier et j'ai simplement rajouté en fin de setup la ligne bitClear(TIMSK0, 0);ce qui revient à mettre le bit TOIE0 à zéro, empêchant ainsi les interruptions par overflow du timer 0.
Le programme fait clignoter la DEL plus rapidement et à la bonne fréquence. J'ai compté 60 allumages en 59,63 secondes (pas mal mes réflexes pour mon âge  :D) soit une fréquence de 1 Hz.

Cela démontre qu'utiliser les timers n'est pas forcément compliqué mais il faut faire attention à ne rien oublier concernant les registres à positionner, notamment l'autorisation ou non de faire des interruptions.

On peut aussi mettre TIMSK0 = 0;Attention à cette façon de faire qui va forcer d'autres bits du registre à zéro : ici, cela n'a pas d'importance, mais dans d'autres registres, cela pourrait en avoir. C'est la raison pour laquelle un bitClear peut être préférable et de plus, on voit mieux ce qui est manipulé.

« Modifié: janvier 31, 2018, 12:54:13 pm par chris_bzg »

jowell88

  • Newbie
  • *
  • Messages: 2
    • Voir le profil
Re : Programmer le timer0 pour faire clignoter une led
« Réponse #5 le: février 09, 2018, 08:24:37 pm »
Et bien merci beaucoup à vous deux  :)