Olá a todos.

Tendo em vista as repetidas dúvidas sobre a utilização do millis(), resolvi criar este tutorial simples e curto para facilitar o entendimento dos colegas que, eventualmente, possam ter dúvidas.

1. O que é o millis()?

O millis() é uma função que retorna um VALOR referente ao TEMPO desde que o PROGRAMA foi iniciado.

Este TEMPO é dado em milissegundos(ms), ou seja, 1 segundo é o mesmo que 1000ms.

Exemplo1: Se o programa já está sendo rodado a 17 segundos, ele retornará 17000. 

Exemplo 2: Se estiver rodando a 1 minuto e 5 segundos, ele retornará 65000, pois 1 minuto = 60.000ms, e 5 segundos = 5000ms, logo, 60.000+5.000 = 65.000

Exemplo3: Programa rodando a 2 horas. (2h = 120min = 7200sec = 7.200.000ms)

Para visualizar a mudança deste valor, você pode criar o seguinte código:

#define velocidade_serial 115200 // 9600 para arduino e 115200 para Esp8266/32

void setup(){

   Serial.begin(velocidade_serial);

}

void loop(){

   Serial.println(millis());

}

Após carregar o código, abra o monitor serial, e veja o valor sendo atualizado constantemente. 

Na imagem temos 2 valores (pois é constantemente atualizado).

valor 1: 55989 milissegundos = 55,989 segundos

valor 2: 56000 milissegundos = 56 segundos

2. Como o millis() é utilizado nos códigos? E quais as vantagens?

Além do seu retorno nativo, é comumente usado como uma forma de "atraso otimizado".

Esses atrasos são sempre produzidos através de uma condição e um calculo. No geral, a grande vantagem está na possibilidade de não "travar" o programa, que é uma consequência do uso da função delay(). 

3. Calculo simples com millis()

Primeiramente, vamos visualizar um calculo simples com o millis(). Este calculo será um: millis() - 1000. Para facilitar, vamos fazer o seguinte código:

void setup(){Serial.begin(115200);}

void loop(){

   Serial.print("Valor do millis() = ");

   Serial.print(millis());

   Serial.print("  -  Valor do calculo = ");

   Serial.print(millis() - 1000);

}

Veja na imagem a seguir o resultado:

Do lado esquerdo, temos o valor atual do retorno da função "millis()", do lado direito, temos o mesmo valor, só que reduzindo em 1000.

Se adicionarmos a função delay(), teríamos uma pausa entre cada uma dessas leituras.

void loop(){

   Serial.print("Valor do millis() = ");

   Serial.print(millis());

   Serial.print("  -  Valor do calculo = ");

   Serial.print(millis() - 1000);

   delay(1000);               ////////////// PAUSA de 1 segundo

}

Perceba que, neste caso, os cálculos e a impressão dos valores estão ocorrendo EXATAMENTE após 1 segundo, devido ao delay(1000). Entretanto, o código "PARA" quando o delay é chamado, ou seja, nada poderá acontecer em "paralelo".

Se você possuir um led que pisca a cada 0,5 segundos, então ele irá piscar a cada 1,5 segundos.

Se tiver um sensor que fica lendo os valores a cada 0,1 segundo, então ele só irá ler a cada 1,1 segundo.

Para muitas aplicações, o uso do delay() é ótimo, mas para outras, ele causa grandes problemas.

Imagine que você tenha 2 leds, e você deseja que o led 1 pisque a cada 3 segundos, e o led 2 a cada 4 segundos. Com o uso simples e direto do delay(), sem cálculos para compensar, seria impossível. 

Imagine ainda que você precisa que um botão fique pressionado por X segundos para uma ação ser ativada. Com delay() seria um grande transtorno.

4. Substituir delay() por millis()

Agora a coisa começa a ficar bem legal, pois teremos a nossa primeira aplicação.

O principio deste novo "delay", é um comparativo entre o valor atual de millis() com um valor armazenado em uma variável qualquer, que também lhe foi atribuído o valor do millis(). Exemplo:

// DELAY de 5 segundo //

unsigned long Var;     

void setup(){

   Serial.begin(115200);  

   Var = millis();   

}

void loop(){

   if (millis() - Var >= 5000){

      Serial.println(millis());

      Var = millis();

   }

}

Vamos explicar o código

unsigned long Var;

Declaração da variável "Var" para o tipo "unsigned long".

"unsigned" -> diz que a variável não irá armazenar números negativos.

"long" -> Armazena até 32 bits.

É a declaração padrão para esta aplicação.

Mais informações: LINK AQUI

Var = millis();   (no setup() )

Ele atribui o valor de millis() para a variável Var.

Ou seja, no exato instante, os dois terão o mesmo valor, entretanto, o valor de millis() é alterado constantemente (item 1, lembra?).

if (millis() - Var >=5000){

A leitura deste código seria assim: "O valor de millis() menos o valor de Var, é maior ou igual a 5000?", então ele retornará "Verdadeiro/True/1" ou "Falso/False/0" 

//Exemplo dentro do exemplo

//No primeiro momento iremos atribuir: Var = millis(), e dizer que o valor de millis() é de 1234. Logo: //Var = 1234, millis() = 1234

//

//Após Segundo 1. Var = 1234, millis() = 2234   (millis() - var => 2234 - 1234 => 1000)

//Após Segundo 2. Var = 1234, millis() = 3234   (millis() - var => 3234 - 1234 => 2000)

//Após Segundo 3. Var = 1234, millis() = 4234   (millis() - var => 4234 - 1234 => 3000)

//Após Segundo 4. Var = 1234, millis() = 5234   (millis() - var => 5234 - 1234 => 4000)

//Após Segundo 5. Var = 1234, millis() = 6234   (millis() - var => 6234 - 1234 => 5000)

Var = millis();

Necessário para "reiniciar o cronometro", afinal, quando ele obtém o novo valor de millis(), a SUBTRAÇÃO de millis() por Var, NO EXATO INSTANTE, voltará a ser ZERO. Veja o resultado na imagem:

Você pode dizer: "Tiago, o resultado é o MESMO que adicionar um delay(5000)". E você estará certo, pois esta aplicação é muito simples! Mas veja o código a seguir:

unsigned long Var;     

void setup(){

   Serial.begin(115200);  

   Var = millis();   

}

void loop(){

   if (millis() - Var >= 5000){

      Serial.println();             // Mudança

      Serial.println(millis());

      Var = millis();

   }

   Serial.print(".");           // Mudança

}

Veja o resultado:

o valor do millis() só estava sendo impresso a cada 5 segundos, entretanto, o ".", estava sendo impresso initerruptamente. Ou seja, temos um "evento em paralelo"!!! 

(continua no próximo post)

Exibições: 175

Responder esta

Respostas a este tópico

5. Múltiplos "delays" com millis()

Veja o seguinte código:

unsigned long var1;

unsigned long var2;

void setup(){

  Serial.begin(115200);

  var1 = millis();

  var2 = millis();

}

void loop(){

  if (millis() - var1 >= 1500){

     Serial.print("instante do print do var1 = ");

      Serial.println(millis());

     var1 = millis();

  }

  if (millis() - var2 >= 2000){

     Serial.print("instante do print do var2 = ");

     Serial.println(millis());

     var2 = millis();

  }

}

Segue o mesmo principio do anterior, veja a imagem:

Continua na próxima postagem

6. Segurar botão com millis()

A ideia é segurar um botão, e após "X" segundos, a ação ser iniciada.

#define BotPin 6         // define o pino do botão

unsigned long Var1;      // define a var para armazenar o millis()

void setup(){

   Serial.begin(115200);  //9600 no arduino

   pinMode(BotPin, INPUT);

}

void loop(){

   if (digitalRead(BotPin) == HIGH) {
      if (millis() - Var1 >= 2000) {
        Serial.print("Botão Pressionado");

        // acontece a ação
      }
   }
   else {
      Var1 = millis();
   }

}

Lendo o código:

if (digitalRead(BotPin) == HIGH) {

Leitura: Se a leitura digital (digitalRead, que retorna 1 ou 0), dopino "BotPin", estiver ALTA...

if (millis() - Var1 >= 2000) {

Leitura: Se, o valor de millis() MENOS o valor de Var1 é maior ou igual a 2000 (2 segundos)....

else {Var1 = millis();}

Leitura: Caso o retorno de "digitalRead(BotPin)" NÃO SEJA "HIGH",  Var1 será atualizado com o valor atual do millis();

O que acontece:

     Enquanto o botão não for pressionado, o "cronometro" (diferença entre millis() e Var1), será sempre de ZERO, pois Var1 está sempre sendo atualizado.

     Quando o botão for PRESSIONADO, Var1 não será atualizado. Caso o botão fique pressionado por mais de 2 segundos (2000ms), a ação irá acontecer.

===========================================

Caso tenha ficado alguma dúvida, pode perguntar.

Olá, Tiago!

   Belíssimo trabalho. Passo a recomendar!

Abração!

D. T. Ribeiro.

Obrigado D. T. Ribeiro! 

Espero que isto ajude bastante a turma.

Bom dia,

muito bom.

Tomara que esta moçada nova aproveite bem a aula.

RV mineirin

Obrigado RV. Estou contando com isso. 

Parabéns Tiago. 

Não canso em comentar - a melhor forma de aprender é ensinando. 

Olá Gustavo.

   É a mais pura verdade.

   Tem até um ditado que diz: "Quando um ensina, dois aprendem" 

Abração!

D. T. Ribeiro

Obrigado JSAM! 

O que você falou é uma grande verdade.

Parabéns Tiago,

Boa explicação para um assunto de duvida recorrente, tenho certeza que ira ajudar muita gente que deseje estudar um pouco em vez de copiar e colar. Bela iniciativa!

Abs.

CK

Exatamente Carlos.

É um recurso simples, mas de aplicações maravilhosas.

millis() para o delay(), é como o SSD para o HDD, é um caminho sem volta.

RSS

© 2023   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço