Como piscar dois LEDs simultaneamente com tempos diferentes sem usar delay no Arduino
Fala pessoal, tudo certo? Bom, neste post eu vou colocar a resposta do desafio postado no Instagram @blogdarobotica (Link: https://www.instagram.com/p/CNdW3hyjQ-f/). Se você não viu, então deixo logo abaixo o vídeo do desafio:
Existem diversas formas de conseguir o resultado mostrado acima e o mais interessante desse desafio foi olhar as respostas em que foram sugeridas formas diferentes de como programar. E sim, cada pessoa pensa e programa de uma forma diferente e o bacana da programação é justamente isso: Diferentes formas de se chegar a um objetivo, no entanto, vale ressaltar que algumas formas vão ser mais eficientes que outras.
Abaixo vou mostrar a forma que eu programei, não significa que seja a melhor, porém deixo aí para vocês estudarem e compararem com o código de vocês e a partir daí novas soluções (melhores) podem sair.
CÓDIGO FONTE
/* ----------- Resposta do #Desafio 1 -------------- ================================================= == BLOG DA ROBOTICA - www.blogdarobotica.com == ================================================= Autor: Kleber Bastos E-mail: contato@blogdarobotica.com Fanpage: facebook.com/blogdarobotica YouTube: youtube.com/user/blogdarobotica Instagram: instagram.com/blogdarobotica */ //Definições de variáveis #define led_1 5 //pino em que o led 1 ficará #define led_2 6 //pino em que o led 2 ficará //Declaração de variáveis unsigned long tempoAtual; //variável que irá receber o tempo em que o arduino está ligado em milissegundos. Long armazenam valores maiores que o tipo int e o unsgined significa que estamos desconsiderando valores negativos, fato que aumenta a capacidade de armazenamento do tipo long long tempoDecorrido = 0; //variável que contará o tempo decorrido para o led 1 long tempoDecorrido2 = 0; //variável que contará o tempo decorrido para o led 2 long tempoLed_1 = 1000; //tempo em milissegundos que quero que o led 1 pisque. Pode ser alterado para o tempo que desejar long tempoLed_2 = 100; //tempo em milissegundos que quero que o led 2 pisque. Pode ser alterado para o tempo que desejar //Condições iniciais do programa void setup() { pinMode(led_1, OUTPUT); //seto a porta do led 1 como saída pinMode(led_2, OUTPUT); //seto a porta do led 2 como saída } //Loop void loop() { tempoAtual = millis(); //atribuo o tempo (em milissegundos) que o arduino está ligado na variável tempoAtual efeito1(); //chamo a função efeito1() que é responsável pelo piscar do led 1 efeito2(); //chamo a função efeito2() que é responsável pelo piscar do led 2 } //Construção da função 1 - Função que faz o led piscar 1000 milissegundos void efeito1() { if (tempoAtual - tempoDecorrido > tempoLed_1) { //verifica se passou 1000 milissegundos e se sim tempoDecorrido = tempoAtual; //subsitui o valor que já passou pelo tempo atual digitalWrite(led_1, !digitalRead(led_1)); //escreve em led_1 o estado inverso em que ele se encontra, ou seja, se está ligado ele desliga e se estiver desligado o led ligará } } //Construção da função 2 - Função que faz o led piscar 100 milissegundos void efeito2() { if (tempoAtual - tempoDecorrido2 > tempoLed_2) { //verifica se passou 100 milissegundos e se sim tempoDecorrido2 = tempoAtual; //subsitui o valor que já passou pelo tempo atual digitalWrite(led_2, !digitalRead(led_2)); //escreve em led_2 o estado inverso em que ele se encontra, ou seja, se está ligado ele desliga e se estiver desligado o led ligará } }
Algumas observações:
A função millis() é responsável por contar quanto tempo a placa está ligada (em milissegundos) executando aquele sketch (programa) e ela tem um limite, ou seja, depois de 50 dias de programa executando sem que a placa desligue haverá um overflow da variável (vai exceder o limite que ela suporta) e quando isso acontecer o tempo voltará a ser contado do zero. Por esse motivo não usamos millis() como um relógio para contar tempos longos que ultrapasse o limite dos 50 dias. Para fazer isso a solução ideal para tempo é a utilização do módulo RTC.
No nosso caso precisamos apenas contar o tempo decorrido de 1000 milissegundos e 100 milissegundos, logo podemos utilizar a função millis() tranquilamente que mesmo que o arduino fique ligado mais de 50 dias não afetará a execução porque a variável tempoAtual vai zerar e consequentemente as outras variáveis tempoDecorrido e tempoDecorrido2 serão atualizadas.
POR QUE NÃO USAR DELAY?
Pelo que vi tiveram pessoas que resolveram o desafio usando delay, mas quando nós utilizamos o delay significa que o programa fica parado naquela linha esperando até que o tempo definido dentro do delay passe, ou seja, se você tiver outras coisas para serem executadas posteriormente não vai acontecer porque o programa fica parado. Já com millis não, o programa executa de maneira sequencial e fica verificando se já passou o tempo que eu defini e se não passou ele segue fazendo as coisas que estão nas linhas abaixo. Só depois de já ter decorrido o tempo especificado é que vai entrar no condicional e fazer o que tá lá dentro. Então sempre que possível use millis() no lugar de delay. =)
Ah, outra coisa bem legal nesse código é essa parte:
digitalWrite(led_2, !digitalRead(led_2)); //escreve em led_2 o estado contrário em que ele se encontra
E essa linha acima substitui isso:
if ( digitalRead(led_2) == HIGH){ //se o led estiver ligado digitalWrite(led_2, LOW); //desligue } else { //se não digitalWrite(led_2, HIGH); //ligue }
Tá vendo como existem formas diferentes de fazer a mesma coisa? Legal, né? 😉
Obrigado a todos que participaram do desafio e espero que tenham aprendido coisas novas.
Até a próxima!
Kleber Bastos.
Bacharel em Engenharia de Computação. Um dos criadores do Blog da Robótica. Faz parte da equipe Casa da Robótica desde 2017. Apaixonado por tecnologias e pelas “loucuras” que é possível criar usando microcontroladores e impressoras 3D. Ex-BBB, mas isso é uma longa história... que poderá ser contada posteriormente.