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.

Figura 1 - Ligação interna de um teclado matricial 4x4.
Figura 1 – 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)
Figura 2 - Pinagem do teclado matricial de membrana.
Figura 2 – Pinagem do teclado matricial de membrana.

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ê:

Figura 3 - Teclas fantasmas teclado matricial
Figura 3 – 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 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.

Figura 4 – Solução para teclas fantasmas.

 


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.

Clique para baixar a biblioteca Keypad

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.

 

Apostila Arduino Básico

 

Privacy Preference Center