MCO018703 2022 2 AULA11

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar

Timers e Interrupções

Temporização é fundamental quando se trabalha com circuitos microcontrolados, seja para um simples delay (tempo de espera) ou para geração de sinais ou eventos periódicos. Todo microcontrolador tem pelo menos um periférico temporizador/contator. Esse periférico possui hardware dedicado para contagem de tempo e o seu correto uso, auxilia em uma programação mais eficiente para realização de diversos projetos. Já uma interrupção é um sinal enviado por um dispositivo de hardware que temporariamente interrompe a tarefa que a CPU está executando no momento, para que o dispositivo seja atendido e, logo após, o programa retoma seu processamento do ponto onde havia parado.


Timers do ATmega328

O Atmega328, utilizado na placa Arduino UNO, possui 3 timers, sendo dois de 8 bits (TIMER0 e TIMER2) e um de 16 bits (TIMER1). Esses temporizadores são utilizados para diversas funcionalidades, tais como:

  • Temporização;
  • Contagem de eventos externos;
  • Geração de sinais PWM;
  • Interrupções periódicas;
  • Medida de intervalos de pulsos.


Cada temporizador possui características próprias e são utilizados conforme os recursos disponíveis. A biblioteca do Arduino abstrai o uso destes temporizadores em muitas de suas funções. Por exemplos, as funções delay(), millis(), micros(), tone(), analogWrite() utilizam recursos de timers para o funcionamento.


O TIMER1 é utilizado somente em algumas bibliotecas no Arduino específicas, podendo ser utilizado para outras finalidades sem causar muito impacto no funcionamento do restante das funções. [1]

Interrupções no Arduino

No Arduino, assim como em qualquer outro microcontrolador, pode-se utilizar interrupções para priorizar ou não tarefas e resolver problemas de tempo (timing). Existe dois tipos de interrupção no Arduino: a interrupção interna que permite interromper um código, caso o Arduino precise "rodar" o código inteiro sem ser interrompido; e a interrupção externa, dada pela portas digitais 2 e 3.


Interrupção Externa

O exemplo abaixo demonstra o uso da interrupção externa de forma simples e funcional. O exemplo adotado é o blink (pisca-pisca) com botão utilizando interrupção externa, a figura abaixo mostra a montagem, e, em seguida apresentamos o código fonte.

Fig33 MCO18703.png

Figura 1 - Circuito exemplo de Interrupção Externa.

Nota
O capacitor de 100nF serve como "delay" para o botão, já que a interrupção é muito rápida e precisa de um atraso para poder funcionar corretamente, e um resistor de 4,7k ohms como Pull-Up.


int pin = 13;
volatile int state = LOW;
volatile int state1 = LOW;

void setup()
{
   pinMode(pin, OUTPUT);
   attachInterrupt(0, blink, FALLING);  // chama a função blink quando o pino 2 (0) for pressionado.
}                                       // o pino vai de HIGH para LOW

void loop()
{
   digitalWrite(pin, state);

}

void blink()
{
   if(state==state1) {
      state = !state1;
   }
   else {
      state=state1; 
   }
}


Entendendo o Hardware

As placas Arduino possuem pinos que podem desempenhar a função de entrada de sinal para interrupção externa. No Arduino UNO são as portas digitais 2 e 3, que para tal função são nomeadas de INT0 e INT1, respectivamente. Veja a tabela a seguir com os pinos de cada placa Arduino que possuem essa qualidade.

Board Digital Pins Usable For Interrupts
Uno, Nano, Mini, other 328-based 2, 3
Mega, Mega2560, MegaADK 2, 3, 18, 19, 20, 21
Micro, Leonardo, other 32u4-based 0, 1, 2, 3, 7
Zero all digital pins, except 4
MKR1000 Rev.1 0, 1, 4, 5, 6, 7, 8, 9, A1, A2
Due all digital pins
101 all digital pins (Only pins 2, 5, 7, 8, 10, 11, 12, 13 work with CHANGE

 

Board int.0 int.1 int.2 int.3 int.4 int.5
Uno, Ethernet 2 3
Mega2560 2 3 21 20 19 18
32u4 based (e.g Leonardo, Micro) 3 2 0 1 7
Due, Zero, MKR1000, 101 interrupt number = pin number


Dessa forma, para que seja possível o uso da interrupção externa, escolhemos o pino digital 2 (INT0), no qual conectamos o botão. Entendendo o programa

Considerando que você já sabe o básico , você já pode entender a maioria dos programas. Dessa forma, iremos nos ater às novidades. Configurando a interrupção externa no Arduino

Para que o Arduino leia uma interrupção, devemos configurá-lo. Para tal usaremos o comando attachInterrupt().

attachInterrupt(INT,FUNCAO,MODO); //Configurando a interrupção

Onde:

INT
Número da porta usada para a interrupção. No Arduino UNO INT 0 corresponde à porta digital 2 e INT 1 corresponde à porta digital 3; Como explicado anteriormente, numa interrupção temos dois pontos chaves: a condição da interrupção e a função que será executada. Dessa forma, o comando attachInterrupt é usado para informar ao programa esses dados. São eles:
FUNÇÃO
Nome da função que será chamada e executada quando ocorrer a interrupção;
MODO
Define em qual tipo de variação do sinal a interrupção será disparada. As opções são:
LOW: Dispara a interrupção quando a tensão no pino está em 0V
CHANGE: Dispara sempre que o sinal no pino muda de estado, borda 0V (0) para 5V(1) ou vice-versa;
RISING: Dispara somente borda de subida, 0v (0) para 5V (1);
FALLING: Dispara somente borda de descida, 5V (1) para 0V (0)
Fig33b MCO18703.png

Figura 2 – Borda de subida e de descida de um pulso. [5]

Em nosso programa exemplo, usamos esse comando da seguinte forma:

attachInterrupt(0,blink,FALLING); //Configurando a interrupção

Portanto, temos como condição de interrupção a mudança de estado de 5V (1) para 0V(0) no pino digital 2 (INT 0) e a função a ser executa se chama interrupção.

Função blink()
Função é um bloco de tarefas a serem executadas pelo programa quando solicitada.
void blink()
{
   if(state==state1) {
      state = !state1;
   }
   else {
      state=state1; 
   }
}

No nosso caso, a função será solicitada quando ocorrer a interrupção e a tarefa executada será trocar o estado do LED.

Interrupção Interna

Os timers podem ser configurados para gerar uma interrupção quando o seu contador chegar ao valor máximo (timer overflow).

A configuração "manual" dos timers é bem trabalhosa pois exige a manipulação de vários registradores do microcontrolador, mas existem algumas bibliotecas que permitem fazer isso de forma simples. Vamos usar a biblioteca Timer1 e Timer3 está no [Arduino Playground].

O primeiro passo é baixar as bibliotecas e coloca-las na pasta hardware/libraries/ que está dentro da pasta do Arduino ou em sketchbook/libraries/. O local exato destes diretórios depende do sistema operacional (Linux, Mac ou Windows) e também da forma como a IDE do Arduino foi instalada.


Usando a biblioteca

A descrição completa do funcionamento da biblioteca está neste [link]. As principais funções da biblioteca são:

initialize(periodo)

Esse método deve ser chamado antes de qualquer outro método, pois ele é responsável pelas configurações iniciais. Você pode opcionalmente informar o intervalo (em microsegundos) no qual a interrupção deve ser gerada. O menor tempo aceito é 1 micro-segundo e o tempo máximo é de 8.388.480 micro-segundos, ou seja, aproximadamente 8,3 segundos. Caos não seja informado nenhum valor, será atribuído o valor padrão de 1.000.000 micro-segundos (1 segudo). Quando usado o timer1 o analogWrite() nos pinos 9 e 10 do Arduino param de funcionar.

setPeriod(periodo)

Modifica o período da interrupção.

attachInterrupt(funcao, periodo)

Atribui uma função para ser chamada a cada interrupção gerada pelo timer. Se não for especificado um período, será utilizado o período definido na inicialização ou por setPeriod.

Testando a biblioteca

Para testar essa biblioteca não é necessário nenhum hardware adicional, basta usarmos o LED conectado ao pino 13 da placa do Arduino e escrever um novo blink.

Aqui está a versão traduzida do exemplo que está na página da biblioteca:

/*
* Timer1 library example
* August 2012 Translated by Tiago de França Queiroz
* June 2008 | jesse dot tane at gmail dot com
*/

#include "TimerOne.h"

void setup()
{
pinMode(13, OUTPUT);
Timer1.initialize(500000); // Inicializa o Timer1 e configura para um período de 0,5 segundos
Timer1.attachInterrupt(callback); // Configura a função callback() como a função para ser chamada a cada interrupção do Timer1
}

void callback()
{
digitalWrite(13, digitalRead(13) ^ 1);
}

void loop()
{
// Seu código vai aqui...
}


Para usar os outros timers basta substituir o #include <TimerOne.h> por #include <TimerTree.h>, #include <TimerFour.h> ou #include <TimerFive.h> e no resto do código substitua Timer1 por Timer3, Timer4, ou Timer5.

Essas bibliotecas são úteis em várias situações, comoquando o loop principal do seu programa está bloqueado por algum motivo (esperando um botão ser pressionado, por exemplo) e você precisa atualizar um display, ou ler um sensor independentemente do loop principal, entre outras.

É importante lembrar que o tempo necessário para executar as funções que são chamadas na interrupção dos timers deve ser MENOR do que o tempo entre as interrupções!

Lembre-se que a versão que eu modifiquei a função de pwm (que eu não falei nesse post) está desativado.

Referências

[1] https://www.embarcados.com.br/timers-do-atmega328-no-arduino/

[2] http://labdegaragem.com/profiles/blogs/tutorial-executando-fun-es-em-intervalos-de-tempo-fixos-timers

[3] http://www.bosontreinamentos.com.br/eletronica/arduino/como-usar-interrupcoes-com-arduino/

[4] https://portal.vidadesilicio.com.br/usando-a-interrupcao-externa-no-seu-arduino/

[5] https://www.electronicwings.com/pic/pic18f4550-timer-capture



Icone voltar.png Icone menu.png Icone prox.png