boa tarde amigos garagistas alguém possa me ajudar com esse código , gostaria de substituir esses delay que marquei no código por Millis, com esses delay na apresentação do lcd meu código fica travado ate a execução, com Millis não tenho esse problema, já tentei mais sem êxito.. segue o código em anexo

Exibições: 480

Anexos

Responder esta

Respostas a este tópico

Olá Marcela de Souza. Tudo bem?

"...na apresentação do lcd meu código fica travado ate a execução" 

"Execução" de que? Seu código está bem objetivo e está sempre executando algo.

Em todo caso, vamos revisar um pouco do temporizador com millis()?

https://www.arduino.cc/reference/pt/language/functions/time/millis/

millis() é uma função que retorna o valor, em milissegundos, desde que a placa foi iniciada. ok?

Isto é, se você ligou a placa agora, e em 10 segundos (exatos e precisos) você bater um "millis()", ele irá retornar 10.000. 

=== Pausa 1) Tudo bem até aqui? ===

Quando queremos criar um "delay" com millis(), inicialmente teremos que entender como gerar uma subtração de uma variável qualquer com o millis().

Exemplo:

se iniciou a placa, a EXATOS (teóricos) 10 segundos, e queremos o valor dela, menos 1 segundo, teremos:

int var = 1000; // que pode ser entendido como 1000 ms ou 1s.

millis() - var ===> 10.000 - 1.000 ===> 9.000.

=== PAUSA 2) Tudo  bem até aqui? ===

Só que, para gerar um "delay", essa variável precisa ter um valor mais preciso. concorda? 

Se queremos 1 seg de "delay", e tendo em vista que nosso "millis()" está em 10seg, nosso "var" deveria ser 9.000.

Assim, 10.000 - 9.000 = 1.000.

=== PAUSA 3) Tudo bem até aqui? ===

Sendo assim, devemos criar uma nova variável para que possamos captar o valor de millis(). Vamos chamar essa variável de VARmillis.

E agora veja este exemplo:

// Declaramos as 2 variáveis que serão usadas

unsigned long VARmillis; // Variável responsável por armazenar o valor do momento "X" de millis()

int VARdelay = 1000; // definimos um tempo para o delay

setup() {

VARmillis = millis(); // Aqui definimos o valor de VARmillis sendo IGUAL ao de millis()

// exemplo: millis() == 00100, VARmillis == 00100

}

// Observe que quando o código CHEGA nesta linha, o valor de VARmillis não será mais igual ao de millis().

// Isto é, millis() == 00101, VARmillis == 00100.

// Percebe, só nisso, que já podemos obter uma diferença entre valores? neste caso, 101 - 100 = 1

// Então, como nosso objetivo é o delay, queremos que esse "1" seja igual a "1000". Correto?

// então daremos continuidade

loop(){

if (millis() - VARmillis == VARdelay){

// aqui acontecerá a ação, se isto for verdadeiro

}

Como definimos VARdelay == 1000, então a ação só irá acontecer SE, e tão somente SE, a diferença entre millis() e VARmillis for EXATAMENTE igual a VARdelay.

"Olha que legal!"

== PAUSA 4) Tudo bem até aqui? ==

Então, nesta situação do loop, observe que o delay só irá acontecer UMA UNICA VEZ. Então vamos entender como isso funciona?

A questão agora é puramente lógica de programação.

Situação 1:

loop(){

if (millis() - VARmillis == VARdelay){

// Irá acontecer SOMENTE se millis() - VARmillis for IGUAL a Vardelay

// isso só acontece 1 vez, pois, millis() representa o tempo, e o tempo "nunca" volta.

}

Situação 2:

loop(){

if (millis() - VARmillis < VARdelay){

// Irá acontecer SOMENTE se millis() - VARmillis for MENOR a VARdelay

// observe que neste cenário, isso irá gerar um loop e só irá PARAR quando o valor de VARdelay for IGUAL ou MAIOR que a subtração de millis() por VARmillis.

}

Situação 3:

loop(){

if (millis() - VARmillis > VARdelay){

// Irá acontecer SOMENTE se millis() - VARmillis for MAIOR que VARrdelay

// Ou seja, enquanto VARdelay for menor ou igual, o evento não irá acontecer, entretanto, quando for maior, ele irá retornar sempre verdadeiro, então o evento se repetirá "infinitamente".

}

=== PAUSA 5) Tudo bem até aqui? ===

Situação 4:

loop(){

if (millis() - VARmillis == VARdelay)

{

// Irá acontecer SOMENTE se millis() - VARmillis for IGUAL a VARdelay

// isso só acontece 1 vez, pois, millis() representa o tempo, e o tempo "nunca" volta.

VARmillis = millis() // Isso irá definir um NOVO valor para VARmillis.

}

Opa! para tudo! Se VARmillis terá o valor igual ao de millis(), o que isso significa? UM RESET!!!

Ou seja, a cada 1 segundo, esta ação irá acontecer.

Então, percebe que sempre que a gente quer reiniciar a condição que gera o atraso, bastará atribuir o valor de VARmillis ao novo valor de millis()!!!

Que legal em?  

=== PAUSA 6) Tudo bem até aqui? ===

Então chegamos ao ponto importante. O que nós desejamos? de todas as situações apresentadas, o que será melhor para o nosso código? Ai é necessário que cada um diga por si.

Existem várias formas de se utilizar o millis(), mas essas são as mais populares.

Boa tarde, tudo bem?

O millis() funciona de forma diferente do daley() e acho que está bem explicado pelo nosso amigo e mestre Mr TM.

Se quiser, tenho uma biblioteca que criei para realizar tarefas concorrentes e mostrar textos em display LCD que você poderá usar como exemplo ou aproveitar as idéias.

Nesta biblioteca, resolvi muitas questões além do uso (e abuso) do millis(), tem também a economia de memória nos textos do display, chamada de funções callback automáticas ou manual, entre outras coisinhas que implementei.

https://github.com/eijuito/IToSmartMenu

Aproveite e boa sorte!!!

  'Eiju

olá novamente Marcela.

 

      Faz algum tempo que não "conversamos" aqui.

 

      Vi o código que vc postou, e fiz uma implementação correspondente, sem usar os diversos delays que originalmente vc usou. Mas antes de falar sobre esta implementação, seguem algumas considerações:

      a)  vc não informou qual placa Arduino está usando. Baseado nos seus tópicos anteriores, eu acredito que seja um ESP8266 ou ESP32. Tranquilo, pois o código que implementei irá funcionar para ambos e também para as demais placas (UNO, Nano, Mega, STM32, etc).

      b)  embora vc esteja usando LCD 16x2, o código pode ser facilmente usado para LCDs com outras "dimensões" para colunas e linhas (se suportado pela Biblioteca utilizada para o LCD).

      c)  no seu código original, vc exibiu textos no Display com uma "printagem" de caracter por caracter. Evite isso, porque sempre há como printar estes textos de forma "normal" ou seja, com o texto "completo" na linha de código. Da forma que vc fez, dificulta ver o que está sendo printado, e aumenta o código de uma forma desnecessária, além de ser extremamente mais trabalhoso. Além disso, vc printou os caracteres via código ASCII em decimal, o que não é necessário, pois bastaria usar o "write" com os caracteres entre apóstrofes, como neste exemplo:  write('A')  ao invés de write( byte(65) ).  Ainda sobre isto, parece que vc usou o caracter ASCII de número "128" para printar um espaço em branco, o que está "incorreto". O caracter que vc deveria ter usado é o "32" (ou 0x20, em Hexadecimal), que é o caracter ASCII oficial do "espaço em branco". Ocorre que o "128" poderá ser um caracter diferente do espaço em branco, dependendo do Controlador do Display usado na placa do módulo LCD.

 

 

      Falando agora sobre as funcionalidades do seu código. Vc implementou três efeitos "animados" na exibição no Display. Vejamos quais são eles:

 

      1)  efeito de exibição "gradual" do texto, caracter por caracter, com estes caracteres sendo printados em um intervalo de tempo especificado. E para isso vc printou cada caracter de forma sequencial no código, com uma função delay entre cada print para cadenciar a exibição do texto completo, e claro: isto causa seu código ficar preso nestas operações até que todo o texto seja printado.

 

      2)  efeito de exibição "correndo" na linha do Display, da direita para a esquerda, com uma velocidade determinada por um intervalo de tempo entre cada printagem (em coluna anterior à que acabou de ser printada). Da mesma forma que no efeito anterior (o "gradual"), isto também causa seu código ficar preso nestas operações até que o texto seja printado na coluna final, pois vc também usou a função delay para cadenciar a sequência de prints.

 

      3)  efeito "pisca/pisca" (ou "Blynk") do Display, com a visualização do mesmo "desligando" e "ligando" por intermédio das funções "lcd.noDisplay()" e "lcd.display()", executadas de forma intercalada em intervalos de tempo que determinam a velocidade do "pisca/pisca". E isto também prende a execução do seu código, até que sejam executados todos os ciclos do "pisca/pisca", entre os quais também estão funções delay.

 

 

      Então implementei estes três efeitos ("gradual", "correndo", e "Blynk"), porém sem prender o código. Além disso para printar qualquer texto usando os efeitos, vc pode fazer isso especificando o texto completo, como no exemplo mostrado a seguir:

 

            set_MSG_gradual_LINHA_n( linha_0, F("Marcela"), 0.25, 4.6 );

 

      Neste exemplo, é requisitado que seja exibido na linha "0" do Display o texto "Marcela", de forma "gradual", ou seja, caracter por caracter, com intervalo de 0.25 segundos (ou 250 mili-segundos). O tempo de exibição (mínimo) é de 4.6 segundos a contar quando todo o texto está completo na linha. Também, o texto será automaticamente centralizado na linha (ou seja, vc não precisa ficar calculando a coluna inicial de acordo com comprimento do texto).

 

 

      Outro exemplo, neste caso com efeito "correndo":

 

            set_MSG_running_LINHA_n( linha_1, F("Robotica"), 0.2, 3.5 );

 

      onde o texto "Robotica" começa "correndo" na linha "1" da direita para a esquerda, com velocidade determinada pelo intervalo de 0.2 segundos, até que o texto esteja centralizado na linha. O tempo de exibição (mínimo) é de 3.5 segundos, a contar a partir do término do efeito "correndo".

 

 

      Exemplo de uso do efeito "Blynk" (ou "pisca/pisca") do Display:

 

            set_Display_Blynk( 0.4, 3 );

 

      Neste caso, o Display "pisca" na velocidade determinada pelo intervalo de tempo de 0.4 segundos, sendo que no total serão 3 piscadas (e ao final das piscadas, o Display fica sempre no "modo visível").

 

 

      Para cada efeito, foi implementa uma Máquina de Estados  para gerenciamento do efeito. Para os efeitos "gradual" e "correndo" as Máquinas tem apenas 4 estados (sendo que um deles é apenas ficar esperando até que uma requisição de printagem seja feita). E a Máquina de Estados que faz o "Blynk" tem apenas 3 estados (onde um deles também é apenas ficar esperando).

      Vc poderá implementar outros efeitos facilmente, se entender como estas Máquinas funcionam no código. Todas as três Máquinas implementadas funcionam do mesmo jeito, e qualquer outro efeito implementado também deverá funcionar do mesmo jeito.

 

      Para que as Máquinas gerenciem corretamente os efeitos, vc NÃO deve "travar" o restante do seu código, ou seja, não use delays nem execute loops intermináveis ou de longa duração. Se vier a usar sensor DS18B20, use o modo de leitura "assíncrona" para impedir que o código fique longamente esperando uma resposta do Sensor. Se vc tiver alguma dificuldade com estas coisas, avise aqui para que eu possa te ajudar.

 

 

      Vamos dar uma olha nas configurações básicas do código implementado, começando pela opção de escolha da Interface de Hardware usada para acesso ao módulo do Display LCD, conforme mostrado na figura a seguir:

 

(clique na figura para "zoom") 

 

 

      Sim, vc pode escolher o tipo da Interface, entre a tradicional Interface Paralela de 4 bits, e a concisa Interface I2C (que é a que vc está usando no seu código original). Na figura está selecionada a Interface I2C, conforme marcado na cor verde. Mude conforme seu Projeto.

      E claro, se vc usar o I2C, deve especificar o endereço do módulo no Barramento I2C, conforme mostrado e marcado na cor laranja na figura a seguir:

 

(clique na figura para "zoom")

 

 

       Para estas Interfaces, há outros settings que podem ser facilmente alterados no código (se selecionar a Interface Paralela de 4 bits, certamente isso será necessário, para especificar os pinos do Arduino usados na Interface).

 

 

      A printagem dos textos, é feita em uma Máquina de Estados "principal", que é praticamente sequencial. Por motivos didáticos, esta Máquina "principal" é implementada dentro da função "loop" do Arduino. Para imprimir um texto, vc deve "requisitar" a operação desejada, pois esta operação será posteriormente executada por uma das Máquinas de Estados que implementam os efeitos no Display. Assim, há uma lógica simples a ser seguida para cada printagem de texto, e que se constitui de duas etapas:

 

      Etapa 1:  requisitar a printagem especificando o texto e parâmetros relacionados ao efeito.

 

      Etapa 2:  aguardar que a printagem seja concluída, chamando uma função que retorna "true" quando a operação de exibição terminar.

 

      E para cada uma destas etapas, implementa-se um estado na Máquina de Estados "principal". Para o código da Marcela, estes estados podem ser vistos na lista no trecho de código mostrado na figura a seguir:

 

(clique na figura para "zoom")

 

 

      Cada cor na figura anterior (exceto as cores amarela e a roxa), corresponde a um processo de exibição no Display, onde nas linhas "0" e "1" do Display são exibidas informações relacionadas entre si. Exemplo: na região laranja é exibida de forma gradual na linha "0", o texto "Marcela", e logo em seguida é exibido "correndo" na linha "1" o texto "Automatização", e em seguida é feito um "pisca/pisca" no Display, e depois o Display é apagado (ou "limpo"). Cada um dos estados é executado, e após cada execução, segue para um dos estados marcados na área em amarelo do código, onde é esperado que seja concluída a exibição que foi requisitada. Ou seja, logo após executar o estado "Exibe_MSG_Marcela", é executado o estado "Aguarda_FIM_MSG_linha_0" (pois a printagem da mensagem foi na linha "0"). E então a execução segue para o estado "Exibe_MSG_Automatizacao" que printa na linha "1" e por isso segue para o estado "Aguarda_FIM_MSG_linha_1", seguindo para o estado "Pisca_MSG_Automatizacao", e assim por diante.

      Se em um determinado estado forem exibidas mensagens em ambas as linhas do Display, então o estado seguinte deve ser o "Aguarda_FIM_MSG_Display" que aguarda o fim das exibições em todas as linhas do Display.

      Em suma, a sequência de execução dos estados é sempre printando no Display, e então aguardando que a operação de printagem termine (estados na área marcada em amarelo).

      O estado marcado na cor roxa, simplesmente aguarda um período de tempo (para isso ele printa uma mensagem "vazia" que demora o tempo desejado), e então reinicia todo o processo a partir do primeiro estado (neste caso o "Exibe_MSG_Bem_vindo", marcado em azul na figura anterior).

 

      Notar que printagens sem efeitos de animação do texto, são feitas especificando-se um intervalo de tempo nulo (igual a zero) na determinação da velocidade da animação do texto. É isso que é feito nos estados "Exibe_MSG_Bem_vindo" e "Exibe_MSG_Casa_Robotica", ambos na área marcada em azul na figura anterior.

 

      A princípio, o processo pode parecer complexo, mas na realidade é simples, como pode ser visto na figura a seguir que mostra toda a Máquina de Estados "principal" sendo executada dentro do "loop" do Arduino:

 

(clique na figura para "zoom")

 

 

      Notar que os estados estão marcados individualmente para facilitar a identificação dos mesmos, e que a cor da marcação correspondem às mesmas cores usadas na figura que mostrou a definição destes estados. Observar que nos estados de printagem de mensagens, as operações são simples e seguem sempre o mesmo padrão. Da mesma forma, nas áreas marcadas em amarelo, que são os estados que esperam a conclusão das operações de printagem, também são muito simples e também seguem um padrão.

 

      Importante:  se forem acrescentados mais estados de printagem no Display, os estados nas áreas em amarelo permanecem os mesmos, pois já contemplam todas as possibilidades de aguardar a conclusão das operações implementadas neste Sistema (printagem na linha "0", na linha "1", em ambas as linhas, e "pisca/pisca").

 

      Então como criar um estado de printagem?   Simples:  dê um nome ao estado, e então acrescente este nome à lista onde está a definição dos estados (pode ser em qualquer ordem na lista, mas tente manter uma organização lógica pra seu próprio benefício). Então, na Máquina de Estados "principal", acrescente a execução do estado seguindo o mesmo padrão usado para aqueles já implementados (acrescente a execução do estado conforme a ordem que vc deseja que seja executado dentro da Máquina de Estados). Dentro do estado, não "invente" nenhuma lógica maluca (principalmente usando loops). Claro, também não devem ser usados delays convencionais dentro dos estados.

 

      É possível tornar ainda mais simples todo o mecanismo de exibição das mensagens. Por exemplo, sem precisar usar os estados para verificar se a exibição foi concluída (estados nas áreas em amarelo). Mas isto requer um pouco mais de memória RAM, e como esta memória é preciosa em alguns Arduinos (como UNO, Nano, etc), não fiz esta implementação para esta versão do código, para garantir que haja no Sistema RAM suficiente para uso com outros dispositivos e suas respectivas estruturas de dados.

 

 

      Para a demonstração do funcionamento dos efeitos, implementei Simulações no Proteus usando os dois tipos de Interface para o LCD, ou seja, Paralela e I2C. Isto foi feito para com Arduino UNO, mas pode ser usado qualquer outro Arduino que esteja disponível no Proteus. O circuito para a Interface I2C é mostrado na figura a seguir:

 

(clique na figura para "zoom")

 

 

       E para a Interface Paralela de 4 bits, mostrado na figura a seguir:

 

(clique na figura para "zoom")

 

 

      Também capturei estas Simulações em vídeo, e elas podem ser vistas nos links a seguir, onde é possível também fazer o download dos vídeos:

 

           Vídeo da Simulação com Interface I2C:  "simul LCD I2C"

 

           Vídeo da Simulação com Interface Paralela:  "simul LCD Paralelo"

 

      Notar que as Simulações feitas, seguem o código original da Marcela, que tem intervalos de tempo de 5 segundos entre algumas etapas de exibição no Display e por isso mesmo em alguns momentos parece que nada está ocorrendo. E claro: lembrar que as Simulações ocorrem em um tempo "virtual" que é sempre mais lento que o tempo real, principalmente no caso da versão com Interface I2C.

 

 

      O código implementado está neste link:  "LCD_16_x_2_Views_02.zip"

 

      E os arquivos para Simulação no Proteus estão aqui:  "Simulacao_Proteus.zip"

 

 

      Qualquer dúvida, não deixe de perguntar.

 

 

      Espero ter ajudado.

 

      Abrçs,

      Elcids

Boa noite Elcids, faz tempo mesmo , fiquei um bom tempo sem mexer com Arduíno, Obrigada pela atenção, vou dar uma estudada sobre Maquina de estados  

Ok Marcela.

      No código que eu postei, está uma implementação completa exatamente com a mesma funcionalidade do seu código original, porém sem usar delay no loop do Arduino. Nos vídeos  das Simulações, que também postei, vc pode conferir o funcionamento.

      Atente exclusivamente para o código no loop  do Arduino (e não se preocupe com o restante das funções), e aí certamente vc vai entender (e sem esforço) o que precisa fazer.

      Mas não deixe de perguntar aqui, caso tenha alguma dúvida.

      Abrçs,

      Elcids

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço