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 4×4:
Teclado Matricial. Fonte da Imagem: eletrogate.com
Ele se destaca por ter 16 teclas de entrada, mas se tem a desvantagem de ocupar 8 portas digitais do microcontrolador. Mas neste tutorial você aprenderá a contornar esta desvantagem e faze-lo utilizar somente duas portas de comunicação do Arduino, as portas I2C. Também iremos demonstrar como fazer um sistema de login utilizando o Teclado Matricial convertido para comunicação I2C.
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 4×4 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.
CI PCF8574. Fonte da Imagem: eletrogate.com
O Circuito Integrado PCF8574 fornece expansão de Entrada / Saída por meio do barramento I2C bidirecional de dois fios (relógio serial (SCL), dados seriais (SDA)). A tensão de operação dele está entre 2,5 V e 6 V. Isso quer dizer que ele pode ser utilizado tanto em microcontroladores que operam em 5V, como quase todos modelos de Arduino, quanto em microcontroladores que operam em 3,3V, como ESP32 ou ESP8266. Este CI possui baixo consumo de corrente, cerca de 2,5uA (de acordo com o datasheet), o que é excelente para projetos que utilizem bateria como alimentação.
O CI PCF8574 possui três pinos para definir o endereço I2C de hardware: A0, A1, A2. Essa característica permite que até oito de cada dispositivo PCF8574 estejam no mesmo barramento I2C de um microcontrolador, então pode haver até 8 desses expansores de I/O PCF8574 juntos no mesmo barramento I2C, suportando até 64 I/O ‘s.
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 16×2 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:
Inicializando o Display, limpando o display e ligando a luz de backlight do mesmo.
Definimos o pino digital à que o buzzer está conectado como Saída, e o inicializamos desligado.
Inicializamos a comunicação I2C e o teclado matricial.
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:Teclas de 0 a 9 = Teclas de inserção da senha;
Tecla # = Tecla para confirmar a entrada da senha;
Tecla * = Tecla para apagar o último caractere da senha;
Tecla B = Tecla para sair do sistema de inserção de senha;
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!
|
A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.
Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!