/*
2025
*/
// INCLUSÃO DA BIBLIOTECA
#include <rdm6300.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
// ===== Declarações e Definições das Bibliotecas ===== //
LiquidCrystal_I2C lcd(0x27, 20, 4); // Cria o objeto LCD | sint.: nome(endereço, numColunas, numLinhas);
byte seta[8] = { // Criando simbolo 'seta'
B00000,
B11000,
B11110,
B11111,
B11110,
B11000,
B00000,
B00000
};
byte setabaixo[8] = { // Criando simbolo 'seta'
B00000,
B11111,
B11111,
B01110,
B01110,
B00100,
B00000,
B00000
};
// DEFINIÇÃO DO PINO DE RX
#define PINO_RX 5
// CRIANDO A VARIÁVEL TIPO RDM6300
Rdm6300 leitor;
// MAPEAMENTO DE HARDWARE
// Controle
#define btb 25 // Up
#define btd 27 // Down
#define bte 33 // Enter
#define btu 26 // Back
bool btu_f, btu_fa, btb_f, btb_fa, btd_f, btd_fa, bte_f, bte_fa, compra, qnt_f;
int line_f, line_list, menu, sub_menu, sub_menu_f, tag_i, n, y, qnt;
const int menu_max = 4;
long int tag;
char* telas[menu_max] = {
"Total: R$ ",
"Adicionar",
"Remover",
"Finalizar Compra"
};
long allTags[] = {
0, // Manter sempre o primeiro como zero, ele é o parâmetro para cancelar função e não identificar tags
12793390,
12780323,
3468522,
3414016,
3347941,
3270061,
3260341,
3181162
};
int range = sizeof(allTags);
float preco[sizeof(allTags)] = {
0.0,
1.99,
4.5,
5.6,
6.5,
7.0,
8.49,
3.5,
4.7
};
char* produto[sizeof(allTags)] = {
"Null",
"Bombom",
"Bolacha",
"Leite",
"Suco",
"Maizena",
"Nescau",
"Macarrao",
"Coca Lata"
};
int lista[sizeof(allTags)] = { // Lista da quantidade de itens comprados
0,
0,
0,
0,
0,
0,
0,
0,
0
};
// Pequeno banco de dados
float total, total_f;
unsigned long int t, t_afk = 10000, t_f;
// ========== Declaração de Funções ========== //
void controle(int estado_compra), attLcd(), functions(int menus);
int lerRFID();
void setup() {
Serial.begin(112500); // Esse valor é referente a frequência de comunicação serial de um Esp32, NUNCA ALTERE
leitor.begin(PINO_RX); // Inicializando o leitor
lcd.init(); // INICIA A COMUNICAÇÃO COM O DISPLAY
lcd.backlight(); // LIGA A ILUMINAÇÃO DO DISPLAY
lcd.clear(); // LIMPA O DISPLAY
lcd.createChar(0, seta); // Criando caracter com simbolo 'seta'
lcd.createChar(1, setabaixo); // Criando caracter com simbolo 'seta p/ baixo'
pinMode(btu, INPUT_PULLUP);
pinMode(btd, INPUT_PULLUP);
pinMode(bte, INPUT_PULLUP);
pinMode(btb, INPUT_PULLUP);
attLcd(); // Atualiza a primeira vez no LCD
}
void loop() {
controle(compra);
if (sub_menu > 1) functions(menu);
}
void controle(int estado_compra) // Ler botões
{
// Ao pressionar botão:
if (!digitalRead(bte)) bte_f = 0x01;
if (!digitalRead(btb)) btb_f = 0x01;
if (!digitalRead(btu)) btu_f = 0x01;
if (!digitalRead(btd)) btd_f = 0x01;
switch (estado_compra) {
case false:
// Ao despressionar Enter
if (digitalRead(bte) && bte_f) {
delay(100);
compra = true; // Inicia-se as compras
sub_menu++;
attLcd();
// Comando a ser executado
bte_f = 0x00;
}
break;
case true:
// Ao despressionar Enter
if (digitalRead(bte) && bte_f) {
delay(100);
if (sub_menu < 2) {
sub_menu++;
attLcd();
sub_menu_f = sub_menu;
}
// Comando a ser executado
bte_f = 0x00;
}
// Ao despressionar Back
if (digitalRead(btb) && btb_f) {
delay(100);
if (sub_menu > 1) {
sub_menu--;
attLcd();
sub_menu_f = sub_menu;
}
// Comando a ser executado
btb_f = 0x00;
}
// Ao despressionar Up
if (digitalRead(btu) && btu_f) {
delay(100);
if (sub_menu == 1) {
if (menu > 0) {
menu--;
if (line_f > 0) line_f--;
attLcd();
}
// Comando a ser executado
}
btu_f = 0x00;
}
// Ao despressionar Down
if (digitalRead(btd) && btd_f) {
delay(50);
if (sub_menu == 1) {
if (menu < menu_max - 1) {
menu++;
if (line_f < 3) line_f++;
attLcd();
}
}
btd_f = 0x00;
}
// Comando a ser executado
break;
}
}
void functions(int menus) {
switch (menus) {
// FUNÇÃO TOTAL
case 0:
if (!qnt_f) {
for (int k = 1; k < range; k++) {
if (k == 1) qnt = 0;
if (lista[k] > 0) qnt++;
}
qnt_f = !qnt_f;
if (!qnt) attLcd();
}
// OBSERVAÇÃO:
// y representa a quantidade de produtos que excedem o limite de espaço de linha disponível, por ex.:
// 3 linhas é o limite para exibição da lista de compra, porém, há 5 produtos no carrinho, então y seria 5 - 3 = 2.
// Portanto, sabendo que y = 2, podemos "descer" a lista duas vezes, para exibir os dois produtos excentes do limite de linha.
if (qnt > 3) {
if (!digitalRead(btu)) btu_f = 0x01;
if (!digitalRead(btd)) btd_f = 0x01;
if (digitalRead(btu) && btu_f) {
delay(100);
if (line_list > 0) {
line_list--;
attLcd();
} else if (y > 0) {
y--;
attLcd();
}
btu_f = 0x00;
}
// Ao despressionar Down
if (digitalRead(btd) && btd_f) {
delay(50);
if (line_list < 2) {
line_list++;
attLcd();
} else if ((qnt - 3) - y) {
y++;
attLcd();
}
btd_f = 0x00;
}
}
if (!digitalRead(btb)) btb_f = 0x01;
if (digitalRead(btb) && btb_f) {
btb_f = 0x00;
sub_menu--;
qnt_f = !qnt_f;
attLcd();
break;
}
break;
case 1:
tag_i = lerRFID();
lista[tag_i]++;
total += preco[tag_i];
attLcd();
total_f = total;
break;
case 2:
tag_i = lerRFID();
if (lista[tag_i] > 0) {
lista[tag_i]--;
total -= preco[tag_i];
attLcd();
total_f = total;
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("! Produto nao esta");
lcd.setCursor(0, 1);
lcd.print(" no carrinho !");
delay(2000);
}
break;
case 3:
break;
}
}
int lerRFID() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(byte(0));
lcd.print(" Aproxime a TAG");
lcd.setCursor(0, 1);
if (menu == 1) lcd.print(" para adicionar o");
else if (menu == 2) lcd.print(" para remover o");
lcd.setCursor(0, 2);
lcd.print(" produto");
tag = 0;
t = millis();
while (tag == 0 /*|| (millis() - t <= t_afk)*/) {
if (leitor.get_new_tag_id()) tag = leitor.get_tag_id(); // Se sim, adiciona esse valor à variável tag
if (!digitalRead(btb)) btb_f = 0x01;
if (digitalRead(btb) && btb_f) {
btb_f = 0x00;
sub_menu--;
attLcd();
break;
}
}
lcd.clear();
lcd.setCursor(0, 0);
for (int i = 1; i < range; i++) {
if (tag == allTags[i - 1]) tag = i;
else if (i >= range - 1) {
lcd.write(byte(0));
lcd.print(" ! Nao Cadastrado !");
delay(3000);
break;
}
}
return tag;
}
void attLcd() // Atualizar LCD
{
lcd.clear();
lcd.setCursor(0, 0);
// Comutar submenu
switch (sub_menu)
{
// Caso seja Sub Menu = 0
// Sub Menu Inicial
case 0: // Caso 0
lcd.write(byte(0));
lcd.print(" Iniciar Compra");
break;
// Caso seja Sub Menu = 1
// Imprimir opções de funções
case 1:
// Comutar posição do indicador de seleção
switch (line_f) {
// Indicador de seleção está na primeira linha
case 0:
// 1ª linha
lcd.write(byte(0)); // Imprime "> " na 1ª linha
lcd.print(" ");
lcd.print(telas[menu]); // Imprime tela com valor do menu atual
if (!menu) lcd.print(total, 2); // Caso menu == 0: Imprime tela com "Total R$"
// 2ª linha
lcd.setCursor(0, 1); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu + 1]); // Imprime tela com valor do menu + 1
// 3ª linha
lcd.setCursor(0, 2); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu + 2]); // Imprime tela com valor do menu + 2
// 4ª linha
lcd.setCursor(0, 3); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu + 3]); // Imprime tela com valor do menu + 3
break;
// Indicador de seleção está na segunda linha
case 1:
// 1ª linha
lcd.print(" ");
lcd.print(telas[menu - 1]); // Imprime tela com valor do menu - 1
if (!(menu - 1)) lcd.print(total, 2); // Caso menu == 0: Imprime tela com "Total R$"
// 2ª linha
lcd.setCursor(0, 1); // Troca a linha
lcd.write(byte(0)); // Imprime "> " na 2° linha
lcd.print(" ");
lcd.print(telas[menu]); // Imprime tela com valor do menu atual
// 3ª linha
lcd.setCursor(0, 2); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu + 1]); // Imprime tela com valor do menu + 1
// 4ª linha
lcd.setCursor(0, 3); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu + 2]); // Imprime tela com valor do menu + 2
break;
// Indicador de seleção está na terceira linha
case 2:
// 1ª linha
lcd.print(" "); // Imprime "> " na 1° linha
lcd.print(telas[menu - 2]); // Imprime tela com valor do menu - 2
if (!(menu - 2)) lcd.print(total, 2); // Caso menu == 0: Imprime tela com "Total R$"
// 2ª linha
lcd.setCursor(0, 1); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu - 1]); // Imprime tela com valor do menu - 1
// 3ª linha
lcd.setCursor(0, 2); // Troca a linha
lcd.write(byte(0)); // Imprime "> " na 3° linha
lcd.print(" ");
lcd.print(telas[menu]); // Imprime tela com valor do menu atual
// 4ª linha
lcd.setCursor(0, 3); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu + 1]); // Imprime tela com valor do menu + 1
break;
// Indicador de seleção está na quarta linha
case 3:
// 1ª linha
lcd.print(" ");
lcd.print(telas[menu - 3]); // Imprime tela com valor do menu - 3
if (!(menu - 3)) lcd.print(total, 2); // Caso menu == 0: Imprime tela com "Total R$"
// 2ª linha
lcd.setCursor(0, 1); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu - 2]); // Imprime tela com valor do menu - 2
// 3ª linha
lcd.setCursor(0, 2); // Troca a linha
lcd.print(" ");
lcd.print(telas[menu - 1]); // Imprime tela com valor do menu - 1
// 4ª linha
lcd.setCursor(0, 3); // Troca a linha
lcd.write(byte(0)); // Imprime "> " na 4° linha
lcd.print(" ");
lcd.print(telas[menu]); // Imprime tela com valor do menu atual
break;
}
break;
// Caso seja Sub Menu == 2
// Imprimir as ações das funções
case 2:
// Comutar menu selecionado
switch (menu) {
// Menu "Total"
case 0:
// Imprimir cabeçalho fixo apresentando o total da lista de compra
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(byte(1));
lcd.print(" ");
lcd.print(telas[menu]);
lcd.print(total, 2);
n = 1; // variável n indica o espaço de linha disponível para exibir os produtos de compra, sendo possível de 1 a 3
// Se nenhum produto foi adicionado ao carrinho:
if (!qnt) {
lcd.setCursor(0, 1); lcd.print(" Nenhum produto");
lcd.setCursor(0, 2); lcd.print(" foi adicionado ao");
lcd.setCursor(0, 3); lcd.print(" carrinho");
} else { // Senão, exibir a mini lista de produtos adicionados ao carrinho:
// Analisa se há produtos no carrinho
for (int j = 0; j < range; j++) {
// Comuta a posição do indicador de seleção da lista do carrinho:
switch (line_list) {
// Indicador de seleção está na primeira linha da lista do carrinho:
case 0:
// Se houver produto na posição "j + y" e o espaço de linha disponível não excedeu seu limite
if (lista[j + y] > 0 && n < 4) {
lcd.setCursor(0, n); // Posiciona cursor do LCD no espaço de linha disponível
if (n == 1) lcd.print("> "); // Imprime o indicador no 1° espaço de linha disponível relativo a posição "line_list"
else lcd.print(" ");
lcd.print(lista[j + y]); // Imprime a quantidade x de produtos da posição "j + y"
lcd.print(" ");
lcd.print(produto[j + y]); // Imprime o nome do produto da posição "j + y"
if (n < 3) n++; // Se n ainda não exceder o limite de linha disponível, passar para a próxima linha
else j = range; // Senão, sair da condição for
}
break;
// Indicador de seleção está na segunda linha da lista do carrinho:
case 1:
// Se houver produto na posição "j + y" e o espaço de linha disponível não excedeu seu limite
if (lista[j + y] > 0 && n < 4) {
lcd.setCursor(0, n);
if (n == 2) lcd.print("> "); // Imprime o indicador no 2° espaço de linha disponível relativo a posição "line_list"
else lcd.print(" ");
lcd.print(lista[j + y]); // Imprime a quantidade x de produtos da posição "j + y"
lcd.print(" ");
lcd.print(produto[j + y]); // Imprime o nome do produto da posição "j + y"
if (n < 3) n++; // Se n ainda não exceder o limite de linha disponível, passar para a próxima linha
else j = range; // Senão, sair da condição for
}
break;
// Indicador de seleção está na terceira linha da lista do carrinho:
case 2:
// Se houver produto na posição "j + y" e o espaço de linha disponível não exceder seu limite
if (lista[j + y] > 0 && n < 4) {
lcd.setCursor(0, n);
if (n == 3) lcd.print("> "); // Imprime o indicador no 3° espaço de linha disponível relativo a posição "line_list"
else lcd.print(" ");
lcd.print(lista[j + y]); // Imprime a quantidade x de produtos da posição "j + y"
lcd.print(" ");
lcd.print(produto[j + y]); // Imprime o nome do produto da posição "j + y"
if (n < 3) n++; // Se n ainda não exceder o limite de linha disponível, passar para a próxima linha
else j = range; // Senão, sair da condição for
}
break;
}
}
}
break;
// Menu "Adicionar Produto"
case 1:
if (sub_menu_f == sub_menu) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.setCursor(0, 0);
lcd.write(byte(1));
lcd.print(" TAG: ");
lcd.print(allTags[tag_i]);
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.print(produto[tag_i]);
lcd.setCursor(0, 2);
lcd.print(" Preco R$ ");
lcd.print(preco[tag_i], 2);
lcd.setCursor(0, 3);
lcd.print(" Quantidade: ");
lcd.print(lista[tag_i]);
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(byte(1));
lcd.print(" Total: ");
delay(500);
lcd.setCursor(0, 1);
lcd.print(" R$ ");
lcd.print(total_f, 2);
delay(500);
lcd.setCursor(0, 2);
lcd.print("+ R$ ");
lcd.print(preco[tag_i], 2);
delay(700);
lcd.setCursor(0, 3);
lcd.print("= R$ ");
lcd.print(total, 2);
delay(1500);
}
break;
case 2:
if (sub_menu_f == sub_menu) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.setCursor(0, 0);
lcd.write(byte(1));
lcd.print(" TAG: ");
lcd.print(allTags[tag_i]);
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.print(produto[tag_i]);
lcd.setCursor(0, 2);
lcd.print(" Preco R$ ");
lcd.print(preco[tag_i], 2);
lcd.setCursor(0, 3);
lcd.print(" Quantidade: ");
lcd.print(lista[tag_i]);
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(byte(1));
lcd.print(" Total: ");
delay(500);
lcd.setCursor(0, 1);
lcd.print(" R$ ");
lcd.print(total_f, 2);
delay(500);
lcd.setCursor(0, 2);
lcd.print("- R$ ");
lcd.print(preco[tag_i], 2);
delay(700);
lcd.setCursor(0, 3);
lcd.print("= R$ ");
lcd.print(total, 2);
delay(1500);
}
break;
case 3:
break;
}
}
Serial.print("Menu: ");
Serial.println(menu + 1);
Serial.print("Sub Menu: ");
Serial.println(sub_menu);
Serial.println("");
}