Introdução
Temporização é fundamental quando se trabalha com circuitos microcontrolados, seja para um simples delay ou para geração de sinais ou eventos periódicos. Desde o mais simples microcontrolador sempre está disponível 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 eficiente para realização de diversos projetos.
Neste artigo vamos explorar os recursos de um dos timers do ATmega328, o TIMER1, utilizado na plataforma Arduino, entendendo seu funcionamento e o uso de seus registradores.
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 importantes 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. A seguir serão apresentadas suas características.
TIMER 1
O TIMER1 é um temporizador de 16 bits que permite a contagem de eventos, geração de sinal PWM, medida de pulsos, etc. Seu diagrama de blocos, conforme apresentado no datasheet do ATmega328 é apresentado na figura 1:
Registradores
O controle do modo de operação do TIMER1 é feito nos registradores TCCR1A e TCCR1B, conforme descrição a seguir.
Bits 7:6 – COM1A1:0: Compare Output Mode for Channel A
Bits 5:4 – COM1B1:0: Compare Output Mode for Channel B
COM1A1:0 e COM1B1:0 controlam os pinos de Output compare (OC1A e OC1B), respectivamente, conforme tabelas a seguir:
Tabela 1: Configuração para Modo não PWM
Tabela 2: Configuração para modo PWM rápido
Tabela 3: configuração para modo PWM com correção de fase e frequência
Bits 1:0 – WGM11:0: Waveform Generation Mode
Juntos com os bits WGM13:2 encontrados no registrador TCCR1B, controlam o funcionamento do TIMER1, conforme tabela 4 a seguir:
Tabela 4: Modos de funcionamento do TIMER 1
Bit 7 – ICNC1: Input Capture Noise Canceler
Bit para habilitar filtro de ruído no pino de captura ICP1.
Bit 6 – ICES1: Input Capture Edge Select
Seleciona qual borda no pino de entrada (ICP1) será usada para disparar evento de captura.
Bit 5 – Reserved
Bit reservado, deve ser escrito zero.
Bit 4:3 – WGM13:2: Waveform Generation Mode
Conforme apresentado anteriormente e exibido na tabela 4
Bit 2:0 – CS12:0: Clock Select
Bits para seleção de clock, conforme tabela 5
Tabela 5 – Configuração para seleção de clock
Conforme observado na figura 1, exitem outros registradores para funcionamento do TIMER1:
TCNT1H and TCNT1L – Timer/Counter1:
Resgistradores de armazenamento de contagem do timer.
OCR1AH and OCR1AL – Output Compare Register 1 A
OCR1BH and OCR1BL – Output Compare Register 1 B:
Registradores para comparação de contagem com o TCNT1. A igualdade pode gerar uma interrupção ou gera uma saída de onda nos pinos OC1A ou OC1B.
ICR1H and ICR1L – Input Capture Register 1:
Registradores para armazenamento de captura quando um evento ocorrer no pino ICP1.
TIMSK1 – Timer/Counter1 Interrupt Mask Register:
Registrador para habilitar as interrupções disponíveis no TIMER1.
TIFR1 – Timer/Counter1 Interrupt Flag Register
Registrador para flags de interrupções.
Para mais detalhes do funcionamento dos registradores, acesse o datasheet do ATmega328.
Utilizando o TIMER1 no Arduino
Modo Normal com interrupção por overflow
O exemplo a seguir exibe como piscar o LED no pino 13, da placa Arduino UNO, em intervalos de 1 segundo e utilizando interrupção por estouro timer:
#define ledPin 13
void setup()
{
pinMode(ledPin, OUTPUT);
// Configuração do timer1
TCCR1A = 0; //confira timer para operação normal pinos OC1A e OC1B desconectados
TCCR1B = 0; //limpa registrador
TCCR1B |= (1<<CS10)|(1 << CS12); // configura prescaler para 1024: CS12 = 1 e CS10 = 1
TCNT1 = 0xC2F7; // incia timer com valor para que estouro ocorra em 1 segundo
// 65536-(16MHz/1024/1Hz) = 49911 = 0xC2F7
TIMSK1 |= (1 << TOIE1); // habilita a interrupção do TIMER1
}
void loop()
{
//loop principal. a manipulação do led é feita na ISR
}
ISR(TIMER1_OVF_vect) //interrupção do TIMER1
{
TCNT1 = 0xC2F7; // Renicia TIMER
digitalWrite(ledPin, digitalRead(ledPin) ^ 1); //inverte estado do led
}
Nesse exemplo o timer foi configurado para modo normal, com pinos OC1A e OC1B desconectados (TCCR1A = 0). Foi selecionado o prescaler para 1024 através do registrador TCCR1B. Para que o timer estoure a cada segundo é necessário iniciar seu valor com a diferença entre o seu valor máximo (65536) e o período desejado. O período é calculado levando em consideração a frequência do oscilador e o prescaler selecionado, além da frequência de interrupção desejada. Por fim foi habilitada a interrupção de estouro do TIMER1 através do bit T0IE1 do registrador TIMSK1. A inversão do LED é feita na rotina de interrupção, note que é necessário recarregar o timer para a correta contagem.
MODO CTC interrupção por comparação
O exemplo a seguir exibe como piscar o LED, utilizando o modo CTC e gerando interrupção por comparação:
#define ledPin 13
void setup()
{
pinMode(ledPin, OUTPUT);
// Configuração do TIMER1
TCCR1A = 0; //confira timer para operação normal
TCCR1B = 0; //limpa registrador
TCNT1 = 0; //zera temporizado
OCR1A = 0x3D09; // carrega registrador de comparação: 16MHz/1024/1Hz = 15625 = 0X3D09
TCCR1B |= (1 << WGM12)|(1<<CS10)|(1 << CS12); // modo CTC, prescaler de 1024: CS12 = 1 e CS10 = 1
TIMSK1 |= (1 << OCIE1A); // habilita interrupção por igualdade de comparação
}
void loop()
{
//loop principal. a manipulação do led é feita na ISR
}
ISR(TIMER1_COMPA_vect) // interrupção por igualdade de comparação no TIMER1
{
digitalWrite(ledPin, digitalRead(ledPin) ^ 1); //inverte estado do LED
}
Nesse exemplo é utilizado o modo CTC, dessa forma o valor de contagem do timer é constantemente comparado com o registrador OCR1A. Para o funcionamento foi selecionado o modo CTC, bit WGM12 = 1 e configurado o prescaler para 1024. O valor de comparação foi carregado no registrador OCR1A e por último foi habilitada a interrupção de comparação. A inversão do LED é feita na rotina de interrupção, e note que não é necessário reiniciar o timer com um valor, pois o modo CTC zera o timer quando atingido valor de comparação.
Está disponível no sites do Arduino uma biblioteca para manipulação do TIMER1. Essa biblioteca abstrai todas as configurações dos registradores facilitando o uso do TIMER1.
Saiba Mais sobre Arduino
Arduino – Entradas/Saídas digitais
Acionamento de uma lâmpada com Arduino





Poderiam me tirar uma dúvida sobre os Timers do Arduino? O Arduino Uno tem 3 Timers, correto? Pelo que entendi, quando a contagem de tempo de um Timer termina, ele envia um sinal ao µC que o faz pausar o fluxo normal de seu programa e desvia para a rotina de interrupção que você criou. Pois bem, o que acontece, por exemplo, se o Timer 0 estiver executando sua rotina de interrupção e, no meio dessa execução, coincidir com o tempo em que o Timer 1 também envia seu sinal de interrupção? O µC larga a execução do Timer 0… Leia mais »
Se ocorrer uma interrupção enquanto outra estiver em execução a segunda será agendada para ser executada logo após o termino da primeira, isso por padrão. Mas também é possível configurar para que a interrupção atual pule a que já está em execução, isso é chamada interrupção aninhada e pode ser visto na página 15 do datasheet da Atmega 328P. Na página 49 é possível ver a lista de prioridade da mais importante para a menos importante.
Ótima referência. Estou sempre consultando.
Obrigado Angélica.
bah me foi muito util. Consegui alterar a rotação do motor de passo para um valor superior á: digitalWrite(PUL, HIGH); //motor de avanço – pino3 delay(1); digitalWrite(PUL, LOW); //motor de avanço – pino3 delay(1); Sem que sem o delay de “1” o motor não gira. A maior rotação que consegui foi com os dados abaixo: TCCR1B |= (0<<CS10)|(1 << CS11)|(0 << CS12); TCNT1 = 0xFCA8; enviando sinal para um driver WD2400 na posição de 200 pulse/rev. Agora me perdi em uma conta. Como eu encontro quantos pulsos/segundo está sendo enviado ? Como posso saber o limite de pulso/segundo que o driver aceita… Leia mais »
Caro professor,estou usando o Arduíno Uno 328 e duas pontes H 43a em um projeto utilizando 2 motores DC24 volts,minha dúvida,é possível eliminar um ruido tipo(tuuuuuuuuuuuu) nos motores?Qual tipo de filtro posso utilizar?Pelo visto este ruido é provocado pelo PWM.Fiz a leitura pelo frequencímetro na saída das pontes,obtive uma leitura de 49 a 50 hz.
Geraldo, isso mesmo, o ruído é causado pela frequência de chaveamento do PWM. Você pode aumentar a frequencia de chaveamento para casa de Khz. Deve eliminar o ruído.
Muito obrigado professor,eu não sabia desta modalidade,e vou procurar fazer esta modificação.Agradeço muito pela atenção.Um forte abraço.Gratidão.
Estou tentando usar o timer 0 e ele não aceita o TIMER0_OVF_vect tentei mudar para timer 0 e alterar os valores para 8 bits porém não consegui.
Qual erro está dando?
Abraços,
Boa Noite! tenho algumas dúvidas: 1 – no seu código não precisou habilitar as interrupções globais com “sei()”? por que? 2 – no arduino, o fuse BOOTRST está habilitado. Então os vetores das interrupções seriam deslocados para o início da sessão de bootloader na memória de programa. Isso implica que o bit IVSEL no MCUCR deveria estar setado para que as interrupções ocorram nos endereços corretos. Por que no seu código não precisou? OBS.: Estou tendo muitos problemas ao utilizar interrupções do timer no arduino. Já tentei com e sem as opções citadas por mim acima. Se me forem sanadas… Leia mais »
Olá Henrique,
segue respostas:
1- Por default as interrupções estão habilitadas em um sketch arduino
2- O código arduino faz a configuração dos vetores
Qual timer vocês quer usar? Verifique se não está tendo conflito de configuração nas funções.
Vai mandando as dúvidas aqui.
Abraços,