0

Leitura do Teclado Matricial e Multiplexação

Teclados são geralmente utilizados em aplicações na qual o utilizador possa interagir com um sistema , como computadores, calculadoras, comandos remotos entre outros. Imagine que desejamos utilizar um teclado com 64 botões na 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, numa placa Arduino Uno por exemplo, impossível. Para evitar este problema podemos ligar as teclas do formato matriz 8×8 gastando apenas 16 pinos e utilizar uma técnica chamada de Multiplexação para realizar a leitura das teclas.

Para demonstrar essa técnica de leitura utilizaremos um Teclado Matricial de membrana 4×4.

Este tutorial requer conhecimento em assuntos abordados em post anteriores. Caso tenha alguma dificuldade em acompanhar os assuntos abordados aqui, consulte alguns dos nossos tutoriais anteriores:

 

O teclado Matricial

Este teclado como o nome indica é formado por 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 como podemos ver na figura abaixo representada.

 

Ligação interna de um teclado matricial 4×4

 

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)

 

Pinagem do teclado matricial de membrana

A Multiplexação

Esta técnica consiste em compartilhar o mesmo barramento por vários dispositivos, entretanto apenas um deles utilizará o barramento na sua vez. No caso do teclado matricial, os barramentos serão linhas do teclado e os dispositivos as colunas. Logo devemos permitir que apenas uma coluna se ligue as linhas por vez. Para desligarmos as colunas que não devem ser lidas devemos configurá-las como entradas (alta impedância).

Algoritmo de varredura simples

No início os pinos ligados 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 verificar se houve alguma alteração nas linhas. Caso haja uma alteração numa linha em que 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ê:

 

Teclas Fantasmas

 

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 com pressionada. Para solucionarmos este problema devemos adicionar um díodo em cada botão para evitar que estes caminhos indesejados sejam formados, como mostra a figura abaixo.

 

Solução para teclas fantasmas

Bibliotecas

A biblioteca Keypad é uma biblioteca especializada na interação de teclados matriciais. O algoritmo de varredura consegue detetar se uma tecla esta pressionada, solta ou sendo sendo segura, entre outras funções.

 

#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.
}

 

Artigo gentilmente cedido por Vida de Silicio

 

Todos os produtos utilizados neste artigo podem ser encontrados na Loja de Eletrónica e Robótica – ElectroFun.

Gostaram deste artigo? Deixem o vosso comentário no formulário a baixo e partilhem com os vossos amigos.

Não se esqueçam de fazer like na nossa Página no Facebook.

Podem ainda colocar as vossas dúvidas no nosso Forum da Comunidade Arduino em Portugal ou no nosso Grupo no Facebook Arduino Portugal – Qual o teu projeto?

Comments

Comentários

ArduinoPortugal.pt

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *

To use BrandCaptcha you must get an API Key