XPsys – Menu com Telas – V1.0.1 (Alfa) – ESP32 com ST7920

XPsys – Menu com Telas – V1.0.1 (Alfa) – ESP32 com ST7920

Nova Versão do XPsys está disponível, acesse a página principal do XPsys

Esta é a primeira versão do sistema XPsys, estou mais focado no ESP32 que possui bastante memória porem este sistema também funciona no Arduíno, pelo menos esta versão, conforme irei adicionar os recursos mais memória ira ser utilizada e menor será o programa

Após compilado o Visual Studio Code informou os seguintes percentuais utilizados do ESP32:

Memoria Flash - 248,11 KB de 1,31 MB - Doit ESP32
18.9%
Memoria RAM - 14,53 KB de 327,68 KB - Doit ESP32
4.4%

Abaixo está um pequeno vídeo demonstrando o XPsys v1.0.1 no hardware XPboard:

Video de demonstração da Versão 1.0.1 Alfa

Código

Irei comenta sobre alguns trechos do programa que na versão 1.0.1 Alfa está com 368 linhas (incluindo os comentários), a maioria das linhas do código fiz questão de comentar para que serve cada linha

/*
  Programa de seleção de Menu com telas, desenvolvido por JailsonBR utilizando a biblioteca u8g2 do olikraus.
   
  PORFAVOR NÃO REMOVA NENHUMA INFORMAÇÃO DESTE CABEÇALHO, ESTE É UM CÓDIGO OPENSOURCE SOB LICENÇA DO CRIADOR
   
  Codigo adaptado por JailsonBR do site XProjetos.net em 03-06-2019, o uso deste código é livre porem deve respeitar e manter o nome do criador
  e também de quem modificou, o código está sob GNU GENERAL PUBLIC LICENSE Versão 3 (https://www.gnu.org/licenses/quick-guide-gplv3.pt-br.html)

  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)

  Copyright(c) sobre o XPsys 2019, XProjetos.net

  XPsys Versão 1.0.1 (Alpha)

============ BSD License for U8g2lib Code ============

Universal 8bit Graphics Library (https://github.com/olikraus/u8g2)

Copyright (c) 2016-2019, olikraus@gmail.com
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list 
  of conditions and the following disclaimer.
  
* Redistributions in binary form must reproduce the above copyright notice, this 
  list of conditions and the following disclaimer in the documentation and/or other 
  materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

============================================================================================================
                                          END OF THE U8G2 license
============================================================================================================
*/

#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#define Bot_PinoADC 1                                        //O compilador substituirá qualquer menção de Bot_PinoADC ao valor 1 no momento da compilação.
#define FontePadrao u8g2_font_5x7_tf                          //Selecione a fotne padrão de todos os menus exceto os icones

U8G2_ST7920_128X64_1_SW_SPI u8g2(U8G2_R0, 33, 32, 35, 27);    //Enable, RW, RS, RESET  

//int Configura as variaveis de -32,768 a 32,767, ocupa 2 bytes (16 bits)
int Bot_LeituraADC = 0;                                       //Variavel para Leitura da porta analogica
int bot_lido_anterior = 0;                                    //Valor temporario da porta analogica
int ChangeMenu = 0;                                           //Registra a nevegação no menu principal
int Tela = -1;                                                //Varíaveis para as telas individuais (-1 é o menu principal)

//bool variável de 0 ou 1, ocupa 1 byte (256 bytes)
bool bot_esquerdo = 0;                                        //Variavel de acionamento do botão (1 = ativado)
bool bot_acima = 0;                                           //Variavel de acionamento do botão (1 = ativado)
bool bot_abaixo = 0;                                          //Variavel de acionamento do botão (1 = ativado)
bool bot_direito = 0;                                         //Variavel de acionamento do botão (1 = ativado)
bool bot_selecionar = 0;                                      //Variavel de acionamento do botão (1 = ativado)
bool bot_voltar = 0;                                          //Variavel de acionamento do botão (1 = ativado)
bool bot_loop = 1;                                            //Variavel para o loop do botão evita que passe mais que uma vez no loop
bool Single_loop = 1;                                         //Variavel para o loop do menu de tela evita que passe mais que uma vez no loop acionado dievrsas vezes o botão;

//unsigned long variável de 0 a 4,294,967,295, ocupa 4 bytes (32 bits)
unsigned long tempo_bot_leitura_ultimo = 0;                   //ultimo tempo que o botão foi pressionado (millis())
unsigned long bot_debounce_tempo = 70;                        //tempo do debounce dos botões em ms
unsigned long diferenca_tempo = 0;                            //diferença dos tempos de acionamento com o millis()


byte ItensMenu = 11;                                          //Coloque o numero de itens do menu

char *listaMenu [] = {                                        //Lista de Itens do Menu, sempre começando do item 0
"Relogio",
"Botoes",
"Configuracoes",
"Bluetooth",
"Wifi",
"Servidor Web",
"Senha",
"LED RBG",
"Bateria",
"Logs",
"Telas"
};

/*====================================================================================
                            Navegação de Botões (Sub-Rotina)
====================================================================================*/
void Botoes_Navegacao(){  
    Bot_LeituraADC = analogRead(Bot_PinoADC);                 //Leitura de porta analógica e armazenamento na variável
    
    if(bot_loop == 1) {                                       //Verifica se já passou no Loop dos botões e limpa as variáveis
      bot_esquerdo = 0;
      bot_acima = 0;
      bot_abaixo = 0;
      bot_direito = 0;
      bot_selecionar = 0;
      bot_voltar = 0;
      bot_loop = 0;
      Single_loop = 0;
    }

//Condição bara o Debounce
  if (Bot_LeituraADC < 3500) {                                //Caso algum botão seja apertado (se nenhum for apertado o valor padrão é 4095)
        tempo_bot_leitura_ultimo = millis();                  //Reinicia a contagem do ultimo tempo de leitura
        bot_lido_anterior = Bot_LeituraADC;                   //Armazena o valor da leitura da porta em aoutra variável
  }
  diferenca_tempo = millis() - tempo_bot_leitura_ultimo;      //Faz a diferença do tempo da ultima vez que o botão foi pressionado

  if (diferenca_tempo > bot_debounce_tempo) {                 //Caso o tempo da ultima vez que o botão foi precionado for maior que o Debounce

    if (bot_lido_anterior < 3500) {                           //Caso algum botão seja apertado (se nenhum for apertado o valor padrão é 4095)
      if(bot_lido_anterior > 0 && bot_lido_anterior < 200)    //Caso o botão Esquerdo seja precionado (Resistor de 1K)
      {
        bot_esquerdo = 1;                                     //Muda o estado da variavel do botão para verdadeiro
      }
      if(bot_lido_anterior > 500 && bot_lido_anterior < 1200) //Caso o botão Acima seja precionado (Resistor de 4K7)
      {
        bot_acima = 1;                                        //Muda o estado da variavel do botão para verdadeiro
      }
      if(bot_lido_anterior > 1200 && bot_lido_anterior < 1800)//Caso o botão Abaxo seja precionado (Resistor de 8K2)
      {
        bot_abaixo = 1;                                       //Muda o estado da variavel do botão para verdadeiro
      }
      if(bot_lido_anterior > 1800 && bot_lido_anterior < 2400)//Caso o botão Direito seja precionado (Resistor de 15K)
      {
        bot_direito = 1;                                      //Muda o estado da variavel do botão para verdadeiro
      }
          if(bot_lido_anterior > 2400 && bot_lido_anterior < 2900)//Caso o botão Selecionar seja precionado (Resistor de 33K)
      {
        bot_selecionar = 1;                                   //Muda o estado da variavel do botão para verdadeiro
      }
          if(bot_lido_anterior > 2900 && bot_lido_anterior < 3500)//Caso o botão Voltar seja precionado (Resistor de 47K)
      {
        bot_voltar = 1;                                       //Muda o estado da variavel do botão para verdadeiro
      }
      bot_loop = 1;                                           //Registra que ja foi passado no laço dos botões
      bot_lido_anterior = 4000;                               //limpa a variável temporária dos botões
    }
  }
} //--------------------------FIM - Navegação de Botões ------------------------------------


//Mais informações deste projeto visite: XProjetos.net


/*====================================================================================
                            Tela de Exemplo (Sub-Rotina)
====================================================================================*/
void TelaExemplo(){                                           //Modelo para uma nova tela
    if (Tela == 10) {                                         //Caso a variável de tela seja ...
    u8g2.firstPage();                                         //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
    do {                                                      //Tudo o que estiver dentro do "do {}" será exibido na tela.
                                                              // Escreva aqui a tela do programa
    }
    while ( u8g2.nextPage() );                                //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
  }
}//--------------------------FIM - Tela de Exemplo ------------------------------------


/*====================================================================================
                            MENU PRINCIPAL (Sub-Rotina)
====================================================================================*/
void Menu_Principal() {                                       //Tela do menu Principal
  if (Tela == -1) {                                           //Caso a variável de tela seja -1
    u8g2.firstPage();                                         //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
    do {                                                      //Tudo o que estiver dentro do "do {}" será exibido na tela.
      u8g2.setFont(u8g2_font_open_iconic_all_1x_t);           //Configura a fonte tipo icone pequeno dos proximos itens
      u8g2.drawGlyph(2, 9, 199);	                            //Desenha um pequeno icone de lista no topo esquerdo da tela
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      
      //Topo do Menu Principal
      u8g2.setCursor(28, 8);                                  //Configura a posição do proximo item a ser escrito na tela
      u8g2.drawStr(28,8,"Menu Principal");                    //Escreve o titulo o topo da página (semelhante ao print porem não aceita UTF-8)
      u8g2.setDrawColor(2);                                   //Permite a sobreposição de itens de forma "transparente"
      u8g2.drawBox(1,0,126,10);                               //Desenha um retangulo preenchido por cima do nome do Menu Principal

      //Desenho dos quadrados dos icones
      u8g2.drawRFrame(1,11,20,20,0);
      u8g2.drawRFrame(22,11,20,20,0);
      u8g2.drawRFrame(43,11,20,20,0);
      u8g2.drawRFrame(64,11,20,20,0);
      u8g2.drawRFrame(85,11,20,20,0);
      u8g2.drawRFrame(106,11,20,20,0);
      u8g2.drawRFrame(1,32,20,20,0);
      u8g2.drawRFrame(22,32,20,20,0);
      u8g2.drawRFrame(43,32,20,20,0);
      u8g2.drawRFrame(64,32,20,20,0);
      u8g2.drawRFrame(85,32,20,20,0);
      u8g2.drawRFrame(106,32,20,20,0);

      //desenha os icones de cada menu, para personalizar olhe a fonte da biblioteca
      u8g2.setFont(u8g2_font_open_iconic_all_2x_t);           //Configura a fonte tipo icone grande dos proximos itens
      u8g2.drawGlyph(3, 29, 123);	                            //Icone do Relogio
      u8g2.drawGlyph(24, 29, 106);	                          //Icone do Botões 
      u8g2.drawGlyph(45, 29, 129);	                          //Icone do Configurações
      u8g2.drawGlyph(66, 29, 94);	                            //Icone do Bluetooth
      u8g2.drawGlyph(87, 29, 248);	                          //Icone do Wifi 
      u8g2.drawGlyph(108, 29, 175);	                          //Icone do Servidor Web 
      // Segunda Linha
      u8g2.drawGlyph(3, 50, 202);	                            //Icone do Senha 
      u8g2.drawGlyph(24, 50, 259);	                          //Icone do LED RBG
      u8g2.drawGlyph(45, 50, 90);	                            //Icone do Bateria
      u8g2.drawGlyph(66, 50, 122);	                          //Icone do Logs
      u8g2.drawGlyph(87, 50, 222);	                          //Icone do Telas
      //u8g2.drawGlyph(108, 50, nuemro do icone);	            //Icone vazio(basta descomentar)

      //item de navegação dos itens com base na posição do "ChangeMenu"
      int SelecBoxMenux[] = {1, 22, 43, 64, 85, 106, 1, 22, 43, 64, 85, 106};   //Posições do x do quadrado de seleção dos icones
      int SelecBoxMenuy[] = {11, 11, 11, 11, 11, 11, 32, 32, 32, 32, 32, 32};   //Posições do y do quadrado de seleção dos icones

      u8g2.setDrawColor(2);                                   //Permite a sobreposição de itens de forma "transparente"
      u8g2.drawBox(SelecBoxMenux[ChangeMenu],SelecBoxMenuy[ChangeMenu],20,20);  //Desenha um quadrado preenchido por cima dos icones utilizando as posições conforme o numero do ChangeMenu


      u8g2.drawRFrame(0,53,127,10,0);                         //Desenha um retangulo em volta do nome do item do menu selecionado
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      u8g2.drawStr(40,61,listaMenu[ChangeMenu]);              //Escreve na tela o nome da listaMenu que é posicionada atraves do ChangeMenu.

      /*************************
       *       BOTÕES
      **************************/
     // Ações dos botões dentro da tela do menu

     // ----BOTÂO ESQUERDO----
      if (bot_esquerdo == 1 && Single_loop == 0) {            //Verifica se o botão Esquerdo foi pressionado e se não passou dentro desse loop
        ChangeMenu--;                                         //Retrocede um item do menu (quadrado de icone e listaMenu)
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
        if(ChangeMenu < 0) {                                  //Verifica se a variável está negativa
          ChangeMenu = ItensMenu - 1;                         //Muda para o ultimo item do menu
        }
      } // Fim - Botão Esquerdo

     // ----BOTÂO ACIMA----
      if (bot_acima == 1 && Single_loop == 0) {               //Verifica se o botão Acima foi pressionado e se não passou dentro desse loop
        ChangeMenu = ChangeMenu - 6;                          //Pula para o item do menu que está acima (quadrado de icone e listaMenu)
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
        if(ChangeMenu < 0) {                                  //Verifica se a variável está negativa
          ChangeMenu = 0;                                     //Muda para o primeiro item do menu
        }
      } // Fim - Botão Acima
      
      // ----BOTÂO ABAIXO----
      if (bot_abaixo == 1 && Single_loop == 0) {              //Verifica se o botão Abaixo foi pressionado e se não passou dentro desse loop
        ChangeMenu = ChangeMenu + 6;                          //Pula para o item do menu que está abaixo (quadrado de icone e listaMenu)
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
        if(ChangeMenu > ItensMenu - 1) {                      //Verifica se o item do menu está maior do que o numero de itens do menu
          ChangeMenu = ItensMenu - 1;                         //Muda para o ultimo item do menu
        }
      }// Fim - Botão Abaixo

      // ----BOTÂO DIREITO----
      if (bot_direito == 1 && Single_loop == 0) {             //Verifica se o botão Acima foi pressionado e se não passou dentro desse loop
        ChangeMenu++;                                         //Avança um item do menu (quadrado de icone e listaMenu)
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
        if(ChangeMenu > ItensMenu - 1) {                      //Verifica se o item do menu está maior do que o numero de itens do menu
          ChangeMenu = 0;                                     //Muda para o primeiro item do menu
        }
      } // Fim - Botão Direito

      // ----BOTÂO SELECIONAR----
      if (bot_selecionar == 1 && Single_loop == 0) {          //Verifica se o botão Acima foi pressionado e se não passou dentro desse loop
        Tela = ChangeMenu;                                    //Muda a tela baseado no numero do item do menu
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
      } // Fim - Botão Selecionar
    }
    while ( u8g2.nextPage() );                                //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
  }
}//--------------------------FIM - MENU PRINCIPAL ------------------------------------


/*====================================================================================
                           1 - TELA DE TESTE DE BOTÃO (Sub-Rotina)
====================================================================================*/
// Exibe as informações importantes para a calibração dos botões
void Tela1() {
    if (Tela == 1) {                                          //Caso a Tela seja 1
    u8g2.firstPage();                                         //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
    do {                                                      //Tudo o que estiver dentro do "do {}" será exibido na tela.
      u8g2.drawRFrame(0,0,127,10,2);                          //Desenha um retangulo em volta do titulo
      u8g2.drawStr(28,8,"Teste de Botao");                    //Escreve o titulo o topo da página (semelhante ao print porem não aceita UTF-8)
      u8g2.drawRFrame(13,16,104,16,2);                        //Desenha um retangulo em volta do nome do botão
      u8g2.setCursor(2, 40);                                  //Configura a posição do proximo item a ser escrito na tela
      u8g2.print("ADC:");                                     //Escreve na tela baseado na posição informada anteriormente..
      u8g2.setCursor(30, 40);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.print(bot_lido_anterior);                          //Escreve na tela a variavel temporaria do botão.
      u8g2.setCursor(60, 40);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.print("GPIO:");                                    //Escreve na tela baseado na posição informada anteriormente..
      u8g2.setCursor(92, 40);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.print(Bot_LeituraADC);                             //Escreve na tela a variavel de leitura analógica em tempo real do botão.
      u8g2.setCursor(2, 50);                                  //Configura a posição do proximo item a ser escrito na tel
      u8g2.print("Pino:");                                    //Escreve na tela baseado na posição informada anteriormente..
      u8g2.setCursor(30, 50);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.print(Bot_PinoADC);                                //Escreve na tela o numero do GPIO configurado do botão.
      
      
      /*************************
       *       BOTÕES
      **************************/
     // Ações dos botões dentro da tela de teste de botões

      if (bot_esquerdo == 1) {                                //Caso o botão Esquerdo for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("ESQUERDO");                                 //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_acima == 1) {                                   //Caso o botão Acima for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("ACIMA");                                    //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);  
      }
      if (bot_abaixo == 1) {                                  //Caso o botão Abaixo for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("ABAIXO");                                   //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_direito == 1) {                                 //Caso o botão Direito for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("DIREITO");                                  //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_selecionar == 1) {                              //Caso o botão Selecionar for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("SELECIONAR");                               //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_voltar == 1) {                                  //Caso o botão Voltar for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("VOLTAR");                                   //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_voltar == 1 && Single_loop == 0) {              //Caso o botão Voltar for pressionado
        Tela = -1;                                            //Configura para o ID do Menu Principal
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)     
      }
    }
    while ( u8g2.nextPage() );                                //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
  }
}//--------------------------FIM - 1 - TELA DE TESTE DE BOTÃO ------------------------------------

/*====================================================================================
                            SETUP (Configurações)
====================================================================================*/


void setup() {
    u8g2.begin();                                             //Inicia a Biblioteca do Display
    u8g2.setFont(FontePadrao);                                //Configura o tipo de Fonte u8g2_font_6x12_tr
    pinMode(23, OUTPUT);                                      //Configura o pino do LED de luz de fundo do LCD (opcional)
    digitalWrite(23, HIGH);                                   //Liga o pino do LED de luz de fundo do LCD (opcional)
}//--------------------------FIM - SETUP ------------------------------------

/*====================================================================================
                            LOOP (Programa)
====================================================================================*/

void loop() {
  Botoes_Navegacao(); //Chama a subrotina dos botões do teclado
  Tela1();            //Chama a subrotina da tela de teste de botão para estar pronta caso a variável Tela seja 1
  Menu_Principal();   //Chama a subrotina da tela de menu Principal para estar pronta caso a variável Tela seja -1
}//--------------------------FIM - LOOP ------------------------------------
XPsys

GitHub

Acesse a página do XPsys no GitHub
Clicando do botão abaixo:

A estrutura do código está dividida da seguinte maneira:

  • Introdução Comentada (Licenças)
  • Declarações de variáveis
  • Sub-rotinas
    • Navegação de Botões
    • Menu Principal (Tela)
    • Teste de Botão (Tela)
  • Setup (Configurações)
  • Loop (Programa)

Introdução Comentada

O cabeçalho do programa é contido as licenças do projeto e também da biblioteca u8g2:

Programa de seleção de Menu com telas, desenvolvido por JailsonBR utilizando a biblioteca u8g2 do olikraus.
POR FAVOR NÃO REMOVA NENHUMA INFORMAÇÃO DESTE CABEÇALHO, ESTE É UM CÓDIGO OPENSOURCE SOB LICENÇA DO CRIADOR
Código adaptado por JailsonBR do site XProjetos.net em 03-06-2019, o uso deste código é livre porem deve respeitar e manter o nome do criador e também de quem modificou, o código está sob GNU GENERAL PUBLIC LICENSE Versão 3 (https://www.gnu.org/licenses/quick-guide-gplv3.pt-br.html)
Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
Copyright(c) sobre o XPsys 2019, XProjetos.net
XPsys Versão 1.0.1 (Alpha)
============ BSD License for U8g2lib Code ============
Universal 8bit Graphics Library (https://github.com/olikraus/u8g2)
Copyright (c) 2016-2019, olikraus@gmail.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Ambas as licenças podem ser lidas na integra:

U8G2 Library – Licença BSD – Versão Inglês / Português
XPsys – Licença GPLv3 – Versão Inglês / Português

Lembrando que o XPsys utiliza a biblioteca U8G2 que foi desenvolvida pelo olikraus, desenvolvida para a Arduino IDE

Este cabeçalho deve ser mantido para preservar as licenças BSD e GPLv3, como sempre estou dizendo ambos os trabalho da biblioteca U8G2 e do XPsys demandaram um esforço e tempo livre para ser desenvolvido e além disso ser disponibilizado gratuitamente, o mínimo que você pode fazer para agradecer é manter estas informações no cabeçalho.

Declarações de variáveis

Como todo o código exige, o tamanho das variáveis foram declaradas conforme a necessidade, além também da inclusão das bibliotecas Arduino.h, U8g2lib.h e SPI.h

A biblioteca Arduino.h foi incluída devido eu utilizar a IDE do Visual Studio Code para programar e compilar o programa, porem se você utilizar o Arduino IDE você pode remove-o, já que é inclusa automaticamente.

As bibliotecas U8g2lib.h e SPI.h são necessárias para o display ST7920, não cheguei a testar ainda outro modelo de display 128×64 pixels, mas acredito que deve funcionar em displays semelhantes.

Você também pode baixar a biblioteca pelo site do XProjetos:

ícone

u8g2 – Biblioteca para Displays Gráficos 49,1MB 453 downloads

Esta é uma biblioteca desenvolvida pelo olikraus U8g2: Biblioteca para displays…

Apos a inclusão das bibliotecas utilizei o recurso de #define para deixar mais organizado o código:

#define Bot_PinoADC 1                                        //O compilador substituirá qualquer menção de Bot_PinoADC ao valor 1 no momento da compilação.
#define FontePadrao u8g2_font_5x7_tf                          //Selecione a fotne padrão de todos os menus exceto os icones

A função de #define é utilizada pelo compilador para substituir o primeiro nome pelo segundo, como “Bot_PinoADC” será substituído pelo numero 1 que sera usado para o GPIO1 no meio do código.
O mesmo vale para o “FontePadrao” que será substituído pela fonte u8g2_font_5x7_tf, caso queira utilizar outra fonte basta verificar o índice de fontes da Biblioteca u8g2.

Para especificar o display basta verificar a documentação dos tipos de displays e também a documentação de como configurá-lo:

U8G2_ST7920_128X64_1_SW_SPI u8g2(U8G2_R0, 33, 32, 35, 27);    //Enable, RW, RS, RESET  

As variáveis declaradas utilizam os seguintes tipos:

TipoTamanho (byte)Quantidade
bool10 até 1
byte10 até 255
int2-32.768 até 32767
unsigned long40 até 4.294.967.295
char1 por letra0 a 255

No caso do char estou usando como um ponteiro, para simplificar a lista do menu, porem ao custo de um pouco mais de memória.

//int Configura as variaveis de -32,768 a 32,767, ocupa 2 bytes (16 bits)
int Bot_LeituraADC = 0;                                       //Variavel para Leitura da porta analogica
int bot_lido_anterior = 0;                                    //Valor temporario da porta analogica
int ChangeMenu = 0;                                           //Registra a nevegação no menu principal
int Tela = -1;                                                //Varíaveis para as telas individuais (-1 é o menu principal)

//bool variável de 0 ou 1, ocupa 1 byte (256 bits)
bool bot_esquerdo = 0;                                        //Variavel de acionamento do botão (1 = ativado)
bool bot_acima = 0;                                           //Variavel de acionamento do botão (1 = ativado)
bool bot_abaixo = 0;                                          //Variavel de acionamento do botão (1 = ativado)
bool bot_direito = 0;                                         //Variavel de acionamento do botão (1 = ativado)
bool bot_selecionar = 0;                                      //Variavel de acionamento do botão (1 = ativado)
bool bot_voltar = 0;                                          //Variavel de acionamento do botão (1 = ativado)
bool bot_loop = 1;                                            //Variavel para o loop do botão evita que passe mais que uma vez no loop
bool Single_loop = 1;                                         //Variavel para o loop do menu de tela evita que passe mais que uma vez no loop acionado dievrsas vezes o botão;

//unsigned long variável de 0 a 4,294,967,295, ocupa 4 bytes (32 bits)
unsigned long tempo_bot_leitura_ultimo = 0;                   //ultimo tempo que o botão foi pressionado (millis())
unsigned long bot_debounce_tempo = 70;                        //tempo do debounce dos botões em ms
unsigned long diferenca_tempo = 0;                            //diferença dos tempos de acionamento com o millis()


byte ItensMenu = 11;                                          //Coloque o numero de itens do menu

char *listaMenu [] = {                                        //Lista de Itens do Menu, sempre começando do item 0
"Relogio",
"Botoes",
"Configuracoes",
"Bluetooth",
"Wifi",
"Servidor Web",
"Senha",
"LED RBG",
"Bateria",
"Logs",
"Telas"
};

Lembrando que o “ItensMenu” deve obedecer a quantidade de itens que você colocar na listagem do “listaMenu“.

Caso você queira que o programa já comece em uma tela especifica basta alterar o valor da variável “Tela” que o padrão é -1 (Menu Principal) para o numero da tela que você deseja.

Sub-rotinas

Cada parte da programação separei em sub-rotinas para simplificar a organização e também os testes caso seja necessário desativar algum recurso basta comentar a linha da sub-rotina no loop que o recurso é desativado, o que é bastante útil caso algo esteja esteja dando conflito, o que ajuda a filtrar a área de busca para corrigir.

Navegação de Botões

Esta sub-rotina é destinada para o debounce por software e também da separação dos botões na leitura analógica, optei pela leitura analógica por ser possível utilizar uma grande quantidade de botões sem ocupar vários pinos do microcontrolador (ESP32), além do mais é possível adicionar muitos botões porem deve ter a tensão de alimentação bem estabilizada para evitar alteração nos valores de leitura, também deve-se estar atento no desgaste dos botões que raramente mudam os valores de leitura.

/*====================================================================================
                            Navegação de Botões (Sub-Rotina)
====================================================================================*/
void Botoes_Navegacao(){  
    Bot_LeituraADC = analogRead(Bot_PinoADC);                 //Leitura de porta analógica e armazenamento na variável
    
    if(bot_loop == 1) {                                       //Verifica se já passou no Loop dos botões e limpa as variáveis
      bot_esquerdo = 0;
      bot_acima = 0;
      bot_abaixo = 0;
      bot_direito = 0;
      bot_selecionar = 0;
      bot_voltar = 0;
      bot_loop = 0;
      Single_loop = 0;
    }

//Condição bara o Debounce
  if (Bot_LeituraADC < 3500) {                                //Caso algum botão seja apertado (se nenhum for apertado o valor padrão é 4095)
        tempo_bot_leitura_ultimo = millis();                  //Reinicia a contagem do ultimo tempo de leitura
        bot_lido_anterior = Bot_LeituraADC;                   //Armazena o valor da leitura da porta em aoutra variável
  }
  diferenca_tempo = millis() - tempo_bot_leitura_ultimo;      //Faz a diferença do tempo da ultima vez que o botão foi pressionado

  if (diferenca_tempo > bot_debounce_tempo) {                 //Caso o tempo da ultima vez que o botão foi precionado for maior que o Debounce

    if (bot_lido_anterior < 3500) {                           //Caso algum botão seja apertado (se nenhum for apertado o valor padrão é 4095)
      if(bot_lido_anterior > 0 && bot_lido_anterior < 200)    //Caso o botão Esquerdo seja precionado (Resistor de 1K)
      {
        bot_esquerdo = 1;                                     //Muda o estado da variavel do botão para verdadeiro
      }
      if(bot_lido_anterior > 500 && bot_lido_anterior < 1200) //Caso o botão Acima seja precionado (Resistor de 4K7)
      {
        bot_acima = 1;                                        //Muda o estado da variavel do botão para verdadeiro
      }
      if(bot_lido_anterior > 1200 && bot_lido_anterior < 1800)//Caso o botão Abaxo seja precionado (Resistor de 8K2)
      {
        bot_abaixo = 1;                                       //Muda o estado da variavel do botão para verdadeiro
      }
      if(bot_lido_anterior > 1800 && bot_lido_anterior < 2400)//Caso o botão Direito seja precionado (Resistor de 15K)
      {
        bot_direito = 1;                                      //Muda o estado da variavel do botão para verdadeiro
      }
          if(bot_lido_anterior > 2400 && bot_lido_anterior < 2900)//Caso o botão Selecionar seja precionado (Resistor de 33K)
      {
        bot_selecionar = 1;                                   //Muda o estado da variavel do botão para verdadeiro
      }
          if(bot_lido_anterior > 2900 && bot_lido_anterior < 3500)//Caso o botão Voltar seja precionado (Resistor de 47K)
      {
        bot_voltar = 1;                                       //Muda o estado da variavel do botão para verdadeiro
      }
      bot_loop = 1;                                           //Registra que ja foi passado no laço dos botões
      bot_lido_anterior = 4000;                               //limpa a variável temporária dos botões
    }
  }
} //--------------------------FIM - Navegação de Botões ------------------------------------

Cada botão possui uma resistência específica para gerar uma tensão diferente, para verificar mais detalhes sobre cada botão olhe no artigo do XPboard que é o hardware que utilizei para este projeto, você pode também montar um em sua Protoboard:

XPboard placa para o XPsys

A XPboard é uma placa para o XPsys, utilizando a interface gráfica do ST7920.

No ESP32 a resolução da porta analógica é de 12 bytes (4096 bits) contra os 10 bytes (1024) do Arduino, caso você queira utilizar este código no Arduíno deve se converter estes valores de leitura do:

if (Bot_LeituraADC < 3500)
         ...
if (bot_lido_anterior < 3500)
         ...
    //e cada botão possui:
if(bot_lido_anterior > 2400 && bot_lido_anterior < 2900)

Para o numero que irá representar de cada botão, para isso você deve alterar já de inicio, antes de compilar e gravar no Arduíno a variável “Tela” para 1 que irá fazer que inicie diretamente na tela de teste de botões, onde você pode anotar os valores lidos de cada botão

A condição “bot_loop” eu utilizo para que sempre limpe as variáveis evitando que “dispare” em outras funções, evitando fica adicionando ou que passe muito rápido nos menus e fique pulando muitos números ou itens do menu.

O debounce por software é feito através desta função:

//Condição bara o Debounce
  if (Bot_LeituraADC < 3500) {                                //Caso algum botão seja apertado (se nenhum for apertado o valor padrão é 4095)
        tempo_bot_leitura_ultimo = millis();                  //Reinicia a contagem do ultimo tempo de leitura
        bot_lido_anterior = Bot_LeituraADC;                   //Armazena o valor da leitura da porta em aoutra variável
  }
  diferenca_tempo = millis() - tempo_bot_leitura_ultimo;      //Faz a diferença do tempo da ultima vez que o botão foi pressionado
  
  if (diferenca_tempo > bot_debounce_tempo) {
      ... //condições dos botões
  }

O tempo de debounce pode ser ajustado através da variável “bot_debounce_tempo” declarada no início do programa, enquanto o botão estiver pressionado, ou seja, a leitura da porta analógica estiver abaixo de 3500 o contador sempre ficará abaixo do tempo do debounce, e a ação do botão só será executada depois que o botão for solto e iniciará o tempo do debouce e depois irá executar a ação do botão.

Menu Principal (Tela)

Resultado final do Menu Principal

A sub-rotina do menu principal pode ser personalizada a seu próprio gosto, você pode alterar os ícones e também a quantidade de itens, que no momento está limitada a 12, porem pretendo fazer mais páginas para incluir mais itens.

/*====================================================================================
                            MENU PRINCIPAL (Sub-Rotina)
====================================================================================*/
void Menu_Principal() {                                       //Tela do menu Principal
  if (Tela == -1) {                                           //Caso a variável de tela seja -1
    u8g2.firstPage();                                         //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
    do {                                                      //Tudo o que estiver dentro do "do {}" será exibido na tela.
      u8g2.setFont(u8g2_font_open_iconic_all_1x_t);           //Configura a fonte tipo icone pequeno dos proximos itens
      u8g2.drawGlyph(2, 9, 199);	                            //Desenha um pequeno icone de lista no topo esquerdo da tela
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      
      //Topo do Menu Principal
      u8g2.setCursor(28, 8);                                  //Configura a posição do proximo item a ser escrito na tela
      u8g2.drawStr(28,8,"Menu Principal");                    //Escreve o titulo o topo da página (semelhante ao print porem não aceita UTF-8)
      u8g2.setDrawColor(2);                                   //Permite a sobreposição de itens de forma "transparente"
      u8g2.drawBox(1,0,126,10);                               //Desenha um retangulo preenchido por cima do nome do Menu Principal

      //Desenho dos quadrados dos icones
      u8g2.drawRFrame(1,11,20,20,0);
      u8g2.drawRFrame(22,11,20,20,0);
      u8g2.drawRFrame(43,11,20,20,0);
      u8g2.drawRFrame(64,11,20,20,0);
      u8g2.drawRFrame(85,11,20,20,0);
      u8g2.drawRFrame(106,11,20,20,0);
      u8g2.drawRFrame(1,32,20,20,0);
      u8g2.drawRFrame(22,32,20,20,0);
      u8g2.drawRFrame(43,32,20,20,0);
      u8g2.drawRFrame(64,32,20,20,0);
      u8g2.drawRFrame(85,32,20,20,0);
      u8g2.drawRFrame(106,32,20,20,0);

      //desenha os icones de cada menu, para personalizar olhe a fonte da biblioteca
      u8g2.setFont(u8g2_font_open_iconic_all_2x_t);           //Configura a fonte tipo icone grande dos proximos itens
      u8g2.drawGlyph(3, 29, 123);	                            //Icone do Relogio
      u8g2.drawGlyph(24, 29, 106);	                          //Icone do Botões 
      u8g2.drawGlyph(45, 29, 129);	                          //Icone do Configurações
      u8g2.drawGlyph(66, 29, 94);	                            //Icone do Bluetooth
      u8g2.drawGlyph(87, 29, 248);	                          //Icone do Wifi 
      u8g2.drawGlyph(108, 29, 175);	                          //Icone do Servidor Web 
      // Segunda Linha
      u8g2.drawGlyph(3, 50, 202);	                            //Icone do Senha 
      u8g2.drawGlyph(24, 50, 259);	                          //Icone do LED RBG
      u8g2.drawGlyph(45, 50, 90);	                            //Icone do Bateria
      u8g2.drawGlyph(66, 50, 122);	                          //Icone do Logs
      u8g2.drawGlyph(87, 50, 222);	                          //Icone do Telas
      //u8g2.drawGlyph(108, 50, nuemro do icone);	            //Icone vazio(basta descomentar)

      //item de navegação dos itens com base na posição do "ChangeMenu"
      int SelecBoxMenux[] = {1, 22, 43, 64, 85, 106, 1, 22, 43, 64, 85, 106};   //Posições do x do quadrado de seleção dos icones
      int SelecBoxMenuy[] = {11, 11, 11, 11, 11, 11, 32, 32, 32, 32, 32, 32};   //Posições do y do quadrado de seleção dos icones

      u8g2.setDrawColor(2);                                   //Permite a sobreposição de itens de forma "transparente"
      u8g2.drawBox(SelecBoxMenux[ChangeMenu],SelecBoxMenuy[ChangeMenu],20,20);  //Desenha um quadrado preenchido por cima dos icones utilizando as posições conforme o numero do ChangeMenu


      u8g2.drawRFrame(0,53,127,10,0);                         //Desenha um retangulo em volta do nome do item do menu selecionado
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      u8g2.drawStr(40,61,listaMenu[ChangeMenu]);              //Escreve na tela o nome da listaMenu que é posicionada atraves do ChangeMenu.

      /*************************
       *       BOTÕES
      **************************/
     // Ações dos botões dentro da tela do menu

     // ----BOTÂO ESQUERDO----
      if (bot_esquerdo == 1 && Single_loop == 0) {            //Verifica se o botão Esquerdo foi pressionado e se não passou dentro desse loop
        ChangeMenu--;                                         //Retrocede um item do menu (quadrado de icone e listaMenu)
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
        if(ChangeMenu < 0) {                                  //Verifica se a variável está negativa
          ChangeMenu = ItensMenu - 1;                         //Muda para o ultimo item do menu
        }
      } // Fim - Botão Esquerdo

     // ----BOTÂO ACIMA----
      if (bot_acima == 1 && Single_loop == 0) {               //Verifica se o botão Acima foi pressionado e se não passou dentro desse loop
        ChangeMenu = ChangeMenu - 6;                          //Pula para o item do menu que está acima (quadrado de icone e listaMenu)
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
        if(ChangeMenu < 0) {                                  //Verifica se a variável está negativa
          ChangeMenu = 0;                                     //Muda para o primeiro item do menu
        }
      } // Fim - Botão Acima
      
      // ----BOTÂO ABAIXO----
      if (bot_abaixo == 1 && Single_loop == 0) {              //Verifica se o botão Abaixo foi pressionado e se não passou dentro desse loop
        ChangeMenu = ChangeMenu + 6;                          //Pula para o item do menu que está abaixo (quadrado de icone e listaMenu)
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
        if(ChangeMenu > ItensMenu - 1) {                      //Verifica se o item do menu está maior do que o numero de itens do menu
          ChangeMenu = ItensMenu - 1;                         //Muda para o ultimo item do menu
        }
      }// Fim - Botão Abaixo

      // ----BOTÂO DIREITO----
      if (bot_direito == 1 && Single_loop == 0) {             //Verifica se o botão Acima foi pressionado e se não passou dentro desse loop
        ChangeMenu++;                                         //Avança um item do menu (quadrado de icone e listaMenu)
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
        if(ChangeMenu > ItensMenu - 1) {                      //Verifica se o item do menu está maior do que o numero de itens do menu
          ChangeMenu = 0;                                     //Muda para o primeiro item do menu
        }
      } // Fim - Botão Direito

      // ----BOTÂO SELECIONAR----
      if (bot_selecionar == 1 && Single_loop == 0) {          //Verifica se o botão Acima foi pressionado e se não passou dentro desse loop
        Tela = ChangeMenu;                                    //Muda a tela baseado no numero do item do menu
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)
      } // Fim - Botão Selecionar
    }
    while ( u8g2.nextPage() );                                //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
  }
}//--------------------------FIM - MENU PRINCIPAL ------------------------------------

Nesta tela a parte personalizável é a dos ícones, onde você pode escolher um ícone da fonte da própria biblioteca u8g2:

Ícones disponíveis (Open Iconic)

Para escolher um ícone é simples, um exemplo é o ícone da engrenagem de opções que é o ícone da 2ª coluna e 5ª Linha, o primeiro ícone dessa quinta linha tem o seguinte código: 128/0080, sendo que 128 é em decimal e 0080 em hexa decimal devendo ser informado no código como 0080h, mas não é esse o ícone que queremos o que queremos é o do lado, nesse caso é só adicionar 1, ficando 129 / 0081h, só informar somente um desses códigos no final do:

u8g2.drawGlyph(45, 29, 129); ou u8g2.drawGlyph(45, 29, 0081h);

A parte dos botões eu programei de modo que a navegação fossem fluida, se você pressionar para baixo ele irá pular para o item abaixo, mas caso pressione abaixo mesmo na linha de baixo ele irá para o ultimo item do menu.

Em cada botão eu coloquei a função “Single_loop” devido a função “do{” do u8g2 ficar executando 5 vezes seguidas o que fazia que a cada pressionada de botão ele executava 5 vezes algum comando, então caso ele já tivesse sido acionado anteriormente ele irá travar até quando voltar para a sub-rotina dos botões e limpar o Single_loop.

Teste de Botão (Tela)

Tela de Teste de Botões

A sub-rotina da tela de teste de botões, foi a primeira tela que tive que desenvolver para conseguir os dados dos botões, qual é o valor lido ao pressionar cada botão.

/*====================================================================================
                           1 - TELA DE TESTE DE BOTÃO (Sub-Rotina)
====================================================================================*/
// Exibe as informações importantes para a calibração dos botões
void Tela1() {
    if (Tela == 1) {                                          //Caso a Tela seja 1
    u8g2.firstPage();                                         //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
    do {                                                      //Tudo o que estiver dentro do "do {}" será exibido na tela.
      u8g2.drawRFrame(0,0,127,10,2);                          //Desenha um retangulo em volta do titulo
      u8g2.drawStr(28,8,"Teste de Botao");                    //Escreve o titulo o topo da página (semelhante ao print porem não aceita UTF-8)
      u8g2.drawRFrame(13,16,104,16,2);                        //Desenha um retangulo em volta do nome do botão
      u8g2.setCursor(2, 40);                                  //Configura a posição do proximo item a ser escrito na tela
      u8g2.print("ADC:");                                     //Escreve na tela baseado na posição informada anteriormente..
      u8g2.setCursor(30, 40);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.print(bot_lido_anterior);                          //Escreve na tela a variavel temporaria do botão.
      u8g2.setCursor(60, 40);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.print("GPIO:");                                    //Escreve na tela baseado na posição informada anteriormente..
      u8g2.setCursor(92, 40);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.print(Bot_LeituraADC);                             //Escreve na tela a variavel de leitura analógica em tempo real do botão.
      u8g2.setCursor(2, 50);                                  //Configura a posição do proximo item a ser escrito na tel
      u8g2.print("Pino:");                                    //Escreve na tela baseado na posição informada anteriormente..
      u8g2.setCursor(30, 50);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.print(Bot_PinoADC);                                //Escreve na tela o numero do GPIO configurado do botão.
      
      
      /*************************
       *       BOTÕES
      **************************/
     // Ações dos botões dentro da tela de teste de botões

      if (bot_esquerdo == 1) {                                //Caso o botão Esquerdo for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("ESQUERDO");                                 //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_acima == 1) {                                   //Caso o botão Acima for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("ACIMA");                                    //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);  
      }
      if (bot_abaixo == 1) {                                  //Caso o botão Abaixo for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("ABAIXO");                                   //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_direito == 1) {                                 //Caso o botão Direito for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("DIREITO");                                  //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_selecionar == 1) {                              //Caso o botão Selecionar for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("SELECIONAR");                               //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_voltar == 1) {                                  //Caso o botão Voltar for pressionado
      u8g2.setCursor(15, 29);                                 //Configura a posição do proximo item a ser escrito na tela
      u8g2.setFont(u8g2_font_unifont_t_latin);                //Configura a fonte para uma fonte diferente do padrão
      u8g2.print("VOLTAR");                                   //Escreve na tela baseado na posição informada anteriormente.
      u8g2.setFont(FontePadrao);                              //Retorna para a fonte padrão do projeto
      }
      if (bot_voltar == 1 && Single_loop == 0) {              //Caso o botão Voltar for pressionado
        Tela = -1;                                            //Configura para o ID do Menu Principal
        Single_loop = 1;                                      //Registra que já passou dentro desse loop ou de outros botões(evita varios pulsos de botões)     
      }
    }
    while ( u8g2.nextPage() );                                //Este comando é parte do loop (imagem) que renderiza o conteúdo da exibição. (Obrigatório)
  }
}//--------------------------FIM - 1 - TELA DE TESTE DE BOTÃO ------------------------------------

Esta parte não precisa de muitas explicações pois todas as linhas estão mentadas, somente sobre o itens mostrados na tela onde o “ADC” é a leitura da variável temporária “bot_lido_anterior“, o “GPIO” é a leitura analógica diretamente do pino e o “Pino” informa qual pino que o programa está utilizando para as leituras.

Setup (Configurações)

O setup é onde você irá fazer as primeiras configurações do Sistema como pinos de entradas e saídas, nesta primeira versão não possui muitos comandos

/*====================================================================================
                            SETUP (Configurações)
====================================================================================*/


void setup() {
    u8g2.begin();                                             //Inicia a Biblioteca do Display
    u8g2.setFont(FontePadrao);                                //Configura o tipo de Fonte u8g2_font_6x12_tr
    pinMode(23, OUTPUT);                                      //Configura o pino do LED de luz de fundo do LCD (opcional)
    digitalWrite(23, HIGH);                                   //Liga o pino do LED de luz de fundo do LCD (opcional)
}//--------------------------FIM - SETUP ------------------------------------

Neste setup inicializo o LCD, configuro a fonte padrão, e configuro o pino do background do LCD esse pinMode e digitalWrite é opcional nesta primeira versão pois ainda não implementei o controle de contraste e nem o modo economia de energia que desligara a luz de fundo do LCD.

Loop (Programa)

O loop é a junção de todas as sub-rotinas eu deixei deste jeito mais compacta para melhorar por conta dos testes.

/*====================================================================================
                            LOOP (Programa)
====================================================================================*/

void loop() {
  Botoes_Navegacao(); //Chama a subrotina dos botões do teclado
  Tela1();            //Chama a subrotina da tela de teste de botão para estar pronta caso a variável Tela seja 1
  Menu_Principal();   //Chama a subrotina da tela de menu Principal para estar pronta caso a variável Tela seja -1
}//--------------------------FIM - LOOP ------------------------------------

Conforme você for criando as telas como sub-rotinas você deve adicioná-la aqui no loop, pois o loop sempre ficará executando o que estiver escrito dentro dele.

Considerações Finais

Esta primeira versão foi muito satisfatória para mim, e tenho grandes expectativas nos restante dos recursos que irei adicionar neste sistema, conforme eu mencionei neste artigo anterior, caso você tenha alguma sugestão ou você encontre algum erro ou algo que possa ser melhorado comente aqui, ainda não cheguei a testar com outros LCD’s, mas acredito que funcione em LCD’s com as mesmas características que o ST7920.

Conforme foi dito anteriormente este sistema é livre você pode utilizá-lo e modificá-lo, porem coloque o meu nome e do olikraus que desenvolveu a biblioteca, ambos dedicamos um tempo precioso para estes projetos, o mínimo de agradecimento é manter os créditos por iniciar e disponibilizá-los gratuitamente.

Licença CC 4.0

Creative Commons

O trabalho “XPsys – Versão 1.0.1 (Alfa)” de JailsonBR está licenciado com uma Licença Creative Commons Atribuição 4.0 Internacional.

Jailson Oliveira

Sou Engenheiro Eletricista com Enfase em Eletrônica e Técnico em Eletrônica, gosto de estar praticando montagens de circuitos e também programar sistemas embarcados. Acredito que compartilhar informações gratuita gera mais informações novas por parte de outras pessoas.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *