Teclado Matricial e Multiplexação
Teclados são geralmente utilizados em aplicações na qual o usuário precisar interagir com um sistema, como computadores, calculadoras, controles remotos entre outros. Imagine que desejamos utilizar um teclado com 64 botões em nossa aplicação. Caso cada botão seja ligado diretamente a um pino do microcontrolador, gastaríamos 64 pinos o que tornaria a implementação dessa interface, em uma placa Uno por exemplo, impossível. Para evitar este problema podemos conectar as teclas no formato de matriz 8×8 gastando agora apenas 16 pinos e utilizar uma técnica chamada multiplexação para realizar a leitura das teclas. Para demonstrar essa técnica de leitura utilizaremos um teclado matricial de membrana 4×4 junto com um Arduino.
Esse tutorial requer conhecimento em assuntos explicados em posts anteriores. Caso tenha dificuldades em acompanhar os assuntos abordados aqui, confira alguns de nossos tutoriais anteriores:
[toc]
O Teclado Matricial
Este teclado como o nome indica é formado de botões organizados em linhas e colunas de modo a formar uma matriz. Quando pressionado, um botão conecta a linha com a coluna na qual está ligado. A figura 1 ilustra a ligação matricial.
O teclado matricial possui a seguinte pinagem:
- Pino 1 (Esquerda) – Primeira Linha (L1)
- Pino 2 – Segunda Linha (L2)
- …
- Pino 5 – Primeira Coluna (C1)
- …
- Pino 8 – Quarta Coluna (C4)
A Multiplexação
Essa técnica consiste no compartilhamento do mesmo barramento por vários dispositivos, entretanto apenas um deles utilizará o barramento por vez. No caso do teclado matricial, os barramentos serão as linhas do teclado e os dispositivos as colunas. Logo devemos permitir que apenas uma coluna se ligue as linhas por vez. Para desconectarmos as colunas que não devem ser lidas devemos configurá-las como entradas (alta impedância).
Mão à obra – Algoritmo de varredura simples
Componentes utilizados
Para esse projeto usaremos os seguintes componentes:
Programação
No início os pinos conectados as linhas serão configurados como entradas com pull up e as colunas como entradas (alta impedância). A varredura consiste em ativar uma coluna por vez (saída em nível lógico baixo) e checar se houve uma alteração nas linhas. Caso uma alteração em uma linha seja identificada, o bounce da tecla deve ser devidamente tratado para que possamos finalmente afirmar que o botão foi pressionado.
const uint8_t row_size = 4; // Quantidade de linhas. const uint8_t col_size = 4; // Quantidade de colunas. const uint8_t row_pin[row_size] = {4, 5, 6, 7}; // Pinos que estão ligados as linhas. const uint8_t col_pin[col_size] = {8, 9, 10, 11}; // Pinos que estão ligados as colunas. const char keys[row_size][col_size] = { // Mapa de teclas do teclado. { '1', '2', '3', 'A' }, { '4', '5', '6', 'B' }, { '7', '8', '9', 'C' }, { '*', '0', '#', 'D' } }; bool stable[row_size][col_size]; // Guarda o último estado estável dos botões. bool unstable[row_size][col_size]; // Guarda o último estado instável dos botões. uint32_t bounce_timer; // Executa o algoritmo de varredura simples. void scan() { for (uint8_t e = 0; e < col_size; ++e) { // Varre cada coluna. pinMode(col_pin[e], OUTPUT); digitalWrite(col_pin[e], 0); // Habilita a coluna "c". for (uint8_t r = 0; r < row_size; ++r) { // Varre cada linha a procura de mudanças. if (changed(r, e)) { // Se houver uma mudança de estado. Serial.print(keys[r][e]); Serial.print(" : "); // Imprime a tecla que sofreu a alteração Serial.println(stable[r][e]); // e seu estado atual. } } pinMode(col_pin[e], INPUT); // Desabilita a coluna "c". } } // Checa se o estado do botão foi alterado além de tratar os efeitos de sua trepidação. bool changed(const uint8_t& row, const uint8_t& col) { bool now = digitalRead(row_pin[row]); // Lê o estado do botão na linha especificada. if (unstable[row][col] != now) { // Checa se houve mudança. bounce_timer = millis(); // Atualiza timer. unstable[row][col] = now; // Atualiza estado instável. } else if (millis() - bounce_timer > 10) { // Checa o tempo de trepidação acabou. if (stable[row][col] != now) { // Checa se a mudança ainda persiste. stable[row][col] = now; // Atualiza estado estável. return 1; } } return 0; } void setup() { Serial.begin(9600); // Configura o estado inicial das linhas como entradas com pull up. for (uint8_t r = 0; r < row_size; ++r) { pinMode(row_pin[r], INPUT_PULLUP); } // Configura o estado inicial das linhas como entradas. for (uint8_t c = 0; c < col_size; ++c) { pinMode(col_pin, INPUT); } // Define estado inicial dos botões; for (uint8_t c = 0; c < col_size; ++c) { for (uint8_t r = 0; r < row_size; ++r) { stable[r] = 1; } } } void loop() { scan(); }
Pressionando várias teclas
Quando pressionamos 3 ou mais teclas um efeito conhecido como tecla fantasma pode ocorrer, vamos observar a animação a seguir para entender o porquê:
Infelizmente os problemas não acabam por aqui. Caso a tecla fantasma seja pressionada e em seguida uma das teclas anteriores for solta, a tecla que foi solta ainda será considerada como pressionada. Para solucionarmos este problema devemos adicionar um diodo em cada botão para evitar que estes caminhos indesejados sejam formados, como mostra a Figura 4.
Bibliotecas
A biblioteca Keypad é uma biblioteca especializada no interfaceamento de teclados matriciais. Seu algoritmo de varredura consegue detectar se uma tecla esta apertada, solta ou sendo segurada, entre outras funções.
Exemplo de aplicação
#include <Keypad.h> const uint8_t row_size = 4; // Quantidade de linhas. const uint8_t col_size = 4; // Quantidade de colunas. const uint8_t row_pin[row_size] = {4, 5, 6, 7}; // Pinos que estão ligados as linhas. const uint8_t col_pin[col_size] = {8, 9, 10, 11}; // Pinos que estão ligados as colunas. const char keys[row_size][col_size] = { // Mapa de teclas do teclado. { '1', '2', '3', 'A' }, { '4', '5', '6', 'B' }, { '7', '8', '9', 'C' }, { '*', '0', '#', 'D' } }; Keypad keypad = Keypad(makeKeymap(keys), row_pin, col_pin, row_size, col_size); void setup() { Serial.begin(9600); } void loop() { char key = keypad.getKey(); // Retorna a última tecla que foi apertada. if (key != NO_KEY) Serial.println(key); // Imprime tecla na porta serial. }
Fechamento
Esperamos que tenham gostado, deixe seu comentário com duvidas, sugestões ou com a foto ou vídeo de seu projeto!! Compartilhe à vontade.
Estudante de Engenharia Elétrica e integrante do PET Elétrica UFES.
6 Comments
Deixe uma pergunta, sugestão ou elogio! Estamos ansiosos para ter ouvir!Cancelar resposta
Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.
Muito bom o artigo! Os diodos usados em teclados matriciais devem sempre ser de silício e de comutação rápida, 4ns. Ou seja, 1N4148, 1N914 por exemplo. Estou fazendo manutenção em um órgão de uma igreja e enquanto não chega um circuito integrado obsoleto, que localizei um na Franca, estou implementando um Arduino MEGA que será ligado no teclado matricial original do órgão 8×8. A conexão USB do Arduino será conectada a um Macbook que ira disparar os arquivos SAMPLES com os sons de órgãos de tubo.
qualquer diodo
Cara muito bom o artigo, parabéns!!!
Tem dois erros de compilação no primeiro programa.
Na linha 58 deveria ser assim:
pinMode(col_pin[c], INPUT);
e na linha 64 deveria ser:
stable[r][c] = 1;
Estou fazendo um projeto que irei utilizar um teclado matricial e um Display LCD e um arduino nano,
O que estou bolando é uma máquina de contar peças, fiz uma programação com uma barreira óptica, o que eu quero chegar nesse projeto, é a utilização do teclado matricial para controlar o proprio display LCD, teria algum email para enviar o projeto ?
Qual o diodo você utilizou no esquema?