



Para alguns projetos é essencial se ter uma boa Interface Homem-Máquina (HMI). E um teclado é um dos principais utilizados para a HMI.
Para um arduino, se tem este teclado Matricial 4x4:

Para este tutorial, é necessário utilizar:
Para um entendimento mais aprofundado dos componentes utilizados, veja os seguintes artigos, aqui mesmo do blog Eletrogate:Como dito antes, o teclado Matricial 4x4 ocupa 8 portas digitais de um microcontrolador.
Para resolver isso, podemos utilizar um Circuito Integrado para utilizar a comunicação I2C entre o teclado Matricial e o Arduino NANO. Este circuito integrado é o PCF8574.

Para fazer o endereçamento do CI, é necessário que se coloque o pino de endereçamento em LOW (0) ou em HIGH (1) [5V em microcontroladores de 5V ou 3V3 em microcontroladores de 3V3]. Utilize a tabela acima para saber o endereço I2C, conforme o endereçamento realizado.
O PCF8574 possui a seguinte pinagem:
A0: endereço de entrada 0
A1: endereço de entrada 1
A2: endereço de entrada 2
P0: I/O 0
P1: I/O 1
P2: I/O 2
P3: I/O 3
GND: Terra 0V
P4: I/O 4
P5: I/O 5
P6: I/O 6
P7: I/O 7
INT: interrupt output (active LOW)
SCL: Pino Serial Clock (Sincronização)
SDA: Pino Serial Data (Dados Seriais)
VCC: Tensão de Alimentação 5V ou 3V3
Para mais detalhes técnicos, consulte o datasheet PCF8574.
Para o desenvolvimento de hardware, siga o seguinte diagrama:
O hardware é composto de um Arduino NANO como microcontrolador, um display LCD 16x2 com comunicação I2C para exibição dos dados e um Teclado Matricial com comunicação I2C.
Utilizaremos o display LCD para exibir as informações que estão ocorrendo no microcontrolador. O Teclado servirá para inserir a senha no sistema.
Para desenvolvermos o software para este tutorial que irá ser carregado para o microcontrolador do Arduino NANO, devemos fazer download de duas bibliotecas: a Keypad e a Keypad_I2C.
Para instalar a biblioteca Keypad, abra o gerenciador de Bibliotecas da Arduino IDE, na barra de pesquisa digite: ‘Keypad’. Clique para instalar no resultado que corresponder o nome da biblioteca e o autor da biblioteca. O autor da biblioteca é o 'Community https://github.com/Chris--A/Keypad'. Para mais informações da biblioteca, acesse este link.
Para instalar a biblioteca Keypad_I2C, acesse o link https://github.com/joeyoung/arduino_keypads/archive/refs/heads/master.zip. Na Arduino IDE, em Sketch -> Incluir biblioteca -> Adicionar biblioteca .ZIP; Selecione o arquivo .ZIP que foi feito o download anteriormente através do link. Para mais informações da biblioteca, acesse este link.
Após instaladas as bibliotecas, cole o seguinte código na IDE Arduino:
/***************************************************
Teclado Matricial I2C 4×4 e Sistema de Login com Arduino Nano Exemplo
Criado em 30 de Julho de 2021 por Michel Galvão
****************************************************/
// Inclusão das bibliotecas
#include <Wire.h>
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
// Definição de endereço I2C do teclado matricial
#define enderecoTeclado 0x26
// Definição de pino do Buzzer para Feedback de Aperto de Tecla
#define pinoBuzzer 2
// número de linhas no teclado
const byte linhas = 4;
// número de colunas no teclado
const byte colunas = 4;
String senha = "159630"; // armazena a senha para efetuar Login
// array que armazena as teclas (Mapeação de teclas)
char keys[linhas][colunas] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
// Definição dos pinos do PCF8574
byte rowPins[linhas] = {0, 1, 2, 3}; // conecta-se aos pinos de linha do teclado
byte colPins[colunas] = {4, 5, 6, 7}; // conecta-se aos pinos de coluna do teclado
// Cria um objeto para o teclado, com os parâmetros mapa de teclas, nº de linhas no teclado, nº de colunas no teclado,
//endereço I2C do teclado e o tipo de Expansor de Porta utilizado (Esta biblioteca, em específico, suporta os chips PCF8574, PCF8574A e PCF8575).
Keypad_I2C teclado(makeKeymap(keys), rowPins, colPins, linhas, colunas, enderecoTeclado, PCF8574 );
// Cria um objeto para o display lcd, com os parâmetros endereço I2C do display,
// nº de colunas no display, e nº de linhas no display
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
lcd.init(); // Inicializa o Display LCD
lcd.clear(); // Limpa a tela LCD
lcd.backlight(); // Deixa a luz de fundo do siplay LCD ligada
lcd.setCursor(0, 0);
lcd.print("Exemplo de Login");
lcd.setCursor(0, 1);
lcd.print("com Teclado I2C ");
pinMode(pinoBuzzer, OUTPUT);
digitalWrite(pinoBuzzer, LOW);
Wire.begin(); // Inicializa a Comunicação I2C
teclado.begin(makeKeymap(keys)); // Inicializa o Teclado Matricial I2C
delay(1500);
lcd.clear(); // Limpa a tela LCD
}
void loop() {
lcd.setCursor(0, 0);
lcd.print(millis() / 1000); // Exibe, ilustrativamente, o tempo em segundos desde que o programa se iniciou
lcd.print(" segundos ");
lcd.setCursor(0, 1);
lcd.print("Tecla A p/ logar");
char tecla = teclado.getKey(); // armazena em uma variável o retorno da tecla obtida
if (tecla) { // se há alguma tecla,...
feedbackSomClique(); // emite um som no buzzer para dar feedback ao usuário de que alguma tecla foi pressionada
if (tecla == 'A') { // se a tecla pressionada foi a tecla A,...
if (efetuaLogin()) // inicia-se o processo para se logar
{
lcd.setCursor(0, 0);
lcd.print("Voce esta logado"); // Caso o usuário efetuar o login com a senha correta, é exibida a mensagem de que está logado
lcd.setCursor(0, 1);
lcd.print(" ");
delay(1500);
lcd.clear();
}
}
}
}
bool efetuaLogin() {
/*
Instruções para o usuário de como proceder com as teclas.
*/
lcd.setCursor(0, 0);
lcd.print("Insira senha: ");
lcd.setCursor(0, 1);
lcd.print("Teclas de 0 a 9 ");
delay(1500);
lcd.setCursor(0, 1);
lcd.print("Tecla # - ENTER ");
delay(1500);
lcd.setCursor(0, 1);
lcd.print("Tecla * - APAGAR");
delay(1500);
lcd.setCursor(0, 1);
lcd.print("Tecla B - SAIR ");
delay(1500);
lcd.clear();
String senhaInserida; // Váriavel para armazenar a senha inserida pelo usuário
String senhaEscondidaExibicao; // Váriavel para armazenar a exibição de caracteres '*' para cada numero inserido pelo usuário
int numeroTentativas = 0; // Váriavel para armazenar o número de tentativas que o usuário executou para se logar
int numeroMaximoTentativas = 3; // Váriavel para armazenar o número máximo de tentativas para que o usuário possa se logar
while (true) { // loop para inserção de senha
lcd.blink(); // faz o cursor do display ficar piscando
char tecla = teclado.getKey(); // armazena em uma variável o retorno da tecla obtida
if (tecla) { // se alguma tecla foi obtida, ...
feedbackSomClique(); // efetua o som de feedback de clique para o usuário
if (tecla == '1' || tecla == '2' || tecla == '3' || tecla == 'A') {
// se alguma tecla da linha 1 do teclado for apertada, temos que fazer debounce, pois se não o microcontrolador irá contabilizar vários cliques. Isso só ocorre na linha 1.
delay(250);
}
if (tecla == '#') { // se a tecla pressionada foi a # (ENTER), ...
if (senhaInserida == senha) { // compara se a senha inserida pelo usuário é igual a senha para fazer login
lcd.noBlink(); // faz o cursor do dislpay LCD parar de piscar
feedbackSomLoginBemSucedido(); // efetua o som de feedback de login bem sucedido
return true; // retorna true para a chamada da função
} else { // se a senhas não forem iguais, ...
lcd.noBlink(); // faz o cursor do dislpay LCD parar de piscar
numeroTentativas++; // incrementa a váriavel de número de tentativas do usuário
senhaInserida = ""; // "zera" a váriavel senhaInserida
senhaEscondidaExibicao = ""; // "zera" a váriavel senhaEscondidaExibicao
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Senha Incorreta ");
lcd.setCursor(0, 1);
lcd.print("Tentativa ");
lcd.print(numeroTentativas);
lcd.print(" de ");
lcd.print(numeroMaximoTentativas);
feedbackSomFalhaLogin(); // efetua o som de feedback de login falhado
lcd.clear();
if (numeroTentativas >= numeroMaximoTentativas) { // testa se o número de tentativas for igual ou superior ao número máximo de tentativas
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tentat. Zeradas ");
lcd.setCursor(0, 1);
lcd.print("Entre novamente ");
feedbackSomTentativasZeradas();
lcd.clear();
return false; // caso o usuário chegue ou ultrapasse o número máximo de tentativas, retorna false para a chamada da função
}
}
} else if (tecla == '*') { // se não, se a tecla pressionada foi a * (APAGAR), ...
// remove o último caractere da váriavel senhaInserida. O caractere a ser removido é o de número que corresponda ao número total de caracteres da váriavel subtraido 1.
senhaInserida.remove(senhaInserida.length() - 1);
senhaEscondidaExibicao.remove(senhaEscondidaExibicao.length() - 1); // também remove o último caractere da váriavel senhaEscondidaExibicao
lcd.clear();
lcd.print(senhaEscondidaExibicao);
} else if (tecla == 'B') { // se a tecla pressionada foi a B (SAIR), ...
return false; // retorna false para a chamada da função
} else if (!isAlpha(tecla)) { // se a tecla pressionada não for nenhuma letra, ...
senhaInserida += tecla; // adiciona a tecla pressionada para a váriavel senhaInserida
senhaEscondidaExibicao += '*'; // adiciona o caractere '*' para a váriavel senhaEscondidaExibicao
lcd.clear(); // limpa o display
lcd.print(senhaEscondidaExibicao); // mostra a váriavel senhaEscondidaExibicao
}
}
}
}
// função de toque do buzzer para feedback do aperto da tecla
void feedbackSomClique() {
digitalWrite(pinoBuzzer, HIGH);
delay(25);
digitalWrite(pinoBuzzer, LOW);
}
// função de toque do buzzer para feedback de Falha de Login
void feedbackSomFalhaLogin() {
digitalWrite(pinoBuzzer, HIGH);
delay(50);
digitalWrite(pinoBuzzer, LOW);
delay(50);
digitalWrite(pinoBuzzer, HIGH);
delay(50);
digitalWrite(pinoBuzzer, LOW);
delay(50);
digitalWrite(pinoBuzzer, HIGH);
delay(50);
digitalWrite(pinoBuzzer, LOW);
delay(50);
digitalWrite(pinoBuzzer, HIGH);
delay(50);
digitalWrite(pinoBuzzer, LOW);
delay(50);
digitalWrite(pinoBuzzer, HIGH);
delay(50);
digitalWrite(pinoBuzzer, LOW);
delay(50);
digitalWrite(pinoBuzzer, HIGH);
delay(50);
digitalWrite(pinoBuzzer, LOW);
}
// função de toque do buzzer para feedback de Tentativas Zeradas
void feedbackSomTentativasZeradas() {
digitalWrite(pinoBuzzer, HIGH);
delay(500);
digitalWrite(pinoBuzzer, LOW);
delay(500);
digitalWrite(pinoBuzzer, HIGH);
delay(500);
digitalWrite(pinoBuzzer, LOW);
delay(500);
digitalWrite(pinoBuzzer, HIGH);
delay(500);
digitalWrite(pinoBuzzer, LOW);
}
// função de toque do buzzer para feedback de Login bem Sucedido
void feedbackSomLoginBemSucedido() {
digitalWrite(pinoBuzzer, HIGH);
delay(100);
digitalWrite(pinoBuzzer, LOW);
delay(50);
digitalWrite(pinoBuzzer, HIGH);
delay(100);
digitalWrite(pinoBuzzer, LOW);
}
No código, inclui-se primeiro as bibliotecas:
Depois temos as definições do pino do Buzzer e do endereço I2C do Display LCD.
Após isso, criamos duas variáveis: uma para a quantidade de linhas no teclado e outra para a quantidade de colunas no teclado. Também criamos uma variável chamada 'senha', para armazenar a senha correta para fazer o login. Em seguida, criamos um array para armazenar as teclas do teclado. Definimos também os pinos do CI PCF8574 associados ao teclado em duas variáveis: uma para as colunas e outra para linhas. Logo após, criamos um objeto da classe Keypad_I2C informando como parâmetros o array que armazenamos as teclas do teclado, número de linhas no teclado, o número de colunas no teclado, o endereço I2C do teclado e o tipo de Expansor de Porta utilizado (PCF8574).
Em seguida, criamos um objeto da classe LiquidCrystal_I2C, informando o endereço I2C do Display LCD, o número de colunas no display e o número de linhas no display.
Em void setup (inicialização do programa) configuramos:



loop (programa principal), mostramos no display lcd o tempo desde quando o programa do microcontrolador foi iniciado, apenas ilustrativamente.
efetuaLogin(), ao inicializarmos-a, mostramos ao usuário instruções de como se deve proceder para efetuar o login:Em seguida, criamos algumas variáveis para armazenar a senha inserida pelo usuário, a exibição de caracteres '*' para cada numero inserido pelo usuário, o número de tentativas que o usuário executou para se logar e o número máximo de tentativas para que o usuário possa se logar.
efetuaLogin(), entramos em um laço de repetição que irá ficar esperando a inserção da senha pelo usuário. Começamos fazendo o cursor do display ficar piscando. Logo após, armazenamos em uma variável a tecla obtida do teclado matricial. Testamos em uma estrutura condicional, se alguma tecla foi obtida do teclado. Caso foi obtida alguma tecla, chamamos a função feedbackSomClique(), para efetuar o som de feedback de clique no teclado. Em seguida, testamos se alguma tecla da linha 1 do teclado foi clicado. Se foi clicado, fazemos um tempo de pausa de 250 milissegundos. É necessário este tempo de pausa, pois caso o usuário continue segurando alguma tecla da linha 1 do teclado, o sistema irá interpretar como vários cliques. isto só é necessário para teclas da linha 1. As outras linhas não ocorrem este problema.
Se sim, testamos se a senha inserida é idêntica à senha correta. Caso as senhas forem iguais, fazemos o cursor do display LCD parar de piscar, efetuams o som de feedback de login bem sucedido com a função feedbackSomLoginBemSucedido(), e retornamos true para a chamada da função.
Se as tecla senhas não forem iguais, fazemos o cursor do display LCD parar de piscar, incrementamos a variável de número de tentativas do usuário, esvaziamos a variável de senha inserida e de senha em caracteres escondidos e, exibimos ao usuário que foi inserida uma senha incorreta, além de também exibirmos, também, o número de tentativas restantes. Executamos o som de feedback de login falhado através da função feedbackSomFalhaLogin(). Em seguida, verificamos se o número de tentativas realizadas forem iguais ou superiores ao número máximo de tentativas. Se o número de tentativas forem superiores ou iguais, exibimos uma mensagem no display LCD informando isso, executamos o som de tentativas zeradas através da função feedbackSomTentativasZeradas() e retornamos false para a chamada da função.
Se sim, temos que remover o último caractere da String senhaInserida, através do método remove, em que informamos o índice do caractere à ser removido. Para informarmos o índice do caractere à ser removido, pegamos o comprimento da String e subtraímos 1. Também precisamos remover o último caractere da variável senhaEscondidaExibicao, fazendo o mesmo processo anterior. Em seguida exibimos no display LCD a String senhaEscondidaExibicao.
Se sim, retornamos false para a chamada da função, saindo, assim, da entrada de senha pelo usuário.
Caso a tecla não seja nenhum caractere alfabético e sim numérico, concatenamos o caractere clicado com a variável senhaInserida. Também concatenamos o caractere '*' com a variável senhaEscondidaExibicao. Em seguida, limpamos a tela do display LCD e exibimos no display a String senhaEscondidaExibicao.
feedbackSomClique(), feedbackSomFalhaLogin(), feedbackSomTentativasZeradas() e feedbackSomLoginBemSucedido() são funções para executar sons de feedback no buzzer.Veja o vídeo abaixo para ver o funcionamento final:
Com este exemplo de transformação do teclado matricial comum em um teclado matricial com comunicação I2C, é possível fazer projetos maiores, já que diminui-se a ocupação de portas digitais. Também, com exemplo de login no arduino com o teclado matricial I2C, abre-se portas para construção de projetos em que se exija segurança. Caso tenha ficado alguma dúvida, nos contate através dos comentários. Espero que o tenha ajudado e até a próxima. Conheça a Metodologia Eletrogate e ofereça aulas de robótica em sua escola!
|
As portas digitais do seu microcontrolador estão quase todas ocupadas e você ainda tem que implementar uma interface Homem-Máquina com um teclado Matricial? Então este post é para você.
Encontre tudo na Loja Eletrogate com frete grátis para compras acima de R$ 200