Os microcontroladores são projetados para executar firmware conciso dedicado a uma aplicação específica. O firmware é um software incorporado, que é gravado na memória do programa. Os códigos de firmware são normalmente curtos e projetados para gerenciar e executar diversas microtarefas até o nível do hardware.
Como os microcontroladores são dedicados a uma única aplicação, esses dispositivos não possuem computação paralela e, por padrão, o código é executado sequencialmente. Isso significa que quaisquer alterações externas (hardware) ou condições de software são pesquisadas em ordem linear através do loop de programação.
No ecossistema do Arduino, esse loop de programação é escrito e executado dentro da função loop .
Polling é o padrão pelo qual um microcontrolador funciona. Polling é o processo em que o controlador aguarda seu estado ou próxima tarefa do dispositivo externo. Isto pode ser problemático quando o controlador precisa responder a uma situação dentro de um curto espaço de tempo — ou imediatamente.
Isto pode ocorrer quando há uma mudança repentina nas condições de programação ou no estado do hardware. Felizmente, os microcontroladores têm uma função para lidar com esses desafios, chamada de interrupções.
O que é uma interrupção?
Uma interrupção em relação aos microcontroladores é um mecanismo que suspende temporariamente o programa principal, passando o controle para um código provisório.
Em termos de Arduino, isso significa que o código típico definido no loop de programação (ou seja, função loop ) é suspenso e um código de resposta é executado, relacionado à condição específica do software ou alteração de hardware. Essa resposta é definida em um bloco de código bem estruturado, denominado Interrupt Service Routine (ISR).
Suponhamos que um microcontrolador em um rover robótico esteja programado para navegar por terrenos acidentados, superando diversos obstáculos. O rover rastreia seu estado monitorando dados, usando sensores ultrassônicos e acelerômetros. A certa altura, um buraco escuro é detectado ao longo do caminho.
No entanto, o poço só é percebido quando o rover está a cerca de 30 centímetros de distância dele, o que é um problema. Os dados dos sensores são monitorados em um loop de programação regular, o que significa que esta mensagem sobre o poço normalmente seria retransmitida tarde demais para que o controlador respondesse a tempo.
Felizmente, uma interrupção salva o dia deste veículo espacial. O sensor acelerômetro, neste caso, gera uma interrupção sempre que há uma mudança repentina na orientação do rover robótico, sinalizando para que ele pare. O código de interrupção salvou o veículo espacial de cair no buraco no último minuto.
Compreendendo a ISR
Uma rotina de serviço de interrupção (ISR) é um bloco de código executado em resposta a uma interrupção. Claro, existem diferentes tipos de interrupções.
A chave é que as interrupções de um microcontrolador devem sempre ser bem definidas e corresponder a uma condição específica de software ou estado de hardware.
No Arduino, as interrupções são identificadas por vetores de interrupção.
Interrupções no Arduino
Existem várias placas diferentes no portfólio Arduino, cada uma com microcontroladores diferentes. Esta tabela resume várias dessas plataformas…
Observação: Esta tabela não inclui placas Arduino aposentadas, como Arduino Esplora, Arduino Industrial 101, Arduino 101, Arduino Ethernet Rev3, LilyPad Arduino, LilyPad Arduino Simple, LilyPad Arduino USB, LilyPad Arduino SimpleSnap, Arduino Gemma, Arduino Yún Mini, Arduino Yún, Arduino Leonardo ETH, Arduino Tian, Arduino M0, Arduino M0 Pro, Arduino Mega ADK Rev3, Arduino Robot, Arduino Pro, Arduino Mini e Arduino Pro Mini.
Como cada microcontrolador possui um conjunto de periféricos integrados e interfaces de entrada/saída, faz sentido que as interrupções sejam diferentes para cada plataforma de microcontrolador.
O controlador central do Arduino Uno e Arduino Nano – ATmega328 – suporta essas interrupções…
Todas as interrupções são geradas pelos periféricos integrados ou interfaces de E/S do ATmega328, que são diferentes em outros microcontroladores.
A prioridade de interrupção indicada na tabela acima é importante quando mais de uma interrupção é gerada ao mesmo tempo. Quando isso acontece, a interrupção de maior prioridade é executada enquanto a de menor prioridade é suprimida.
“Reset” é a interrupção de maior prioridade e não possui vetor de interrupção. Isso significa que na reinicialização/reinicialização, nenhuma rotina definida pelo usuário pode ser executada.
Em termos gerais, as interrupções são classificadas em duas categorias.
1. Interrupções de hardware:
gerado pelos pinos de entrada/saída do microcontrolador. Um hardware/componente externo aciona uma mudança no sinal de tensão para o pino de entrada/saída do Arduino.
No Arduino, existem dois tipos de interrupções de hardware: interrupções externas e interrupções de mudança de pino.
2. Interrupções de software:
gerado por instruções de programa definidas pelo usuário. Eles estão sempre associados aos periféricos integrados e à porta de comunicação do microcontrolador. Essas interrupções são
não
acionado por um componente de hardware externo, mas por alterações nos periféricos integrados ou na configuração do software.
Os periféricos integrados devem ser configurados para gerar interrupções escrevendo instruções de programa. Caso contrário, a interrupção é gerada automaticamente após a conclusão de uma instrução de software associada a uma porta/periférico de comunicação.
Por exemplo, interrupções de temporizador são interrupções de software. As interrupções do temporizador devem ser configuradas por instruções de programa definidas pelo usuário. As interrupções geradas pelas portas de comunicação também são interrupções de software, pois são acionadas quando o processo de comunicação de dados é concluído pelas instruções do programa definidas pelo usuário.
Implementando interrupções no Arduino
Os ISRs são definidos como blocos separados de código além da função loop principal. As interrupções já estão habilitadas por padrão. Todas as interrupções de software requerem programação definida.
Por exemplo, temporizadores podem ser configurados para gerar interrupções somente quando programados pelo usuário. As interrupções de hardware (ou seja, interrupções externas e de mudança de pino) devem ser configuradas na função setup .
Também é possível habilitar ou desabilitar interrupções na função loop para evitar interrupções na execução do programa ou reativar interrupções.
Para desabilitar interrupções, chame a função noInterrupts dentro da função loop da seguinte maneira…
laço {
…
noInterrupções ;
}
Quando as interrupções são desabilitadas, um código crítico e sensível ao tempo deve seguir e ser executado ininterruptamente. As interrupções podem ser reativadas na função loop chamando a função interrupts .
laço {
…
noInterrupts ;//desabilita interrupções
// código crítico e urgente..
interrupts //reativando interrupções
}
As interrupções podem ser atendidas escrevendo uma rotina, na qual uma determinada interrupção é identificada passando seu vetor de interrupção como parâmetro. Normalmente, essa rotina é denominada ISR .
Por exemplo, para servir a interrupção do temporizador, configure-o na função loop e no ISR . No entanto, a interrupção do temporizador deve ser definida fora do loop .
laço {
…
//instruções para configurar e ativar a interrupção Overflow do Timer/Counter0
…
}
ISR(TIMER0_OVF_vect){
//Código servindo interrupção de overflow do Timer/Counter0
}
As interrupções de software e de hardware podem ser atendidas usando seus vetores de interrupção. Para configurar e ativar as interrupções de software, os registros integrados associados ao Arduino devem ser modificados ou programados pelo usuário.
As interrupções externas são configuradas chamando a função attachmentInterrupt na função setup . As interrupções externas são desabilitadas na função loop , utilizando a função detachInterrupt . As interrupções de mudança de pinos são configuradas ou ativadas modificando ou programando os registros integrados associados ao Arduino.
Interrupções externas
Existem dois tipos de interrupções de hardware: interrupções externas e interrupções de mudança de pino. As interrupções externas estão disponíveis nos pinos seletivos do Arduino.
Aqui está uma lista dos pinos utilizáveis para interrupções externas em diferentes placas Arduino.
As interrupções externas devem ser configuradas usando a função attachmentInterrupt no setup.
configurar {
…
attachmentInterrupt(digitalPinToInterrupt(pino), ISR, modo);
}
O attachmentInterrupt aceita três parâmetros.
1. O primeiro parâmetro especifica o número do pino no qual a interrupção externa é ativada. Esse número pin deve ser passado como parâmetro para a função digitalPinToInterrupt .
2. O segundo parâmetro é o nome da rotina de serviço de interrupção que atende a interrupção externa em um determinado pino.
3. O terceiro parâmetro é o modo de interrupção ou transição de sinal no qual a interrupção deve ser gerada.
Aqui estão os modos possíveis de uma interrupção externa…
- BAIXO: a interrupção é gerada quando o sinal digital no pino está baixo.
- MUDAR: a interrupção é gerada quando os valores dos pinos mudam.
- ASCENDENTE: a interrupção é gerada quando o sinal digital no pino se move de baixo para alto.
- CAINDO: a interrupção é gerada quando o sinal digital no pino se move de alto para baixo.
As placas Due, Zero e MKR1000 também suportam um quinto modo.
- ALTO: a interrupção é gerada quando o sinal digital no pino está alto.
Uma interrupção externa definida para o pino 2 do Arduino Uno é a seguinte…
volátil int interrupçãoPin = 2;
configurar {
…
pinMode(interruptPin, INPUT_PULLUP);
attachmentInterrupt(digitalPinToInterrupt(interruptPin), ISR, modo);
}
laço {
…
}
ISR {
//Código para lidar com interrupção externa no pino 2
…
}
Se necessário, as interrupções externas também podem ser desabilitadas na função loop chamando a função detachInterrupt .
laço {
…
detachInterrupt(digitalPinToInterrupt(interruptPin))
}
Escrevendo ISRs
Há diversas considerações importantes ao escrever rotinas de serviço de interrupção.
-
Faça-os curtos e amáveis.
Os ISRs destinam-se a respostas repentinas e de emergência. Eles não foram feitos para executar longos blocos de códigos. Portanto, os ISRs devem ser curtos, precisos e relevantes.
-
Evite funções de temporização.
As funções de temporização — como milis , micros , delayMicroseconds ou delay — nunca devem ser usadas em um ISR. Isso ocorre porque eles usam interrupções de temporizador. Não é possível chamar ou usar uma interrupção em outra interrupção. Portanto, não faz sentido usar funções de temporização com ISRs.
-
Evite protocolos de comunicação serial
. As interfaces de comunicação geram suas próprias interrupções, que são de prioridade mais baixa e não podem substituir as interrupções de hardware ou de temporizador. Além disso, quaisquer dados trocados durante a execução de um ISR serão perdidos. Se for importante armazenar a data durante a execução de um ISR, isso só poderá ser feito alterando as variáveis globais. Na função loop , o estado dessas variáveis pode ser usado para imprimir ou comunicar mensagens.
-
Lembre-se: ISRs não possuem parâmetros.
As rotinas de serviço de interrupção não podem aceitar nenhum parâmetro, exceto o vetor de interrupção. Argumentos adicionais só podem ser passados para um ISR através de variáveis globais.
-
ISRs não retornam nada.
ISRs têm um tipo de dados nulo. Eles não podem retornar nenhum valor. Se um valor precisar ser passado do ISR para o loop principal, ele só poderá ser passado modificando as variáveis globais. (Embora seja possível ler e escrever pinos de entrada/saída digital dentro de um ISR.)
-
Use variáveis voláteis.
As variáveis usadas dentro e fora dos ISRs devem ser variáveis globais e definidas como voláteis. Variáveis voláteis não são otimizadas pelo compilador e não apresentam risco de remoção durante a compilação do código-fonte. No entanto, é importante evitar definir todas as variáveis em um ISR como voláteis porque elas tornam o código mais lento. Portanto, defina apenas as variáveis dentro e fora do ISR como voláteis.
Conclusão
As interrupções fornecem uma função importante no mundo dos microcontroladores. Eles são o único recurso ao lidar com situações críticas ou desafiadoras.
Existem interrupções de hardware e software. As interrupções de hardware são geradas por componentes externos nos pinos de entrada/saída do controlador. O Arduino tem dois tipos, interrupções externas e interrupções de mudança de pino.
As interrupções de software estão relacionadas aos periféricos integrados e às portas de comunicação do microcontrolador. Estas interrupções devem ser ativadas e configuradas por instruções de programa definidas pelo usuário.