Come faccio a creare un interrupt timer con Arduino?


9

Sto cercando di creare un'interruzione di ritardo con Arduino. Vorrei usare la funzione interrupt (), perché è un interrupt interno.

Esempio: diciamo, vorrei far accendere e spegnere una luce, con solo il tempo dell'interruzione.

Esiste un codice di esempio, ma utilizza interrupt esterni (attachInterrupt ()). Vorrei rimanere usando gli interrupt interni.


2
Penso che il punto che anche Kortuk abbia dimostrato sia che attachInterrupt sia una cosa astratta, non stai collegando alcun componente esterno :)
clabacchio

Questo articolo potrebbe aiutarti. engblaze.com/…
Seth Archer Brown,

Risposte:


10

Il blog di Noah Stahl ha un esempio di lampeggiamento di un LED con Timer2 . Con questo e la scheda tecnica, dovresti essere in grado di adattarlo a qualsiasi interruzione che desideri utilizzare, ovvero l'interruzione la cui normale funzione ti puoi permettere di rinunciare o che sei disposto a modificare. Timer2 viene solitamente utilizzato per alcune funzioni PWM.

Il suo esempio cita l'ATmega2560; Posso confermare che funziona anche con un ATmega328p. Cerca nel suo sito esempi di interruzioni Arduino più utili.

Modificare:

Ecco la mia versione leggermente modificata - principalmente nei commenti - della versione del codice di Noè. Chiama Timer2init () dalla funzione setup () di Arduino dopo aver inizializzato qualsiasi struttura di dati o hardware correlata, poiché il tempismo - e l'interruzione - inizierà una volta che lo fai.

Per esempio, l'ho usato per multiplexare un display a 7 segmenti a 3 cifre, quindi prima di inizializzare il timer, ho inizializzato i registri I / O del display e cancellato i dati del display nel punto in cui l'ISR lo cercherà.

C'è una tabella nei commenti di alcuni dati di temporizzazione utili dalla scheda tecnica e i miei calcoli come riferimento per impostare un altro schema di temporizzazione.

La macro ISR () si occupa della creazione di un codice di ingresso e di uscita di interrupt per un ISR anziché di una normale voce di ingresso e uscita e di collegarlo al vettore di interrupt corretto. Il resto di quella funzione è 1) il codice da eseguire ad ogni interruzione e 2) il codice per resettare il timer per l'interruzione successiva.

Come scritto, questo dovrebbe cadere in uno schizzo .pde o .ino (o in un file .cpp, se usi eclipse, f / ex). Lo schizzo deve #definire LEDPIN e setup () deve chiamare Timer2init (). La funzione loop può essere vuota o no; il LED dovrebbe iniziare a lampeggiare durante il download (bene, letteralmente, dopo che viene chiamato 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
};

(@Kortuk: Il commento a cui ti riferisci è stata la mia osservazione di diversi commentatori qui e non mirato a te personalmente ed è stato inutile. Mi scuso e l'ho rimosso.) Ho ampliato la mia risposta come hai suggerito e spero che sia ora non solo dimostrativo, ma anche istruttivo. Include i commenti che ho scritto nel codice per uso personale (significato: se riesco a capirli tra 6 mesi, anche qualcun altro sarà in grado di farlo), nonché alcune istruzioni "come usare" nella risposta. Grazie per i vostri suggerimenti.
JRobert,

Si noti che non sono disponibili le prescrizioni di 32 e 128 per timer0 e timer1 (almeno con atmega328).
tuupola,

Buono a sapersi, grazie. Lo uso per Timer2 (finora) ed è sostanzialmente un drop-in.
JRobert,

5

La funzione attachInterrupt () in realtà sta collegando un interrupt a un cambio di stato esterno su un pin, non ha altre opzioni.

Nella stessa pagina le opzioni della modalità sono elencate come:

mode definisce quando deve essere attivato l'interrupt. Quattro costanti sono predefiniti come valori validi:

  • BASSO per attivare l'interrupt ogni volta che il pin è basso,
  • CAMBIA per attivare l'interrupt ogni volta che il pin cambia valore
  • RISING da innescare quando il pin passa da basso ad alto,
  • CADUTA per quando il perno passa da alto a basso.

Mi dispiace essere il portatore di cattive notizie, questa è una delle prime cose che ho cercato anche.


Penso che significhi che vuole usare un timer interno, anziché un dispositivo esterno ... ma non conosco molto bene Arduino, quindi non posso dire se è possibile
clabacchio

@clabacchio, sto dicendo che l'unica opzione è quella di utilizzare un trigger esterno, non esiste una funzione timer interna.
Kortuk,

Ah, bene :) ma almeno le schede Arduino hanno dei timer?
clabacchio

Sì, è così che realizzano cose come il ritardo.
Kortuk,

1
@ icarus74 ATMega328 ha davvero 3 timer (uno è 16b e due sono 8b) ma tutti sono usati da Arduino. Uno è usato per funzioni come delay () e millis () e tutti e tre sono usati per PWM (puoi trovare maggiori informazioni nella funzione 'init ()', file 'cablaggio.c' nell'IDE di Arduino).
Vasco,

2

Questo articolo su PWM chiarirà molti dei tuoi dubbi sull'utilizzo dei timer Arduino. Esistono due timer a 8 bit e un timer a 16 bit su Arduino. Non esiste un'API di alto livello per agganciare la funzione ISR direttamente sui timer, fornita con Arduino SDK (ovvero come libreria standard), ma un metodo un po 'di livello inferiore per impostare registri di funzioni speciali e bit-arithmetic / operazioni su di essi. Tuttavia esiste una libreria fornita dall'utente chiamata Timer one .


In realtà ci sono diverse combinazioni di timer possibili a seconda di quale Arduino viene chiamato. La risposta è fuorviante.
Apparentemente, quindi, il

@SeeminglySo, ti interessa elaborare? Se stai parlando dell'hardware di Arduino, nota che la risposta è nel contesto della domanda e anche il momento in cui viene posta la domanda.
Icarus74,

Arduino Mega (basato su ATmega1280) è stato rilasciato il 26 marzo 2009 e Mega 2560 (ATmega2560) è stato rilasciato il 24 settembre 2010, entrambi molto prima che questa domanda fosse posta. Entrambi i microcontrollori hanno più del timer / contatore 2x 8 bit e 1x 16 bit specificato nella risposta.
Apparentemente, quindi, il

La maggior parte delle interazioni che ho visto finora hanno un riferimento inequivocabile ad Arduino nel senso di Duemilanove o Uno, ovvero le schede basate sulla serie 328. Altre schede sono sempre state esplicitamente qualificate dalla serie uP n. o Mega, Nano, Micro ecc. Comunque, accetterò umilmente la correzione. In questo contesto, un chiarimento è migliore.
Icarus74,

1

Arduino utilizza tutti e tre i timer in ATMega328. Timer1(16 bit) è utilizzato per funzioni come delay()ed millis()e per l'uscita PWM sui pin 5 e 6. Gli altri due timer - Timer0e Timer2sono utilizzati per l'uscita PWM sui pin 3, 9, 10, 11.

Pertanto, non esiste alcuna funzione Arduino per l'interruzione del timer. Ma c'è un modo. È possibile utilizzare questo codice per abilitare l'interruzione del timer su Timer2:

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

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

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

Ho scritto questo codice senza test, quindi è possibile che abbia fatto un errore. In tal caso, consultare la scheda tecnica, p . 156 .

Se si desidera modificare la frequenza del timer (prescaler), è sufficiente cambiare registro TCCR2A. Per maggiori informazioni guarda la scheda tecnica pagina 153. Ma se cambi la frequenza del timer, cambi anche la frequenza del segnale PWM su due pin di uscita!


AFAIK su ATmega328 Timer0e Timer2sono 8 bit e solo Timer116 bit.
tuupola,

No, questo non è corretto. È Timer0, non Timer1, utilizzato per delay () e millis () e per l'uscita PWM sui pin 5 e 6. Timer0 è un timer a 8 bit. Vedi ad esempio Arduino Timer e Interrupts .
Peter Mortensen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.