Tutoriais

Millis( ): Funcionamento e exemplos

Eletrogate 18 de abril de 202410 minutos

O que faz a função millis( )?

A função millis() retorna para o usuário o tempo, em milissegundos, de atividade do programa na placa desde a última vez em que o código foi iniciado. Essa função é capaz de gravar até 4.294.967.295 milissegundos, ou o equivalente a 49,7 dias.


Qual a diferença entre o millis( ) e o delay( )?

A principal diferença entre essas duas funções se dá pelo fato da função delay(), quando chamada no código, pausar o programa pelo intervalo de tempo determinado pelo programador, impossibilitando o core da placa de realizar qualquer outra atividade durante esse período. Enquanto isso, a função millis( ) não é, necessariamente uma pausa no programa, mas sim, um contador de tempo de atividade do mesmo, que pode ser usado, também, como uma espécie de delay.

Imagine quando a sua placa lê a linha em que está escrito “delay (1000)”. Quando isso acontece, automaticamente ela para por 1000 milissegundos e se mantêm impossibilitada de ler qualquer outra linha durante esse intervalo de tempo.

Já quando utilizamos o millis() como um delay, isso não acontece mais. A placa não executará um trecho do programa durante o período, mas poderá ler e executar todo o resto do código, até que o intervalo de tempo que você escolheu tenha sido atingido. Isso evita que seu código fique travado e que você perca eficiência na hora de executar seu programa. Além disso, também evita que você utilize mais de uma placa microcontrolada em seu projeto.

Blog-Eletrogate-Diagrama-Millis-Delay

Diagrama de funcionamento do delay() e do millis()


Como programar um delay utilizando a função millis( )?

Antes de tudo, é importante que você saiba como funciona a lógica por trás dessa utilização.

Primeiro, precisamos de uma variável que guarde o valor de millis() para que nós possamos utiliza-lo no código. É importante escolher o tipo de variável correto. O mais indicado é o tipo unsigned long, que é capaz de armazenar de 0 a 4.294.967.295, este último, que é justamente o valor máximo que o millis() pode nos fornecer.

Além disso, precisamos declarar uma variável auxiliar de mesmo tipo, que servirá como uma espécie de “memória” do valor do millis() na última vez que a ação pretendida foi executada.

Não é recomendável utilizar variáveis do tipo int pois são capazes de armazenar entre -2.147.483.648 e 2.147.483.647. Perceba que estamos trabalhando com tempo, e a contagem de tempo tempo inicia-se em zero e é progressivo, sendo incapaz de ser negativo, por isso, perderíamos metade do valor máximo que poderíamos armazenar, caindo de 49,7 dias para 24,85 dias – por esse motivo utilizamos o modificador “unsigned”, que recebe somente valores positivos.

Para facilitar, faremos um LED piscar como exemplo:

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/


void setup()
{
  pinMode(13, OUTPUT); /*Vamos usar um LED como exemplo*/
}

No void loop (), você deve iniciar igualando uma das variáveis ao millis(), assim, toda vez em que o código passar pela primeira linha, o valor do millis() será atualizado dentro da variável.

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/


void setup()
{
  pinMode(13, OUTPUT); /*Vamos usar um LED como exemplo*/
}

void loop()
{
 tempo = millis (); /*Atualização do valor dentro da variável*/

}

Nesse momento, caso você execute o código dentro da placa, o valor de millis() já estará sendo atualizado dentro da variável.

Agora, vamos definir a condição para que o LED acenda: depois de 1000 milissegundos (1 segundo) após o código ser executado.

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/


void setup()
{
  pinMode(13, OUTPUT); /*Vamos usar um LED como exemplo*/
}

void loop()
{
 tempo = millis (); /*Atualização do valor dentro da variável*/

  if (tempo - auxiliar >= 1000){
    digitalWrite (13, HIGH);
    
   }

}

Perceba que a princípio a condição “tempo – auxiliar” será igual a millis(), já que tempo é igual a millis() (linha 13) e auxiliar é igual a zero quando o código inicia (linha 3).

Agora, para que o LED permaneça ligado por um segundo e apague após isso, precisamos que essa subtração seja igual a 2000 milissegundos (1000 milissegundos para ligar + 1000 milissegundos permanecido ligado).

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/


void setup()
{
  pinMode(13, OUTPUT); /*Vamos usar um LED como exemplo*/
}

void loop()
{
 tempo = millis (); /*Atualização do valor dentro da variável*/

  if (tempo - auxiliar >= 1000){
    digitalWrite (13, HIGH);
    
   }

  if (tempo - auxiliar >= 2000){
    digitalWrite (13, LOW);

   }

}

Agora, após 1 ciclo de liga/desliga, o LED precisa novamente acender, e para que a primeira condição (linha 15) seja verdadeira novamente, precisamos igualar o valor da variável “auxiliar” com o valor da variável “tempo”, reduzindo novamente a diferença entre as duas variáveis para zero, de modo a reiniciar o ciclo.

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/


void setup()
{
  pinMode(13, OUTPUT); /*Vamos usar um LED como exemplo*/
}

void loop()
{
 tempo = millis (); /*Atualização do valor dentro da variável*/

  if (tempo - auxiliar >= 1000){
    digitalWrite (13, HIGH);
    
   }

  if (tempo - auxiliar >= 2000){
    digitalWrite (13, LOW);

     auxiliar = tempo;

   }

}

Dessa forma, o código já estará funcionando, acendendo o LED da porta 13, esperando 1 segundo e apagando ele. Após isso, espera-se mais 1 segundo, o LED acende e o ciclo recomeça.

Blog-Eletrogate-Exemplo1-Millis()

Diagrama do primeiro exemplo

Verifique abaixo o código em funcionamento:


Utilizando o millis( ) para piscar dois LEDs alternadamente

Para que você perceba o princípio de funcionamento de forma mais clara, faremos um LED piscar em intervalos de 0,4 segundos, e o outro piscar em intervalos de 1 segundo (1000 milissegundos).

Como alterações no código do exemplo anterior, ao invés de 1000 e 2000 milissegundos nas condicionais do primeiro LED, colocaremos 400 e 800 milissegundos.

Para o segundo LED, adicionaremos uma nova variável auxiliar, responsável pela memória do millis() do segundo LED. Ainda, declararemos o pino 12 (2º LED) como OUTPUT e faremos a mesma lógica condicional do exemplo anterior (agora para o 2º LED), adicionando 1000 milissegundos para o LED acender, e em 2000 milissegundos (1000 milissegundos depois), para ele apagar, esperando mais 1000 milissegundos para acender novamente.

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/

unsigned long auxiliar_2 = 0; /*Variável auxiliar*/


void setup()
{
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
}

void loop()
{
 tempo = millis (); /*Atualização do valor dentro da variável*/

  if (tempo - auxiliar >= 400){
    digitalWrite (13, HIGH);
    
   }

  if (tempo - auxiliar >= 800){
    digitalWrite (13, LOW);

     auxiliar = tempo;

   }
  
  if (tempo - auxiliar_2 >= 1000){
    digitalWrite (12, HIGH);
    
  }
  
  if (tempo - auxiliar_2 >= 2000){
    digitalWrite (12, LOW);
    
    auxiliar_2 = tempo;
    
  }

}

Veja como montar o 2º exemplo:

Blog-Eletrogate-Millis-Exemplo-3

 

Verifique abaixo o código em funcionamento:

 

Nessa situação, seria inviável o uso do delay(). Veja no diagrama abaixo a explicação:

Blog-Eletrogate-Millis-delay-Exemplo

Fluxograma de inviabilidade de utilização do delay() para ativação de dois LEDs alternadamente

Como exemplificado no fluxograma acima, é inviável a utilização do delay(). Ao manipular o acionamento dos LEDs com delay(), a máquina (seu Arduino), “travará” a leitura do código durante o período determinado por você. Assim, a utilização do millis() se torna mais vantajosa ao passo que você necessita de poucas linhas para realizar o controle e independe da necessidade de os valores dos intervalos de tempo de acionamento dos LEDs serem múltiplos. Além disso, é possível adicionar quantos LEDs você quiser no seu projeto, de forma a acioná-los simples e intuitivamente.


Imprimindo o valor de millis( ) no monitor serial

Vamos agora imprimir o valor de millis () no monitor serial a cada 5 segundos. Para isso, precisamos, iniciar a serial.

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/


void setup(){
  Serial.begin (9600); /*Inicia a Serial*/
}


void loop()
{
tempo = millis();

}

Assim como no exemplo anterior, precisamos definir a condição para que a ação seja executada. Nesse caso, se a diferença entre “tempo” e “auxiliar” for de 5000 milissegundos.

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/


void setup(){
  Serial.begin (9600); /*Inicia a Serial*/
}


void loop()
{
tempo = millis();

  if (tempo - auxiliar >= 5000){
    
Serial.println (millis());
    
    }

}

Agora, para limitar que apenas a cada 5000 milissegundos o valor seja escrito no monitor serial, igualamos o valor de “auxiliar”, antes zero, ao valor de “tempo” no momento em que millis() foi escrito.

unsigned long tempo = 0; /*Variável utilizada para salvar o valor do millis*/

unsigned long auxiliar = 0; /*Variável auxiliar*/


void setup(){
  Serial.begin (9600); /*Inicia a Serial*/
}


void loop()
{
tempo = millis();

  if (tempo - auxiliar >= 5000){
    
Serial.println (millis());

auxiliar = tempo;   
 
    }

}

Assim, seu código estará em pleno funcionamento, imprimindo o valor de millis() a cada 5 segundos.

Verifique abaixo o código em funcionamento:


Conclusão

A grande vantagem em se utilizar millis( ) se resume na possibilidade de não pausar o código por completo, e consequentemente continuar a leitura do algoritmo somente quando o tempo de espera acabasse (como ocorre com delay ( )). Isso abre um leque de possibilidades em seus projetos, e esperamos ter contribuído com isso através desse post.


Sobre o Autor


Pedro Cavalcante

Estudante de Sistemas de Energia Renovável no Instituto Federal da Paraíba. Entusiasta da automação em Arduino, ESP32 e Raspberry Pi.


Eletrogate

18 de abril de 2024

A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!

Eletrogate Robô

Cadastre-se e fique por
dentro de novidades!