Como Substituir delay() e millis() no Arduino com a Biblioteca NeoTimer

Substituir as funções de temporização com a Biblioteca NeoTimer [Guia Completo com Exemplos]

Objetivo

Este artigo tem como objetivo apresentar uma alternativa eficiente ao uso das funções delay() e millis() no Arduino, utilizando a biblioteca NeoTimer. Essa biblioteca oferece uma forma mais intuitiva e modular de trabalhar com temporizadores, permitindo o desenvolvimento de sistemas sem pausas, com multitarefas cooperativas e código mais legível. Ideal para projetos com LCD, sensores, atuadores e botões com debounce.

Vantagens da NeoTimer:

  • Código mais limpo e intuitivo.

  • Elimina a lógica complexa com millis().

  • Permite multitarefas cooperativas reais.

  • Otimizar o uso de recursos: Reduzir o uso de memória, melhorar a performance.
  • Ideal para projetos com LCD, LEDs, sensores, atuadores, debounce e controle de estado.

O que a Biblioteca NeoTimer Substitui:

A NeoTimer substitui:

  • delay() — pausa a execução do loop principal (e, consequentemente, todo o programa) pelo período de tempo especificado. Durante esse tempo de pausa, nenhuma outra tarefa pode ser executada.

  • millis() + lógica manual — que exige variáveis auxiliares e condicionais repetitivas complexas.

Com a NeoTimer, você pode:

  • Programar tarefas periódicas.

  • Criar vários temporizadores simultâneos.

  • Implementar debounce de botões.

  • Fazer atualizações em LCDs e monitorar sensores em tempos diferentes, tudo sem pausar o loop.

Definições

Multitarefa (multitasking) é a capacidade de executar várias tarefas ou processos de forma simultânea (ou quase simultânea) em um sistema. No Arduino, isso é tipicamente simulado, pois há apenas um núcleo de processamento. 

O que parece ser a execução simultânea de várias tarefas é, na verdade, o processador alternando entre elas muito rapidamente. Essa técnica é frequentemente chamada de "time-slicing".

Multitarefa Cooperativa Real no Arduino significa que:

  • Você divide seu código em pequenas tarefas.

  • Cada tarefa não bloqueia as outras (ou seja, sem delay()!).

  • Todas as tarefas compartilham o mesmo loop (loop() do Arduino).

  • O controle do tempo é feito por funções como millis(), ou bibliotecas como NeoTimer.

Referências

Como usar temporizadores no Arduino

Bouncing e Debouncing: Entenda e Resolva Problemas de Ruído nos Botões

Instalando a biblioteca NeoTimer

1. Abra o Arduino IDE. Vá em Sketch (Rascunho) > Incluir Biblioteca > Gerenciar Bibliotecas....

2. Digite NeoTimer no campo pesquisar e clique em INSTALAR.

 

3. Verifique se a biblioteca foi instalada. Obs.: Caso deseje excluí-la, clique em REMOVER.

4. Para mais informações sobre a biblioteca leia README.

O que é a NeoTimer?

A NeoTimer é uma biblioteca que simplifica o uso de temporizadores em projetos Arduino, permitindo criar múltiplos timers com métodos intuitivos como:

Observações:

  • start(), done() e repeat() são os métodos mais usados para substituição direta de millis() e delay().

  • O método stop() é essencial para evitar múltiplas execuções não intencionais após o tempo terminar.

Exemplos usando a biblioteca NeoTimer

Aqui vão alguns exemplos práticos do uso da biblioteca NeoTimer no Arduino em situações comuns. Todos são sem delay, e ideais para projetos com LCD, botões, LEDs, sensores, etc.

Exemplo 1:

Espera 3 segundos para apagar o led uma única vez.

#include <neotimer.h>

Neotimer timerLed(3000);              // 3000 ms = 3 segundos

const byte ledPin = 13;

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  timerLed.start();                  // inicia o temporizador  
}

void loop() {
  if (timerLed.done()) {              // chegou no tempo de definido = true             
    digitalWrite(ledPin, LOW);
    timerLed.stop();                  // para o temporizador
  }
}
}

Observações:

  • NeoTimer timer(3000);: Cria um temporizador de 3000 milissegundos (3 segundos).

  • timer.start();: Inicia o temporizador no setup().

  • timer.done(): Retorna true quando os 3 segundos se completam.

  • O método stop() da biblioteca NeoTimer serve para interromper ou desativar o temporizador, impedindo que ele continue contando ou retorne true em done() após o tempo definido.
    • Após chamar stop(), o temporizador para completamente.

    • done() não retornará mais true, mesmo que o tempo tenha passado.

    • É útil para eventos únicos, onde o temporizador não deve ser reutilizado sem reinicialização.

Exemplo 2: 

Piscar LED com NeoTimer (intervalo de 500ms)

#include <neotimer.h>

Neotimer ledTimer(500);          // Cria o timer com intervalo de 500ms

const byte ledPin = 13;

void setup() {
  pinMode(ledPin, OUTPUT);
  ledTimer.start();                 // Inicia o temporizador
}

void loop() {
  if (ledTimer.repeat()) {       // Se tempo completou, reinicia automaticamente
    digitalWrite(ledPin, !digitalRead(ledPin)); 
  }
    
}

Observações:

  • NeoTimer timer(500); cria um timer de 500 milissegundos.
  • digitalWrite(..., !digitalRead(...)): inverte o estado atual do pino, fazendo o LED piscar.

  • repeat() foi feito exatamente para esse caso: ele reinicia o timer somente se o tempo foi concluído.

Diferença-chave — repeat() vs done() + start()

  • done() apenas detecta o fim do intervalo uma vez, então você precisa de start() para reiniciar manualmente.

  • repeat() já faz isso automaticamente: ele retorna true toda vez que o tempo expira e reinicia internamente o timer.

Portanto repeat() otimiza o código abaixo:

#include <neotimer.h>

Neotimer ledTimer(500);          // Cria o timer com intervalo de 500ms

const byte ledPin = 13;

void setup() {
  pinMode(ledPin, OUTPUT);
  ledTimer.start();                 // Inicia o temporizador
}

void loop() {
  if (ledTimer.done()) {       // Se tempo completou
    digitalWrite(ledPin, !digitalRead(ledPin));
    ledTimer.start();          // Inicia novamente o timer
  }    
}

Atenção:

  • O método restart() reinicia o timer a partir do tempo da última execução. Portanto, para esse caso deve-se usar o métiodo repeat() ou done() + start().

Exemplo 3:

LED aceso por 500ms e apagado por 2000ms

#include <neotimer.h>

const byte ledPin = 13;

Neotimer timerOn(500);   // Tempo que o LED fica ACESO
Neotimer timerOff(2000); // Tempo que o LED fica APAGADO

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);   // Começamos com o LED aceso
  timerOn.start();              // Inicia o timer de LED aceso
}

void loop() {
  if (digitalRead(ledPin) && timerOn.done()) {
    digitalWrite(ledPin, LOW);   // Desliga o LED
    timerOff.start();            // Inicia o timer de LED apagado
  }

  if (!digitalRead(ledPin) && timerOff.done()) {
    digitalWrite(ledPin, HIGH);  // Liga o LED
    timerOn.start();             // Inicia o timer de LED aceso
  }
}
Observações:
  • Usamos dois timers:
    • timerOn: controla o tempo que o LED fica aceso (500 ms)

    • timerOff: controla o tempo que o LED fica apagado (1000 ms)

  • O controle do estado do LED é feito pel lógica digitalRead(ledPin) que verifica o estado do LED, se aceso ou apagado. 
  • No setup(), o LED é iniciado como HIGH (aceso).

  • O timerOn é iniciado primeiro (tempo que o LED ficará aceso inicialmente).

Usando o NeoTimer para multitarefas

Exemplo 1:

Dois LEDs piscando em intervalos diferentes (500ms e 1000ms)

  • Exemplo de multitarefa cooperativa em Arduino, controlando múltiplos eventos temporizados sem usar delay().
#include <neotimer.h>

const byte led1Pin = 12;
const byte led2Pin = 13;

Neotimer timerLed1(500);   // LED 1 pisca a cada 500ms
Neotimer timerLed2(1000);  // LED 2 pisca a cada 1000ms

void setup() {
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  
  timerLed1.start();
  timerLed2.start();
}

void loop() {
  if (timerLed1.repeat()) {
    digitalWrite(led1Pin, !digitalRead(led1Pin)); // Inverte estado do LED 1
  }

  if (timerLed2.repeat()) {
    digitalWrite(led2Pin, !digitalRead(led2Pin)); // Inverte estado do LED 2
  }
}

Observações:

  • A cada vez que o intervalo termina (repeat() retorna true), o LED correspondente troca de estado (acende ou apaga).

  • !digitalRead(...) inverte o estado atual do LED, simulando o piscar.

Usando o NeoTimer como debounce de botões

Botões físicos possuem ruído mecânico: ao serem pressionados ou soltos, o sinal oscila rapidamente por alguns milissegundos antes de se estabilizar. Isso pode causar múltiplas leituras erradas como se o botão tivesse sido pressionado várias vezes. Leia Bouncing e Debouncing: Entenda e Resolva Problemas de Ruído nos Botões

A biblioteca NeoTimer é uma forma prática e intuitiva de substituir o uso do delay() e do millis() para gerenciar temporizações sem bloquear o loop(). Ela não foi criada especificamente para debounce, mas pode ser usada para isso com uma lógica um pouco mais simples do que millis().

Exemplo 1:

Botão interruptor com debounce NeoTimer (Botão acende e apaga um led)

#include <neotimer.h>

// Pinos
const int buttonPin = 2;
const int ledPin = 13;

// Estado do LED
bool ledState = false;

// Timer de debounce
Neotimer debounceTimer(50);

// Estado anterior do botão (para detecção de borda)
bool lastStableState = HIGH;
bool lastReadState = HIGH;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (botaoPressionado()) {
    ledState = !ledState;
    digitalWrite(ledPin, ledState);
  }
}

// --- Função que retorna true apenas quando o botão é pressionado com debounce ---
bool botaoPressionado() {
  bool current = digitalRead(buttonPin);

  // Detecta mudança de estado
  if (current != lastReadState) {
    debounceTimer.start();       // Inicia o timer de debounce
    lastReadState = current;     // Atualiza a leitura anterior
  }

  // Se o tempo passou e o estado estável mudou
  if (debounceTimer.done() && current != lastStableState) {
    lastStableState = current;

    // Detecta borda de descida (pressionamento)
    if (current == LOW) {
      return true;
    }
  }

  return false;
}

✅ Funcionamento:

  • A função botaoPressionado() detecta toques com estabilidade de 50 ms (configurado no Neotimer).

  • Apenas mudanças de HIGH → LOW (toque real) disparam true.

  • O LED responde com alternância (interruptor), sem múltiplas detecções acidentais.

Observações:

  • Usa INPUT_PULLUP para evitar resistores externos.

  • Botão montado entre o pino 2 e o GND, com o resistor pull-up interno ativado (INPUT_PULLUP), o comportamento será:

    • Botão não pressionado → HIGH.

    • Botão pressionado → LOW → LED alterna.

ATENÇÃO:

Vamos comparar o uso de NeoTimer, millis(), e a biblioteca Bounce2 em termos de debounce de botões, sob os critérios mais relevantes:

Para saber como utilizar a biblioteca Bounce2 leia: Bouncing e Debouncing: Entenda e Resolva Problemas de Ruído nos Botões

NeoTimer vs millis()

NeoTimer:

    • Abstrai a lógica com start() e done().

    • ✅ Ideal para quem quer evitar complexidade de controle manual de tempo.

    • ✅ Muito útil para iniciantes ou projetos pequenos/médios com vários timers simples.

    • ❌ Não possui lógica nativa de detecção de borda (↑ ou ↓), apenas temporização.

millis():

    • ✅ Máxima flexibilidade e controle.

    • ✅ Zero dependência de bibliotecas externas.

    • Mais verboso: exige unsigned long, controle de tempo manual e comparação de estados.

    • ❌ Fácil cometer erros com "overflow" ou lógica de tempo incorreta.

NeoTimer é melhor que millis() quando você quer legibilidade, simplicidade e foco no projeto (não na mecânica de tempo). Mas millis() ainda é imbatível para máximo controle e uso avançado com precisão absoluta.

NeoTimer vs Bounce2

Bounce2:

    • Feita especificamente para debounce de botões.

    • ✅ Lógica completa: .fell(), .rose(), .update(), .read() — tudo pronto.

    • ✅ Leitura por evento de borda: "pressionado", "liberado".

    • ✅ Gerencia internamente o estado atual, anterior e tempo de estabilidade.

    • ✅ Suporta múltiplos botões facilmente.

    • ❌ Levemente mais pesada (mas nada que atrapalhe em Arduinos típicos).

NeoTimer:

    • ✅ É uma ferramenta genérica de temporização.

    • Não gerencia eventos de borda nativamente.

    • ❌ Precisa de lógica manual para lidar com transições de estado de botão.

    • ✅ Pode ser combinada com qualquer entrada, não apenas botões.


Para botões físicos, Bounce2 é superior ao NeoTimer, pois:

    • É específica para esse propósito.

    • Exige menos código para detectar toques, bordas, e fazer debounce corretamente.

    • É mais clara e mais fácil de integrar em projetos complexos.

Quando usar cada um?

  • millis(): quando você quer controle absoluto, lógica customizada, ou está otimizando tempo com precisão.

  • NeoTimer: para projetos rápidos e simples, temporizadores múltiplos, delays não-bloqueantes.

  • Bounce2: para botões físicos com confiabilidade, menor código, maior robustez e suporte a múltiplos estados.

Exemplo 2:

Botão interruptor com debounce NeoTimer (Led espera 3 segundos para acender)

#include <neotimer.h>

// Pinos
const int buttonPin = 2;
const int ledPin = 13;

// Estados
bool ledState = false;

// Timer de debounce
Neotimer debounceTimer(50);

// Timer para religar após 3 segundos
Neotimer religaTimer(3000); // 3000 ms = 3 segundos

// Estados de leitura
bool lastStableState = HIGH;
bool lastReadState = HIGH;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (botaoPressionado()) {
    // Se LED estava ligado, apaga e inicia o timer de religa
    if (ledState) {
      ledState = false;
      digitalWrite(ledPin, LOW);
      religaTimer.start(); // Inicia temporizador de 3 segundos
    }
    // Se LED estava desligado, liga e para o timer (se estiver rodando)
    else {
      ledState = true;
      digitalWrite(ledPin, HIGH);
      religaTimer.stop(); // Cancela religamento automático
    }
  }

  // Se LED estiver desligado e o timer de religamento terminou, religa o LED
  if (!ledState && religaTimer.done()) {
    ledState = true;
    digitalWrite(ledPin, HIGH);
  }
}

// --- Função: Detecta toque com debounce ---
bool botaoPressionado() {
  bool currentRead = digitalRead(buttonPin);

  if (currentRead != lastReadState) {
    debounceTimer.start();
    lastReadState = currentRead;
  }

  if (debounceTimer.done() && currentRead != lastStableState) {
    lastStableState = currentRead;

    if (currentRead == LOW) {
      return true;
    }
  }

  return false;
}

Usando as bibliotecas Neotimer  e Bounce2

No exemplo abaixo vamos utilizar as bibliotecas Neotimer para o temporizador do Led e Bounce 2 para fazer o debounce do botão (push button).

Exemplo 1:

Botão interruptor com debounce Bounce2 e temporizado com Neotimer (Led espera 3 segundos para acender)

#include <Bounce2.h>
#include <neotimer.h>

// Pinos
const byte buttonPin = 2;
const byte ledPin = 13;

// Instâncias
Bounce debouncer = Bounce();       // Objeto de debounce
Neotimer religaTimer(3000);        // Timer para religar após 3 segundos

bool ledState = true;

void setup() {
  pinMode(ledPin, OUTPUT);

  digitalWrite(ledPin, HIGH);

  // Configura botão com debounce
  debouncer.attach(buttonPin, INPUT_PULLUP);
  debouncer.interval(50); // 50ms de debounce
}

void loop() {
  debouncer.update(); // Atualiza estado do botão

  if (debouncer.fell()) { // Detecta transição de HIGH para LOW (botão pressionado)
    if (ledState) {
      ledState = false;
      digitalWrite(ledPin, LOW);
      religaTimer.start();
    } else {
      ledState = true;
      digitalWrite(ledPin, HIGH);
      religaTimer.stop(); // Cancela religamento automático
    }
  }

  // Verifica se deve religar o LED após 3 segundos
  if (!ledState && religaTimer.done()) {
    ledState = true;
    digitalWrite(ledPin, HIGH);
  }
}

Observações:

O anúncio abaixo ajuda a manter o Squids Arduino funcionando

Comentários

×

Infomações do site / SEO








×

Adicionar Marcadores