Trilha de aprendizado · Nível 10 · Tutorial 5

Intervalos com o Timer1 em modo CTC

Configurar o Timer1 do Uno R3 próprio para produzir intervalos calculados e consultar seus eventos no loop, sem alterar a base de tempo de millis.

  • Nível: Intermediário
  • Duração: 24 min
  • 9 passos
Intervalos com o Timer1 em modo CTC

O que você vai percorrer

  1. Um contador que funciona em hardware Reconheça o Timer1 como contador de hardware independente do loop e prepare o uso responsável dos temporizadores do Uno R3. 2 min
  2. Como o CTC forma um intervalo Entenda como a sequência de contagem do modo CTC determina o intervalo entre comparações. 2 min
  3. Escolha o prescaler e calcule OCR1A Selecione um prescaler que faça o intervalo caber no contador e confira o valor realmente representado. 4 min
  4. Traduza o cálculo em campos de registradores 3 min
  5. Consulte e limpe a flag sem esperar Consulte OCF1A no loop e limpe-a corretamente por escrita direta, sem transformar o evento em uma espera bloqueante. 3 min
  6. Inicialize antes de liberar o clock Prepare o Timer1 em um estado conhecido e só libere seu clock depois de definir todos os parâmetros, preservando o Timer0. 3 min
  7. Dois eventos formam um ciclo do LED Relacione cada comparação atendida à alternância do LED e preveja o ciclo completo da saída. 2 min
  8. Teste o intervalo no seu Uno R3 Grave e observe um sketch completo que alterna o LED integrado por consulta não bloqueante da flag de comparação do Timer1. 4 min
  9. Aplique um novo intervalo e confira o resultado Aplique a configuração de 250 ms com prescaler 64, confira o ciclo do LED e valide as condições de uso seguro do Timer1. 3 min

O que você vai aprender

  • Calcular prescaler e OCR1A para um intervalo que caiba no contador.
  • Configurar o Timer1 em CTC a partir dos campos documentados.
  • Consultar e limpar a flag de comparação sem bloquear o fluxo principal.
  • Prever o período de um LED alternado a cada comparação.
  • Identificar por que reconfigurar um temporizador pode afetar outros recursos que dependem dele.

Antes de começar

  • Sequências de contagem com contadores síncronos
  • Amplitude, frequência, fase e valor eficaz
  • Temporização não bloqueante com millis
  • Controle de GPIOs por registradores no ATmega328P

Passo 1 de 9

Um contador que funciona em hardware

Reconheça o Timer1 como contador de hardware independente do loop e prepare o uso responsável dos temporizadores do Uno R3.

Timer1 avança enquanto o programa trabalha

Timer1 não é um laço de software

Nesta prática, a referência é o Arduino Uno R3 com ATmega328P, cujo clock nominal é de 16 MHz. Não transfira automaticamente estes valores, registradores ou comportamentos para Uno R4, ESP32 ou outras placas.

O Timer1 é um periférico de hardware com um contador de 16 bits. Ele pode assumir valores de 0 a 65535. Depois de configurado, seu contador recebe pulsos de clock e avança sem depender de o processador estar executando rapidamente ou lentamente as instruções do loop().

Assim, o loop() continua disponível para ler entradas, atualizar estados e comandar saídas enquanto o Timer1 conta em paralelo no hardware.

Clock, divisor e contador

Diagrama mostrando o clock passando por um divisor até o contador Timer1, enquanto um fluxo separado representa tarefas do loop.

O prescaler divide o clock antes de ele chegar ao Timer1. A contagem ocorre em hardware, independentemente das tarefas executadas no loop.

Dividir não é bloquear

O papel do prescaler

O prescaler é o divisor aplicado ao clock antes da contagem. Se o divisor reduz a frequência entregue ao Timer1, cada avanço do contador leva mais tempo. Nos próximos passos, você escolherá esse divisor e definirá o limite de contagem para formar intervalos calculados.

Por enquanto, retenha o fluxo: clock de 16 MHz → prescaler → contador Timer1. O processador não precisa executar uma instrução para cada incremento do contador.

Dica

Sem parar o fluxo principal

Enquanto Timer1 conta, o loop() não deve ficar esperando a contagem terminar. A ideia será consultar eventos do temporizador e retornar logo às demais tarefas — uma organização compatível com a temporização não bloqueante já estudada com millis().

Preserve e reserve recursos

Quem pode usar cada temporizador?

O Uno R3 possui mais de um temporizador. Nesta prática, preserve o Timer0: o núcleo Arduino o utiliza para serviços temporais, incluindo millis(). Portanto, não vamos alterar a configuração do Timer0.

Também trate o Timer1 como recurso exclusivo deste exemplo. Reconfigurá-lo muda o funcionamento de tudo que depende dele. Entre os recursos que podem ser afetados estão analogWrite() nos pinos 9 e 10 e bibliotecas que usam Timer1.

Antes de usar esta técnica em um projeto, verifique quem já controla cada temporizador.

Recursos compartilhados exigem planejamento

Esquema de temporizadores do Uno mostrando Timer0 protegido para serviços de tempo e Timer1 ligado aos pinos 9 e 10 e a uma biblioteca.

Uma mesma configuração do Timer1 não deve ser disputada por funções, bibliotecas ou saídas que esperam outro modo de operação.

Atenção

Atenção a conflitos

Evite alterar registradores de um temporizador apenas para “testar”. Uma mudança aparentemente local pode interromper millis(), alterar uma saída ou causar falha em uma biblioteca que já dependia daquele periférico.

Pratique: detecte o conflito

Verifique o uso do Timer1

Um sketch usa analogWrite(9, 128) para controlar uma saída e também pretende reconfigurar o Timer1 para esta prática. Qual conclusão é correta?

Passo 2 de 9

Como o CTC forma um intervalo

Entenda como a sequência de contagem do modo CTC determina o intervalo entre comparações.

A sequência do modo CTC

CTC: contar, comparar e reiniciar

No modo CTC (Clear Timer on Compare), o Timer1 conta de 0 até o valor guardado em OCR1A. Quando a contagem alcança esse limite, ocorre a comparação do canal A e o contador retorna a 0 por hardware para começar outro ciclo.

O loop() não precisa mandar esse retorno acontecer. Ele pode continuar executando outras instruções enquanto o contador avança conforme seu clock dividido pelo prescaler.

Diagrama do fluxo clock dividido, contador de 0 a 4, comparação ao chegar ao limite e retorno automático a zero, enquanto o loop segue independente.

OCR1A estabelece o limite da contagem; o hardware faz o reinício após a comparação.

Conte os valores, incluindo o zero

O limite também é um passo

Considere o exemplo visual com OCR1A = 4. A sequência é:

0 → 1 → 2 → 3 → 4 → 0 → ...

Embora 4 seja o valor máximo contado, há cinco valores no ciclo: 0, 1, 2, 3 e 4. Portanto, o ciclo ocupa OCR1A + 1 passos do clock do contador.

A comparação acontece quando o contador chega a 4. O passo seguinte já inicia a nova contagem em 0.

Exemplo

Exemplo: limite 4

Se o clock que chega ao contador tiver período de 16 µs e OCR1A = 4, cada ciclo terá 5 passos:

T = 5 × 16 µs = 80 µs

Não use apenas OCR1A para contar os passos: isso excluiria indevidamente o valor zero.

A fórmula do intervalo

Da contagem ao tempo

O intervalo entre duas comparações consecutivas é:

T = N × (OCR1A + 1) / f_clock

Em que:

  • T é o intervalo em segundos;
  • N é o prescaler, sem unidade;
  • OCR1A + 1 é a quantidade de passos por ciclo;
  • f_clock é o clock nominal do Uno R3, 16 MHz (16 000 000 Hz).

O termo N / f_clock fornece a duração de um passo do contador. Ao multiplicá-la pela quantidade de passos, obtemos o intervalo completo.

Exemplo

Aplicando a fórmula

Para um exemplo hipotético com prescaler N = 8 e OCR1A = 999:

  • passos por ciclo: 999 + 1 = 1000;
  • duração de um passo: 8 / 16 000 000 s = 0,5 µs;
  • intervalo: 1000 × 0,5 µs = 500 µs.

O próximo step mostrará como escolher valores que atendam a um intervalo desejado e caibam no contador.

Pratique o termo + 1

Verifique a contagem

Em CTC, se OCR1A = 6, quantos passos do clock do contador ocorrem entre comparações consecutivas?

Passo 3 de 9

Escolha o prescaler e calcule OCR1A

Selecione um prescaler que faça o intervalo caber no contador e confira o valor realmente representado.

Encontre uma faixa possível

Do clock ao passo de contagem

O Timer1 recebe o clock nominal de 16 MHz do Uno R3, mas o prescaler o divide antes da contagem. Assim, cada incremento do contador demora:

passo = N / 16 MHz

Como o contador e OCR1A têm 16 bits, o maior valor de OCR1A é 65535. Um ciclo CTC pode, portanto, ter no máximo 65536 passos. Escolha um divisor que faça o intervalo desejado caber nessa faixa.

Opções internas do Timer1

Valores calculados para o clock nominal de 16 MHz e o maior ciclo possível, com OCR1A = 65535.

Quanto maior o divisor, maior o passo e o intervalo máximo possível.
Prescaler NDuração de 1 passoMaior intervalo CTC
10,0625 µs4,096 ms
80,5 µs32,768 ms
644 µs262,144 ms
25616 µs1,048576 s
102464 µs4,194304 s

O divisor define a duração de cada passo

Diagrama mostrando o clock de 16 MHz passando por divisores e chegando ao contador com passos cada vez mais espaçados.

O prescaler não altera o clock da placa: ele determina apenas a frequência que chega ao contador do Timer1.

Calcule e verifique 500 ms

Transforme o requisito em OCR1A

Partindo da fórmula já vista, isole OCR1A:

OCR1A = T × f_clock / N − 1

Use T em segundos, f_clock = 16 000 000 Hz e N como o prescaler. O resultado deve ficar entre 0 e 65535. Depois, substitua o valor escolhido na fórmula do intervalo para conferir o valor nominal obtido.

Não escolha o divisor pelos bits de configuração agora; aqui ele é apenas um número da tabela.

Exemplo

Caso-base: uma opção inválida

Requisito: comparação a cada 500 ms = 0,5 s.

Com N = 64:

OCR1A = 0,5 × 16 000 000 / 64 − 1
OCR1A = 124999

Esse valor ultrapassa 65535. Embora o passo de 4 µs pareça pequeno, essa opção não comporta 500 ms em um ciclo CTC.

Exemplo

Caso-base: uma opção válida

Com N = 256:

OCR1A = 0,5 × 16 000 000 / 256 − 1
OCR1A = 31249

O valor cabe na faixa. Conferindo:

T = 256 × (31249 + 1) / 16 000 000
T = 0,5 s = 500 ms

Logo, N = 256 e OCR1A = 31249 produzem, nominalmente, uma comparação a cada 500 ms.

Represente o intervalo mais próximo

Quando o valor não é inteiro

Nem todo requisito gera OCR1A inteiro. Suponha que o divisor esteja fixado em N = 1024 e o intervalo desejado seja 123 ms.

OCR1A = 0,123 × 16 000 000 / 1024 − 1
OCR1A = 1920,875

OCR1A só aceita inteiros. Arredondando para 1921, recalcule o intervalo real; não anuncie 123 ms como se fosse um valor exato.

Exemplo

Recalcule após arredondar

Com OCR1A = 1921:

T_efetivo = 1024 × (1921 + 1) / 16 000 000
T_efetivo = 0,123008 s = 123,008 ms

O erro em relação ao requisito é +0,008 ms, ou +8 µs. O requisito desejado, o valor representável e o intervalo efetivo são grandezas diferentes.

Se outro arredondamento for escolhido, faça a mesma conferência e compare o erro.

Dica

Regra prática

Para um intervalo, primeiro verifique se o OCR1A calculado cabe de 0 a 65535. Se não couber, tente um prescaler maior. Se não for inteiro, escolha um inteiro próximo e calcule novamente o intervalo efetivo.

Pratique o cálculo

Calcule uma configuração válida

Você precisa de comparações a cada 250 ms, com prescaler N = 64. Qual valor inteiro de OCR1A configura esse intervalo nominal?

Valor de comparação

OCR1A = ____

Confira a faixa

Para o caso de 500 ms, qual afirmação está correta?

Passo 4 de 9

Traduza o cálculo em campos de registradores

Localize cada parâmetro

Quatro funções, quatro registradores

No ATmega328P do Uno R3, o Timer1 é controlado por registradores com papéis diferentes:

  • TCCR1A: contém parte da seleção de modo e os campos das saídas de comparação.
  • TCCR1B: contém outra parte da seleção de modo e o campo que seleciona ou para o clock.
  • TCNT1: mostra a contagem atual do temporizador.
  • OCR1A: guarda o limite de comparação calculado.

Para o caso de 500 ms já calculado, OCR1A = 31249. Ele define o limite; não escolhe sozinho nem o modo CTC nem o prescaler.

Mapa dos controles do Timer1

Diagrama relacionando TCCR1A e TCCR1B aos controles, TCNT1 à contagem atual e OCR1A ao limite de comparação.

TCCR1A e TCCR1B configuram o funcionamento; TCNT1 e OCR1A representam valores do contador e da comparação.

Forme CTC e escolha N = 256

Modo e saídas de comparação

O modo CTC usado aqui é o modo 4. Seus bits de seleção devem formar WGM13:0 = 0100:

  • WGM12 = 1, em TCCR1B;
  • WGM13, WGM11 e WGM10 = 0.

Com essa combinação, OCR1A é o topo da contagem. Os campos COM1A1:0 e COM1B1:0, localizados em TCCR1A, permanecem em zero. Assim, os pinos de saída de comparação ficam desconectados: a comparação acontece internamente, mas não comanda um pino automaticamente.

Campos documentados

Os campos necessários para esta prática

Basta esta referência para montar os campos do caso estudado.
CampoRegistradorFunção nesta prática
COM1A1:0TCCR1AManter em 00: saída A desconectada
COM1B1:0TCCR1AManter em 00: saída B desconectada
WGM11:0TCCR1AManter em 00 para o modo 4
WGM13TCCR1BManter em 0 para o modo 4
WGM12TCCR1BColocar em 1: seleciona CTC 4
CS12:0TCCR1BEscolher clock ou parar o contador

Campo de seleção do clock

O campo CS12:0 define o clock que chega ao contador. O padrão 000 para o Timer1; os demais padrões internos úteis são:

  • 001: N = 1
  • 010: N = 8
  • 011: N = 64
  • 100: N = 256
  • 101: N = 1024

No caso-base, N = 256, portanto CS12:0 = 100. Isso significa CS12 ativo e CS11, CS10 zerados. A escolha do divisor fica em TCCR1B, junto de WGM12.

Verifique sua tradução

Pratique a configuração dos campos

Considere estas atribuições como a tradução dos campos para o caso-base. Elas mostram quais bits representam CTC 4, prescaler 256 e saídas desconectadas; a ordem completa e segura de inicialização será tratada no próximo passo.

Complete as três lacunas sem alterar os demais termos.

Complete os campos

Preencha os campos de TCCR1A e TCCR1B para CTC 4 com prescaler 256.

cpp
TCCR1A = ;
TCCR1B = _BV() | _BV();

Passo 5 de 9

Consulte e limpe a flag sem esperar

Consulte OCF1A no loop e limpe-a corretamente por escrita direta, sem transformar o evento em uma espera bloqueante.

Flag pendente, loop livre

Uma indicação persistente

Quando a contagem do Timer1 alcança OCR1A, o hardware ativa a flag OCF1A no registrador TIFR1. Ela indica que existe uma comparação do canal A pendente de reconhecimento pelo programa.

A flag é persistente: depois de ficar em 1, continua em 1 até que o programa a limpe. Portanto, o loop() pode consultá-la sem ficar esperando. Se ela ainda estiver em 0, o fluxo simplesmente segue para as outras tarefas.

Timer e loop trabalham em paralelo

Diagrama mostrando o Timer1 gerando uma comparação e ativando uma flag, enquanto o loop faz consultas sucessivas sem parar.

O Timer1 gera o evento em hardware; o loop apenas verifica se há uma pendência.

Reconheça sem bloquear

Consulte e reconheça

A consulta usa uma máscara, como nas leituras de bits já estudadas. O operador & verifica se OCF1A está ativo. Quando a condição é verdadeira, execute uma ação curta e limpe a pendência.

A limpeza de flags em TIFR1 tem uma regra especial: escrever 1 limpa o bit correspondente. Use atribuição direta da máscara. Escrever 0 não limpa nada.

Consulta e limpeza corretas

Trecho para usar dentro de loop(). A consulta não bloqueia: se ainda não houve comparação, o programa continua após o if.

cpp
if (TIFR1 & _BV(OCF1A)) {
  // Atenda rapidamente a comparação pendente.

  TIFR1 = _BV(OCF1A);  // Escrever 1 limpa OCF1A.
}

// Outras tarefas do loop continuam aqui.

Atenção

Atenção à escrita especial

Evite TIFR1 |= _BV(OCF1A);. Essa forma lê todas as flags que já estão em 1 e depois escreve esses 1s de volta; como 1 significa “limpar”, outras flags pendentes poderiam ser apagadas junto.

Para reconhecer somente OCF1A, escreva diretamente TIFR1 = _BV(OCF1A);.

Complete o reconhecimento

Pratique a consulta

Complete o trecho que consulta uma comparação pendente do canal A e limpa somente essa flag.

cpp
if ( & _BV()) {
  // ação curta para a comparação
   = _BV();
}

O que a flag não conta

Duas comparações antes da consulta

Uma flag não é um contador. Imagine que OCF1A esteja em 0, ocorram duas comparações antes da próxima consulta e o loop então leia TIFR1.

O que o programa consegue saber nesse instante?

Limite da flag

Após duas comparações sem limpeza entre elas, qual informação OCF1A fornece ao loop?

Dica

Consequência prática

Planeje o loop() para retornar logo à consulta. Se uma tarefa demora demais, várias comparações podem ocorrer enquanto OCF1A já está em 1; depois da limpeza, essas ocorrências anteriores não poderão ser recuperadas individualmente.

Passo 6 de 9

Inicialize antes de liberar o clock

Prepare o Timer1 em um estado conhecido e só libere seu clock depois de definir todos os parâmetros, preservando o Timer0.

Prepare o Timer1 parado

Comece em um estado conhecido

A configuração deve começar com o Timer1 parado. Assim, nenhum pulso avança o contador enquanto você define o modo, o limite e o estado inicial.

Não suponha que o Timer1 esteja no estado desejado por causa do núcleo Arduino ou de outro trecho do programa. Nesta prática, ele é um recurso exclusivo: estabeleça explicitamente uma condição conhecida em setup().

O Timer0 não participa desta configuração. Não escreva nos registradores dele: é assim que millis() continua funcionando normalmente.

Diagrama da inicialização: Timer1 permanece parado durante a preparação e só recebe clock ao final; Timer0 fica separado e inalterado.

Preparar primeiro e liberar o clock por último evita uma contagem iniciada com parâmetros parciais.

Dica

Consulta, não interrupção

Mantenha também as interrupções específicas do Timer1 desabilitadas nesta prática:

TIMSK1 = 0;

Isso não muda a habilitação global de interrupções. Apenas garante que nenhum evento do Timer1 será atendido por interrupção; aqui, o programa reconhecerá a comparação consultando TIFR1 no loop().

O atendimento por interrupção será assunto do próximo tutorial.

Defina tudo antes de contar

Sequência completa em setup

Com o clock parado, configure as saídas de comparação desconectadas, zere a contagem e carregue o limite calculado. Para o caso de 500 ms já calculado, use OCR1A = 31249.

Uma flag OCF1A poderia ter ficado pendente antes da sua configuração. Limpe-a escrevendo 1 na máscara correspondente, por atribuição direta. Só então selecione CTC e o prescaler 256 em TCCR1B.

Inicialização do Timer1 para 500 ms

Trecho para colocar em setup(). O LED e o loop serão completados mais adiante.

cpp
#include <avr/io.h>

void setup() {
  TIMSK1 = 0;                 // prática por consulta
  TCCR1A = 0;                 // COM1A/COM1B desconectados; WGM11:10 = 0
  TCCR1B = 0;                 // clock parado; WGM13:12 = 0
  TCNT1 = 0;                  // contagem inicial conhecida
  OCR1A = 31249;              // 500 ms com prescaler 256
  TIFR1 = _BV(OCF1A);         // escreve 1 para limpar pendência
  TCCR1B = _BV(WGM12) | _BV(CS12); // CTC 4 e prescaler 256
}

void loop() {
  // consulta de OCF1A virá aqui
}

Exemplo

O clock é liberado no final

A última atribuição reúne dois campos já conhecidos: WGM12 seleciona o modo CTC 4 quando os demais bits WGM estão em zero; CS12 corresponde ao padrão 100, que seleciona o prescaler 256.

Depois dessa linha, o hardware começa a contar. Por isso ela deve vir depois de TCNT1, OCR1A e da limpeza da flag.

Verifique a ordem

Atenção

Qual é a ordem segura?

Coloque as operações na ordem apropriada para iniciar o Timer1 em CTC por consulta. Considere que o contador está parado antes do primeiro item.

Descreva a sequência

Ordene da primeira à última operação.

Escreva pelo menos 120 caracteres (0/120).

Ordem de inicialização

Agora organize a sequência concreta.

Organize as operações da primeira para a última.

  1. TCCR1A = 0; TCNT1 = 0; OCR1A = 31249
  2. TIMSK1 = 0 e TCCR1B = 0
  3. TCCR1B = _BV(WGM12) | _BV(CS12)
  4. TIFR1 = _BV(OCF1A)

Deixe o hardware seguir contando

Não reinicialize durante a operação

A inicialização pertence a setup(), que é executado uma vez. Não a repita em loop().

Se loop() escrever repetidamente TCNT1 = 0, a contagem recomeçará antes de alcançar OCR1A. Se repetir a limpeza da flag, pode apagar uma comparação antes de atendê-la. E reescrever a configuração do temporizador sem necessidade torna o comportamento mais difícil de prever.

No loop(), a tarefa será apenas consultar a flag, atender o evento quando ela estiver presente e limpá-la corretamente.

Checagem rápida

Por que TCNT1 = 0 não deve ser repetido a cada passagem por loop()?

Passo 7 de 9

Dois eventos formam um ciclo do LED

Relacione cada comparação atendida à alternância do LED e preveja o ciclo completo da saída.

Do evento ao estado do LED

Uma comparação, uma alternância

A cada comparação do Timer1 que o loop() encontra e atende, o programa alterna o LED integrado: se estava desligado, liga; se estava ligado, desliga.

Portanto, uma comparação muda um estado, mas um ciclo completo do LED precisa de duas comparações: uma para ir de desligado para ligado e outra para voltar a desligado.

Eventos e nível do LED

Diagrama temporal com comparações regulares do Timer1, consultas do loop pouco depois delas e o nível do LED alternando a cada evento atendido.

Duas comparações atendidas formam um ciclo completo: um trecho ligado e um trecho desligado.

Previsão para 500 ms

Dois eventos por ciclo

Se o Timer1 gera comparações a cada intervalo T_comparação e todas são atendidas, o período nominal do LED é:

T_LED = 2 × T_comparação

A frequência do LED vem do período completo:

f_LED = 1 / T_LED

Não confunda a frequência das comparações com a frequência de piscar do LED: como são necessários dois eventos por ciclo, o LED completa ciclos à metade da frequência das comparações.

Exemplo

Exemplo: comparação a cada 500 ms

Com comparações a cada 500 ms:

  • após uma comparação atendida, o LED fica ligado por cerca de 500 ms;
  • após a seguinte, fica desligado por cerca de 500 ms;
  • o ciclo completo dura cerca de 1 s;
  • a frequência do LED é cerca de 1 Hz.

As comparações do hardware seguem o valor calculado com o clock nominal de 16 MHz. Já a mudança no LED acontece quando o loop() consulta a flag e a atende. Se o loop() demora, a mudança pode ocorrer depois da comparação. Se mais de uma comparação ocorrer antes da limpeza, a flag continua representando apenas uma pendência; ela não informa quantas ocorreram.

Pratique o cálculo

Confira a previsão

O Timer1 gera uma comparação a cada 500 ms, e o loop() atende cada uma delas sem demora relevante. Qual é o período completo e a frequência aproximada do LED alternado a cada comparação?

Período e frequência do LED:

Passo 8 de 9

Teste o intervalo no seu Uno R3

Grave e observe um sketch completo que alterna o LED integrado por consulta não bloqueante da flag de comparação do Timer1.

Resultado esperado

Meta da prática

Agora você vai reunir a configuração já estudada em um único sketch para o Uno R3 com ATmega328P. O Timer1 gerará uma comparação a cada 500 ms; o loop() consultará a flag sem ficar parado esperando.

O LED integrado é o D13, correspondente a PB5. Ele começa apagado. Cada comparação reconhecida alterna esse pino; portanto, dois eventos formam um ciclo completo: aproximadamente 1 s.

O que observar

Diagrama relacionando comparações do Timer1 a cada 500 ms, consultas rápidas do loop e o LED integrado alternando de estado para completar um ciclo em aproximadamente um segundo.

A comparação ocorre a cada 500 ms; o período completo nominal do LED é aproximadamente 1 s.

Grave o sketch completo

Sketch completo: comparação a cada 500 ms

Crie um sketch na IDE Arduino local, substitua seu conteúdo por este código, selecione a placa e a porta do seu Uno R3 e grave-o pela conexão USB. Não conecte componentes externos nesta prática.

O programa não usa bibliotecas adicionais. Ele preserva o Timer0: não escreve em registradores desse temporizador e, portanto, não altera a base usada por millis().

cpp
#include <avr/io.h>

void setup() {
  DDRB |= _BV(DDB5);        // LED integrado: PB5 / D13
  PORTB &= ~_BV(PORTB5);    // começa apagado

  TCCR1A = 0;               // saídas desconectadas; WGM11:0 = 0
  TCCR1B = 0;               // Timer1 parado
  TIMSK1 = 0;               // sem interrupções do Timer1
  TCNT1 = 0;
  OCR1A = 31249;
  TIFR1 = _BV(OCF1A);       // limpa pendência escrevendo 1

  TCCR1B = _BV(WGM12) | _BV(CS12);
}

void loop() {
  if (TIFR1 & _BV(OCF1A)) {
    TIFR1 = _BV(OCF1A);     // reconhece e limpa a comparação
    PINB = _BV(PINB5);      // alterna o LED
  }

  // Outras tarefas curtas podem ser atendidas aqui.
}
Saída esperada
LED integrado (D13): alterna aproximadamente a cada 500 ms.
Ciclo completo esperado: aproximadamente 1 s.

A IDE não exibirá uma saída textual para este sketch. A saída a conferir é visual: o LED integrado deve ficar aproximadamente 500 ms apagado, 500 ms aceso e repetir esse ciclo em cerca de 1 s. A observação visual não é uma medição de precisão.

Confira a parte não bloqueante

Complete o atendimento da comparação

Antes de gravar, complete mentalmente ou no exercício o trecho central que ficará dentro de loop(). Ele deve atender rapidamente uma comparação pendente, sem espera ativa.

cpp
if ( & _BV()) {
   = _BV();
   = _BV();
}

Verifique o resultado

Observe e audite

Após gravar, observe o LED integrado por alguns ciclos. O comportamento esperado é cerca de meio segundo em cada estado e um ciclo completo próximo de 1 s.

Faça também uma leitura rápida do sketch: não há delay(), laço de espera, escrita em Timer0 nem outro uso do Timer1. O if apenas atende a flag quando ela está presente; quando não está, o fluxo prossegue imediatamente para as demais tarefas.

Atenção

Limite da verificação

Se o LED integrado não estiver visível no seu modelo ou se você não puder gravar a placa agora, analise o código e faça a previsão, mas não trate essa análise como uma observação física.

Registre o que você observou

Descreva sua verificação. O LED alternou aproximadamente a cada 500 ms, formando um ciclo próximo de 1 s? Cite uma evidência no código de que o loop() não fica bloqueado e uma condição que precisa continuar verdadeira para este sketch funcionar como previsto.

Escreva pelo menos 80 caracteres (0/80).

Passo 9 de 9

Aplique um novo intervalo e confira o resultado

Aplique a configuração de 250 ms com prescaler 64, confira o ciclo do LED e valide as condições de uso seguro do Timer1.

Calcule e preveja

Do requisito aos valores

Novo requisito: produza uma comparação a cada 250 ms com o prescaler fixado em N = 64.

Com o clock nominal de 16 MHz do Uno R3:

OCR1A = T × f_clock / N − 1

OCR1A = 0,250 × 16.000.000 / 64 − 1 = 62.499

Portanto, OCR1A = 62499. Cada ciclo do contador tem 62.500 passos. Como o LED alterna a cada comparação reconhecida, ele permanece aproximadamente 250 ms em cada estado. O ciclo completo do LED é nominalmente 500 ms.

Dois eventos completam o ciclo

Diagrama do clock dividido por 64 alimentando um contador que vai até 62499 e reinicia; abaixo, o LED fica alto por uma comparação e baixo pela seguinte.

Com N = 64 e OCR1A = 62499, a comparação é nominalmente a cada 250 ms. Duas comparações formam um ciclo de 500 ms do LED.

Aplique nos registradores

Configure o novo intervalo

Complete os valores que liberam o Timer1 em CTC com comparação de 250 ms.

cpp
// Trechos finais da configuração em setup()
OCR1A = ;
TIFR1 = _BV(OCF1A);       // descarta uma pendência anterior
TCCR1B = _BV(WGM12) | _BV() | _BV();

Grave e faça uma auditoria

Sketch completo para 250 ms

Adapte o sketch de 500 ms da prática anterior: mantenha a estrutura, a consulta de OCF1A e o controle do LED integrado. Altere somente OCR1A e a seleção do prescaler no final de setup(). Grave este sketch no seu Uno R3 por USB e observe o LED integrado; não conecte componentes externos.

cpp
#include <avr/io.h>

void setup() {
  DDRB |= _BV(DDB5);        // LED integrado: PB5 / D13
  PORTB &= ~_BV(PORTB5);    // começa apagado

  TCCR1A = 0;               // saídas desconectadas; WGM11:0 = 0
  TCCR1B = 0;               // Timer1 parado
  TIMSK1 = 0;               // sem interrupções do Timer1
  TCNT1 = 0;
  OCR1A = 62499;
  TIFR1 = _BV(OCF1A);       // limpa pendência escrevendo 1

  TCCR1B = _BV(WGM12) | _BV(CS11) | _BV(CS10);
}

void loop() {
  if (TIFR1 & _BV(OCF1A)) {
    TIFR1 = _BV(OCF1A);     // reconhece e limpa a comparação
    PINB = _BV(PINB5);      // alterna o LED
  }

  // Outras tarefas curtas podem ser atendidas aqui.
}
Saída esperada
LED integrado alternando aproximadamente a cada 250 ms:
- cerca de 250 ms aceso
- cerca de 250 ms apagado
- ciclo completo próximo de 500 ms

A observação visual não é uma medição de precisão. O instante exato de cada alternância também depende de quando o loop consulta a flag.

Auditoria de recursos

Qual situação invalida a prática tal como está escrita?

Revise e conclua

Registre sua verificação

Após gravar, descreva o que observou e faça a previsão com base no código: qual deve ser o tempo aproximado de um ciclo completo do LED? Indique também uma condição do programa que evita perder comparações e uma situação em que este sketch não deve ser combinado com outro código.

Escreva pelo menos 80 caracteres (0/80).

Resumo

Síntese final

  • Para 250 ms com clock nominal de 16 MHz e N = 64, use OCR1A = 62499.
  • Em CTC, WGM12 ativo e CS12:0 = 011 configuram o modo e o prescaler escolhidos.
  • A consulta de OCF1A não bloqueia o loop; limpe-a escrevendo 1 diretamente na máscara correspondente.
  • Uma flag não contabiliza eventos acumulados: consultas frequentes e tarefas curtas são necessárias.
  • Alternar o LED a cada comparação de 250 ms produz um ciclo nominal de 500 ms.
  • Preserve o Timer0 para millis e mantenha o Timer1 exclusivo nesta configuração.

Tutorial concluído

Parabéns! Você concluiu: Intervalos com o Timer1 em modo CTC

Parabéns! Você concluiu a aplicação de intervalos com o Timer1 em modo CTC.

Baixe o Aplicativo agora para ter acesso a + de 5000 cursos gratuitos, exercícios, certificado e muito conteúdo sem pagar nada!

  • Cursos online 100% gratuitos do início ao fim

    Milhares de cursos online em vídeo, ebooks e áudiobooks.

  • Mais de 60 mil exercícios gratuitos

    Para testar seus conhecimentos no decorrer dos cursos online

  • Certificado Digital gratuito válido em todo o Brasil

    Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail

Aplicativo Cursa na tela de ebook, na tela de curso em vídeo e na tela de exercícios do curso, mais o certificado de conclusão de curso