HMI FLProg + Nextion. Lição 2



Na última lição, falei sobre o painel IHM do Nextion e sobre a criação de projetos para este painel no Editor do Nextion.
Neste tutorial, mostrarei como controlar esse painel usando o programa FLProg de uma placa Arduino. Por exemplo, vamos coletar a estação meteorológica mais simples, que lerá os dados do sensor de temperatura e umidade DHT-22 e os exibirá no painel. Um gráfico das alterações nesses parâmetros também será desenhado. O brilho da luz de fundo da tela do painel será alterado usando um resistor variável.

Layout da bancada de teste.


Primeiro, você precisa fazer o upload do projeto no painel (o arquivo do projeto no archive é um link para o qual, no final do artigo, é Lesson2.hmi).
Este projeto consiste em três telas.
A primeira tela é usada para exibir a temperatura (índice da página “página 0” - 0).



É composto pelos seguintes elementos:
1 - Foto com a imagem de um termômetro de álcool.
2 - O elemento "Barra de progresso". Com sua ajuda, o termômetro é simulado.

Configurações do item.


Eu recomendo os elementos com os quais se planeja tornar global sempre via UART (o atributo "vccope" é "global") e, consequentemente, atribua nomes exclusivos a eles (o atributo "objname") durante todo o projeto. Isso acelera o trabalho do controlador Arduino e reduz o código para ele. Eu vou explicar o porquê.
Ao tentar escrever o atributo de um elemento local, você deve primeiro solicitar a página atual do painel (essa é uma solicitação separada que leva pelo menos 20 ms.). Se a página for a qual o elemento pertence, o valor será enviado ao painel; caso contrário, o valor destinado ao envio será gravado na variável (para a qual é necessário o mesmo espaço de memória). Ao ir para uma página com um elemento, você deve atualizar imediatamente seus atributos com os valores reais mais recentes, pois ao renderizar uma página, as variáveis ​​locais são inicializadas com os valores especificados ao criar o projeto. E se houver muitos elementos gerenciados a partir do controlador na página, ao mudar para ele, esse controlador ficará ocupado por um longo tempo atualizando todos os elementos.
Para um elemento global, tudo é muito mais simples. Você pode registrar valores de atributo a qualquer momento e os últimos valores são usados ​​ao renderizar a página. Isso significa que não há necessidade de solicitar um número de página antes do envio e não é necessário alterar para armazenar o valor.
Mas é claro que tudo depende do projeto. Se o projeto para o painel for muito grande e não houver espaço suficiente para elementos globais, você poderá, por assim dizer, obter memória do controlador e torná-los locais.
3. Caixa de texto para exibição da temperatura.

Parâmetros do item.


A imagem recortada é selecionada como plano de fundo (atributo "sta" valor "recortar imagem"). E, como a imagem usada para cortar, o mesmo é usado para o fundo de toda a página (o atributo "picc" é o índice da imagem da biblioteca de imagens). Graças a isso, o tex é obtido com um fundo transparente.
Como já escrevi na última lição, o painel não sabe trabalhar com números fracionários e negativos, e para a temperatura é possível. Portanto, para exibir o valor da temperatura, é usado um campo de texto no qual a linha final será enviada imediatamente do controlador.
4. A imagem cortada.

Parâmetros do item.


Com a ajuda deste elemento, o sol será exibido quando a temperatura exceder um limite predeterminado. Na verdade, era possível usar uma imagem comum e alterar sua visibilidade, mas desde o exemplo do treinamento, decidi usar esse elemento em particular. Eu mesmo há muito tempo entendo a ideologia desse elemento, tentarei mostrar como ele funciona. Por seu trabalho, eu fiz duas fotos, uma com o sol e a outra sem o sol.





O elemento exibe a parte da imagem anexada a ele (o atributo "picc" é o índice da imagem na biblioteca de imagens). O canto superior esquerdo desta seção está nas coordenadas de inserção do elemento (atributos "x" e "y") e possui a largura e a altura do elemento (atributos "w" e "h"). Durante a operação do programa do controlador, se necessário, a ligação do elemento à imagem será alterada.

5. Botão.

Parâmetros do item.


Quando você clica no botão, ele vai para a próxima página. Eu usei uma imagem como pano de fundo para o botão. Usei a mesma imagem para ambos os estados (os atributos "pic" e "pic2" são os índices das imagens na biblioteca de imagens), pois o estado pressionado nunca será visível. Quando você clica no botão, ele passa imediatamente para a próxima página. Como não mudaremos nada nesse botão, deixei local e o nome padrão.

Código no evento "Touch Press Event".


A segunda tela é usada para exibir a umidade (índice da página “página1” - 1).


Para o fundo da página, usei uma imagem com uma imagem preparada da escala higrométrica.


Considere os elementos incluídos na página.

1. O elemento "Gaude", que simula a operação de um higrômetro.

Parâmetros do item.


Como o controlaremos a partir do controlador, ele será global. A imagem recortada (o atributo “sta”) é selecionada como plano de fundo e a imagem de fundo da página (atributo “picc”) é selecionada como plano de fundo.

2. Campo numérico.

Parâmetros do item.


O valor da umidade será exibido neste campo. Como o painel não suporta trabalhar com números fracionários, exibiremos o valor da umidade sem uma parte fracionária. A imagem recortada é selecionada como plano de fundo (atributo "sta" valor "recortar imagem"). E, como a imagem usada para cortar, o mesmo é usado para o fundo de toda a página (o atributo "picc" é o índice da imagem da biblioteca de imagens). Por uma questão de beleza da exibição, defino o alinhamento à direita (valor do atributo “xcen” - 2) e, ao lado, coloquei um campo de texto (3) com o valor “%”. As configurações de plano de fundo são semelhantes às configurações do campo numérico.

Opções de campo de texto (3).


4 e 5. Botões página anterior e página seguinte. Quando você pressiona o botão 4, vai para a primeira página e, quando clica no botão 5, para a próxima. As configurações de exibição dos botões são semelhantes às da primeira página.

Configurações do botão 4 (“Página anterior”)


Código no “Evento Touch Press” para o botão 4 (“Página anterior”).


Configurações do botão 5 (“Próxima página”)


Código no “Touch Press Event” para o botão 5 (“Próxima página”).


Terceira página - Gráfico das mudanças de temperatura e umidade (índice “página2” - 2).


Nesta página, será exibido um gráfico das mudanças de temperatura e umidade. Considere os elementos incluídos na página.

1. O elemento Waveform.

Parâmetros do item.


Na última lição, eu já escrevi que esse elemento não pode (espero até agora) se tornar global, ou seja, o valor do atributo pode ser alternado, mas isso não levará a nada. Então eu deixei local (quem sabe, mas de repente ele ainda come a memória de variáveis ​​globais). Haverá dois canais de exibição neste elemento (valor do atributo "ch" - 2).

2 e 3 são simplesmente campos de texto mostrando o eixo dos gráficos.

4 - Botão de volta. É semelhante ao mesmo botão na tela anterior, com exceção do código no manipulador de eventos.

O código em "Touch Press Event" para o botão 4 ("Previous Page").


Nós descobrimos o painel, agora vamos cuidar do controlador. Não vou dizer como abrir o programa FLProg, criar um projeto e desenhar um diagrama. Tudo isso eu contei nas lições anteriores (lição 1 , lição 2 ) e, além disso, muitas informações sobre isso estão no centro de treinamento no site do projeto. Portanto, mostrarei imediatamente as placas de circuito prontas e direi o que está acontecendo nelas.

Placa 1. Lendo dados do sensor.


Para obter valores de temperatura e umidade com o sensor DHT-22, é usado o bloco B1 - “DHT11, DHT21, DHT22” (biblioteca de elementos, pasta “Sensores”).

Bloqueie as configurações (chamadas clicando duas vezes nele).


Nas configurações, o pino é atribuído ao qual a saída "Dados" do sensor está conectada, o tipo de sensor e a presença de saídas de temperatura e umidade. O modo de polling do sensor também está selecionado. Eu configurei o polling do sensor uma vez a cada 5 segundos.

Como os controladores Arduino não funcionam muito bem com números de ponto flutuante e o trabalho com eles consome muita memória, traduzo imediatamente todos os valores para o formato Inteiro. Para fazer isso, use os blocos B3 e B4 - “Converter flutuador em número inteiro” (biblioteca de elementos, pasta “Conversão de tipo”), que cortam a parte fracionária do número. Para não perder décimos de grau, o valor da temperatura obtido pelo sensor é primeiro multiplicado por 10 usando o bloco B2 - “MUL (*)” (biblioteca de elementos, pasta “Matemática”).
Em seguida, os valores obtidos no formato Inteiro são inseridos nas variáveis ​​correspondentes.

Placa 2. Exibe o valor da temperatura no painel.


Neste projeto, eu uso conexões nomeadas. Você pode aprender mais sobre eles na lição correspondente .
Para limitar a carga no controlador, faz sentido enviar dados para o painel somente quando os dados forem alterados. Portanto, primeiro determinamos que os dados foram alterados. Para fazer isso, use o bloco B5 - “Detector de mudança de número” (biblioteca de elementos, pasta - “Blocos de base”). Esta unidade controla o número "Valor" em sua entrada e, quando alterada, gera um pulso de saída de um ciclo de execução do programa na saída.
Depois disso, preparamos uma string para enviar para o campo de texto do painel. Primeiro, divida o valor da temperatura, multiplicado por 10, por uma constante do tipo Float com um valor de 10. Assim, obtemos o valor da temperatura com uma parte fracionária. Fazemos isso usando o bloco B6 - “DIV (/)” (biblioteca de elementos, pasta “Matemática”). Em seguida, transformamos o valor obtido no formato Float em uma string usando o bloco B7 - "Conversão de strings" (biblioteca de elementos, pasta "Conversão de tipos"). Em seguida, conectamos a string resultante à constante "C" usando o bloco B8 - "Adição de linhas" (biblioteca de elementos, pasta "Linhas"). A linha resultante é alimentada na entrada da unidade para gravar o valor do atributo no painel Nextion HMI B9 - "Set Parameter" (biblioteca de elementos -> pasta "Nextion HMI Panel" -> pasta "Elements").
Este bloco grava o valor no atributo especificado.

Parametrização do bloco.

Ao clicar duas vezes no bloco, a janela do editor de blocos é aberta.


Se ainda não foram criados painéis no projeto, é necessário criar um painel. Se o painel necessário já tiver sido criado, ele poderá ser selecionado na lista suspensa pressionando o botão 3. O painel selecionado pode ser alterado usando o botão "Alterar painel" (2). Para criar um painel, clique no botão "Adicionar painel" (1). A janela de criação do painel será aberta.


Nesta caixa de diálogo, selecione a porta para conectar o painel (em nossa lição - SoftwareSerial). Se você selecionar SoftwareSerial, também deverá selecionar os pinos atribuídos como sinais RX e TX da porta UART (no nosso caso, 2 e 3). Também é necessário atribuir um nome de painel. Deve ser único. Vários painéis podem ser conectados em um projeto, desde que haja portas UART livres suficientes. O nome de cada painel deve ser exclusivo dentro do projeto. Na mesma caixa de diálogo, você pode adicionar as páginas incluídas no painel. O que vamos fazer? Clique no botão Adicionar página. A janela de criação da página é aberta.


Nesta janela, precisamos inserir o nome da página e seu ID. Essas informações podem ser aprendidas com o projeto no Editor Nextin.


Por padrão, a página inicial (aberta quando o controlador é inicializado) será uma página com um ID 0, mas você pode marcar a caixa "Página inicial" nas propriedades de qualquer página e ela se tornará a página inicial.
Nesta janela, você pode adicionar os elementos de interesse que estão nesta página. Clique no botão "Adicionar item".
A janela de criação do item é aberta.


Aqui, precisamos selecionar o tipo e o tipo do elemento, inserir seu nome, índice e, se o elemento for global, defina a caixa de seleção correspondente. Todos esses dados podem ser vistos no projeto no Editor Nextin.


Após preencher todos os dados, clique em "Concluir" e, na janela de criação da página, da mesma maneira, adicione todos os elementos de interesse para nós nesta página.


Depois de criar todos os elementos da página, também clicamos no botão "Concluir" na janela de criação da página e na janela para criar um painel usando o mesmo cenário, crie o restante da página.






Terminamos de criar o painel com o familiar botão "Concluir".
No editor de blocos, selecione a página “page0” elemento “Text” com o nome “tnt” e seu atributo “Text (txt)”. Como o valor, selecione a entrada.


O bloco está configurado.
Consideramos o esquema ainda mais.
Empiricamente, foi definitivamente determinado que um valor de -40 graus de um termômetro desenhado corresponde a um valor de 10 no elemento "Barra de progresso" localizado nele, e um valor de 50 graus a um termômetro corresponde a um valor de progresso de 91 bar. De acordo com isso, escalamos o valor com a variável “Temperature x10” usando o bloco B10 - “Scale” (Biblioteca de elementos, pasta “Scaling”) sem esquecer que temos o valor da temperatura multiplicado por 10. Parâmetros desse bloco.


O valor da temperatura escalonada é enviado ao painel usando o bloco B11 - “Set Parameter” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Elements”). Configurações para este bloco.


O próximo bloco B12 - "Comparador" (biblioteca de elementos, pasta "Comparação") determina se a temperatura atual excede o ponto de ajuste pelo valor padrão da variável "Ponto de ajuste - Quente". É 290 (não esqueça que em todos os lugares temos temperaturas multiplicadas por 10).


O bloco B12 está configurado para emitir uma unidade lógica em sua saída quando o valor na entrada "I1" excede o valor na entrada "I2".


Os blocos B13, B14 e B15 formam circuitos de detecção de alteração de sinal discretos. Os blocos B13 e B14 - Rtrig (biblioteca de elementos, pasta "Triggers"), quando uma borda principal de um sinal discreto aparecer, emitem um pulso de saída com a duração de 1 ciclo do programa. O bloco B14, devido à inversão em sua entrada, detecta a borda de fuga do sinal "Excedendo o limiar". O bloco B15 –OR (biblioteca de elementos, pasta “Elementos Básicos”), se houver uma unidade lógica em qualquer uma das entradas, gera uma unidade lógica para sua saída. Assim, um sinal é formado "Enviando dados quando o limite é excedido". Na borda principal deste sinal, um comando é enviado para alterar a cor da fonte do campo de texto que exibe a temperatura atual. O envio ocorre usando o bloco B17 - “Definir Parâmetro” (biblioteca de elementos -> pasta “Nextion HMI Panel” ->Pasta de elementos). Configurações para este bloco.


O valor transmitido no comando é selecionado usando o bloco B16 - “Switch” (biblioteca de elementos, pasta “Switch”). Este bloco com um nível lógico baixo em sua entrada transfere o valor da entrada "0" para a saída e, com um valor alto, da entrada "1". Os valores de cores fornecidos para as entradas do comutador são definidos usando os blocos B44 e B45 - “Color constant Hight Color” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Color”). A cor é selecionada no editor de blocos (clique duas vezes no bloco).


Para selecionar uma cor, clique no botão "Alterar". O seletor de cores é aberto.


Nele, definindo o valor dos componentes R (vermelho), G (verde) e B (azul), a cor necessária é selecionada.
Além disso, na extremidade superior do sinal "Enviando dados quando o limite é excedido", um comando é enviado para alterar a ligação da imagem cortada. Isso acontece usando o bloco B19 - "Set Parameter" (biblioteca de elementos -> pasta "Nextion HMI Panel" -> pasta "Elements").
Configurações para este bloco.


O índice da imagem é selecionado usando o bloco B18 - “Switch” (biblioteca de elementos, pasta “Switch”). Seu trabalho foi descrito acima. O valor do índice da imagem necessária pode ser visualizado no projeto do Nextion Editor na biblioteca de imagens.

Com a transferência dos dados de temperatura concluída. Vamos para a umidade.

Quadro 3. Conclusão da umidade.


Como no caso da temperatura, primeiro criamos o sinal "Enviando dados quando a umidade muda". Fazemos isso usando o bloco B20 - “Detector de mudança de número” (biblioteca de elementos, pasta - “Blocos de base”). A operação desta unidade foi descrita anteriormente. Este sinal envia o valor para um campo numérico que exibe umidade. Isso é feito usando o bloco B21 - “Set Parameter” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Elements”).
Configurações para este bloco.


Empiricamente, foi definitivamente determinado que, para o valor de umidade de 0% da escala de higrômetro desenhada no design do painel, o elemento "Gayge" que desenha a seta é 314 e para a umidade de 100% é 226. Ao mesmo tempo, a seta ultrapassa o valor 0. Quando convertida em valores lineares, obtemos contínua varia de -46 (0%) a 226 (100%). De acordo com esses dados, configuramos o bloco B22 - “Escala”.
Parâmetros de bloco.


Como os valores do elemento "Gauge" não podem ser negativos, para calcular o ângulo da seta nesses valores, no caso de um valor negativo, é adicionado o valor 360. Fazemos isso usando o bloco B23- "SUMM (+)" (biblioteca de elementos, Pasta Matemática). Determinamos que o número é menor que 0 usando o bloco B26 - “Comparador” (biblioteca de elementos, pasta “Comparação”). Sua saída controla o interruptor B24 - “Switch” (biblioteca de elementos, pasta “Switch”) e o valor selecionado é enviado ao painel usando o bloco B25 - “Set Parameter” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Elements” )
Configurações para este bloco.


O próximo quadro exibe um gráfico das mudanças de temperatura e umidade.


Como escrevi no início da lição, o elemento Waveform não sabe como ser um elemento global e é redesenhado toda vez que você abre a página em que está localizado. Temos que contornar essa limitação. Primeiro, determine o número da página atualmente carregada no painel. Para fazer isso, use o bloco B27 - “Obter ID da página atual” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Page”). Nas configurações deste bloco, você só precisa selecionar o painel que acessaremos com esta solicitação.


O número da página obtido deste bloco é comparado com o índice da página que precisamos (2) usando o bloco B28 - “Comparador” (biblioteca de elementos, pasta “Comparação”). Se a página desejada estiver aberta, a unidade lógica será gravada na variável “Abrir página do gráfico”; caso contrário, será um zero lógico.
Utilizando o bloco B29 - "Gerador" (biblioteca de elementos, pasta "Temporizadores"), um sinal é gerado para registrar o próximo ponto no gráfico. Este bloco gera pulsos com uma determinada duração e pausa.
Bloquear configurações.


O tipo de gerador selecionado é "Multivibrador simétrico", o que significa que a duração do pulso é igual à duração da pausa. Ao definir a duração do pulso para 5 segundos, respectivamente, a pausa será igual a 5 segundos. A borda principal do pulso ocorrerá a cada 10 segundos. Essa frente é destacada pelo bloco B30 - “Rtrig” (biblioteca de elementos, pasta “Triggers”) e é gravada na variável “Command to record the next point”.
Na extremidade superior do sinal "Abrir página de gráfico", que será selecionado usando o bloco B31 - "Rtrig" (biblioteca de elementos, pasta "Triggers"), o sinal "Enviar histórico do gráfico" será gerado. Por esse sinal, o conteúdo das matrizes será enviado para o painel no gráfico, no qual os valores dos pontos que exibem o gráfico de alterações são armazenados. Para temperatura, isso será feito usando o bloco B32 - “Enviando a matriz para o gráfico” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Graph”). O bloco é configurado usando o editor de blocos.


Primeiro, você precisa criar uma matriz na qual o histórico do gráfico de temperatura será armazenado. Para fazer isso, clique no botão "Criar". A janela de criação da matriz é aberta.


Nesse oceano, você deve digitar o nome da matriz, digite (use Byte, pois o elemento Waveform ocupa um valor máximo de 255). O tamanho é igual à largura do gráfico (330).
Após a criação, selecione o painel, página, elemento e canal no qual o gráfico será desenhado.


Da mesma forma, configuramos o bloco para enviar uma matriz com dados de umidade para o painel B33 - “Enviando a matriz para o gráfico” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Graph”). Em suas configurações, criamos outra matriz para armazenar esses dados.


Agora você precisa preparar os dados para o gráfico de temperatura. Este gráfico terá uma linha ao longo de seu eixo, a uma altura de 160 pontos da parte inferior do gráfico. Para tornar as mudanças de temperatura mais visíveis, dividimos o valor da variável “Temperature x10” por 5 (ou seja, como se multiplica o valor real da temperatura por 2) usando o bloco B35 e adicionamos o deslocamento usando o bloco B36. O resultado será inserido na variável "Temperatura com uma mudança para o gráfico".
Usando o bloco B37 - "Pilha" (biblioteca de elementos, pasta "matrizes"), o pulso da variável "Comando para gravar o próximo ponto" é gravado na matriz pela temperatura com uma mudança para o gráfico usando o princípio da pilha (o primeiro elemento da matriz é excluído, o restante é deslocado por um e o último valor é escrito). O bloco é parametrizado usando o editor de blocos.


No editor, selecione a matriz desejada clicando no botão "Selecionar".
Da mesma forma, configuramos o bloco B34 - "Stack" (biblioteca de elementos, pasta "matrizes") para gravar valores de umidade na matriz, selecionando na matriz correspondente.
Se a página do gráfico estiver aberta, a transferência de matrizes para o gráfico será concluída e o comando para registrar o próximo ponto será recebido. Em seguida, os valores dos novos pontos serão enviados para os gráficos correspondentes. Isso é necessário para que os gráficos continuem sendo construídos enquanto a página estiver sendo exibida. O cumprimento dessas condições é monitorado usando o bloco B38 - “AND” (biblioteca de elementos, pasta “Elementos básicos”). Este bloco emite uma unidade em sua saída se houver uma unidade lógica em todas as suas entradas. O próximo valor de temperatura com uma mudança é enviado ao gráfico usando o bloco B40 - “Adicionar um ponto ao gráfico” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Graph”).
Bloquear configurações.


O bloco para enviar o próximo valor de umidade para o gráfico B39 também é configurado - “Adicionar um ponto ao gráfico” (biblioteca de elementos -> pasta “Nextion HMI Panel” -> pasta “Chart”).


Finalizado com a conclusão do cronograma.

Placa 5. Ajuste o brilho da luz de fundo.


O valor da luz de fundo definida usando um resistor variável é lido usando o bloco de entrada analógica "Brightness". Como o valor do brilho da luz de fundo do painel está definido no intervalo de 0 a 100, escalamos o valor de leitura do intervalo de 0 a 1023 ao intervalo de 0 a 100 usando o bloco B41 - "Escala".
Bloquear configurações.


Em seguida, determinamos o fato de uma alteração nesse valor usando o bloco B42 - “Detector para alterar o número”. Este bloco possui algumas configurações fora do padrão.


Para não alterar o brilho de cada movimento do resistor variável, a banda morta é configurada na unidade com um valor de 5. Ou seja, a unidade funcionará quando o valor de entrada for alterado em mais de 5 em qualquer direção. Quando a unidade é acionada, um comando será enviado ao painel para definir um novo brilho da luz de fundo usando o bloco B43 - "Definir nível de luz de fundo" (biblioteca de elementos -> pasta "Nextion HMI Panel" -> pasta "System").
Configurações de bloco O


trabalho no programa para o controlador está concluído.

Para aqueles que estão interessados ​​no código para o skoller de esboço resultante.
#include <SoftwareSerial.h>
#include "DHT.h"
DHT _dht1(4, DHT22);

SoftwareSerial Serial100(2, 3);

byte _FLPArray142003126[330] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte _FLPArray239384258[330] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int _SUETFLPATemp = 0;
byte _nextionSaveDataVAL_P0_E2;
long _nextionSaveDataPCO_P0_E3;
String _nextionSaveDataTXT_P0_E3;
byte _nextionSaveDataPICC_P0_E4;
int _nextionSaveDataVAL_P1_E2;
long _nextionSaveDataVAL_P1_E4;
String _nextionCommandTempString;
struct _nextionLissenStruct {
  char code;
  String result;
  long number;
};
_nextionLissenStruct _nextionTempLissen;
int nextionGetPageIdTempVar = 0;
int NextionPanel_47525121_PageIdOut = 0;
int _hasNumberChangeInTemp = 0;
int _gtv1;
int _gtv2;
int _gtv3 = 290;
bool _gtv4 = 0;
bool _gtv5 = 0;
int _gtv6;
unsigned long _dht1Tti = 0UL;
float _dht1t = 0.00;
float _dht1h = 0.00;
bool _changeNumber1_Out = 0;
int _changeNumber1_OLV;
bool _nextionSetAttr1_isNU = 0;
bool _nextionSetAttr1_oldState = 0;
bool _nextionSetAttr2_isNU = 0;
bool _nextionSetAttr2_oldState = 0;
bool _trgrt1 = 0;
bool _trgrt1I = 0;
bool _trgrt2 = 0;
bool _trgrt2I = 0;
bool _nextionSetAttr3_isNU = 0;
bool _nextionSetAttr3_oldState = 0;
long _swi1;
bool _nextionSetAttr4_isNU = 0;
bool _nextionSetAttr4_oldState = 0;
byte _swi2;
bool _nextionSetAttr5_isNU = 0;
bool _nextionSetAttr5_oldState = 0;
bool _changeNumber2_Out = 0;
int _changeNumber2_OLV;
int _swi3;
bool _nextionSetAttr6_isNU = 0;
bool _nextionSetAttr6_oldState = 0;
bool _trgrt3 = 0;
bool _trgrt3I = 0;
bool _gen1I = 0;
bool _gen1O = 0;
unsigned long _gen1P = 0UL;
bool _trgrt5 = 0;
bool _trgrt5I = 0;
bool _nextionAddPointToWave1_OldState = 0;
bool _nextionAddPointToWave2_OldState = 0;
bool _SFLPAS1;
bool _SFLPAS2;
bool _nextionSendArraytToWave1_OldState = 0;
bool _nextionSendArraytToWave2_OldState = 0;
bool _nextionSetLighting1_OldStae = 0;
bool _changeNumber3_Out = 0;
int _changeNumber3_OLV;
void setup()
{
  Serial100.begin(9600);
  _dht1.begin();
  nextionSendCommand("", 100);
  nextionAck(100);
  nextionSendCommand("page 0", 100);
  delay(100);
  nextionAck(100);
}
void loop()
{ nextionGetPageIdTempVar = nextionAskPageNamper(100);
  if ( ! (nextionGetPageIdTempVar < 0) ) {
    NextionPanel_47525121_PageIdOut = nextionGetPageIdTempVar;
  };
  if (_isTimer(_dht1Tti, 5000)) {
    _dht1Tti = millis();
    float tempDht4;
    tempDht4 = _dht1.readTemperature();
    if (!(isnan(tempDht4))) {
      _dht1t = tempDht4;
    }
    tempDht4 = _dht1.readHumidity();
    if (!(isnan(tempDht4))) {
      _dht1h = tempDht4;
    }
  }



  _gtv1 = (int((_dht1t) * (10)));
  _gtv2 = (int(_dht1h));
  if ((_gtv1) > (_gtv3)) {
    if (_trgrt1I) {
      _trgrt1 = 0;
    } else {
      _trgrt1 = 1;
      _trgrt1I = 1;
    }
  } else {
    _trgrt1 = 0;
    _trgrt1I = 0;
  };
  if ((_gtv1) > (_gtv3))
  {
    _swi1 = 63488;
  }
  else
  {
    _swi1 = 2016;
  }
  if (!((_gtv1) > (_gtv3))) {
    if (_trgrt2I) {
      _trgrt2 = 0;
    } else {
      _trgrt2 = 1;
      _trgrt2I = 1;
    }
  } else {
    _trgrt2 = 0;
    _trgrt2I = 0;
  };
  if ((_gtv1) > (_gtv3))
  {
    _swi2 = 2;
  }
  else
  {
    _swi2 = 0;
  }
  if (_changeNumber1_Out) {
    _changeNumber1_Out = 0;
  } else {
    _hasNumberChangeInTemp = _gtv1;
    if (_hasNumberChangeInTemp != _changeNumber1_OLV) {
      _changeNumber1_OLV = _hasNumberChangeInTemp;
      _changeNumber1_Out = 1;
    }
  }
  if (_changeNumber1_Out) {
    if (! _nextionSetAttr1_oldState ) {
      _nextionSetAttr1_oldState = 1;
      _nextionSetAttr1_isNU = 1;
      _nextionSaveDataTXT_P0_E3 =  ((( _floatToStringWitRaz((_gtv1) / (10.00), 1))) + (String(" C"))) ;
    }
  } else {
    _nextionSetAttr1_oldState = 0;
  } if (_nextionSetAttr1_isNU) {
    _nextionCommandTempString = String("page0.tnt.txt=\"") + _nextionSaveDataTXT_P0_E3 + String("\"");
    nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
    _nextionSetAttr1_isNU = 0;
  } if (_changeNumber1_Out) {
    if (! _nextionSetAttr2_oldState ) {
      _nextionSetAttr2_oldState = 1;
      _nextionSetAttr2_isNU = 1;
      _nextionSaveDataVAL_P0_E2 =  (map((_gtv1), (-400), (500), (10), (91))) ;
    }
  } else {
    _nextionSetAttr2_oldState = 0;
  } if (_nextionSetAttr2_isNU) {
    _nextionCommandTempString = String("page0.tpb.val=") + String(_nextionSaveDataVAL_P0_E2);
    nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
    _nextionSetAttr2_isNU = 0;
  } if (( (_trgrt1) || (_trgrt2) )) {
    if (! _nextionSetAttr3_oldState ) {
      _nextionSetAttr3_oldState = 1;
      _nextionSetAttr3_isNU = 1;
      _nextionSaveDataPCO_P0_E3 =  _swi1 ;
    }
  } else {
    _nextionSetAttr3_oldState = 0;
  }
  if (nextionAskPageNamper(100) == 0) {
    if (_nextionSetAttr3_isNU) {
      _nextionCommandTempString = String("page0.tnt.pco=") + String(_nextionSaveDataPCO_P0_E3);
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
      _nextionCommandTempString = "ref tnt";
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
      _nextionSetAttr3_isNU = 0;
    }
  } else {
    _nextionSetAttr3_isNU = 1;
  }
  if (( (_trgrt1) || (_trgrt2) )) {
    if (! _nextionSetAttr4_oldState ) {
      _nextionSetAttr4_oldState = 1;
      _nextionSetAttr4_isNU = 1;
      _nextionSaveDataPICC_P0_E4 =  _swi2 ;
    }
  } else {
    _nextionSetAttr4_oldState = 0;
  }
  if (nextionAskPageNamper(100) == 0) {
    if (_nextionSetAttr4_isNU) {
      _nextionCommandTempString = String("page0.tci.picc=") + String(_nextionSaveDataPICC_P0_E4);
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
      _nextionCommandTempString = "ref tci";
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
      _nextionSetAttr4_isNU = 0;
    }
  } else {
    _nextionSetAttr4_isNU = 1;
  }
  if (((map((_gtv2), (0), (100), (-46), (226)))) < (0))
  {
    _swi3 = ((map((_gtv2), (0), (100), (-46), (226)))) + (360);
  }
  else
  {
    _swi3 = (map((_gtv2), (0), (100), (-46), (226)));
  }
  if (_changeNumber2_Out) {
    _changeNumber2_Out = 0;
  } else {
    _hasNumberChangeInTemp = _gtv2;
    if (_hasNumberChangeInTemp != _changeNumber2_OLV) {
      _changeNumber2_OLV = _hasNumberChangeInTemp;
      _changeNumber2_Out = 1;
    }
  }
  if (_changeNumber2_Out) {
    if (! _nextionSetAttr5_oldState ) {
      _nextionSetAttr5_oldState = 1;
      _nextionSetAttr5_isNU = 1;
      _nextionSaveDataVAL_P1_E4 =  _gtv2 ;
    }
  } else {
    _nextionSetAttr5_oldState = 0;
  } if (_nextionSetAttr5_isNU) {
    _nextionCommandTempString = String("page1.humN.val=") + String(_nextionSaveDataVAL_P1_E4);
    nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
    _nextionSetAttr5_isNU = 0;
  } if (_changeNumber2_Out) {
    if (! _nextionSetAttr6_oldState ) {
      _nextionSetAttr6_oldState = 1;
      _nextionSetAttr6_isNU = 1;
      _nextionSaveDataVAL_P1_E2 =  _swi3 ;
    }
  } else {
    _nextionSetAttr6_oldState = 0;
  } if (_nextionSetAttr6_isNU) {
    _nextionCommandTempString = String("page1.humG.val=") + String(_nextionSaveDataVAL_P1_E2);
    nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
    _nextionSetAttr6_isNU = 0;
  } if (1) {
    if (! _gen1I) {
      _gen1I = 1;
      _gen1O = 1;
      _gen1P = millis();
    }
  } else {
    _gen1I = 0 ;
    _gen1O = 0;
  }
  if (_gen1I) {
    if ( _isTimer ( _gen1P , 5000 )) {
      _gen1P = millis();
      _gen1O = ! _gen1O;
    }
  }
  if (_gen1O) {
    if (_trgrt5I) {
      _trgrt5 = 0;
    } else {
      _trgrt5 = 1;
      _trgrt5I = 1;
    }
  } else {
    _trgrt5 = 0;
    _trgrt5I = 0;
  };
  if (_gtv4) {
    if (_trgrt3I) {
      _trgrt3 = 0;
    } else {
      _trgrt3 = 1;
      _trgrt3I = 1;
    }
  } else {
    _trgrt3 = 0;
    _trgrt3I = 0;
  };
  _gtv4 = (NextionPanel_47525121_PageIdOut) == (2);
  _gtv5 = _trgrt5;
  if (_trgrt3) {
    if ( ! _nextionAddPointToWave1_OldState) {
      _nextionAddPointToWave1_OldState = 1;
      if (nextionAskPageNamper(100) == 2) {
        for (int nextionSATWTemp = 0;  nextionSATWTemp < 330;  nextionSATWTemp ++) {
          _nextionCommandTempString = String ("add 1,1,") + String (_FLPArray142003126[nextionSATWTemp]);
          nextionSendCommand(_nextionCommandTempString.c_str(), 100);
        } delay (50);
      }
    }
  } else {
    _nextionAddPointToWave1_OldState = 0;
  }

  if (_trgrt3) {
    if ( ! _nextionAddPointToWave2_OldState) {
      _nextionAddPointToWave2_OldState = 1;
      if (nextionAskPageNamper(100) == 2) {
        for (int nextionSATWTemp = 0;  nextionSATWTemp < 330;  nextionSATWTemp ++) {
          _nextionCommandTempString = String ("add 1,0,") + String (_FLPArray239384258[nextionSATWTemp]);
          nextionSendCommand(_nextionCommandTempString.c_str(), 100);
        } delay (50);
      }
    }
  } else {
    _nextionAddPointToWave2_OldState = 0;
  }

  if (_gtv5) {
    if (!_SFLPAS1) {
      _SFLPAS1 =  1;
      for (_SUETFLPATemp = 0; _SUETFLPATemp < 329; _SUETFLPATemp = _SUETFLPATemp + 1 ) {
        _FLPArray239384258[_SUETFLPATemp ] = _FLPArray239384258[_SUETFLPATemp + 1];
      }  _FLPArray239384258[329] = _gtv2;
    }
  }  else {
    _SFLPAS1 = 0;
  }
  _gtv6 = ((_gtv1) / (5)) + (160);
  if (_gtv5) {
    if (!_SFLPAS2) {
      _SFLPAS2 =  1;
      for (_SUETFLPATemp = 0; _SUETFLPATemp < 329; _SUETFLPATemp = _SUETFLPATemp + 1 ) {
        _FLPArray142003126[_SUETFLPATemp ] = _FLPArray142003126[_SUETFLPATemp + 1];
      }  _FLPArray142003126[329] = _gtv6;
    }
  }  else {
    _SFLPAS2 = 0;
  }
  if (( (_gtv5) && (!(_trgrt3)) && (_gtv4) )) {
    if ( ! _nextionSendArraytToWave1_OldState) {
      _nextionSendArraytToWave1_OldState = 1;
      if (nextionAskPageNamper(100) == 2) {
        _nextionCommandTempString = String ("add 1,0,") + String (_gtv2);
        nextionSendCommand(_nextionCommandTempString.c_str(), 100); delay (50);
      }
    }
  } else {
    _nextionSendArraytToWave1_OldState = 0;
  }

  if (( (_gtv5) && (!(_trgrt3)) && (_gtv4) )) {
    if ( ! _nextionSendArraytToWave2_OldState) {
      _nextionSendArraytToWave2_OldState = 1;
      if (nextionAskPageNamper(100) == 2) {
        _nextionCommandTempString = String ("add 1,1,") + String (_gtv6);
        nextionSendCommand(_nextionCommandTempString.c_str(), 100); delay (50);
      }
    }
  } else {
    _nextionSendArraytToWave2_OldState = 0;
  }

  if (_changeNumber3_Out) {
    _changeNumber3_Out = 0;
  } else {
    _hasNumberChangeInTemp = (map(( (analogRead (0))), (0), (1023), (0), (100)));
    if (((_hasNumberChangeInTemp > _changeNumber3_OLV) && ((_hasNumberChangeInTemp - _changeNumber3_OLV ) > 5)) || ((_hasNumberChangeInTemp < _changeNumber3_OLV) && ((_changeNumber3_OLV - _hasNumberChangeInTemp ) > 5) ))
    {
      _changeNumber3_OLV = _hasNumberChangeInTemp;
      _changeNumber3_Out = 1;
    }
  }
  if (_changeNumber3_Out) {
    if (!(_nextionSetLighting1_OldStae)) {
      _nextionSetLighting1_OldStae = 1;
      _nextionCommandTempString = String("dim=") + String((map(( (analogRead (0))), (0), (1023), (0), (100))));
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);
    }
  } else {
    _nextionSetLighting1_OldStae = 0;
  }




}
bool _isTimer(unsigned long startTime, unsigned long period )
{
  unsigned long currentTime;
  currentTime = millis();
  if (currentTime >= startTime) {
    return (currentTime >= (startTime + period));
  } else {
    return (currentTime >= (4294967295 - startTime + period));
  }
}
String  _floatToStringWitRaz(float value, int raz)
{
  float tv;
  int ti = int(value);
  String ts = String(ti);
  if (raz == 0) {
    return ts;
  }
  ts += ".";
  float tf = abs(value - ti);
  for (int i = 1; i <= raz; i++ )
  {
    tv = tf * 10;
    ti = int(tv);
    ts += String(ti);
    tf = (tv - ti);
  }
  return ts;
}
void nextionSendCommand(const char* cmd, byte port )
{
  while (Serial100.available()) {
    Serial100.read();
  }
  Serial100.print(cmd);
  Serial100.write(0xFF);
  Serial100.write(0xFF);
  Serial100.write(0xFF);
}
boolean nextionAck( byte port )
{
  uint8_t bytes[4] = {0};
  Serial100.setTimeout(20); if (sizeof(bytes) != Serial100.readBytes((char *)bytes, sizeof(bytes))) {
    return 0;
  }

  if ((bytes[1] == 0xFF) && (bytes[2] == 0xFF) && (bytes[3] == 0xFF)) {
    switch (bytes[0]) {
      case 0x00:
        return false; break;
      case 0x01:
        return true; break;
      default:
        return false;
    }
  }
}
struct _nextionLissenStruct nextionListen( byte port )
{
  char _bite;
  char _end = 0xff;
  String cmd;
  _nextionLissenStruct temp;
  int countEnd = 0;
  delay(10);
  while (Serial100.available() > 0) {
    if (Serial100.available() > 0) {
      _bite = Serial100.read();
      cmd += _bite;
      if (_bite == _end) {
        countEnd++;
      }
      if (countEnd == 3) {
        break;
      }
    }
  }
  temp.result = "";
  temp.code = 'z';
  temp.number = 0;
  switch (cmd[0]) {
    case 'e':
      temp.code = 'e';
      countEnd = 0;
      for (uint8_t i = 0; i < cmd.length(); i++) {
        if (cmd[i] == _end) {
          countEnd++;
        }
        temp.result += String(cmd[i], HEX);
        if (countEnd == 3) {
          return temp;
        }
        temp.result += " ";
      }
      break;
    case 'f':
      temp.code = 'f';
      temp.result = String(cmd[1], DEC);
      return temp;
      break;
    case 'g':
      temp.code = 'g';
      temp.result = String(cmd[2], DEC) + "," + String(cmd[4], DEC) + "," + String(cmd[5], DEC);
      return temp;
      break;
    case 'h':
      temp.code = 'h';
      temp.result = String(cmd[2], DEC) + "," + String(cmd[4], DEC) + "," + String(cmd[5], DEC);
      temp.result = "68 " + temp.result;
      return temp;
      break;
    case 'p':
      temp.code = 'p';
      temp.result = cmd.substring(1, cmd.length() - 3);
      return temp;
      break;
    case 'q':
      temp.code = 'q';
      temp.number = (cmd[4] << 24) | (cmd[3] << 16) | (cmd[2] << 8) | (cmd[1]);
      return temp;
      break;
    default:
      return temp;
      break;
  }
  return temp;
}
int nextionAskPageNamper(byte port)
{
  int result;
  _nextionLissenStruct temp;
  nextionSendCommand("sendme", port);
  temp = nextionListen(port);
  if ((temp.code == 'f') && (temp.result != "")) {
    result = temp.result.toInt();
  } else {
    result = -1;
  }
  return result;
}


Um pequeno vídeo com uma demonstração.


Arquive com o projeto para o painel e o projeto para o controlador.
Na próxima lição, aprenderemos como controlar o controlador Arduino a partir do painel.

Source: https://habr.com/ru/post/pt392685/


All Articles