A utilização de timers, ou temporizadores, no Arduino é um método avançado para executar códigos sem perturbar o resto do programa. Eles permitem ativar funções a intervalos de tempo precisos. Os timers são utilizados em muitas bibliotecas, de forma completamente transparente para o usuário (milis(), Servo.h, PWM, etc.)
Em alguns casos, é possível utilizar bibliotecas que configuram timers, para simplificar o uso.
Material
- Arduino UNO
- Cabo USB A/ USB B
Descrição
Os timers são registros do microprocessador que aumentam de acordo com impulsos de relógio ou impulsos externos. É possível configurá-los para modificar o seu comportamento.
O microprocessador Arduino UNO (ATmega328P) tem 3 temporizadores:
- timer0 (8 bits) conta de 0 a 256 e controla o PWM dos pinos 5 e 6. É também utilizado pelas funções delay(), millis() e micros().
- timer1 (16 bits) conta de 0 a 65535 e é utilizado para o comando PWM dos pinos 9 e 10. É também utilizado pela biblioteca Servo.h
- timer2 (8 bits) que é utilizado pela função Tone() e pela geração de PWM nos pinos 3 e 11.
Configuração dos timers
A parte mais complicada da utilização dos sensores é a sua configuração. Um temporizador é configurado por meio do seu registro de controle. Veja um resumo dos registros.
Timer 0 | Timer 1 | Timer 2 | Papel |
---|---|---|---|
TCNT0 | TCNT1L | TCNT2 | Timer (bit 0 a 7) |
– | TCNT1H | – | Timer (bit 8 a 15) |
TCCR0A | TCCR1A | TCCR2A | Registro de controle |
TCCR0B | TCCR1B | TCCR2B | Registro de controle |
– | TCCR1C | – | Registro de controle |
OCR0A | OCR1AL | OCR2A | Output Compare (bit 0 a 7) |
– | OCR1AH | – | Output Compare (bit 8 a 15) |
OCR0B | OCR1BL | OCR2B | Output Compare (bit 0 a 7) |
– | OCR1BH | – | Output Compare (bit 8 a 15) |
– | ICR1L | – | Input Capture (bit 0 a 7) |
– | ICR1H | – | Input Capture (bit 8 a 15) |
TIMSK0 | TIMSK1 | TIMSK2 | Interrupt Mask |
TIFR0 | TIFR1 | TIFR2 | Interrupt Flag |
O registro TCNTx contém o valor do temporizador/contador. Os TCCRxA e TCCRxB são os registros de controle. Os OCRxA e OCRxB contêm os valores de registro a serem comparados. O TIMSKx contém a máscara de interrupção e o TIFRx contém as flags de ativação.
Código usando o timer2
Para este exemplo, utilizamos o timer2 que é codificado em 8bits (256). Desse modo, precisamos introduzir um contador adicional.
unsigned long elapsedTime, previousTime; void onTimer() { static boolean state = HIGH; elapsedTime=millis()-previousTime; Serial.print(F("Set LED 13 : ")); if(state){ Serial.print(F("ON")); }else{ Serial.print(F("OFF")); } Serial.print(F(" - "));Serial.print(elapsedTime);Serial.println(F("ms")); digitalWrite(13, state); state = !state; previousTime=millis(); } void setup(){ Serial.begin(9600); pinMode(13, OUTPUT); cli(); // disable all interrupts TCCR2A = (1<<WGM21)|(0<<WGM20); // Mode CTC TIMSK2 = (1<<OCIE2A); // Local interruption OCIE2A TCCR2B = (0<<WGM22)|(1<<CS22)|(1<<CS21); // Frequency 16Mhz/ 256 = 62500 OCR2A = 250; //250*125 = 31250 = 16Mhz/256/2 sei(); // enable all interrupts } ISR(TIMER2_COMPA_vect){ // timer compare interrupt service routine static int counter=0; if (++counter >= 125) { // 125 * 4 ms = 500 ms counter = 0; onTimer(); } } void loop(){ }
Código usando o timer1
Neste exemplo, vamos utilizar o timer1.
unsigned long elapsedTime, previousTime; void onTimer() { static boolean state = HIGH; elapsedTime=millis()-previousTime; Serial.print(F("Set LED 13 : ")); if(state){ Serial.print(F("ON")); }else{ Serial.print(F("OFF")); } Serial.print(F(" - "));Serial.print(elapsedTime);Serial.println(F("ms")); digitalWrite(13, state); state = !state; previousTime=millis(); } void setup(){ Serial.begin(9600); pinMode(13, OUTPUT); cli(); // disable all interrupts TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 31250; // compare match register 16MHz/256/2 = 31250 TCCR1B = (1 << WGM12); // CTC mode TCCR1B = (1 << CS12); // // Frequency 16Mhz/ 256 = 62500 TIMSK1 = (1 << OCIE1A); // Local interruption OCIE1A sei(); // enable all interrupts } ISR(TIMER1_COMPA_vect){ // timer compare interrupt service routine onTimer(); } void loop(){ }
Obs: Acrescentamos uma medição do tempo decorrido para exemplificar, mas é preciso ter cuidado ao utilizar funções baseadas em interrupções nas funções chamadas por interrupções. Pode haver interferência.
Resultado
Uma vez iniciado o programa, o LED de bordo acende e apaga a cada 500ms
Fontes
Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie