Comment créer une interruption de minuterie avec Arduino?

9

J'essaie de créer une interruption temporisée avec Arduino. Je voudrais utiliser la fonction interrupts (), car c'est une interruption interne.

Exemple: Disons, je voudrais faire un clignotement léger allumé et éteint, avec seulement le temps de l'interruption.

Il existe un exemple de code, mais il utilise des interruptions externes (attachInterrupt ()). Je voudrais continuer à utiliser les interruptions internes.

Aléatoire
la source
2
Je pense que le point que Kortuk a également montré est que attachInterrupt est une chose abstraite, vous
n'attachez
Cet article pourrait vous aider. engblaze.com/…
Seth Archer Brown

Réponses:

10

Le blog de Noah Stahl a un exemple de clignotement d'une LED avec Timer2 . Avec cela et la fiche technique, vous devriez être en mesure de l'adapter à l'interruption que vous souhaitez utiliser - c'est-à-dire l'interruption dont vous pouvez vous permettre d'abandonner la fonction normale ou que vous êtes prêt à modifier. Timer2 est généralement utilisé pour certaines fonctions PWM.

Son exemple cite l'ATmega2560; Je peux confirmer qu'il fonctionne également avec un ATmega328p. Parcourez son site pour des exemples d'interruptions Arduino plus utiles.

Éditer:

Voici ma version légèrement modifiée - principalement dans les commentaires - du code de Noah. Appelez Timer2init () à partir de la fonction de configuration Arduino () après avoir initialisé toutes les structures de données ou le matériel associés, car le chronométrage - et l'interruption - commencera une fois que vous le ferez.

F / ex, je l'ai utilisé pour multiplexer un affichage à 3 chiffres à 7 segments, donc avant d'initialiser la minuterie, j'ai initialisé les registres d'E / S d'affichage et effacé les données d'affichage à l'endroit où l'ISR le recherchera.

Il y a un tableau dans les commentaires de quelques données de synchronisation utiles de la fiche technique et mes propres calculs pour référence pour mettre en place un autre schéma de synchronisation.

La macro ISR () prend soin de créer un code d'entrée et de sortie d'interruption pour un ISR à la place de l'entrée et de la sortie d'une fonction normale, et de le lier avec le vecteur d'interruption approprié. Le reste de cette fonction est 1) le code à exécuter à chaque interruption, et 2) le code de code pour réinitialiser le temporisateur pour la prochaine interruption.

Tel qu'il est écrit, cela devrait se retrouver dans une esquisse .pde ou .ino (ou un fichier .cpp, si vous utilisez eclipse, f / ex). L'esquisse doit # définir LEDPIN, et setup () doit appeler Timer2init (). La fonction de boucle peut être vide ou non; la LED devrait commencer à clignoter au téléchargement (enfin, littéralement, après l'appel de Timer2init ()).

/*
 * From sample interrupt code published by Noah Stahl on his blog, at:
 * http://arduinomega.blogspot.com/p/arduino-code.html
 * 
 */


/*** FUNC

Name:           Timer2init

Function:       Init timer 2 to interrupt periodically. Call this from 
                the Arduino setup() function.

Description:    The pre-scaler and the timer count divide the timer-counter
                clock frequency to give a timer overflow interrupt rate:

                Interrupt rate =  16MHz / (prescaler * (255 - TCNT2))

        TCCR2B[b2:0]   Prescaler    Freq [KHz], Period [usec] after prescale
          0x0            (TC stopped)     0         0
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000


Parameters: void

Returns:    void

FUNC ***/

void Timer2init() {

    // Setup Timer2 overflow to fire every 8ms (125Hz)
    //   period [sec] = (1 / f_clock [sec]) * prescale * (255-count)
    //                  (1/16000000)  * 1024 * (255-130) = .008 sec


    TCCR2B = 0x00;        // Disable Timer2 while we set it up

    TCNT2  = 130;         // Reset Timer Count  (255-130) = execute ev 125-th T/C clock
    TIFR2  = 0x00;        // Timer2 INT Flag Reg: Clear Timer Overflow Flag
    TIMSK2 = 0x01;        // Timer2 INT Reg: Timer2 Overflow Interrupt Enable
    TCCR2A = 0x00;        // Timer2 Control Reg A: Wave Gen Mode normal
    TCCR2B = 0x07;        // Timer2 Control Reg B: Timer Prescaler set to 1024
}



/*** FUNC

Name:       Timer2 ISR

Function:   Handles the Timer2-overflow interrupt

Description:    Maintains the 7-segment display

Parameters: void

Returns:    void

FUNC ***/

ISR(TIMER2_OVF_vect) {
    static unsigned int led_state = 0; // LED state

    led_state = !led_state;         // toggles the LED state
    digitalWrite(TOGGLE_PIN, led_state);

    TCNT2 = 130;     // reset timer ct to 130 out of 255
    TIFR2 = 0x00;    // timer2 int flag reg: clear timer overflow flag
};
JRobert
la source
(@Kortuk: Le commentaire auquel vous faites référence était mon observation de plusieurs commentateurs ici et ne visait pas personnellement vous et c'était inutile. Je m'excuse et je l'ai supprimé.) J'ai développé ma réponse comme vous l'avez suggéré et j'espère que c'est maintenant non seulement démonstratif, mais aussi instructif. Il comprend des commentaires que j'ai écrits dans le code pour mon usage personnel (ce qui signifie: si je peux les comprendre dans 6 mois, quelqu'un d'autre le pourra aussi), ainsi que quelques instructions "comment utiliser" dans le réponse. Merci pour vos suggestions.
JRobert
Notez que les pré-échelles de 32 et 128 ne sont pas disponibles pour timer0 et timer1 (au moins avec atmega328).
tuupola
C'est bon à savoir - merci. Je l'utilise pour Timer2 (jusqu'à présent) et c'est essentiellement un drop-in.
JRobert
5

La fonction attachInterrupt () attache en fait une interruption à un changement d'état externe sur une broche, elle n'a pas d'autres options.

Sur la même page, les options de mode sont répertoriées comme:

mode définit quand l'interruption doit être déclenchée. Quatre constantes sont prédéfinies en tant que valeurs valides:

  • LOW pour déclencher l'interruption chaque fois que la broche est basse,
  • CHANGE pour déclencher l'interruption chaque fois que la broche change de valeur
  • RISING de se déclencher lorsque la broche passe de bas en haut,
  • CHUTE quand la goupille passe de haut en bas.

Désolé d'être porteur de mauvaises nouvelles, c'est aussi une des premières choses que j'ai recherchées.

Kortuk
la source
Je pense qu'il veut dire qu'il veut utiliser une minuterie interne, au lieu d'un appareil externe ... mais je ne connais pas très bien Arduino, donc je ne peux pas dire si c'est possible
clabacchio
@clabacchio, je dis que la seule option est d'utiliser un déclencheur externe, il n'y a pas de fonction de temporisation interne.
Kortuk
Ah, bien :) mais au moins les cartes Arduino ont-elles des minuteries?
clabacchio
Oui, c'est ainsi qu'ils accomplissent des choses comme le retard.
Kortuk
1
@ icarus74 ATMega328 a vraiment 3 temporisateurs (un est 16b et deux sont 8b) mais tous sont utilisés par Arduino. L'un est utilisé pour des fonctions comme delay () et millis () et les trois sont utilisés pour PWM (vous pouvez trouver plus d'informations dans la fonction 'init ()', fichier 'câblage.c' dans Arduino IDE).
vasco
2

Cet article sur PWM clarifiera beaucoup de vos doutes concernant l'utilisation des minuteries Arduino. Il y a deux temporisateurs 8 bits et un temporisateur 16 bits sur Arduino. Il n'y a pas d'API de haut niveau pour accrocher la fonction ISR directement sur les temporisateurs, qui est livrée avec le SDK Arduino (c'est-à-dire en tant que bibliothèque standard), mais une méthode de niveau un peu plus bas pour définir les registres de fonctions spéciales et l'arithmétique des bits / opérations sur eux. Cependant, il existe une bibliothèque contribuée par l'utilisateur appelée Timer one .

icarus74
la source
Il existe en fait plusieurs combinaisons de minuteries possibles selon l'Arduino auquel il est fait référence. La réponse est trompeuse.
Apparemment, le
@SeeminglySo, voulez-vous élaborer? Si vous parlez de matériel Arduino, notez que la réponse est dans le contexte de la question et aussi du moment où la question est posée.
icarus74
L'Arduino Mega (basé sur ATmega1280) est sorti le 26 mars 2009, et le Mega 2560 (ATmega2560) est sorti le 24 septembre 2010, les deux bien avant que cette question ne soit posée. Les deux microcontrôleurs ont plus que le temporisateur / compteur 2x 8 bits et 1x 16 bits spécifié dans la réponse.
Apparemment, donc le
La plupart des interactions que j'ai vues jusqu'à présent ont une référence sans équivoque à Arduino pour signifier similaire à Duemilanove ou Uno, c'est-à-dire les cartes basées sur la série 328. D'autres cartes ont toujours été explicitement qualifiées par la série uP no. ou Mega, Nano, Micro etc. Quoi qu'il en soit, j'accepterai humblement la correction. Dans ce contexte, une clarification est préférable.
icarus74
1

Arduino utilise les trois temporisateurs dans ATMega328. Timer1(16 bits) est utilisé pour les fonctions comme delay()et millis()et pour la sortie PWM sur les broches 5 et 6. Les deux autres temporisateurs - Timer0et Timer2sont utilisés pour la sortie PWM sur les broches 3, 9, 10, 11.

Il n'y a donc pas de fonction Arduino pour l'interruption de la minuterie. Mais il y a un moyen. Vous pouvez utiliser ce code pour activer l'interruption du minuteur sur Timer2:

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

void setup() {
  // Enable Timer2 interrupt.
  TIMSK2 = (0<<OCIE2A) | (1<<TOIE2);
}

void loop() {
  // Your main loop.
}

J'ai écrit ce code sans tester, il est donc possible que j'ai fait une erreur. Dans ce cas, consultez la fiche technique, p.156 .

Si vous souhaitez changer la fréquence de la minuterie (pré-échelle), changez simplement le registre TCCR2A. Pour plus d'informations, consultez la fiche technique page 153. Mais si vous changez la fréquence de la minuterie, vous changez également la fréquence du signal PWM sur deux broches de sortie!

vasco
la source
AFAIK sur ATmega328 Timer0et Timer2sont 8 bits et seulement Timer116 bits.
tuupola
Non, ce n'est pas correct. C'est Timer0, pas Timer1, qui est utilisé pour delay () et millis () et pour la sortie PWM sur les broches 5 et 6. Timer0 est un temporisateur 8 bits. Voir par exemple les temporisateurs et les interruptions Arduino .
Peter Mortensen