Processando interrupt no Arduino


Interrupts no arduino

Interrupt é uma forma de atender a demandas típicas dos sistemas que operam em tempo real. A estrutura básica do desenvolvimento de firmware na plataforma arduino separa o código em duas partes. A parte de “setup”, que  contém o código que só é executado uma única vez, durante a inicialização. E a parte “loop”, que  contem o código que fica permanentemente sendo executado , em laço contínuo.

Esta estrutura funciona muito bem para uma grande variedade de situações, mas falha em um ponto crucial para o caso de sistemas que devem operar em tempo real. Sistemas de tempo real devem ser capazes de responder corretamente no tempo adequado. Se o seu programa está numa função que necessita de alguns segundos para operar e uma chave fecha, pode ser que, quando o microcontrolador for ler a chave, esta já esteja aberto, ou mesmo que o evento que deveria ser realizado logo após o fechamento não possa ser realizado após decorrido este tempo.

Precisamos de uma forma de interromper o fluxo normal do programa para atender estes eventos que podem ocorrer a qualquer momento, e depois de atendido, retornar ao fluxo do programa como nada tivesse ocorrido!

Esta forma de interromper o fluxo normal do programa é denominada, com muita propriedade, de interrupt. Observe a figura a seguir:

Atendendo a uma interrupção

Tipos de interrupt no arduino

Diferentes eventos podem interromper um programa no arduino. Estes eventos podem ser gerados externamente, ou pelos circuitos internos da CPU. Vamos ver aqui os tipos de interrupts que são reconhecidos pelo ATMEGA328P, circuito utilizado no UNO. Se você estiver utilizando outra placa, identifique a CPU utilizada na mesma e veja na página http://www.nongnu.org/avr-libc/user-manual/group_avr os interrupts que a mesma pode reconhecer.

Nome do vetor Descrição do evento
Fim de conversão AD
ANALOG_COMP_vect Saída do comparador analógico
EE_READY_vect EEprom pronta
INT0_vect Interrupt externo 0
INT1_vect Interrupt externo 1
PCINT0_vect Interrupt na mudança pino 0 (pinos D8 a D13)
PCINT1_vect Interrupt na mudança pino 1 (pinos A0 a A5)
PCINT2_vect Interrupt na mudança pino 2 (pinos D0 a D7)
SPI_STC_vect Transferência serial completa
SPM_READY_vect Memória de armazenamento de programa pronta
TIMER0_OVF_vect Estouro do timer/contador 0
TIMER1_COMPA_vect Casamento comparador “A” com Timer/Counter1
TIMER1_COMPB_vect Casamento comparador “B” com Timer/Counter1
TIMER1_OVF_vect Estouro do timer/counter1
TIMER2_OVF_vect Estouro do timer/counter2
USART_RX_vect recebido caractere na USART
USART_UDRE_vect Registro de dados da usart vazio
WDT_vect Interrupt do watch dog

Como associar um interrupt externo a uma função (arduino UNO)

O arduino UNO possui dois interrupts externos, denominados de 0 e 1. O int0 corresponde ao pino D2 e o int1 ao pino D3.

Utilizamos a função attachInterrupt para associar um interrupt a uma função especifica. A sintaxe é:

attachInterrupt(interrupt, ISR, mode)

  • interrupt pode ser 0 ou 1, correspondendo ao int 0 ou 1.
  • ISR é o nome da rotina que será processada quando ocorre o int.
  • mode é a forma de detecção do int. Pode ser uma das seguintes formas:
  • LOW: evento ocorrerá sempre que o pino está em nível baixo
  • CHANGE: evento ocorrerá sempre que o pino mudar de estado
  • RISING: evento ocorrerá sempre que o pino vai de baixo para alto
  • FALLING: evento ocorrerá sempre que o pini vai de alto para baixo

O trecho de código a seguir mostra como utilizamos a attachInterrupt

.Processando INT0 (software original<a href="https://cdn.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/"> https://cdn.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/</a>)

int pin = 13;
volatile int estado = LOW;

void setup()
{
pinMode(pin, OUTPUT);   //utilizamos a led da placa para a demostração
attachInterrupt(0, blink, CHANGE); //associamos o int a função pisca
}

void loop()
{
digitalWrite(pin, state); //liga ou desliga o led, dependendo do estado
}

void pisca()
{
estado = !estado;
}

Para desconectar o evento associado à função, utilize a instrução detachInterrupt()

.desconectando interrupts externos

detachInterrupt(0) //desconecta o interrupt 0
detachInterrupt(1) //desconecta o interrupt 1

O qualificador “volatile”

No código anterior utilizamos o qualificador de variável “volatile”. Isto é necessário porque existe uma variável (estado) , que deve persistir durante toda a vida do programa, esteja a rotina de interrupção sendo executada ou não. “Volatile” garante a existência da variável mesmo após a término de execução da rotina de interrupção. Se não definirmos desta forma, a variável poderia se alterar aleatoriamente entre as chamadas de interrupção, levando a um comportamento errático do programa.

Habilitando e desabilitando interrupts no arduino

Muitas vezes é necessário garantir que um determinado trecho de código não será interrompido por nada. Para estas situações temos a instrução noInterrupts(). Para habilitar todas as interrupções novamente utilize a instrução interrupts()

Processando interrupções internas

Para o processamento de interrupções internas temos uma forma diferente de codificar. Esta forma pode ser utilizada também com as interrupções externas, porém neste caso o uso de attachInterrupt/dettchInterrupt é mais fácil.

Esta forma utiliza macros para definir o ponto de entrada de uma rotina de interrupção. Chamamos as rotinas de interrupção de ISR (interrupt service routine). o código fica da seguinte forma:

Utilizamos a macro ISR(nomedovetor)

.Processando um interrupt INT0

ISR(ADC_vect)
{
 //aqui fica o código a ser executado quando chega o interrupt de finalização de conversão AD
}

// SPI interrupt routine
ISR (SPI<i>STC</i>vect)
{
// aqui fica o código a ser executado quando a transferência serial foi completada
}

Dicas para escrever o código de atendimento a uma interrupção

  • Deve ser curto e rápido
  • Não utilize a função delay()
  • Não utilize a função Serial.print()
  • Variáveis devem ser volatile
  • Não ligue os desligue interrupts dentro do código

Exemplo de processamento de interrupções internas e externas simultaneamente

Vamos desenvolver um programa para o arduino UNO que tenha a seguinte funcionalidade:

  • Ao ser ligado, o led da placa pisca com uma frequência de 1 Hz
  • Quando aterramos a entrada D2, a frequência aumenta
  • Quando aterramos a entrada D3, a frequência diminui

Não deve ser utilizado nenhum componente externo, além dos interruptores que permitem aterrar D2 e D1. Que podem ser substituídos por um pedaço de fio!

Veja se você consegue implementar este programa com as informações aqui repassadas e compare com a nossa solução, disponível na página https://cadernodelaboratorio.com.br/scripts-softwares-e-arquivos-de-configuracao/, sob o nome pack171002.tar.gz . Se achar a sua solução melhor do que a nossa e deseja compartilhá-la, nos envie (GNU General Public License), para que a divulguemos juntamente com a nossa alternativa.

Deixe um comentário