Como criar um menu em C para seus projetos em Arduino 6

Quando você quer mudar o toque do seu smartphone provavelmente seguirá algum caminho como: acessar o menu de configurações, ir no item “Som” e no item “Toque do telefone” que abrirá uma tela para a seleção do som. Já se você desejar alterar a hora, é necessário seguir algum caminho como: acessar o menu de configurações, ir no item “Sistema”, no item “Data e hora” e por fim no item “Definir Data”, que irá abrir a tela de ajuste da hora. Fácil achar o que você quer quando as várias opções estão organizadas, não? Pois é, quando temos várias opções dentro de um programa, a melhor forma de organizarmos o programa pra que ninguém se perca é utilizando menus navegáveis e telas, que é exatamente o que você vai aprender como fazer neste post, criando um menu em C como exemplo!

Teclado matricial com membrana e display

Material Necessário

Aqui vai depender bastante do seu projeto, mas teremos alguns itens básicos:

– Uma placa de desenvolvimento, como um Arduino Pro Mini, Nano ou Uno;

– Um display de LCD (não necessariamente gráfico) ou OLED;

Chaves tácteis, um teclado ou um encoder pra navegar pelos menus;

O que são menus navegáveis?

Primeiro vamos entender o que é um menu navegável (ou simplesmente menu), item e tela. Observe o menu da seguinte imagem:

Menu em C no display OLED

Nesta imagem, temos um menu em um Display OLED 0.96 polegadas I2C Branco (eu juro que é branco, embora esteja azul na foto), com cinco itens: Tela 1, Tela 2, Tela 3, Tela 4 e Retornar. Cada item, quando selecionado, pode ter duas possibilidades: ir para uma tela ou para outro menu! Um exemplo de menu que leva a outro menu é o início deste post: do menu de configurações você cai no menu de som, ao tocar no item som do menu de configurações. Se ficou confuso, dá uma olhada neste fluxograma:

fluxograma do menu

Ainda difícil?

– Menu é um conjunto de itens (opções);
– Item é cada elemento (opção) presente em um menu;
– Tela é a parte do programa onde você vai ajustar um parâmetro, vai exibir um texto, dado ou gráfico.

Se ainda está um pouco embaraçado, dá uma olhada nesses GIFs:

funcionamento do menu em C

Aqui temos um menu, por exemplo, de configuração de algum projeto. Nele temos os itens Som, Brilho e etc. Vamos supor que eu selecionasse o item Brilho. Ele me levaria a uma tela, por exemplo assim:

funcionamento do menu em C 2

Esta é a tela de ajuste de brilho, onde como o nome sugere bem, é possível ajustar o brilho do display. Dela eu voltaria para o menu de configurações, por exemplo, ou para uma tela inicial.

Como criar um menu em C?

Existe uma forma fácil e uma forma mais completa. Eu vou ensinar a completa pois, intuitivamente, se você sabe um pouquinho a mais de programação, vai ver como não vale a pena a forma fácil, que seria estruturar tudo isso dentro da função main (ou loop. Ah, Arduino, porque loop?).
Para isto, sugiro que dê uma revisada em alguns conceitos da linguagem, para vermos o menu em C:

  • enum;
  • funções;
  • ponteiros;
  • typedef.

Dito isto, eis o código do menu em C! Sugiro primeiro dar uma olhada no fluxograma, depois no código e então seguir para a explicação. Já adianto que, neste exemplo, sempre retornaremos de uma tela para o Menu, mas isto não é regra!

fluxograma do menu

(Instruções da tela podem ser, por exemplo, no GIF que apresentamos, desenhar aquele menu, escrevendo as palavras, destacando o item selecionado, monitorar os botões que movem o cursor do menu pra cima ou pra baixo e o botão de selecionar item).

// Código do menu em C
// Início onde tem headers, declaração de variáveis globais e etc
//Estes dois enum servem apenas para facilitar a compreensão do código
typedef enum itens {Item1 = 1, Item2};
typedef enum telas
{
Menu,
Tela1,
Tela2
}
Telas;
//*************************************************************************
// Menu de opções do programa
//*************************************************************************
void menu(uint8_t *Tela_de_destino)
{
//declare aqui as suas variáveis locais
itens menu;
uint8_t retornar = 0;
uint8_t posição_do_menu = Item1, posição_anterior_do_menu = Item2;
    while(retornar == 0)
{
//Escreva aqui o seu código do que vai acontecer no menu, sejam animações, tocar um beep quando apertar uma tecla e etc
        if(posição_anterior_do_menu != posição_do_menu)
{
switch(posição_do_menu)
{
case Item1:
{
//escreva aqui o código que vai desenhar seu menu em C quando o primeiro item estiver selecionado.
//pode ser que nem o do GIF, uma seta do lado indicando, mudar a cor do texto.
break;
}
case Item2:
{
//escreva aqui o código que vai desenhar seu menu em C quando o segundo item estiver selecionado.
//pode ser que nem o do GIF, uma seta do lado indicando, mudar a cor do texto.
break;
}
case default: break;//deu ruim!
}
            posição_anterior_do_menu = posição_do_menu;
        }
        //código responsável por ler botões, encoder e etc pra mudar a posição selecionada no menu
if(botão_pra_baixo == 1 && posição_do_menu != Item2)
posição_do_menu++;
else if(botão_pra_cima == 1 && posição_do_menu != Item1)
posição_do_menu--;
        //Se pressionado o botão pra selecionar o item em destaque no menu, saia do menu
if(botão_de_seleção == 1)
retornar = 1;
}
    *Tela_de_destino = posição_do_menu;
}
//*************************************************************************
// Tela1, selecionada no menu pelo "Item1"
//*************************************************************************
void tela1(uint8_t *Tela_de_destino)
{
//declare aqui as suas variáveis locais
uint8_t retornar = 0;
    while(retornar == 0)
{
//Escreva aqui o seu código do que vai acontecer nesta tela, como mostrar ou receber dados, acender um LED, etc
LED1 = 1;
        //Aqui é a condição de retorno/saída da tela. Pode ser um botão pressionado, uma interrupção, um comando pelo terminal.
if(botão_de_seleção == 1)
retornar = 1;
}
    //ao sair desta tela, retorna para o menu. Você pode mudar isto nesta linha.
*Tela_de_destino = Menu;
}
//*************************************************************************
// Tela2, selecionada no menu pelo "Item1"
//*************************************************************************
void tela2(uint8_t *Tela_de_destino)
{
//declare aqui as suas variáveis locais
uint8_t retornar = 0;
    while(retornar == 0)
{
//Escreva aqui o seu código do que vai acontecer nesta tela, como mostrar ou receber dados, acender um LED, etc
LED2 = 1;
        //Aqui é a condição de retorno/saída da tela. Pode ser um botão pressionado, uma interrupção, um comando pelo terminal.
if(botão_de_seleção == 1)
retornar = 1;
}
    //ao sair desta tela, retorna para o menu. Você pode mudar isto nesta linha.
*Tela_de_destino = Menu;
}
//*************************************************************************
// Função principal
//*************************************************************************
void main()
{
//declare aqui as suas variáveis locais
uint8_t Tela_de_destino = Menu;
    //insira aqui o restante do código da sua main
while(1)
{
//este é o loop do seu programa. Pra quem programa Arduino, este while é sua função loop()
//insira aqui o que quiser, desde que não bloqueie o funcionamento do switch abaixo
//Este switch é responsável por fazer seu programa ir de uma tela para a outra
switch(Tela_de_destino)
{
case Menu:
{
menu(&Tela_de_destino);
break;
}
            case Tela1:
{
tela1(&Tela_de_destino);
break;
}
            case Tela2:
{
tela2(&Tela_de_destino);
break;
}
}
}
}

Antes de mais nada, uma coisa: o menu também é uma tela. “COMO ASSIM?”. É, o menu é uma tela, ou pelo menos será tratado como uma pelo programa. Se você observar, a estrutura das funções menu, tela1 e tela2 é quase a mesma, se comportam de maneira similar. Digo isto apenas para que você não se confunda ao ver no enum “telas” escrito “Menu”.

Começando pela main, criamos uma variável que vai controlar para qual tela o programa vai a cada momento enquanto o usuário navega no menu em C. Esta variável será passada como ponteiro para cada função que lida com telas ou menus. Em seguida, a única parte a mais acrescida é, dentro do loop, colocar um switch case responsável por, baseado no valor da variável Tela_de_destino, direcionar o programa para a tela certa.

O switch chama então uma função. Vamos ver a função menu, que é a mais completa. As funções das telas tela1 e tela2 são de funcionamento similar e mais simples do que o menu, portanto, entendendo este, terá entendido tudo.

A função é declarada esperando receber um ponteiro, que é a variável que indica para qual tela, ao sair desta, o programa deverá ir. No nosso exemplo, é a variável lá da main, a Tela_de_destino. Se você não sabe porquê ponteiro, recomendo pesquisar e conhecer este conceito importantíssimo da linguagem C, mas que, resumindo, é um valor que aponta para o endereço de uma variável e não propriamente para o valor dela. Sabendo o endereço da variável, ou seja, onde ela está na memória, podemos acessar ela de qualquer função, mesmo a variável sendo local de outra função (desde que esta função não tenha terminado e a variável tenha sido extinta).

No começo da função declaramos algumas variáveis que precisaremos: retornar, que indicará ao programa que ele deve sair da tela atual (inicializada com 0 para garantir que o programa entrará no laço); posição_do_menu, responsável por apontar qual item no menu está em destaque; e posição_anterior_do_menu, que guarda o que o nome dela diz, e nos ajuda a desenhar o display apenas uma vez, ao invés de ficar dando um refresh constantemente. Veja que ambas DEVEM ser inicializadas e com valores DIFERENTES, senão o programa irá apresentar problema, uma vez que variáveis não inicializadas podem assumir um valor qualquer. Se forem inicializadas com valores iguais, o programa só vai desenhar o menu no display quando o usuário mover o cursor do menu.

Em seguida criamos um laço while dependente da variável retornar, fazendo com que o programa possa sair em algum momento desta tela. Dentro deste laço, temos uma comparação, por meio de um if, do valor das variáveis relacionadas à posição do menu. Se o valor delas for diferente, ou seja, o usuário mudou o item indicado, o programa precisa atualizar o display. Então dentro deste if teremos um switch case responsável justamente por atualizar o display conforme a nova posição e, depois disto, atualizamos o valor da variável posição_anterior_do_menu, para que o programa, quando voltar no switch case, atualize o display sem que o usuário tenha mudado algo. Isto salva processamento e, por consequência, bateria.Temos, na sequência, três if: dois deles verificam dois botões para mover o cursor no display e um terceiro seleciona o item apontado. Esta seleção muda a variável retornar para 1, fazendo o programa sair do while e, saindo dele, grava na variável Tela_de_destino o valor selecionado no menu.
Esses botões podem ser alterados pra o que sua imaginação permitir, como por exemplo, entradas do monitor serial, para você criar um programa que crie varias opções no terminal serial. Aí é com você soltar sua imaginação.

Por fim, ao sair desta função, voltamos dentro do loop na main, que vai rodar o switch case que vai nos levar pra tela selecionada, através da variável Tela_de_destino. E pronto! Está feito seu programa com Menus e Telas! Agora é só juntar isso com aquela sua ideia engavetada, comprar o que precisa na loja virtual da MakerHero e se juntar a nós Makers.

Gostou de aprender como fazer um menu em C? Deixe seu comentário logo abaixo.

Faça seu comentário

Acesse sua conta e participe

6 Comentários

  1. Estou criando uma etiquetadora e estou com dificuldade em criar o menu e tratar as tela

  2. Bom dia caro Stephem! Parabéns pela iniciativa em compartilhar informações.

    Pode me ajudar com um projeto? Trata-se de um simulador de centrais de injeção eletrônica para Caminhões.
    Principais componentes utilizados.
    Placa Esp32
    Display ST7920 128X64
    Encoder KY-040
    Estou com problemas em relação a seleção de telas e menus, se puder ajudar lhe envio detalhes sobre o projeto por email.
    Grato
    Edi

    1. Olá. Consegue mandar sua dúvida aqui? Talvez ela ajude outros;

    2. Caro amigo Souza. Tbem tô montando um projeto com esp32 pra simulador .

  3. Pode me mandar esec sketch no email?

    1. Não possuo skecth. Disponível há apenas o mesmo código publicado aqui, que é apenas uma base para seus próprios projetos.
      Bons projetos!