
Passo 1 de 7
Esperar o momento sem parar o loop
Compare espera bloqueante, espera ativa e consulta temporal curta antes de montar a lógica com millis.
Trilha de aprendizado · Nível 10 · Tutorial 1
Controlar duas sequências de LEDs com intervalos independentes no Uno R3 próprio, mantendo o fluxo principal disponível e tratando corretamente o retorno da contagem de millis.
Esperar o momento sem parar o loop
Compare espera bloqueante, espera ativa e consulta temporal curta antes de montar a lógica com millis. 2 min
Consultar o relógio e guardar uma referência
Organize leituras e referências temporais antes de construir a condição de tempo decorrido. 2 min
Trocar delay por uma condição de tempo decorrido
Substitua a pausa bloqueante por uma comparação de tempo decorrido e uma atualização condicional da referência. 2 min
Continuar funcionando quando a contagem volta a zero
Rastreie a comparação temporal quando o contador de `millis()` passa do maior valor de 32 bits para zero e preserve a verificação por subtração sem sinal. 2 min
Controlar dois LEDs com tempos independentes
Implemente duas sequências de LEDs independentes no Uno R3 usando uma única leitura de millis por passagem no loop. 4 min
Entender os limites do tempo observado
Reconheça que a temporização por millis atende o evento na próxima observação disponível e mantenha o restante do loop curto. 2 min
Validar e explicar a solução completa
Consolide a solução com dois LEDs e valide como as verificações temporais independentes mantêm o fluxo principal em atividade. 2 min

Passo 1 de 7
Compare espera bloqueante, espera ativa e consulta temporal curta antes de montar a lógica com millis.
Quando um sketch chama delay(300), ele fica nessa chamada por cerca de 300 ms. Nesse período, loop() não chega às instruções seguintes: não lê outra entrada, não atualiza outra saída nem toma outra decisão.
Isso pode servir a um teste bem simples. Mas, quando o programa precisa continuar atento a mais de uma atividade, a espera deixa de ser apenas uma pausa visual: ela interrompe o atendimento do restante do fluxo.

À esquerda, a espera ocupa o fluxo. À direita, o programa verifica se chegou a hora e volta a percorrer as demais tarefas.
Na temporização não bloqueante, o programa não fica esperando o relógio avançar. A cada passagem por loop(), ele faz uma consulta rápida: “já é o momento da ação?”.
Se ainda não for, ele simplesmente continua para as próximas instruções. Se for, executa uma ação curta — por exemplo, mudar o nível de um LED — e continua também.
Não há duas partes do sketch executando ao mesmo tempo. Há um único fluxo que retorna rapidamente às tarefas e as intercala em muitas passagens por loop(). Nas próximas etapas, construiremos essa consulta temporal com millis().
Exemplo
Imagine um loop() que precisa alternar um LED periodicamente e também verificar uma entrada:
loop() pode verificar se é hora de mudar o LED e, na mesma passagem, verificar a entrada.A resposta à entrada ainda depende de o loop() chegar até sua leitura, mas não fica retida por uma espera longa.
Trocar delay() por um while que apenas espera o tempo passar não resolve o problema. Embora a condição seja testada repetidamente, o processador permanece dentro do while até ela ser satisfeita.
Como loop() não avança para o restante do código durante esse laço, as outras atividades continuam sem atendimento. Uma solução não bloqueante faz uma verificação curta e sai dela imediatamente quando ainda não é hora de agir.
Considere um LED que ainda não deve mudar e uma entrada que precisa ser lida durante o intervalo. Compare as três estratégias: delay(), um while usado somente para esperar o tempo passar e uma consulta temporal curta seguida da leitura da entrada.
Em 3 a 5 frases, indique qual estratégia deixa o fluxo disponível e justifique por que as outras duas bloqueiam o atendimento da entrada.
Escreva pelo menos 120 caracteres (0/120).

Passo 2 de 7
Organize leituras e referências temporais antes de construir a condição de tempo decorrido.
millis() consulta quantos milissegundos se passaram desde o início do programa. No Uno R3, seu resultado tem o tipo unsigned long, com 32 bits.
Nesta etapa, separe três papéis:
agora: instante lido na passagem atual por loop();anterior: instante registrado quando ocorreu uma mudança anterior;intervalo: duração desejada entre mudanças.Os três representam tempo e, por isso, devem usar unsigned long. O sufixo UL mantém constantes como 300UL compatíveis com esse tipo.

A leitura atual, a referência anterior e o intervalo têm funções diferentes.
Faça uma nova leitura no começo de cada passagem por loop(). Ela retrata o instante em que o programa está executando aquela passagem.
Trecho para estudar; ainda não decide nem altera o LED.
unsigned long agora = millis();Dica
A variável agora pode ser local porque será lida de novo na próxima passagem. Já anterior não pode nascer dentro de loop(): se fosse criada ali, perderia a marca guardada assim que a passagem terminasse.
Declare a marca anterior fora de setup() e loop(), para que ela exista durante toda a execução. Em setup(), inicialize-a com uma leitura de millis().
O intervalo também é um valor que permanece disponível para o programa. A palavra const deixa claro que este exemplo não pretende alterá-lo.
Estrutura de dados temporais. A lógica que usa esses valores será construída na próxima etapa.
const unsigned long intervalo = 300UL;
unsigned long anterior;
void setup() {
anterior = millis();
}
void loop() {
unsigned long agora = millis();
// Outras atividades curtas podem continuar aqui.
}
agora é renovado em cada passagem; anterior permanece guardado entre elas.
Relacione cada elemento ao seu papel neste esqueleto de temporização. Ainda não há condição de decisão: o foco é organizar os dados corretamente.
Associe cada elemento à sua função.
Faça as associações.
Toque em um item e depois no par correspondente.
Complete a declaração que permite guardar a referência temporal entre passagens por loop().
const unsigned long intervalo = 300UL;
;
void setup() {
anterior = millis();
}
void loop() {
unsigned long agora = millis();
}
Passo 3 de 7
Substitua a pausa bloqueante por uma comparação de tempo decorrido e uma atualização condicional da referência.
A cada passagem por loop(), compare o instante lido em agora com a marca persistente anterior:
agora - anterior >= intervalo
A subtração produz o tempo decorrido desde a última mudança. Se ele já alcançou o intervalo, faça uma ação curta: alterne o LED e registre uma nova marca. Caso contrário, não faça nada nessa condição e o restante de loop() continua imediatamente.
Mantenha agora, anterior e intervalo como unsigned long.

A consulta ocorre rapidamente em toda passagem pelo loop; não há uma espera dentro da condição.
Dica
Não use == para procurar exatamente 300 ms. O programa pode consultar em 299 ms e voltar a consultar somente em 301 ms. Com >=, a mudança ocorre na primeira consulta que perceber o limite ou um valor maior.
Atribua anterior = agora apenas dentro do if. Se essa atribuição ficasse fora, a referência seria reiniciada em todas as passagens e o tempo decorrido poderia nunca chegar a 300 ms.
Este sketch alterna o LED integrado a cada intervalo observado de 300 ms. Copie-o para a IDE Arduino local, selecione seu Uno R3 e a porta correta, compile e grave. Não é preciso montar componente externo nesta etapa.
O LED integrado deve alternar aproximadamente a cada 300 ms, enquanto loop() continua sendo executado entre as trocas.
const unsigned long intervalo = 300UL;
unsigned long anterior;
bool ledLigado = false;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
anterior = millis();
}
void loop() {
unsigned long agora = millis();
if (agora - anterior >= intervalo) {
ledLigado = !ledLigado;
digitalWrite(LED_BUILTIN, ledLigado ? HIGH : LOW);
anterior = agora;
}
// Outras tarefas curtas podem ser atendidas aqui.
}LED integrado: alterna aproximadamente a cada 300 ms. Monitor Serial: nenhuma saída.
O efeito é físico no LED integrado da placa. Como o sketch não usa `Serial`, o Monitor Serial permanece sem mensagens.
Complete a verificação e a atualização. A marca deve mudar somente junto com a alternância do LED.
Preencha as lacunas do trecho.
if () {
ledLigado = !ledLigado;
digitalWrite(LED_BUILTIN, ledLigado ? HIGH : LOW);
anterior = ;
}Considere anterior = 1000UL e intervalo = 300UL. O loop() consulta a condição em 1299 ms e, na passagem seguinte, em 1302 ms. A condição não precisa observar exatamente 1300 ms para funcionar.
Qual alternativa descreve corretamente essas duas passagens por loop()?

Passo 4 de 7
Rastreie a comparação temporal quando o contador de millis() passa do maior valor de 32 bits para zero e preserve a verificação por subtração sem sinal.
millis() devolve um contador unsigned long de 32 bits. No Uno R3, ele avança em milissegundos desde o início do programa, mas não cresce para sempre: depois de aproximadamente 49,7 dias, passa do maior valor representável para 0.
Esse retorno não exige um caso especial quando a condição usa a forma já aprendida:
agora - anterior >= intervalo
Como os valores são sem sinal, a subtração acompanha a contagem cíclica. Para a aplicação funcionar corretamente, use intervalos muito menores que uma volta completa e avalie a condição com frequência.

A passagem pelo zero continua pertencendo à mesma sequência de valores sem sinal.
Exemplo
Considere uma referência registrada pouco antes do retorno e uma consulta feita logo depois:
anterior = 4294967200ULagora = 80ULA subtração sem sinal calcula agora - anterior dentro da faixa de 32 bits. Embora a representação numérica tenha voltado a valores baixos, o resultado é 176 ms: o tempo realmente transcorrido entre essas duas marcas.
Acompanhe a mesma referência sem precisar esperar dias nem alterar o relógio da placa. Os valores servem apenas para rastrear a expressão.
| anterior | agora | agora - anterior | Atingiu 150 ms? |
|---|---|---|---|
| 4294967200 | 4294967250 | 50 ms | Não |
| 4294967200 | 0 | 96 ms | Não |
| 4294967200 | 80 | 176 ms | Sim |
Atenção
Não troque a subtração por uma comparação de “prazo” como esta:
agora >= anterior + intervalo
Se anterior = 4294967200UL e intervalo = 150UL, a soma dá a volta e resulta em 54UL. Antes de transcorrer 150 ms, por exemplo quando agora ainda vale 4294967250UL, a comparação agora >= 54UL seria verdadeira indevidamente.
Mantenha a diferença entre o instante atual e a referência:
agora - anterior >= intervalo
A subtração modular preserva o tempo decorrido enquanto ele cabe na faixa de 32 bits. Em outras palavras, não pode transcorrer uma volta completa do contador entre a marca e a avaliação.
Neste tutorial, os intervalos são de centenas de milissegundos e loop() consulta o relógio repetidamente, muito antes desse limite. Se uma volta inteira ocorresse sem avaliação, a diferença sozinha não informaria quantas voltas aconteceram nem recuperaria a duração total.
Associe cada situação ao resultado correto. Em todos os casos, considere valores unsigned long de 32 bits e a condição agora - anterior >= intervalo.
Faça as associações entre cada conjunto de marcas e sua conclusão.
Toque em um item e depois no par correspondente.

Passo 5 de 7
Implemente duas sequências de LEDs independentes no Uno R3 usando uma única leitura de millis por passagem no loop.
Cada saída guarda seus próprios dados: uma marca da última mudança e um estado atual. Assim, o LED integrado pode alternar a cada 300 ms enquanto o LED externo alterna a cada 700 ms, sem que uma sequência reinicie a outra.
No início de cada passagem por loop(), faça uma única leitura de millis() em agora. Depois, teste as duas condições em if separados. Se as duas condições forem verdadeiras naquela passagem, os dois blocos são atendidos, um após o outro, sem espera ativa.

A leitura atual pode ser compartilhada; a marca anterior e o estado de cada LED não.
Atenção
Com a placa desconectada do USB, monte o LED externo vermelho em série com um resistor de 1 kΩ: pino digital 7 → resistor → ânodo do LED; cátodo do LED → GND. Confira a polaridade antes de energizar.
Nesta prática, alimente a placa somente pelo USB. Não conecte uma fonte externa a VIN nem ao pino de 5 V.

Use este esquema apenas como referência visual da montagem: D7 → resistor de 1 kΩ → ânodo; cátodo → GND.
Copie o sketch para a IDE Arduino local, selecione seu Uno R3 e a porta correta, compile e grave. O LED integrado deve alternar aproximadamente a cada 300 ms; o LED externo, aproximadamente a cada 700 ms. Não há delay(), laço de espera nem necessidade de Monitor Serial.
Sketch para editar, compilar e gravar no Uno R3.
const byte pinoExterno = 7;
const unsigned long intervaloInterno = 300UL;
const unsigned long intervaloExterno = 700UL;
unsigned long anteriorInterno;
unsigned long anteriorExterno;
bool estadoInterno = LOW;
bool estadoExterno = LOW;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(pinoExterno, OUTPUT);
digitalWrite(LED_BUILTIN, estadoInterno);
digitalWrite(pinoExterno, estadoExterno);
anteriorInterno = millis();
anteriorExterno = anteriorInterno;
}
void loop() {
unsigned long agora = millis();
if (agora - anteriorInterno >= intervaloInterno) {
estadoInterno = !estadoInterno;
digitalWrite(LED_BUILTIN, estadoInterno);
anteriorInterno = agora;
}
if (agora - anteriorExterno >= intervaloExterno) {
estadoExterno = !estadoExterno;
digitalWrite(pinoExterno, estadoExterno);
anteriorExterno = agora;
}
}
LED_BUILTIN alterna aproximadamente a cada 300 ms. LED vermelho externo no pino 7 alterna aproximadamente a cada 700 ms. Nenhuma saída é exibida no Monitor Serial.
O resultado é físico, observado nos LEDs da placa e da montagem. O sketch não envia mensagens ao Monitor Serial.
Complete as duas marcas temporais usadas nas verificações. Cada if deve consultar e atualizar somente a referência da saída que ele controla.
Preencha as marcas corretas, sem criar uma referência compartilhada.
if (agora - >= intervaloInterno) {
estadoInterno = !estadoInterno;
digitalWrite(LED_BUILTIN, estadoInterno);
anteriorInterno = agora;
}
if (agora - >= intervaloExterno) {
estadoExterno = !estadoExterno;
digitalWrite(pinoExterno, estadoExterno);
anteriorExterno = agora;
}Em uma passagem por loop(), tanto o intervalo de 300 ms quanto o de 700 ms já foram atingidos. O que ocorre?
Após gravar o sketch, descreva em uma ou duas frases o que você observou nos dois LEDs. Inclua se a alternância de um pareceu impedir a do outro.
Escreva pelo menos 30 caracteres (0/30).

Passo 6 de 7
Reconheça que a temporização por millis atende o evento na próxima observação disponível e mantenha o restante do loop curto.
millis() deixa o loop() seguir adiante, mas a condição temporal só é avaliada quando o programa chega ao respectivo if.
Se o intervalo de um LED é 300 ms e o loop() volta a essa verificação aos 340 ms, a mudança ocorre aos 340 ms. O programa não consegue executar retroativamente a ação que seria desejada em 300 ms. A condição com >= aceita esse atendimento tardio.
Temporização não bloqueante significa não ficar esperando o tempo passar. Ela não promete que cada mudança ocorrerá no instante físico exato do limite.

A saída muda na primeira verificação que encontra o tempo decorrido igual ou maior que o intervalo.
Exemplo
Considere uma saída cujo último atendimento foi em 0 ms e cujo intervalo é 300 ms. O loop() só alcança esse if em 340 ms. Como a condição já foi atingida, a saída muda nessa passagem.
A política usada neste tutorial atualiza a referência com anterior = agora quando a saída muda. Portanto, depois do atendimento atrasado, a nova espera começa no instante realmente observado.
| Instante observado | Teste | Ação e referência |
|---|---|---|
| 0 ms | inicialização | anterior = 0 ms |
| 300 ms | nenhuma verificação | nenhuma mudança |
| 340 ms | 340 - 0 >= 300 | muda; anterior = 340 ms |
| 639 ms | 639 - 340 < 300 | não muda |
| 640 ms ou depois | agora - 340 >= 300 | próxima mudança |
Para sinalização simples, esse deslocamento geralmente é adequado: o LED continua alternando e o loop() continua disponível para as demais verificações.
Porém, as atividades entre uma consulta e outra precisam ser curtas. Um cálculo ou laço que ocupe muito tempo atrasa a próxima chegada ao if. Trocar delay() por outro laço que espera o relógio avançar continua bloqueando o fluxo principal.
millis() organiza a decisão temporal; ele não torna automaticamente rápida uma tarefa demorada.
Se anterior era 0 ms, o intervalo é 300 ms e a condição é atendida quando agora vale 340 ms, após a mudança anterior passa a ___ ms.
Verdadeiro ou falso: retirar delay() garante que o LED mudará exatamente a cada 300 ms, mesmo se outra tarefa no loop() levar muito tempo para terminar.

Passo 7 de 7
Consolide a solução com dois LEDs e valide como as verificações temporais independentes mantêm o fluxo principal em atividade.
Uma solução completa com duas saídas temporizadas mantém estes critérios juntos:
unsigned long para instantes, marcas e intervalos;millis() em agora a cada passagem;agora - anterior >= intervalo;if independentes;delay() ou laço esperando o relógio avançar.Assim, cada passagem por loop() consulta as duas condições e termina rapidamente. Se nenhum prazo venceu, nada muda nos LEDs — mas o programa já está livre para começar outra passagem pelo loop.

Os dois ramos usam o mesmo instante agora, mas cada um compara sua própria marca e seu próprio intervalo.
Complete as três lacunas sem transformar as duas temporizações em uma única referência compartilhada.
const byte pinoExterno = 7;
const unsigned long intervaloInterno = 300UL;
const unsigned long intervaloExterno = 700UL;
unsigned long anteriorInterno;
unsigned long anteriorExterno;
bool estadoInterno = LOW;
bool estadoExterno = LOW;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(pinoExterno, OUTPUT);
anteriorInterno = millis();
anteriorExterno = anteriorInterno;
}
void loop() {
unsigned long agora = millis();
if (agora - anteriorInterno intervaloInterno) {
estadoInterno = !estadoInterno;
digitalWrite(LED_BUILTIN, estadoInterno);
anteriorInterno = ;
}
if (agora - anteriorExterno >= ) {
estadoExterno = !estadoExterno;
digitalWrite(pinoExterno, estadoExterno);
anteriorExterno = agora;
}
}Sem esperar dias na placa, rastreie este caso: anterior = 4294967200UL, agora = 80UL e intervalo = 150UL. Qual é o resultado de agora - anterior >= intervalo?
Na IDE Arduino local, altere somente esta linha do sketch para testar uma cadência diferente no LED externo:
const unsigned long intervaloExterno = 1000UL;
Mantenha intervaloInterno = 300UL e todo o restante inalterado. Compile, grave no Uno R3 e observe os dois LEDs. Em 2 ou 3 frases, relate o que mudou no LED externo, o que permaneceu no LED integrado e por que o loop continua disponível entre as mudanças.
Escreva pelo menos 80 caracteres (0/80).
Resumo
unsigned long para millis(), marcas anteriores e intervalos; escreva intervalos constantes com sufixo UL.agora - anterior >= intervalo; essa forma continua válida ao atravessar o retorno da contagem, desde que não transcorra uma volta completa sem avaliação.millis() uma vez por passagem e aplique dois if independentes para que os LEDs possam ser atendidos separadamente ou na mesma passagem.millis() não elimina tarefas demoradas: o restante do loop também precisa ser curto para que as verificações ocorram com frequência.Parabéns! Você concluiu: Temporização não bloqueante com millis
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