Tutorial: Executando funções em intervalos de tempo fixos (timers) com Arduino

Esse tutorial eu postei originalmente no meu blog: blog.tiago.eti.br, e decidi reproduzi-lo aqui.

Embora o Ardiono seja uma plataforma muito fácil de utilizar e com bastante recursos, eu acho que ela ainda deixa a desejar em alguns apectos. Um deles é a falta do acesso direto aos timers pela biblioteca padrão do arduino. Nesse post eu vou mostrar como utilizar uma biblioteca para configurar de forma simples os timers do Arduino.

Mas o que são os Timers?

Um timer nada mais é do que um contador que é incrementado a cada intervalo de tempo (em alguns microcontroladores intervalo pode ser configurado, o Arduino é um deles). Os timers funcionam como um relógio que pode ser usado para contar o tempo, medir a duração de certos eventos, entre outras aplicações.

O Arduino vem equipado com um microcontrolador ATmega168 ou ATmega328 (que diferem apenas na quantidade de memória interna). Esses microcontroladores possuem e timrestimer0, timer1 and timer2, Timer0 e timer2 são contadores de 8bits, ou seja, contam de 0 a 255, e o timer1 é um contador de 16bits, conta de 0 a 65535.

O Arduino Mega vem equipado com o ATmega1280 ou ATmega2560 (que diferem apenas na quantidade de memória). Eles possuem 6 timerstimer0, timer1, timer2, timer3, timer4, timer5. Os timers 0, 1 e 2 são idênticos aos do ATmega168/328, e os timers 3, 4 e 5 são ambos de 16bits.

Timer0:

timer0 é utilizado pelo Arduino para funções como delay()millis() e micros(). Então não se deve utilizar esse timer para evitar comprometer essa funções.

Timer1:

No Arduino UNO esse é o timer utilizado pela biblioteca de controle de servos. Caso você não esteja utilizando essa biblioteca, esse timer está livre para ser utilizado para outros propósitos. No Arduino Mega esse timer só será utilizado para controlar os servos se você estiver usando mais de 12 servos.

Timer2:

Esse timer é utilizado pela função tone(). Então se você não precisar da função tone() esse timer está livre para outras aplicações.

Timer3 e Timer4:

Esses timers só estão presentes no Arduino Mega e eles só serão utilizados pela biblioteca do Arduino caso vocês esteja utilizando mais de 24 servos. De 25 a 36 servos o timer3 será utilizado e de 37 a 48 servos o timer4 será utilizado.

Timer5:

No Arduino Mega esse é o timer padrão para o controle de servos, ou seja, se você estiver utilizando de 1 a 12 servos, apenas esse timer será utilizado pela biblioteca.

Usando os timers

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

Interrupções

No Arduino (e nos microcontroladores de forma geral) o programa é executado sequencialmente, linha após linha, instrução após instrução. Uma interrupção é um evento externo que interrompe a execução do programa e chama uma função para tratar a interrupção, após o fim dessa função a execução normal do programa é retomada de onde parou.

Os timers podem ser configurados para quando atingirem o valor máximo da contagem (overflow) gerarem uma interrupção e chamarem uma função específica.

Configurando os timers

A configuração "manual" dos timers é bem chata e trabalhosa pois exige a manipulação de vários registradores do microcontrolador, mas felizmente existem algumas bibliotecas que permitem fazer isso de forma bem simples. O meu objetivo é mostrar como usar a biblioteca Timer1 e Timer3 que está no Arduino Playground, e também em uma versão modificada delas que eu fiz para poder trabalhar com os timers 4 e 5. A minha versão modificada pode ser baixada aqui.

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, mas eu irei fazer um breve resumo aqui. 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:

http://letsmakerobots.com/node/28278

http://arduino.cc/playground/Code/Timer1

Load Previous Comments
  • Frank Albrecht Andriessen

    Bom dia Tiago, pode me ajudar? estou montando um sistema que me avisa quando a caixa d'água chega no vazio, ai dispara um BUZZER, queria adicionar um botao que quando presionado espera 5 minutos para verificar se a caixa encheu, caso contrario ele dispara o buzzer novamente.

    Se quiser e puder,  te mando o programa  para analisar.

    Obrigado

  • José Ewerton da Silva Sousa

    Boa tarde, gostaria de saber como faço ara alterar o tempo que o led fica ligado no void loop usando a biblioteca timer1

    #include "TimerOne.h"

    int timer;


    void setup()
    {
    pinMode(13, OUTPUT);
    Timer1.initialize(timer); // 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()
    {


    timer = 5000000; // novo tempo
    // CODIGO
    }

  • Natalino Aparecido de Abreu

    Valeu! Foi a melhor explicação que achei para o funcionamento do Timer1.