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)
Tags:
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.
Bem-vindo a
Laboratorio de Garagem (arduino, eletrônica, robotica, hacking)
© 2023 Criado por Marcelo Rodrigues.
Ativado por