Vamos programar com o Arduino – #05: Interrupts
No último tutorial, vimos como funcionam os tempos de espera no nosso Arduino, foi falado na função delay e na micros, funções que nos permitem fazer "tempos de espera" no tempo na nossa placa. No tutorial de hoje iremos falar de Interrupts, uma maneira mais pertinente de trabalharmos com a gestão de eventos no nosso Arduino.
Os Interrupts, como o próprio nome indica, são interrupções que existem no nosso programa. Numa maneira muito resumida, uma interrupção ou Interrrupt é um sinal emitido, para o nosso programa, indicando que um determinado evento está a precisar da sua total atenção. Para tal, precisa imediatamente de parar o que está a fazer e dar atenção a esse evento. Após ter efetuado essa ação prioritária, o programa continua o seu funcionamento a partir de onde foi interrompido.
No Arduino podemos trabalhar com os Interrupts externos e Timer Interrupts.
Interrupts Externos
Os Interrupts, num modo geral, são efetuados ao nível do Hardware, onde um evento externo é acionado e enviado um sinal para o processador. Por exemplo, quando um botão é premido ou quando recebemos informação de um encoder de um motor. Basicamente quando há uma ação ao nível do hardware e queremos que seja efetuada de imediato, que seja prioritária. Contudo os Interrupts externos são fantásticos mas tornam-se um pouco limitados, não a sua capacidade mas em relação à sua quantidade, nem todas os pinos no Arduino suportam Interrupts externos. No caso do Arduino Uno somente suporta dois interrupts (0 e 1) que estão atribuídos nos pinos digitais 2 e 3 da nossa placa. Mas, para grande satisfação, o Arduino Due tem todos os pinos digitais Interrupts. O código para os Interrupts externos é bastante simples e fácil de entender, basicamente basta indicar o interrupt, o que irá fazer e quando o irá executar.
int botao = 2;
unsigned long tempoanterior = 0;
const long intervalo = 1000;
void setup() {
pinMode(botao, INPUT_PULLUP);
attachInterrupt(0, teste, RISING); // Definição do Interrupt:(O Interrupt a usar, função para ser executada, Executar quando for de LOW para HIGH
Serial.begin(9600);
}
// Função para o Interrupt
void teste() {
Serial.println("Interrupt Externo");
}
void loop() {
if (millis() - tempoanterior >= intervalo) {
tempoanterior = millis();
Serial.println("Programa a executar");
}
}
Como podemos ver no código acima apresentado, somente temos que adicionar duas coisas para podermos usar um Interrupt externo, a declaração do Interrupt e uma função que contenha o código que queiramos que seja executado. Nos parâmetros de entrada do attachInterrupt() é necessário colocar o número do Interrupt que vai ser usado, (no caso do Arduino Uno o Interrupt 0 está atrubuido ao pino digital 2 e o Interrupt 1 ao pino digital 3), a função que irá ser executada assim que o Hardware chama ou der sinal ao Arduino. No nosso código temos como último parâmetro RISING, isto significa que o Interrupt irá ser ativado quando o pino do Interrupt for de LOW para HIGH, ou seja, quando for de 0 para 1. Além do RISING existem outros parâmetros, tais como:
- FALLING - Quando vai de LOW para HIGH
- CHANGE - Quando o estado do pino é alterado
- LOW - Quando o nosso pino estiver em LOW
- HIGH - Quando o nosso pino estiver em HIGH ( esta opção só está disponível no Arduino DUE, Zero e MKR1000)
No código apresentado irá sempre apresentar a mensagem "Programa a executar" a cada 1 segundo, sempre que o utilizador prima o botão que está ligado ao pino 2, uma interrupção ocorre no nosso programa e durante esse tempo é mostrada a mensagem "Interrupt Externo".
Timer Interrupts
Os Timer Interrupts têm um objetivo de funcionamento semelhante aos Interrupts Externos, só que somente é usado Software. Este tipo de Interrupts são muito pertinentes pois não contêm limitação de pinos, uma vez que tudo é tratado a nível do Software. Como não podemos ativar a interrupção segundo um tipo de estado de um determinado pino, para fazer a interrupção iremos usar o tempo. Ou seja de x em x de tempo uma interrupção vai acontecer no nosso programa e será executada uma determinada ação. Funciona exatamente da mesma maneira que os Interrupts externos, mas invés de estar à espera de uma determinada ação do Hardware, é através de tempo. Uma das utilizações para os Timer Interrupts é nas leituras dos Sonares, onde queremos que, num determinado tempo, o eco do nosso sonar seja lido, mas num tutorial mais à frente iremos falar do funcionamento dos Sonares e aí entramos em mais pormenor.
Para usarmos os Timer Interrupts no nosso Arduino é necessário usar a a biblioteca TimerOne. Podemos fazer o download da mesma nos repositórios oficiais do Arduino. Esta biblioteca pode ser usada em todos os Arduinos exceto no Arduino Due onde, neste caso, a biblioteca semelhante é a DuoTimer.
#include <TimerOne.h>
unsigned long tempoanterior = 0;
const long intervalo = 1000;
void setup() {
Timer1.initialize(2500) // Inicializa o Timer da interrupção(microsegundos)
Timer1.setPeriod(25000); // Define o Tempo em que irá ocorrer a proxima interrupção(microsegundos)
Timer1.attachInterrupt(teste); // Atribui a função teste ao Interrupt
Serial.begin(9600);
}
// Função para o Interrupt
void teste() {
Serial.println("Timer Interrupt");
}
void loop() {
if (millis() - tempoanterior >= intervalo) {
tempoanterior = millis();
Serial.println("Programa a executar");
}
}
O código acima apresentado tem o mesmo objetivo que o exemplo dos External Interrupts, mas fazendo uma pequena alteração: invés de a interrupção existir com a indicação do Hardware (neste caso do botão) é com uma indicação temporal, em cada 2,5 segundos irá haver uma interrupção no programa e irá ser executada a função teste().
Como podemos observar neste artigo, o uso de Interrupts é muito simples e, ao mesmo tempo, muito útil. Após termos este conhecimento, podemos deixar de parte a função delay() que tantos problemas nos dá quando estamos a trabalhar em multitasking no nosso Arduino. Neste tutorial foi apenas exemplificado o básico da utilização dos Interrupts, iremos trabalhar mais neles em futuros projetos.
Este artigo tem mais de um ano
Na minha sincera opinião quem revela algum tipo de gosto por este tipo de abordagem software/hardware deveria não aprofundar mais o conhecimento em bibliotecas e IDE Arduino e passar para placas de desenvolvimento e linguagens de programação mais sofisticadas.
Quando muito programar placas Arduino em C. Com IDEs que possam ser realmente ser apelidados de IDE e não com IDE Arduino. Não há lugar para Lego na tecnologia. Não nos podemos contentar com uma aplicação que funcione sem entendermos porque. Sem conhecermos tudo o que está por trás disso. Sem entendermos realmente que o overhead por trás de um simples firmware desenvolvido com Arduino IDE e bibliotecas, tem uma enorme probabilidade de falhar. Sem que nunca cheguemos a entender porquê.
Vamos começar a pensar mais à frente um pouco no tempo. Vamos ser BONS naquilo que fazemos, ou pelo menos tentarmos.
A abordagem e a filosofia do Arduino como a maioria conhece é boa … Mas apenas para os primeiros tempos. Para nos habituarmos à electrónica e programação. Mas mal se entenda a essência daquilo temos que mudar.
Se nos deixarmos ficar por umas bibliotecas “pré-fabricadas” e “moduladas” para todo o tipo de projecto nunca vamos ser mais do que montadores de Lego.
Digo:
” Se nos deixarmos ficar por umas bibliotecas “pré-fabricadas” e “moduladas” para todo o tipo de projecto *senão* nunca vamos ser mais do que montadores de Lego. “
Digo:
” Se nos deixarmos ficar por umas bibliotecas “pré-fabricadas” e “moduladas” para todo o tipo de projecto *senão* nunca vamos ser mais do que montadores de Lego. “
concordo com o seu comentário, devemos de saber o que realmente esta a acontecer ao correr com o programa, os registos que estao a ser usados e muito mais, eu comecei por programar microchips, realmente da para fazer de tudo, depois descobri o arduino, que para pequenos projetos pessoais é bem mais fácil de fazer coisas simples.
Pode indicar microchips que usou?
tudo depende do objectivo, para muitos arduinos é passatempo ou para pequenos projectos pessoais.
Quanto a bibliotecas pre-fabricadas, sinceramente toda a gente usa, seja em java, C# ou outra linguagem 😀
Optimo artigo. No entanto deixo aqui uma critica construtiva: o pessoal que frequenta o Pplware é na sua maioria putos novos, iniciados na informática muito depois do comum uso de interrupts quer para configuração de hardware através de jumpers quer em programação, especialmente em Assembly. Portanto seria bastante útil explicar de forma simples o que é um interrupt, e a maneira mais simples que encontro é:
Um interrupt é como se faixa um canal reservado, como que uma faixa de uma autoestrada. Imaginem que ha uma autoestrada com um numero exagerado de faixas, uma reservada a ambulâncias, uma a taxis, uma a autocarros, etc. No entanto quando nenhum destes veículos esta presente na estrada, qualquer outro poderá nalguns casos usa-la, mas assim que um veiculo precisa de usar essa faixa reservada para ele (interrupt), ele apita (pedido de interrupcao), e todos os outros e tudo o resto que acontece a sua volta perde prioridade e é exigida de imediato a libertação desse canal de interrupt. Basicamente, uma tabela de interrupts são canais reservados para pedidos de interrupção ao sistema (BIOS) por parte de dispositos, ou portas que são designados para cada um desses canais.
Vou usar como exemplo a tabela de interrupts do tempo do DOS:
Interrupt 10h – reservado para pedidos de interrupção da placa gráfica
Interrupt 21h – reservado para pedidos do DOS
Mas ha muito a saber nesta area, e muito disso não interessa para este assunto, mas aconselho a familiarizarem-se com o funcionamento de Interrupts, pesquisem, ha muita informação sobre isso, pode parecer assustadora e complexa mas o que precisam de reter é apenas como funcionam.
Desculpem intrometer-me no vosso artigo e espero que de alguma forma a minha tentativa de ajuda tenha ajudado.
Muito boa abordagem, agradeço a sua critica 🙂
Ainda sou do tempo dos jumpers, da necessidade de usar Assembly para se poder tirar partido da maquina, e dos super-rapidos 286 a 12Mhz com disco de 20Mb e monitor monocromatico de 256 tonalidades de cinza. Lol.
Acho que hoje em dia se descura muito o real funcionamento do hardware, e para se poder ter uma boa e saudavel mente de programador acho que isso além de benéfico é quase como que obrigatório. Essa lacuna trás problemas que são facilmente detetáveis nos utilizadores de computadores da actualidade. Nos tempos do “boom” informático, nesses tempos que descrevo acima, muita gente sabia resolver muitas das dificuldades de configuração, instalação, erros de Software e Hardware, e não havia a Internet e o Youtube para ajudar, para poder copiar o que os outros fazem, tínhamos de pesquisar com a pouca informação que tinhas disponível, puxar pelo miolo e usar a experiência, a lógica e muita experimentação. Hoje em dia todos vao atras uns dos outros e nem sabem o que fazem e/ou porque fazem. Atenção que não os culpo, mas talvez à rápida evolução tecnológica, que é inegável e irreversível, e com essa celeridade exige-se também uma celeridade na formação de novos profissionais aos quais se ensina muito pouco da base e começa-se ao meio “da história”, onde se perdem os capítulos em que se cria a base da história. MAs estou convencido que pelo menos os mais apaixonados e com a capacidade de reconhecerem a grandiosidade, a extensão, a complexidade da tecnologia dos nossos dias, tenham a curiosidade e os “tomates” para irem às raízes e perceberem como tudo funciona “atrás do pano”.
de acordo, é importante saber o que é uma interrupção e para que serve, mas neste caso acho que se deve de salientam que um dos maiores interesse na utilização de interrupção (em pequenos projectos com o arduino) é não termos de estar sempre a verificar se algum acontecimento aconteceu, alem disso convem que certos eventos sejam logo tratados, pois se o programa continuasse quando formos dar atenção ao evento da interrupção as condições já podiam ter se alterado. de salientam que o código numa interrupção deve de ser bastantes curto, para não comprometer o resto do programa. ex. se queremos saber um valor externo analógico de segundo a segundo, na interrupção apenas deve de estar a leitura do pin, e a criação de uma flag, e depois na altura mais apropriada essa informação deve de ser tratada no programa geram
Correto. Até porque um interrupt “consome” mais ciclos que uma transação de dados diretamente pela porta (endereço). E por esse mesmo motivo convém também minimizar as chamadas de interrupts em ciclos de curta duração pelo menos.
Eu sugeria procurar por AVR programming. Há muita coisa na net e manuais. Uso para programar código DMX(luzes) baseados no código do Hendrik Hoelscher ou Ulrich Radig agora ando a aprender a multiplexar leds de 7 segmentos (para os endereços DMX)
O que falta neste artigo – cores nesses códigos.
Como apanho os episodios anteriores?
Dantes tinham cuidado em por os links e agr fica tudo ao deus dará?
Deus dará? Nem pensar, aqui no PPLWARE nunca.
Repara que todos os artigos têm uma tag https://pplware.sapo.pt/tag/arduino/ no final do artigo. Dessa forma podes ter acesso a tudo de forma individualizada. Depois, há artigos (guias) que t~em pelo meio a ligação para os anteriores.