Comment mettre à jour une variable dans un ISR à l'aide de minuteries

8

J'essaie de vérifier la fréquence de Timer3 à l'aide d'un compteur. La valeur du compteur, déclarée volatile, est incrémentée dans l'ISR et chaque seconde la somme est affichée dans la boucle principale et la valeur remise à zéro.

La minuterie a été correctement configurée. (Si je choisis une minuterie à 3 Hz, je peux voir le voyant clignoter)

Le problème

Le compteur n'est pas incrémenté. Voici la sortie:

Setup Completed
tick: 1
tick: 0
tick: 0
tick: 0

CODE

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);

  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B = 20; // 800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();

  Serial.println("Setup completed");
}

void loop()
{
  if (millis() % 1000 == 0)
  {
    Serial.print(" tick: ");
    Serial.println(cont);
    cont = 0;
  }
}

ISR(TIMER3_COMPB_vect)
{
  //digitalWrite(13, digitalRead(13) ^ 1);
  cont++;
}

EDIT Ce temporisateur est utilisé pour lire une valeur de journal d'un accéléromètre et la stocker dans un tableau de float. Mais pour le moment, je suis bloqué sur ce problème de mise à jour.

SOLUTION 1 Merci à Gerben

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3A = 20; // 20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  delay(1000);
  Serial.println(cont);
  cont = 0;
}

ISR(TIMER3_COMPB_vect)
{
  cont++;
}

SOLUTION 2 Merci à BrettM

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B =  20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  //TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  Serial.println(cont); 
  cont = 0;
  delay(1000);

}

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}
UserK
la source
Et si vous décommentez la digitalWriteligne, vous voyez la LED clignoter environ une fois par seconde (toutes les 0,66s)?
Ricardo
Oui, si je ne commente pas digitalWriteet que OCR3B = 5;le voyant clignote à environ cette fréquence.
UserK
Ensuite, c'est un mystère. Avez-vous essayé de commenter l' cont = 0;intérieur de la boucle? Que se passe-t-il alors?
Ricardo
1
Essayez d'augmenter la fréquence. Je pense que votre déclaration if peut effacer le compteur plus souvent que l'interruption n'est appelée, d'une manière ou d'une autre. Mais alors vous devriez en voir plus dans la sortie. Laissez également fonctionner plus longtemps (disons 1 minute) et collez les résultats. De plus, lorsque vous mettez à jour la question, laissez l'ancienne sortie pour que votre question ait un sens (sans l'historique des modifications).
Ricardo
1
Je soupçonne que la routine d'interruption n'est appelée qu'une seule fois, puis elle est désactivée. J'ai lu quelque part que les interruptions sont désactivées lorsqu'un code d'interruption est en cours d'exécution, et dans certains cas, vous devez le réactiver, mais je ne sais vraiment pas si c'est le cas. J'espère que quelqu'un de plus compétent viendra à notre secours ...
Ricardo

Réponses:

5

En mode CTC, le top n'est OCR3Apas OCR3B!

Après cela TIMSK3 |= (1 << OCIE3B);devrait également être changé à TIMSK3 |= (1 << OCIE3A);, et ISR(TIMER3_COMPB_vect)àISR(TIMER3_COMPA_vect)

Pour 3Hz, OCR3Adevrait être 5208, pas 20.

Techniquement TCCR3B |= (1 << WGM12);devrait êtreTCCR3B |= (1 << WGM32);

Gerben
la source
Avec votre configuration, le compteur n'est pas mis à jour et chaque seconde la phrase "Installation terminée", (écrite dans la fonction setup ()!) Est affichée. Comportement vraiment bizarre.
UserK
Résolu en utilisant TIMSK3 |= (1 << OCIE3B);. Merci Gerben! Veuillez modifier votre réponse et je l'accepterai comme solution.
UserK
1
J'ai oublié la mention que vous avez également besoin de changer le vecteur ISR. ISR(TIMER3_COMPB_vect)devrait être ISR(TIMER3_COMPA_vect). Si un ISR n'est pas défini, l'AVR se réinitialisera, comme vous le faisiez. Heureux que tu es parvenu à le faire fonctionner.
Gerben
3

Il semble que ma réponse à cette question était auparavant incomplète, merci d'avoir souligné que le mode CTC ne fonctionne qu'avec OCR3A Gerben. Je m'excuse de ne pas avoir testé une réponse avant de la poster.

Étant donné les informations contenues uniquement dans cette question, la réponse de Gerben est complète, mais comme votre autre question implique que vous ne pouvez pas utiliser OCR3A en raison de la bibliothèque de servomoteurs, j'ajouterai un peu. (J'ai également modifié cette réponse)

vous pouvez émuler le comportement du mode CTC en définissant TCNT3 sur 0 dans votre routine d'interruption. N'oubliez pas de supprimer la ligne qui active le mode CTC dans votre code.

J'ai testé votre code avec cet ISR:

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}

et cette configuration des registres de temporisation

OCR3B = 5208; // 800Hz 5; // 3 Hz
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);

Cela pourrait être un peu moins précis aux hautes fréquences que le CTC, je ne suis pas sûr, mais à 3 Hz, cela fonctionnait parfaitement. Notez que 5208 était la valeur OCR correcte, pas 20 (encore une fois grâce à Gerben).

BrettAM
la source
J'ai essayé votre code mais le compteur n'est pas incrémenté. J'ai ajouté le TCNT3=0;dans l'ISR () et supprimé //TCCR3B |= (1 << WGM32);dans le setup () comme vous l'avez dit. J'ai également essayé de commenter la cont=0;ligne, mais rien n'a changé
UserK
1
Assurez-vous que le code correspond à ce qui est publié dans la question de toute autre manière. Essayez de changer votre boucle en juste println(cont); delay(1000);. Aussi, vous incluez toujours les bits avec cli () et TCCR3A, etc. correct?
BrettAM
OK merci. À 800 Hz, c'est toujours précis!
UserK