Manual

do

Maker

.

com

Display LCD 4 bits com Arduino (LCD 16x2)

Display LCD 4 bits com  Arduino (LCD 16x2)

Antes de começarmos, caso deseje controlar um display desse com I2C, o link é esse. Como prometi no post sobre o sensor de temperatura LM35, vamos aprimorar o projeto de controle de temperaturas utilizando um display LCD.

Esse display possui 5 botões, mas todos eles utilizam a porta analógica 0. O que faz com que seja possível reconhecer qual botão foi pressionado é a frequẽncia que ele gera; cada botão possui uma resistência diferente.

Além disso, pode-se ver no esquema os pinos utilizados. Porém, mesmo sem o esquemático, não só para esse LCD shield mas também para outros shields, existe uma referência do site oficial do Arduino que mostra a pinagem em uma lista, nesse link

Então para testar, vamos usar a biblioteca disponível para download no próprio site (e obviamente recomendo a compra na WebTronico). Baixe e descomprima a biblioteca dentro do sub-diretório libraries do diretório arduino-1.0 (que é a versão disponível até o momento que escrevi esse post).

display_0.webp

Ao ligar, automaticamente o display se acende e a matriz fica preenchida por quadrados pretos, então, não se assuste; não há nada de anormal com ele.

Ao tentar compilar o programa, obtive um erro de comprimento da string. Diminua 2 bytes a partir da linha 12 do array. No meu caso, deixei a variável em uma só linha dessa forma:

char msgs[5][15] = {"Direita OK   ","Cima OK      ","Baixo OK     ","Esquerda OK  ", "Select OK    " };

display_msg1.webp

Após compilar e subir o programa, o display exibirá a mensagem "Keypad testing...". Pressionando cada um dos botões, a mensagem se alterará. Na imagem acima, ao apertar o botão para baixo, surgiu a mensagem "Baixo OK".

Trabalharemos duas etapas distintas. Primeiramente, será necessário criar um método que possa tratar os resultados dos botões e manipular o array de mensagens também. Isso será feito porque há um objetivo principal; criar um menu para poder escolher qual sensor exibir a temperatura.

O segundo objetivo é exibir mensagens de temperatura na tela. Para converter esse valor em um array de char utilizaremos a função dtostrf(), mas não se preocupe com isso, estará claro no código de exemplo.

Para não virar um mega-projeto, utilizarei apenas 2 sensores LM35 para a temperatura, mas é possível adicionar outros tipos de sensores funcionando juntamente.

Nada desse mundo é perfeito

Esse fabuloso display tem lá suas deficiências. Não sei porque, mas infelizmente ele não vem com os slots para utilizar os demais pinos analógicos e os digitais, além de energia e terra. Então, foi necessário soldar os demais slots e obtive o resultado da imagem inicial desse post.

Enfeitando um pouco

Não há muito que se possa fazer de verdade, mas é possível colocar um pouco de charme no display, gerando um delay para a exibição do texto, de uma forma mais suave como se pode ver no video. Para isso, foi necessário mexer diretamente na biblioteca do display. Entre no diretório libraries/LCD4Bit_mod do Arduino e edite o arquivo LCD4Bit_mod.cpp.
No método pulseEnablePin(), troque os delays por 100,100 e 10. É só o que dá para fazer.

Criando o fluxo do menu

Aproveitei todo o código do exemplo da biblioteca do LCD, apenas adicionando algumas linhas. Claro que pode-se criar um menu extenso, com muitos ítens de submenu, mas o que fiz foi simplesmente adicionar um submenu a cada botão de direção; apertando esquerda, aparece Esquerda: 4. Apertando então Select, aparece Submenu 4.

Agora trocarei a mensagem de esquerda e direita para Sensor 1 e Sensor 2 respectivamente. Quando pressionados, exibirão a mensagem "Exibir valor". Pressionando então select, exibirá o valor do sensor correspondente.

O código

Para aproveitar exatamente o mesmo código, pensei em criar alguns artifícios que me permitissem interagir com o fluxo original. Antes de Setup() adicionei algumas variáveis:

int veryOldKey = -1;
char submenu[5][16] = {"submenu 1      ",
"submenu 2      ",
"submenu 3      ",
"submenu 4      ",
"submenu 5      "};
int keyRepeated = 9;

No final do código, criei uma função para trocar a mensagem do display. Depois de testado, fiz com que exibisse o valor do sensor:

void menu(int botaoX, int lastClicked){
int i;

//se for select...
if (botaoX == 4 && oldkey != -1){
if (lastClicked == 3){
temperatura = (5.0 * freq1 * 100.0)/1024.0;
}
else if (lastClicked == 0){
temperatura = (5.0 * freq2 * 100.0)/1024.0;
}

if (lastClicked == 3 || lastClicked == 0){
mensagem = dtostrf(temperatura,2,2,buf);
Serial.println(mensagem);
//mensagem.toCharArray(conversor,16);
mensagem.getBytes(justBytes,7);
//strcpy(msgs[botaoX],submenu[lastClicked]);

for (i=0;i<17;i++){
msgs[botaoX][i] = ' ';
}
for (i=0;i<5;i++){
msgs[botaoX][i] = justBytes[i];
}
}
else{
for (i=0;i<5;i++){
msgs[botaoX][i] = ' ';
}
}

}
keyRepeated = botaoX;
}

Tem dois "ifs" no código verificando a mesma condição (ok, entendi, mas o código não é meu):

if (key != oldkey)

Logo abaixo dessa segunda condicional, deixei com as seguintes linhas:

veryOldKey = oldkey;
oldkey = key;
menu(key,veryOldKey);

Além disso, tive que modificar a classe do display em alguns lugares. Não vou entrar em detalhes sobre as mudanças.

Para fazer uso dos botões (C)ima e (B)aixo, coloquei a função de acender e apagar um LED. O display está devidamente configurado para a exibição da mensagem, mas por algum motivo ainda não descoberto, não acendi o LED. Quer tentar?
O código utilizado no display é esse:

#include <LCD4Bit_mod.h>

//create object to control an LCD.
//number of lines in display=1
LCD4Bit_mod lcd = LCD4Bit_mod(2);

//Key message
unsigned char msgs[5][17] = {"(D) Sensor 2 ","(C) LED On ","(B) LED Off ","(E) Sensor 1 "," "};
int adc_key_val[5] ={30, 150, 360, 535,760 };
int NUM_KEYS = 5;
int adc_key_in;
int key=-1;
int oldkey=-1;
int veryOldKey = -1;
unsigned char submenu[5][16] = {"submenu 1 ","submenu 2 ","submenu 3 ","submenu 4 ","submenu 5 "};
int keyRepeated = 9;
String mensagem = " ";
unsigned char justBytes[16] = {''};
unsigned char titulo[] = " suhanko.com ";
char buf[50];
//sensor1
float temperatura;
int freq1 = 0;

//sensor2
int freq2 = 0;

void setup() {
pinMode(13, OUTPUT); //we'll use the debug LED to output a heartbeat
Serial.begin(9600);

lcd.init();
//optionally, now set up our application-specific display settings, overriding whatever the lcd did in lcd.init()
//lcd.commandWrite(0x0F);//cursor on, display on, blink on. (nasty!)
lcd.clear();
lcd.printIn(titulo);
}

void loop() {
//leitura do sensor1
freq1 = analogRead(1);
freq2 = analogRead(2);

adc_key_in = analogRead(0); // read the value from the sensor
digitalWrite(13, HIGH);

key = get_key(adc_key_in); // convert into key press
if (key != oldkey){ // if keypress is detected
delay(50); // wait for debounce time
adc_key_in = analogRead(0); // read the value from the sensor
key = get_key(adc_key_in); // convert into key press
if (key == -1){key = oldkey;}
if (key != oldkey){
veryOldKey = oldkey;
oldkey = key;
menu(key,veryOldKey);
Serial.println(key);
Serial.println(veryOldKey);
if (key >=0){
lcd.cursorTo(2, 0); //line=2, x=0
/*
De 0 a 4 sao as chaves. A partir daqui pode-se
chamar um metodo que trate, gerencie uma matriz
e trate um menu.
Para trocar a mensagem sera necessario trocar a
mensagem da matriz msgs
*/
lcd.printIn(msgs[key]);
}
}
}
//delay(1000);
digitalWrite(13, LOW);
}

// Convert ADC value to key number
int get_key(unsigned int input)
{
// return 30;

int k;
for (k = 0; k < NUM_KEYS; k++){
if (input < adc_key_val[k]){
return k;
}
}
if (k >= NUM_KEYS)
k = -1; // No valid key pressed
return k;
}

void menu(int botaoX, int lastClicked){
int i;

//se for select...
if (botaoX == 4 && oldkey != -1){
if (lastClicked == 3){
temperatura = (5.0 * freq1 * 100.0)/1024.0;
}
else if (lastClicked == 0){
temperatura = (5.0 * freq2 * 100.0)/1024.0;
}

if (lastClicked == 3 || lastClicked == 0){
mensagem = dtostrf(temperatura,2,2,buf);
Serial.println(mensagem);
//mensagem.toCharArray(conversor,16);
mensagem.getBytes(justBytes,7);
//strcpy(msgs[botaoX],submenu[lastClicked]);

for (i=0;i<17;i++){
msgs[botaoX][i] = ' ';
}
for (i=0;i<5;i++){
msgs[botaoX][i] = justBytes[i];
}
}
else{
for (i=0;i<5;i++){
msgs[botaoX][i] = ' ';
}

if (lastClicked == 1){
digitalWrite(5,HIGH);
}
else if (lastClicked == 2){
digitalWrite(5,LOW);
}
}

}
keyRepeated = botaoX;
}

Quando corrigir o problema, atualizo o post; como está certamente já é útil. Eis o video.

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.