Interrupção e timer com Arduino • Do bit Ao Byte
Djames Suhanko 12 de novembro de 2015 4 min read
Tenho escrito bastante a respeito de interrupções e timer com PIC, mas ainda não havia escrito nada sobre interrupção e timer com Arduino porque é bem mais simples, mas cheguei à conclusão que não deixa de ser importante ter essa referência.
Existem 2 tipos de interrupção; a externa e a interna. O Arduino UNO, Nano e Mini utilizam os pinos 2 e 3 para interrupção, o Leonardo utiliza o 0,1,2,3 e o 7. O DUE utiliza TODOS!
Estado inicial da interrupção
A interrupção pode monitorar vários estados:
Na queda de tensão do pino.
Na subida de tensão do pino.
Quando o pino é colocado em LOW
Quando o pino é colocado em HIGH
Quando o pino muda de estado
Função (ou ISR – Interrupt Service Routine)
Quando uma interrupção acontece, uma rotina será executada, caso a interrupção esteja sendo tratada. Logo, cria-se uma função de um nome qualquer que não tenha retorno (deve ser 'void') e que não receba parâmetros.
Quando se pretende tratar interrupções, sua inicialização deve ser feita em setup(), desse modo:
//attachInterrupt(PIN,ISR,CONDITION);
attachInterrupt(digitalPinToInterrupt(2), changeState, FALLING);
Desse modo, quando ocorrer o evento na queda de tensão do pino, a função changeState() será chamada.
Pode parecer um exemplo estúpido, mas fará bastante sentido observando o código.
boolean ON_OFF = 0;
ON_OFF = !ON_OFF;
//considere que o programa morreria aqui, porque mais nada pode acontecer
Serial.println("Voce nunca vera essa mensagem");
Como você pode ver, na função loop() tem um outro loop while(1) (que não deveria existir, é errado fazer isso, uma vez que a função loop() já mantém o programa rodando 'infinitamente'). Esse loop while() prende a execução do código para sempre, tanto que a mensagem seria jamais será observada. O loop while() não faz nada a não ser gerar delays.
Como funciona a interrupção?
Interrupções tem maior prioridade para a MCU, então quando uma interrupção ocorre (e ela está sendo tratada), a função (ISR) relacionada ao tratamento é executada, depois o código principal é retomado de onde parou.
Isso funciona como uma thread. No Arduino é bastante simplificado esse procedimento, de forma que erros são evitados. Em PIC o tratamento de interrupções é um pouco mais braçal, e é comum ver erros do tipo chamada de função dentro do tratamento da interrupção. Mas para ver detalhes disso (caso lhe interesse), procure por 'PIC' aí na caixa de busca e veja como as interrupções são tratadas em baixo nível. No Arduino também é bastante parecido, mas a interface de altíssimo nível nos permite programar com mais flexibilidade (a custo de utilização de recursos, que no Arduino tem de sobra).
Se necessário, você pode desabilitar as interrupções por tempo e depois reativá-las em outra parte do código:
//executa alguma coisa que não deve ser tratada...
//volta à rotina comum.
Se quiser desabilitar a interrupção em apenas um determinado pino, também é fácil:
Deixemos de lado as interrupções por enquanto e vamos entrar em outro assunto; contagem de tempo, ou timer.
Mais uma vez, o Arduino permite a utilização de tempo de uma maneira muito simples:
int secs    = 0;
long interval = 1000; //ms
void myClock(){
secs +=1;
minutes +=1;
if (minutes > 59){
if (hours > 24){
if(current - previousMillis > interval) {
//guarda o novo periodo...
previou = current;
// inverte o estado do LED
digitalWrite(PIN_LED, ON_OFF);
Não utilize isso como um relógio porque facilmente perderá a precisão, ainda que a utilização da MCU seja dedicada a isso. Se pretende ter precisão de relógio, utilize um RTC.
Essa função é bacana, auxilia bastante em contagem, mas o ideal é que o tempo seja contado de forma independente, de forma que qualquer código que você esteja executando não influencie na contagem. Por exemplo, se o código ficar detido no loop antes de entrar nessa função, quando chegar nela, a verificação é:
"A DIFERENÇA DE TEMPO É MAIOR QUE 1000ms?". Pode ter passado 4 segundos, a resposta será simplesmente "SIM", e um segundo será incrementado através da função clock(). Por isso o ideal é utilizar interrupções do timer. E adivinha? O Arduino tem biblioteca pra isso também, você não precisará tratar nada em baixo nível utilizando a biblioteca TimerOne desse link.
Um exemplo simples de utilização:
Inicialize o timer…
initialize(x);//uSecs
…e defina um periodo (até 8.3 segundos).
setPeriod(x); //uSecs
Ou se quiser interromper com uma função:
attachInterrupt(function, period);
Desse modo, a função myClock() seria bastante precisa (não tanto quanto um RTC) pois a interrupção tem prioridade na MCU. Nas referencias tem mais algumas diversões que você pode utilizar, vale a pena conferir!
Se quiser ver um exemplo prático do uso da interrupção e timer com Arduino, veja esse post.
Gostou do post? Compartilhe nas redes sociais e siga-nos no facebook. Semana que vem teremos o sorteio de um Arduino Leonardo para os que nos seguem nas redes sociais (DobitAoByte no facebook)