Manual

do

Maker

.

com

Interrupção e timer com Arduino

Interrupção e timer com Arduino

interrupção e timer com Arduino

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.

Tipos de interrupção
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:

FALLING
Na queda de tensão do pino.

RISING
Na subida de tensão do pino.

LOW
Quando o pino é colocado em LOW

HIGH
Quando o pino é colocado em HIGH

CHANGE
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;
void changeState(){
    ON_OFF = !ON_OFF;
}

void setup(){
    Serial.begin(9600);
    pinMode(2, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(2), changeState, FALLING);
}

void loop(){
    while(1){
        //considere que o programa morreria aqui, porque mais nada pode acontecer
        delay(1000);
    }
    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:

noInterrupts();
//executa alguma coisa que não deve ser tratada...
  interrupts();
  //volta à rotina comum.

Se quiser desabilitar a interrupção em apenas um determinado pino, também é fácil:

detachInterrupt(digitalPinToInterrupt(pin));

Timer com Arduino

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;
int minutes = 0;
int hours   = 0;
long interval = 1000; //ms
long previous = 0;
unsigned long current = millis();

void myClock(){
  secs +=1;
  if (secs > 59){
    minutes +=1;
    secs = 0;
  }
  if (minutes > 59){
    hours += 1;
    minutes = 0;
  }
  if (hours > 24){
    ...
  }
}
...
loop(){
...
  if(current - previousMillis > interval) {
    //guarda o novo periodo...
    previou = current;
    // inverte o estado do LED
    ON_OFF = !ON_OFF;
    digitalWrite(PIN_LED, ON_OFF);
    myClock();
  }
}

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.

Interrupção do Timer
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.

Inscreva-se em nosso canal Dobitaobyte no Youtube!

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.