
Passo 1 de 7
Do evento de comparação à retomada do programa
Entenda a sequência entre uma comparação do Timer1, o atendimento por interrupção e a retomada do programa.
Trilha de aprendizado · Nível 10 · Tutorial 6
Atender eventos do Timer1 com uma rotina curta de interrupção, enquanto o fluxo principal mantém outra atividade de sinalização no Uno R3 próprio.
Do evento de comparação à retomada do programa
Entenda a sequência entre uma comparação do Timer1, o atendimento por interrupção e a retomada do programa. 2 min
A flag, a máscara e o vetor corretos
Associe a comparação A do Timer1 à flag, à máscara e ao vetor corretos, distinguindo a ocorrência do evento de sua autorização para atendimento. 3 min
Uma ISR que apenas alterna o LED
Defina uma ISR curta para a comparação A do Timer1, alternando o LED integrado sem espera nem variáveis compartilhadas. 3 min
Habilitar a interrupção somente ao final
Prepare o Timer1 e a saída antes de permitir que a ISR de comparação A seja atendida. 3 min
Por que a rotina precisa terminar rápido
Reconheça por que uma ISR precisa ser mínima e quais operações devem permanecer no fluxo principal. 2 min
Duas sinalizações no seu Uno R3
Prática local no Uno R3: uma ISR curta alterna D13 enquanto o loop mantém a sinalização não bloqueante em D7. 5 min
Aplicação final: mudar o loop sem mudar a ISR
Ajuste a atividade não bloqueante de D7 sem tocar na ISR e confirme a separação de responsabilidades. 3 min

Passo 1 de 7
Entenda a sequência entre uma comparação do Timer1, o atendimento por interrupção e a retomada do programa.
No tutorial anterior, o loop consultava a flag de comparação do Timer1 e decidia o que fazer. Agora a comparação pode solicitar um atendimento automático: uma interrupção.
Quando o evento é aceito para atendimento, o processador desvia temporariamente do ponto atual do programa para uma rotina curta chamada ISR (Interrupt Service Routine, ou rotina de serviço de interrupção). Ao terminar essa rotina, ele retorna ao fluxo principal exatamente para continuar o trabalho interrompido.

A interrupção é um desvio temporário; o fluxo principal não é apagado nem reiniciado.
A comparação do Timer1 é um evento de hardware: ela acontece quando o contador alcança o valor configurado, independentemente da instrução que o programa está executando naquele instante.
O atendimento pela ISR vem depois. Entre o evento e o começo da rotina pode haver um pequeno atraso, pois o processador conclui a instrução em andamento antes de desviar. Portanto, evento de comparação e primeira instrução da ISR não são necessariamente o mesmo instante.
Exemplo
Pense em uma única pessoa alternando entre duas tarefas. Ela estava seguindo o fluxo principal, recebe um chamado do hardware, faz rapidamente o atendimento e volta à tarefa anterior. Ela não executa as duas tarefas ao mesmo tempo.
O Timer1 continua sendo um periférico de hardware; a ISR é código do processador executado por um breve intervalo.
Organize a sequência típica após uma comparação do Timer1.
Coloque os acontecimentos na ordem correta.
Nesta etapa, guarde este modelo mental:
Nos próximos passos, você verá quais condições permitem esse atendimento e qual rotina corresponde especificamente à comparação A do Timer1.
Resumo

Passo 2 de 7
Associe a comparação A do Timer1 à flag, à máscara e ao vetor corretos, distinguindo a ocorrência do evento de sua autorização para atendimento.
No step anterior, a comparação do Timer1 foi apresentada como um evento que pode desviar temporariamente o processador para uma ISR. Para esse desvio ocorrer, não basta a comparação acontecer: duas permissões precisam estar ativas.
No núcleo Arduino AVR do Uno R3, a habilitação global já está ativa antes de setup() começar. Mesmo assim, a máscara específica do Timer1 continua desabilitada até o seu programa ativá-la.

A comparação pode ocorrer sempre que o Timer1 estiver configurado e em funcionamento; o atendimento exige as permissões global e específica.
Para a comparação do canal A do Timer1, use esta associação no ATmega328P:
OCF1A, em TIFR1: flag que indica que ocorreu a comparação A.OCIE1A, em TIMSK1: máscara que autoriza o atendimento por interrupção desse evento.TIMER1_COMPA_vect: vetor que identifica a rotina destinada à comparação A.A flag responde “o evento aconteceu?”. A máscara responde “este evento pode interromper?”. O vetor responde “qual rotina será executada?”.
Os nomes parecidos ajudam a lembrar a relação: OCF1A é a flag, OCIE1A é a habilitação da interrupção e COMPA identifica o canal A no vetor.
Referência rápida dos símbolos envolvidos na interrupção de comparação A do Timer1.
| Elemento | Local | Função |
|---|---|---|
| OCF1A | TIFR1 | Indica comparação A ocorrida |
| OCIE1A | TIMSK1 | Permite atendimento da comparação A |
| TIMER1_COMPA_vect | Vetor de interrupção | Identifica a rotina de atendimento |
| Habilitação global | Estado do processador | Permite aceitar interrupções em geral |
Considere o Timer1 funcionando e ocorrendo uma comparação A. Qual elemento precisa estar habilitado especificamente para que esse evento possa chamar sua rotina de interrupção?
Escreva pelo menos 5 caracteres (0/5).
Associe cada elemento ao seu papel na comparação A do Timer1.
Escreva pelo menos 30 caracteres (0/30).
Se OCIE1A estiver desabilitado, a comparação A deixa de acontecer?
Com a máscara OCIE1A desabilitada, uma comparação A do Timer1 não ocorre e OCF1A nunca é ativada.
Complete a instrução que habilita apenas a máscara da comparação A do Timer1, preservando os demais bits do registrador.
|= _BV();
Passo 3 de 7
Defina uma ISR curta para a comparação A do Timer1, alternando o LED integrado sem espera nem variáveis compartilhadas.
No exemplo anterior, loop() consultava a flag de comparação. Agora, quando a comparação A for atendida, o processador desvia temporariamente para uma rotina de serviço de interrupção (ISR).
A macro ISR(...), disponível em avr/interrupt.h, associa o corpo da rotina diretamente ao vetor TIMER1_COMPA_vect. Portanto, a ISR fica fora de setup() e de loop() e não deve ser chamada como uma função comum.
Nesta aplicação, ela terá uma única responsabilidade: alternar o LED integrado, ligado a PB5 (D13).

A ISR é um desvio curto: uma ação no LED e retorno ao ponto em que o programa foi interrompido.
Inclua os cabeçalhos para os nomes dos registradores, bits e vetores AVR. A declaração ISR(TIMER1_COMPA_vect) define a rotina que o hardware executará no atendimento da comparação A.
A escrita de 1 no bit PB5 de PINB alterna o bit correspondente de PORTB; como PB5 será preparado como saída, isso alterna o LED integrado. Não use delay(), laços de espera ou operações longas aqui.
Também não há variável da aplicação acessada tanto por ISR quanto por loop() neste exemplo. Essa troca de dados exige cuidados próprios e será tratada no próximo tutorial.
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER1_COMPA_vect) {
PINB = _BV(PB5);
}Dica
Quando o ATmega328P aceita este vetor, o hardware limpa automaticamente a flag OCF1A. Assim, esta ISR não deve escrever em TIFR1 para limpar essa flag.
Antes que o atendimento possa ser habilitado, PB5 precisa estar configurado como saída. A sequência completa — incluindo preparar PB5, configurar o Timer1, limpar uma pendência e só então habilitar a máscara — vem no próximo step.
Complete a definição mínima da ISR. Ela deve incluir o cabeçalho de interrupções, atender a comparação A e alternar apenas PB5.
#include <avr/io.h>
ISR() {
= ;
}Qual corpo é adequado para a ISR TIMER1_COMPA_vect desta aplicação?

Passo 4 de 7
Prepare o Timer1 e a saída antes de permitir que a ISR de comparação A seja atendida.
A ISR já foi definida; agora importa quando ela pode começar a executar. Durante a inicialização, mantenha o Timer1 parado e sua interrupção de comparação A desabilitada. Assim, o periférico continua reservado à aplicação, mas nenhum atendimento ocorre enquanto registradores e pinos ainda estão sendo preparados.
A ordem segura é: preparar o LED e o Timer1 em CTC, limpar uma possível pendência, iniciar o clock do temporizador e, por último, permitir o atendimento com OCIE1A.

A máscara de interrupção é habilitada somente depois que a saída e o temporizador estão prontos.
Use a configuração de referência já calculada: clock de 16 MHz, prescaler de 256 e OCR1A = 31249. Em CTC, ela produz uma comparação A a cada 500 ms.
TCCR1A e TCCR1B começam em zero: as saídas de comparação ficam desconectadas e não há clock para o Timer1. A configuração WGM12 seleciona CTC; CS12 inicia o clock com prescaler 256. Como COM1A e COM1B permanecem em zero, o Timer1 não assume o controle de pinos de saída.
Sketch mínimo para observar a ordem de inicialização. A ISR pode ficar acima ou abaixo de setup(), mas não é chamada diretamente.
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER1_COMPA_vect) {
PINB = _BV(PB5);
}
void setup() {
DDRB |= _BV(DDB5); // D13 como saída
TIMSK1 = 0;
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 31249;
TCCR1B |= _BV(WGM12); // CTC
TIFR1 = _BV(OCF1A); // limpa pendência
TCCR1B |= _BV(CS12); // prescaler 256
TIMSK1 |= _BV(OCIE1A); // habilita por último
}
void loop() {
}
O LED integrado D13 muda de estado aproximadamente a cada 500 ms. Um ciclo completo de acender e apagar dura cerca de 1 s.
A percepção visual pode variar com a iluminação, mas a mudança de estado do LED integrado deve ocorrer aproximadamente duas vezes por segundo.
Uma comparação pode ter ocorrido antes ou durante a preparação. Nesse caso, OCF1A pode estar pendente. Ao escrever 1 nesse bit de TIFR1, a pendência é descartada antes de permitir o atendimento.
Se OCIE1A fosse habilitado cedo demais, com a flag pendente e as interrupções globais já ativas no núcleo Arduino, a ISR poderia iniciar no meio da configuração. Ela poderia alternar PB5 antes de PB5 ser saída ou antes de o Timer1 estar na condição planejada.
Iniciar o clock antes da máscara é seguro: uma comparação futura apenas deixa a flag pendente até que a máscara seja habilitada.
Dica
A máscara não deve ser a primeira permissão da sequência. Ela só libera o atendimento quando GPIO, modo CTC, contador e comparação já têm estados conhecidos.
Organize as ações na sequência segura. Considere que preparar o Timer1 inclui zerar TCNT1, carregar OCR1A = 31249 e selecionar CTC sem ainda escolher o clock.
Coloque as ações na ordem correta de inicialização.
Agora complete as duas ações finais: primeiro o clock com prescaler 256 e depois a máscara da comparação A.
Preencha as máscaras das duas ações finais.
// GPIO, CTC, contador, OCR1A e TIFR1 já foram preparados
TCCR1B |= ;
TIMSK1 |= ;
Passo 5 de 7
Reconheça por que uma ISR precisa ser mínima e quais operações devem permanecer no fluxo principal.
Em uma ISR normal do AVR, o processador atende a rotina e só depois retorna ao ponto em que interrompeu o programa. Enquanto ela executa, as interrupções ficam globalmente desabilitadas nesta aplicação: não há aninhamento.
Um evento de hardware ainda pode acontecer nesse intervalo e sua flag pode ficar pendente, mas o atendimento correspondente espera a ISR atual terminar. Portanto, interrupção não cria execução simultânea: ela apenas troca temporariamente qual trecho o único processador está executando.

O hardware pode registrar eventos durante a ISR, mas seus atendimentos ficam adiados até o retorno.
A ISR de comparação A deste tutorial tem uma responsabilidade deliberadamente pequena: alternar PB5, ligado ao LED integrado. Essa escrita direta é adequada porque termina rapidamente e não depende de espera.
| Ação proposta | Lugar adequado | Motivo |
|---|---|---|
| `PINB = _BV(PB5);` | ISR | Escrita curta para alternar D13 |
| `delay(100);` | Fora da ISR | Depende de serviços temporais afetados na ISR |
| Laço esperando uma condição | Fora da ISR | Pode prolongar o bloqueio sem limite previsível |
| Cálculo ou processamento demorado | Fora da ISR | Prolonga a suspensão do firmware |
| Atualizar D7 por `millis()` | loop | Depende da base temporal do Timer0 |
Atenção
Evite delay(), laços de espera e processamento demorado no corpo da ISR. No Arduino AVR, delay() depende de serviços temporais ligados ao Timer0. Durante uma ISR normal, os atendimentos estão desabilitados; por isso, delay() não é uma espera confiável nesse contexto e pode manter a rotina presa de modo inválido ou imprevisível.
Uma ISR longa também adia o atendimento do Timer0 e, consequentemente, a atualização da base usada por millis(). Mantenha a ação mínima na ISR. Uma tarefa maior deve ficar no fluxo principal; a comunicação segura entre ISR e loop() será abordada no próximo tutorial.
Exemplo
Considere esta proposta para a ISR de comparação do Timer1:
ISR(TIMER1_COMPA_vect) {
PINB = _BV(PB5);
while (entradaAindaNaoEstaPronta()) {
// espera por uma condição externa
}
}A escrita em PINB é curta. O problema é o laço: não há garantia de quando a condição ficará pronta. Enquanto ele continua, a ISR não retorna ao loop() e outros vetores aguardam atendimento.
Qual alternativa explica corretamente por que essa ISR é inadequada?
Uma ISR não acelera uma tarefa longa nem a executa em paralelo ao loop(). Ela interrompe o fluxo principal, executa uma ação curta e retorna.
Para esta aplicação, a rotina deve apenas alternar PB5. Esperas, laços que aguardam algo e operações demoradas ficam fora dela. Assim, o loop() continua responsável por suas atividades, e os demais atendimentos não ficam bloqueados por uma ISR extensa.
Você decidiu colocar uma espera ou um processamento de cerca de 200 ms dentro da ISR para deixar o LED visível. O que pode acontecer com o loop() e com atendimentos dependentes do Timer0 enquanto essa ISR ainda está ativa?
Escreva pelo menos 80 caracteres (0/80).

Passo 6 de 7
Prática local no Uno R3: uma ISR curta alterna D13 enquanto o loop mantém a sinalização não bloqueante em D7.
Monte a segunda sinalização com a placa desenergizada: conecte D7 → resistor de 1 kΩ → ânodo do LED; conecte o cátodo (terminal mais curto ou lado achatado) ao GND. Depois, alimente o Uno R3 somente pelo cabo USB de dados conectado ao computador.
O LED integrado em D13 não precisa de montagem externa. Nesta prática, ele será alternado pela ISR do Timer1; o LED externo em D7 será controlado exclusivamente pelo loop() usando millis().

D7 aciona o LED externo; D13 corresponde ao LED integrado do Uno R3.
Atenção
Não conecte fonte externa a VIN nem ao pino de 5 V durante esta prática. Confira a polaridade do LED antes de ligar o USB: um LED invertido normalmente não acende, mas a montagem deve sempre ser revisada com a placa sem alimentação.
Copie o sketch completo para a IDE Arduino, selecione Arduino Uno e a porta correta, depois grave na sua placa. Não acrescente bibliotecas que usem o Timer1.
A ISR só escreve em PINB para alternar PB5/D13. O loop() mantém seu próprio estado e sua própria marca de tempo para D7. Não há consulta a OCF1A no loop() e não há variável compartilhada entre os dois fluxos.
Sketch completo para o Uno R3
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER1_COMPA_vect) {
PINB = _BV(PB5); // alterna somente o LED integrado (D13)
}
void setup() {
DDRB |= _BV(DDB5); // D13 como saída
DDRD |= _BV(DDD7); // D7 como saída
PORTD &= ~_BV(PORTD7);
TIMSK1 = 0;
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 31249;
TCCR1B |= _BV(WGM12); // CTC
TIFR1 = _BV(OCF1A); // limpa pendência
TCCR1B |= _BV(CS12); // prescaler 256
TIMSK1 |= _BV(OCIE1A); // habilita por último
}
void loop() {
static unsigned long ultimoD7 = 0;
static bool d7Ligado = false;
unsigned long agora = millis();
if (agora - ultimoD7 >= 200) {
ultimoD7 = agora;
d7Ligado = !d7Ligado;
if (d7Ligado) {
PORTD |= _BV(PORTD7);
} else {
PORTD &= ~_BV(PORTD7);
}
}
}D13 muda de estado a cada cerca de 500 ms. D13 completa um ciclo em cerca de 1 s. D7 muda de estado a cada cerca de 200 ms. D7 completa um ciclo em cerca de 400 ms.
O resultado é físico: observe os LEDs na placa após gravar o sketch. As cadências são aproximadas e podem variar ligeiramente.
Complete o nome do vetor que liga a ISR ao evento de comparação A do Timer1. A rotina não é chamada pelo loop(); o hardware a atende quando a comparação habilitada ocorre.
Preencha a lacuna com o vetor correto.
#include <avr/interrupt.h>
ISR() {
PINB = _BV(PB5);
}Após gravar o sketch, observe os dois LEDs por alguns segundos. O LED integrado D13 deve mudar de estado a cada comparação, aproximadamente a cada 500 ms; por isso, seu ciclo completo fica perto de 1 s. O LED externo em D7 muda de estado aproximadamente a cada 200 ms, com ciclo completo perto de 400 ms.
As duas cadências não significam que o processador executa ISR e loop() simultaneamente: a ISR é breve, termina e o processador retoma o loop().
Relate o que você observou na sua placa: qual LED pareceu mais rápido e qual trecho do programa controla cada um? Se algo não funcionou, descreva o comportamento observado e a ligação que você conferiu.
Escreva pelo menos 80 caracteres (0/80).

Passo 7 de 7
Ajuste a atividade não bloqueante de D7 sem tocar na ISR e confirme a separação de responsabilidades.
A cadeia desta aplicação é: a comparação A do Timer1 ocorre, OCF1A indica o evento, a máscara OCIE1A e as interrupções globais permitem o atendimento, e o vetor TIMER1_COMPA_vect leva à ISR. A rotina alterna somente D13 e termina; então o processador retoma o ponto em que o loop() foi interrompido.
Isso não é execução simultânea: é uma troca rápida e temporária de fluxo. Como D7 é controlado apenas pelo loop(), sua cadência pode mudar sem alterar a ISR nem a configuração do Timer1.

A ISR atende D13 por um instante; o loop retoma e continua responsável por D7.
Na IDE Arduino do seu computador, abra o sketch da prática anterior. Altere somente o intervalo usado pelo loop() para alternar D7: de 200 ms para 800 ms.
Não modifique OCR1A, os registradores do Timer1, TIMSK1 nem o corpo da ISR. Mantenha a verificação temporal não bloqueante: ela precisa continuar usando a comparação de tempo decorrido, sem delay().
Grave o sketch no seu Uno R3. O LED externo em D7 deve completar um ciclo em aproximadamente 1,6 s, pois alterna a cada 800 ms. O LED integrado em D13 continua alternando a cada 500 ms, com ciclo aproximado de 1 s.
Complete as duas partes que preservam a separação da aplicação: o intervalo de D7 e a máscara que habilita a comparação A do Timer1.
Preencha apenas os elementos que já foram estudados.
const unsigned long intervaloD7 = ;
// Depois de configurar o Timer1 e limpar uma pendência:
TIMSK1 = ;Após observar a placa, registre sua previsão confirmada: como ficaram as duas sinalizações? Em seguida, explique por que colocar delay(800) dentro da ISR seria inadequado.
Escreva pelo menos 80 caracteres (0/80).
Resumo
Critérios que você validou
Parabéns! Você concluiu: Interrupções de comparação do Timer1
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks