[DESAFIO 2] Dá pra piscar o led sem delay com um Codigo Menor ???

Olá Galera,

    Abri um tópico anterior com o desafio BLINK MINIMO, e realmente ao meu ver foi um sucesso ( veja AQUI ) !  ele foi vencido pelo grande Eduardo Silva.

    Agora o desafio é um pouco mais difícil,  o desafio é:

    É possível diminuir o blink sem o uso de delay abaixo :

unsigned long conter=0;      // declara variavel

void setup() {
pinMode(13,OUTPUT);    // indica pino do led 13 como saida
}

void loop() {
if(millis() > conter+1000){      // se o millis for maior que a variavel mais mil entra no condicional
conter=millis();    //  atribui o ultimo millis a variavel
digitalWrite(13, !digitalRead(13));     // inverte a situacao do led
}
}

E ai quem diminui o codigo ?

Exibições: 2699

Responder esta

Respostas a este tópico

Zé Augusto, a ideia é reduzir mantendo funcional, e VC mesmo citiou que não será possível sequer ver a oscilação do led, então isso não resolve o desafio, tem que ser menor mas tem que ser útil.

É só você testar esse código que te passei. Ele vai funcionar perfeitamente fazendo piscar o led em 1000 milissegundos. Se quiser mudar o tempo é só mudar o valor 1000 para 2000 ou 3000. Fique a vontade para testar...

Eu já testei e funcionou.

É que, por coincidência, estou trabalhando em uma library para leds que funciona de forma assíncrona. inclusive com efeitos de fade para leds. A versão que te passei é uma versão reduzida do código para atender especificamente a sua necessidade. A versão que estou desenvolvendo é ligeiramente diferente porque eu não necessito que o código fique mínimo.

Zé Augusto eu só terei acesso a um Arduíno na segunda, vou testar sim. A minha ideia com esses desafios é criar algo simples, funcional e entendível pra que todos .
Afinal todos temos guardados alguns códigos básicos que sempre reutilizamos.
Quanto ao código de abertura que coloquei, pensei nele apenas pra um teste, mas pra uso efetivo permanentemente bastaria: if(millis() > conter+1000 || millis()==1){ pronto toda vez que o millis estourasse e voltasse a ser 1 ele entraria no condicional e reiniciaria a variável conter tambem

Weider, Ok.

Só tome cuidado com a expressão (conter + 1000).

O que pode acontecer: O compilador vai somar um int (1000) com um unsigned long e aí ele vai fazer um cast automático para unsigned long. Quando o contador estiver muito próximo do limite do millis que é 4.294.967.295 pode ocorrer um overflow por que você está somando 1000 a mais do que a capacidade dele.Aí o resultado pode ser imprevisível.

Mas você só precisa se preocupar com isso se sua aplicação vai ficar no ar (rodando) por um período maior que 50 dias

Abraço,

José Cintra

Olá José Augusto,

    Cara, testei sua montagem logica e ela realmente funciona,  mas ai como você mesmo disse, ele fica a cada ciclo do mc setando a porta,  dai como internamente mcs são compostos por conjuntos de transistores, a chance de haver um problema pelo excesso de setagens é grande.

    Mas a titulo de curiosidade é valido.

    Queria que você explicasse sua montagem, achei bem curioso,  não conheço a expressão %2.

    digitalWrite(13, (((int)(millis() / 1000)) % 2) == 0);  

    Quanto a expressão conter+1000 não precisa se preocupar, eu tinha ideia do que iria acontecer, mas preferi testar e tava certo,  quando o maximo do valor de uma classe de variavel estoura, ele só faz reiniciar,  tipo uma variavel que vai até 100, se você tem 90 e manda somar 20,  o resultado vai ser 10.

    Eu fiz testes na pratica e tudo que vai acontecer é em um dos condicionais, ele não piscará , só isso, no proximo ciclo devido a condicional if millis()==1  entao ele reinicia tudo certinho.

    Logo, o desafio ainda me parece aberto,  retificando o codigo pra não estourar ta ele completo aqui, será que não dá mesmo pra diminuir e ainda assim mantê-lo util ?

unsigned long conter=0;      // declara variavel

void setup() {
pinMode(13,OUTPUT);}    // indica pino do led 13 como saida

void loop() {
if(millis() > conter+1000 || millis()==1){  // entra no laco se uma das condicoes estiver correta
conter=millis();    //  atribui o ultimo millis a variavel
digitalWrite(13, !digitalRead(13));}}     // inverte a situacao do led

A  expressão (int)(millis() / 1000)) % 2) == 0 faz o seguinte:

A expressão (millis() / 1000) divide millis em blocos de 1000 que é o tempo desejado. Isso pode ser alterado pra qualquer outro tempo, como 2000,3000, etc.

A parte inteira dessa divisão trará para cada bloco de 1000, o valor 0,1,2,3,4,5,

A seguir % 2 == 0 testará se o resultado é par e setará V,F,V,F no pino a cada bloco de 1000, causando o efeito desejado.

Como o nosso amigo Odilon falou, esse código já está bastante enxuto e diminui-lo mais é possível, mas com as consequências que você viu.

Uma sugestão que não vai dar problema nenhum com o reset ou com o overflow do millis() é esta: Ao invés de somar 1000, divida por 1000. Isso resolve todos os problemas e funciona direitinho sem sobrecarregar o pino:

unsigned counter = 0;
void setup() {
  pinMode(13,OUTPUT);    
  }

void loop() {
if ( (long)(millis() / 1000) > counter ) {
  digitalWrite(13,!digitalRead(13));
  counter = (long)(millis() / 1000);
  }    
}

Zé augusto, que fantastico amigo,  o que adoro no mundo arduino é que sempre temos algo a aprender,  eu não conhecia a expressão % 2 == 0,  para fazer o teste de par ou impar, simplesmente genial.  obrigado por ter passado o conhecimento.

AÊEEEEEEEEEEEE,  A UNIÃO FAZ A FORÇA...  Tá aqui o codigo com 5 linhas, funcional e sem problema de ferrar com portas do Uc,  a união das 2 ideias utilizando seu codigo, só que do lado de fora com um IF condicional.

    O led tá piscando de um jeito engraçado,  mas tá piscando certinho.

     Testem ai.

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

void loop() {
if( (((int)(millis() / 1000)) % 2) == 1 ){
digitalWrite(13, !digitalRead(13));}}

Weider. Ok, funciona. Mas caiu naquele problema que você citou do excesso de setagens que tinha no meu código.

Desse jeito, ele está setando sempre quando o valor é ímpar, porque o resto da divisão é 1 (% 2 == 1) ou seja, 1000 vezes seguidas no 1, 3, 5 , etc.

Isso é muito rápido. Por isso que ele pisca engraçado como você falou, pelo excesso de setagens. Nos números pares ele está mantendo o último estado por 1000 milissegundos.

No código antigo que você enviou, ele somente setava de 1000 em 1000, conforme deveria. Assim o brilho era mais uniforme...

Weider, Parabéns!

Mude apenas o seguinte:

if( (((long)(millis() / 1000)) ) == 1 )

Pois assim ele vai mudar corretamente o estado a cada 1000 milissegundos e não vai piscar engraçado.

Tem razão a união faz a força. Acho que está resolvido

% é o operador "módulo", ou resto da divisão (inteiro).

o resto da divisão de um número inteiro por 2 será sempre 1 ou 0.

por isso usamos este operador para saber se determinado int é par.

https://pt.wikipedia.org/wiki/Opera%C3%A7%C3%A3o_m%C3%B3dulo

Weider, Parabéns!

Mude apenas o seguinte:

if( (((long)(millis() / 1000)) ) == 1 )

Pois assim ele vai mudar corretamente o estado a cada 1000 milissegundos e não vai piscar engraçado.

Tem razão a união faz a força. Acho que está resolvido

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço