Teclado Prototípico de 64 Teclas com Arduino: Matriz com Registradores de Deslocamento
Componentes e Materiais Necessários
| Componente | Quantidade |
|---|---|
| Arduino UNO | 1 |
| 1N4148 – Diodo de Comutação Rápida de Propósito Geral | 64 |
| Chave Táctil, Atuação Superior | 64 |
| Headers de pinos | 1 |
| Registrador de Deslocamento 74HC595 | 1 |
Ferramentas e Máquinas Necessárias
- Ferro de solda (genérico)
Aplicativos e Serviços Online
- Arduino IDE
Sobre o Projeto
Atualização: Melhorei o código, veja "Atualização" no final.
Estou trabalhando atualmente em um projeto que terá um teclado integrado, o que apresentou um problema: como incluir um teclado no protótipo da placa de desenvolvimento? Não posso usar um teclado USB ou um teclado baseado em Arduino existente, porque o teclado no projeto real é conectado diretamente ao microcontrolador que gerencia todas as outras funções. Por isso, projetei esta matriz de teclado prototípica de 64 teclas baseada em PCB.
Este PCB não contém nenhum CI (circuito integrado). As linhas e colunas da matriz do teclado são conectadas diretamente aos headers de pinos para que o teclado possa ser conectado a um Arduino ou qualquer outro microcontrolador. É perfeito para prototipar seus projetos que incluirão um teclado integrado.
Incluí código detalhado e amplamente comentado para fazer isso funcionar com qualquer placa de desenvolvimento compatível com Arduino que tenha pinos I/O suficientes disponíveis — 11 pinos são necessários. O teclado tem 64 teclas, incluindo modificadores para shift, caps, ctrl, alt, fn e "special". Há também seis teclas adicionais que podem ser usadas para o que você quiser. A função de cada tecla pode ser definida individualmente, incluindo a função de cada tecla quando um modificador está ativo. Na minha opinião, isso é significativamente mais útil do que códigos de teclado existentes que limitam severamente sua capacidade de personalizar o comportamento das teclas.
O código fornecido imprime texto no Serial. Isso pode ser facilmente alterado se você quiser que o texto vá para outro lugar.
Nota Sobre o Tamanho do Programa
O código que forneço é bastante grande, porque não utiliza nenhuma biblioteca existente. Escrevi este código completamente do zero para permitir a personalização que eu precisava. Em um Arduino UNO, isso usará 9100 bytes (28%) do espaço de armazenamento do programa e as variáveis globais usarão 394 bytes (19%) da memória dinâmica.
Meu código provavelmente poderia ser mais eficiente e certamente existem bibliotecas e sketches para teclados menores, mas esta é a única maneira que pude imaginar para fornecer flexibilidade completa sobre cada tecla com cada modificador. Também leva em conta o uso real de teclado. Por exemplo, com meu código, pressionar a tecla Shift enquanto o Caps Lock está ativado resultará em uma letra minúscula, como deve ser. Por padrão, segurar a tecla FN enquanto pressiona ESC não fará nada. Mas esse comportamento é completamente personalizável, então você pode alterá-lo como quiser.
Suprimentos
- PCB personalizado
- Botões tácteis momentâneos 6x6x5mm (x64)
- Diodos de comutação 1N4148 (x64)
- Headers de pinos 1x8, fêmea ou macho (x2)
- Registrador de deslocamento 74HC595
- Jumpers
- Protoboard
- Arduino Uno ou qualquer placa de desenvolvimento compatível com Arduino
Passo 1: Como Funciona uma Matriz de Teclado
Por que uma matriz de teclado é necessária?
Este teclado tem 64 teclas. Se você conectasse cada um desses botões diretamente à sua placa de desenvolvimento, precisaria de 64 pinos I/O. Isso é muito pinos e mais do que a maioria das placas de desenvolvimento tem disponíveis. Para reduzir a um número muito mais razoável, podemos usar uma matriz de teclado, que requer apenas um número de pinos igual à raiz quadrada (arredondada para cima) do número de teclas.
Uma matriz de teclado é configurada para que cada chave em uma linha seja conectada e cada chave em uma coluna seja conectada. Quando queremos ver quais teclas estão pressionadas, "ativamos" a primeira linha e depois verificamos cada coluna. Se uma coluna específica estiver ativa, sabemos que a tecla naquela coluna e linha 1 foi pressionada. Desativamos então a linha 1 e ativamos a linha 2, e verificamos todas as colunas novamente. Depois que todas as linhas forem ativadas, simplesmente voltamos à primeira linha.
Como escaneamos a matriz do teclado:
Como estamos trabalhando com um microcontrolador, "ativar" significa definir essa linha como LOW ou HIGH. Neste caso, estamos definindo a linha como LOW porque estamos usando os resistores de pull-up internos do microcontrolador em nossos pinos de entrada de coluna. Sem um resistor de pull-up ou pull-down, um pino de entrada reagirá de forma imprevisível devido a interferências, registrando pressionamentos falsos de botões.
O microcontrolador ATmega328P usado no Arduino UNO não tem resistores de pull-down internos, apenas pull-up. Então estamos usando estes. Os resistores de pull-up conectam cada pino de entrada a 5V, garantindo que eles sempre leiam HIGH até que um botão seja pressionado.
Todas as linhas também são normalmente definidas como HIGH, o que impede que os pinos de coluna se conectem aos pinos de linha, seja um botão pressionado ou não. Mas quando estamos prontos para verificar uma linha, podemos definir essa linha como LOW. Se um botão naquela linha for pressionado, isso fornecerá um caminho para o pino de entrada ser puxado para o terra — resultando nessa coluna agora lendo como LOW.
Resumindo: definimos uma linha como LOW e depois verificamos quais pinos de coluna agora leem LOW. Estes correspondem aos botões pressionados. Este processo acontece muito rápido, então podemos escanear o teclado inteiro muitas vezes por segundo. Meu código limita isso a 200 vezes por segundo, o que equilibra performance, debounce e garante que cada pressionamento de tecla seja capturado.
Diodos, ghosting e n-key rollover:
Os diodos no circuito estão lá para evitar pressionamentos não intencionais quando certas combinações de botões são mantidas pressionadas. Diodos só permitem que a corrente flua em uma direção, o que evita ghosting. Se não usássemos diodos, pressionar certas teclas poderia fazer com que outra tecla não pressionada fosse registrada, já que a corrente flui através dos interruptores adjacentes. Isso é mostrado no gráfico simplificado onde pressionar três teclas adjacentes faz com que a tecla no quarto canto seja registrada mesmo quando não está pressionada. Os diodos evitam isso e permitem "n-key rollover", o que significa que podemos pressionar quantas teclas quisermos em qualquer combinação sem problemas.
Economizando pinos com registrador de deslocamento:
Os mais atentos provavelmente notaram que eu disse que uma matriz de teclado requer um número de pinos igual à raiz quadrada do número de teclas, mas que também disse que meu design de teclado requer apenas 11 pinos. Deveria ser 16, certo? Não, porque estamos usando um registrador de deslocamento 74HC595. Este registrador nos permite usar apenas três dos pinos I/O do Arduino para controlar até oito pinos de saída. Esses três pinos nos permitem enviar um byte (oito bits) para o registrador de deslocamento, que define seus oito pinos de saída como HIGH ou LOW. Ao usar o registrador de deslocamento para os pinos de saída das linhas, economizamos 5 pinos I/O inteiros!
"Por que não usar um registrador de deslocamento para os pinos de entrada também?" você pergunta. A resposta mais simples é que a entrada requer um tipo diferente de registrador de deslocamento e eu não tinha esse tipo em mãos. Mas usar um registrador de deslocamento para entrada também complica como lemos as colunas e pode causar problemas com ruído e "bouncing". Basta dizer que é uma dor de cabeça que não precisei enfrentar neste caso.
schematic.pdf
Passo 2: Design do PCB
Design do Esquemático
Agora que você entende como uma matriz de teclado funciona, meu design de PCB deve ser direto. Projetei o PCB no KiCAD (desculpem juízes do Eagle) e comecei com o esquemático. Simplesmente coloquei um símbolo de botão e um símbolo de diodo, depois copiei e colei até ter minha grade de 64 teclas. Então adicionei dois símbolos de header de pinos 1x8, um para as linhas e outro para as colunas. Um lado dos botões foi conectado em colunas e o outro lado dos botões foi conectado em linhas.
O próximo passo foi atribuir footprints de PCB a cada um desses símbolos esquemáticos. A biblioteca de footprints incluída no KiCAD tinha os footprints necessários embutidos. Ao projetar seus próprios PCBs, você deve ter muito cuidado ao escolher os footprints corretos, porque são eles que realmente acabarão no seu PCB. Existem muitos componentes com footprints muito semelhantes, mas com pitches ligeiramente diferentes ou algo assim. Certifique-se de escolher aqueles que correspondem aos seus componentes reais.
Footprints e Números de Pinos
Preste atenção especial aos números de pinos. O KiCAD tem um problema estranho onde os números de pinos do símbolo esquemático do diodo não correspondem aos números de pinos do footprint. Isso resulta em diodos invertidos, o que é um problema sério dada sua polaridade. Não percebi esse erro e tive que jogar fora o primeiro lote de PCBs que encomendei. Para corrigir esse problema na segunda revisão, tive que criar um footprint de diodo personalizado com os números de pinos invertidos.
Layout do PCB
Com o esquemático pronto e footprints atribuídos, passei para o layout real do PCB. O contorno da placa foi criado no Autodesk Fusion 360, exportado como DXF e depois importado no KiCAD na camada Edge Cuts. A grande maioria do trabalho depois disso foi simplesmente organizar os botões para que tivessem um layout semelhante a um teclado normal.
Então todas as trilhas foram roteadas. Como o layout real dos botões não corresponde à matriz organizada e limpa do esquemático, esta parte ficou um pouco confusa e tive que recorrer ao uso de vias em alguns lugares. Vias permitem rotear uma trilha de uma camada para outra, o que é realmente útil quando você está usando uma placa de 2 camadas que tem muitas trilhas sobrepostas. Finalmente, adicionei regiões preenchidas, porque é uma boa prática.
Fabricação do PCB
Com a placa projetada, simplesmente plotei todas as camadas e as adicionei a uma pasta zip. Essa pasta é fornecida aqui e pode ser enviada diretamente para um serviço de fabricação de PCB como JLCPCB.
Aqui está o link para os arquivos Gerber do PCB: https://drive.google.com/file/d/10YriLLtghV0Sb84Wm...
Passo 3: Montagem do PCB
Este é o passo mais fácil, mas mais tedioso de todo o projeto. Apenas solde todos os componentes no lugar. Eles são todos componentes through-hole e fáceis de soldar. Preste atenção especial à orientação dos diodos. A marca nos diodos deve corresponder às marcas no PCB.
Na minha experiência, foi mais fácil segurar o PCB no lugar com uma terceira mão e colocar todos os diodos primeiro. Depois vire a placa e solde todos, depois corte os terminais. Depois coloque todos os botões e solde-os. Depois solde os headers de pinos no lugar. Você pode usar headers fêmea ou macho, é totalmente por sua conta. Se usar header macho e colocá-los embaixo da placa, o espaçamento está correto para enfiá-los diretamente em uma protoboard.
Passo 4: Conecte o Teclado ao Seu Arduino
A fiação parece complicada, mas realmente não é tão ruim quando você presta atenção para onde tudo está indo.
Oito jumpers irão do header de coluna diretamente para os seguintes pinos do Arduino:
- Coluna 1 > A0
- Coluna 2 > A1
- Coluna 3 > A2
- Coluna 4 > A3
- Coluna 5 > A4
- Coluna 6 > A5
- Coluna 7 > 5
- Coluna 8 > 6
Em seguida, coloque o registrador de deslocamento 74HC595 na sua protoboard atravessando a divisão central. Observe a orientação do chip! O ponto indica o Pino 1.
Veja o diagrama de fiação para ver onde vão as conexões de 5V e Terra. O registrador de deslocamento tem dois pinos conectados a 5V e dois pinos conectados a Terra.
Apenas três fios são necessários para conectar o registrador de deslocamento ao Arduino. Eles são:
- Shift (Clock) 11 > 4
- Shift (Latch) 12 > 3
- Shift (Data) 14 > 2
Por algum motivo bobo, os pinos de saída do registrador de deslocamento são organizados de forma contra-intuitiva. Preste atenção especial ao diagrama de pinout do registrador de deslocamento ao conectá-los aos seus pinos de linha. Eles são:
- Linha 1 > Shift (Q0) 15
- Linha 2 > Shift (Q1) 1
- Linha 3 > Shift (Q2) 2
- Linha 4 > Shift (Q3) 3
- Linha 5 > Shift (Q4) 4
- Linha 6 > Shift (Q5) 5
- Shift 7 > Shift (Q6) 6
- Shift 8 > Shift (Q7) 7
Nada está conectado aos pinos 0 ou 1 do Arduino, porque esses também são usados para a porta Serial e causam conflitos.
Passo 5: Grave o Código no Arduino
Grave seu Arduino com o código fornecido aqui. Não há nada de especial nisso, apenas faça o upload do código como faria com qualquer outro projeto Arduino.
Tudo no código tem comentários detalhados que você pode ler, então não entrarei em muitos detalhes aqui. Basicamente, os pinos são configurados como entradas e saídas. O loop principal contém apenas uma função de timer. A cada 5ms, ele chama a função para escanear o teclado. Essa função chama uma função separada para configurar o registrador de deslocamento antes de verificar as colunas. Teclas pressionadas imprimem seu valor no Serial.
Se você quiser alterar o que é impresso quando pressiona uma tecla, apenas altere o Serial.print("_"); na declaração if que corresponde à condição. Por exemplo, você pode definir o que é impresso quando segura FN e pressiona N. O mesmo vale para todas as outras teclas com cada modificador.
Muitas teclas não fazem nada neste código, porque ele apenas imprime no Serial. Isso significa que a tecla backspace não tem efeito, porque você não pode apagar do monitor Serial — aqueles dados já foram recebidos. Você é, no entanto, livre para alterar isso se quiser.
Usando o Teclado com Seus Próprios Projetos
É legal imprimir no serial, mas esse não é realmente o objetivo deste teclado. O propósito deste teclado é para prototipar projetos mais complexos. É por isso que é fácil alterar a funcionalidade. Se, por exemplo, você quisesse imprimir o texto digitado em uma tela OLED, poderia simplesmente substituir todo Serial.print( por display.print( ou o que seu display particular exigir. A ferramenta Substituir Tudo da Arduino IDE é ótima para substituir todos de uma vez.
Obrigado por ler e espero que este teclado ajude em seus projetos!
ProtoKeyboardV1.1-Shifted.ino
Atualização de 30/01/21
Este novo código foi completamente reescrito e funciona melhor que o código original. Isso foi feito principalmente para resolver um problema com meu algoritmo que impedia que caracteres fossem inseridos toda vez que uma tecla era pressionada. O código original verificava se uma tecla específica não era a última tecla pressionada. Isso causava um problema se 2 ou mais teclas fossem mantidas pressionadas, o que causaria algo como "fgfgfgfgfgfgfgfgfgfg" a ser inserido. Isso também impedia que você inserisse a mesma tecla repetidamente muito rapidamente, como quando digita os dois m's na palavra "bummer".
O novo código resolve ambos os problemas e também é mais elegante. Em vez de rastrear a última tecla pressionada, verificamos o estado de todo o teclado e o comparamos com o estado de todo o teclado no loop anterior. Isso significa que o loop pode rodar muito mais rápido, e você também pode inserir a mesma tecla repetidamente muito rapidamente. O desempenho é dramaticamente melhorado. Todos os caracteres também estão em arrays no topo, então você pode encontrá-los e alterá-los facilmente. Existem arrays independentes para cada modificador. O código também é muito mais curto.
A única desvantagem desta nova abordagem é que usa mais memória dinâmica — embora use significativamente menos espaço de programa. Em um Arduino Uno, agora usa: 3532 bytes (10%) de espaço de armazenamento do programa e 605 bytes (29%) de memória dinâmica.
Como bônus adicional, este código funciona tão bem em microcontroladores rápidos como o ARM Cortex-M4. O timer de intervalo para verificar o teclado está em microssegundos, então terá o mesmo desempenho em qualquer placa. Você também pode ajustar facilmente com que frequência o teclado é verificado. Por padrão, roda um loop a cada 500 microssegundos. Leva 8 loops para verificar o teclado, totalizando 4000 microssegundos (4 milissegundos, ou 250 vezes por segundo) — embora possa demorar mais se o micro não for rápido o suficiente para rodar o código tão rapidamente.
Código
ProtoKeyboardV1.1-Shifted.ino (Arduino)
Sem preview (apenas download).
ProtoKeyboardV1-Bits.ino (Arduino) - Código Atualizado
/* Sketch para Teclado de Prototipagem V1.2
* por Cameron Coward 30/01/21
*
* Testado no Arduino Uno. Requer PCB personalizado
* e um registrador de deslocamento 74HC595.
*
* Mais info: https://www.hackster.io/cameroncoward/64-key-prototyping-keyboard-matrix-for-arduino-4c9531 */
const int rowData = 2; // pino Data do registrador de deslocamento para linhas
const int rowLatch = 3; // pino Latch do registrador de deslocamento para linhas
const int rowClock = 4; // pino Clock do registrador de deslocamento para linhas
// estes são nossos pinos de entrada de coluna. Pino 0 e Pino 1 não são usados,
// porque causam problemas (presumivelmente porque são TX e RX)
const int colA = A0;
const int colB = A1;
const int colC = A2;
const int colD = A3;
const int colE = A4;
const int colF = A5;
const int colG = 5;
const int colH = 6;
// shiftRow é o byte necessário do registrador de deslocamento para cada linha, rowState conterá teclas pressionadas para cada linha
const byte shiftRow[] = {B01111111, B10111111, B11011111, B11101111, B11110111, B11111011, B11111101, B11111110};
byte rowState[] = {B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000};
byte prevRowState[] = {B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000};
// Códigos ASCII para teclas sem modificadores pressionados. Modificadores são NULL (0),
// porque verificaremos esses separadamente e seus valores não devem ser impressos.
const char key[] = {
0, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 0, 9,
113, 119, 101, 114, 116, 121, 117, 105, 111, 112, 91, 93, 92, 7,
97, 115, 100, 102, 103, 104, 106, 107, 108, 59, 39, 0, 0,
122, 120, 99, 118, 98, 110, 109, 44, 46, 47, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0
};
// Códigos ASCII para teclas com shift pressionado E caps ativo
const char capsShiftKey[] = {
0, 33, 64, 35, 36, 37, 94, 38, 42, 40, 41, 95, 43, 0, 9,
113, 119, 101, 114, 116, 121, 117, 105, 111, 112, 123, 125, 124, 7,
97, 115, 100, 102, 103, 104, 106, 107, 108, 58, 22, 0, 0,
122, 120, 99, 118, 98, 110, 109, 44, 46, 47, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0
};
// Códigos ASCII para teclas com shift pressionado.
const char shiftKey[] = {
0, 33, 64, 35, 36, 37, 94, 38, 42, 40, 41, 95, 43, 0, 9,
81, 87, 69, 82, 84, 89, 85, 73, 79, 80, 123, 125, 124, 7,
65, 83, 68, 70, 71, 72, 74, 75, 76, 58, 22, 0, 0,
90, 88, 67, 86, 66, 78, 77, 44, 46, 47, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0
};
// Códigos ASCII para teclas com ctrl pressionado.
const char ctrlKey[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0
};
// Códigos ASCII para teclas com spcl pressionado.
const char spclKey[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
// Códigos ASCII para teclas com alt pressionado.
const char altKey[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
// Códigos ASCII para teclas com fn pressionado.
const char fnKey[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
// Códigos ASCII para teclas com caps ativo
const char capsKey[] = {
0, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 0, 9,
81, 87, 69, 82, 84, 89, 85, 73, 79, 80, 91, 93, 92, 7,
65, 83, 68, 70, 71, 72, 74, 75, 76, 59, 39, 0, 0,
90, 88, 67, 86, 66, 78, 77, 44, 46, 47, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0
};
long previousKeyboardMicros = 0; // armazenará a última vez que o teclado foi verificado
long keyboardInterval = 500; // intervalo para verificar o teclado (microssegundos)
int rowToCheck = 0; // Verificamos uma linha por loop de checkKeyboard(), isso combinado com keyboardInterval
// dá tempo ao registrador de deslocamento para atualizar completamente entre verificações de linha
bool caps = false; // caps lock está ligado?
bool shift = false; // shift esquerdo ou direito está pressionado?
bool capsShift = false; // shift E caps estão ativos?
bool ctrl = false; // tecla ctrl está pressionada?
bool spcl = false; // tecla spcl está pressionada?
bool alt = false; // tecla alt está pressionada?
bool fn = false; // tecla function está pressionada?
void setup() {
Serial.begin(9600);
// configura todos os pinos de coluna como entradas com resistores pull-up internos
pinMode(colA, INPUT_PULLUP);
pinMode(colB, INPUT_PULLUP);
pinMode(colC, INPUT_PULLUP);
pinMode(colD, INPUT_PULLUP);
pinMode(colE, INPUT_PULLUP);
pinMode(colF, INPUT_PULLUP);
pinMode(colG, INPUT_PULLUP);
pinMode(colH, INPUT_PULLUP);
// saídas necessárias para controlar o registrador de deslocamento 74HC595
pinMode(rowLatch, OUTPUT);
pinMode(rowClock, OUTPUT);
pinMode(rowData, OUTPUT);
updateShiftRegister(B11111111); // certifica que o registrador de deslocamento começa com todos HIGH
}
void loop() {
mainTimer();
}
void mainTimer() {
unsigned long currentMicros = micros(); // quantos microssegundos o Arduino está rodando?
if(currentMicros - previousKeyboardMicros > keyboardInterval) {
// se o tempo decorrido desde a última verificação excede o intervalo
// salva a última vez que o teclado foi verificado
previousKeyboardMicros = currentMicros;
checkKeyboard(); // verifica todas as teclas e imprime os resultados no serial
}
}
void updateShiftRegister(byte row) {
// esta função configura o registrador de deslocamento de acordo com o byte passado
digitalWrite(rowLatch, LOW); // define latch como low para podermos escrever um byte inteiro de uma vez
shiftOut(rowData, rowClock, MSBFIRST, row); // escreve aquele byte
digitalWrite(rowLatch, HIGH); // define latch de volta para high para que o registrador permaneça estável até a próxima mudança
}
void checkKeyboard() {
// configura o registrador de deslocamento para o valor do byte da linha atual, do array shiftRow[]
updateShiftRegister(shiftRow[rowToCheck]);
// Verifica cada coluna
if (digitalRead(colA) == LOW) { bitSet(rowState[rowToCheck], 0); } else { bitClear(rowState[rowToCheck], 0); }
if (digitalRead(colB) == LOW) { bitSet(rowState[rowToCheck], 1); } else { bitClear(rowState[rowToCheck], 1); }
if (digitalRead(colC) == LOW) { bitSet(rowState[rowToCheck], 2); } else { bitClear(rowState[rowToCheck], 2); }
if (digitalRead(colD) == LOW) { bitSet(rowState[rowToCheck], 3); } else { bitClear(rowState[rowToCheck], 3); }
if (digitalRead(colE) == LOW) { bitSet(rowState[rowToCheck], 4); } else { bitClear(rowState[rowToCheck], 4); }
if (digitalRead(colF) == LOW) { bitSet(rowState[rowToCheck], 5); } else { bitClear(rowState[rowToCheck], 5); }
if (digitalRead(colG) == LOW) { bitSet(rowState[rowToCheck], 6); } else { bitClear(rowState[rowToCheck], 6); }
if (digitalRead(colH) == LOW) { bitSet(rowState[rowToCheck], 7); } else { bitClear(rowState[rowToCheck], 7); }
// define todos os pinos do registrador de deslocamento como HIGH, isso evita que valores "vazem" para o próximo loop
updateShiftRegister(B11111111);
rowToCheck = rowToCheck + 1; // itera para a próxima linha
// após verificar a 8ª linha, verifica os estados (teclas pressionadas) e reinicia na 1ª linha
if (rowToCheck > 7) {
checkPressedKeys();
rowToCheck = 0;
}
}
void checkPressedKeys() {
// verifica se alguma tecla shift está pressionada
if (bitRead(rowState[5], 1) | bitRead(rowState[6], 4)) { shift = true; } else { shift = false; }
// verifica se alguma tecla ctrl está pressionada
if (bitRead(rowState[6], 5) | bitRead(rowState[7], 3)) { ctrl = true; } else { ctrl = false; }
// verifica se alguma tecla spcl está pressionada
if (bitRead(rowState[6], 6) | bitRead(rowState[7], 2)) { spcl = true; } else { spcl = false; }
// verifica se alguma tecla alt está pressionada
if (bitRead(rowState[6], 7) | bitRead(rowState[7], 1)) { alt = true; } else { alt = false; }
// verifica se tecla FN está pressionada
if (bitRead(rowState[7], 4)) { fn = true; } else { fn = false; }
// verifica se caps está ativo e shift está pressionado
if (shift == true && caps == true) { capsShift = true; } else { capsShift = false; }
for (int i = 7; i >= 0; i--) { // itera através de cada linha
for (int j = 7; j >= 0; j--) { // itera através de cada bit naquela linha
bool newBit = bitRead(rowState[i], j); // verifica o estado daquele bit
bool prevBit = bitRead(prevRowState[i], j); // verifica o estado anterior daquele bit
if ((newBit == 1) && (prevBit == 0)) { // só permite pressionamento se o estado mudou para true
int thisChar = (i * 8) + j; // calcula qual posição no array de char selecionar
if (capsShift == true) { processKey(capsShiftKey[thisChar]); }
else if (shift == true) { processKey(shiftKey[thisChar]); }
else if (ctrl == true) { processKey(ctrlKey[thisChar]); }
else if (alt == true) { processKey(altKey[thisChar]); }
else if (spcl == true) { processKey(spclKey[thisChar]); }
else if (fn == true) { processKey(fnKey[thisChar]); }
else if (caps == true) { processKey(capsKey[thisChar]); }
else { processKey(key[thisChar]); }
}
if (newBit == 1) {
bitSet(prevRowState[i], j); // define estado anterior do bit como true se uma tecla está pressionada
} else {
bitClear(prevRowState[i], j); // define estado anterior do bit como false se tecla não está pressionada, para que possa ser pressionada novamente
}
}
}
}
void processKey(char receivedKey) {
if (receivedKey == 7) { // verifica funções especiais da mesma forma que caps (adicione novos "else if")
caps = !caps;
} else {
Serial.print(receivedKey); // se char não corresponde a uma função especial, simplesmente imprime aquele char
}
}
Peças Personalizadas e Gabinetes
Envie o arquivo .zip completo para seu serviço de fabricação de PCB
keyplots_4xipOSLHzg.zip
Esquemáticos
Processo de manufatura
- Painel de Controle para Flight Simulator 2020 com Arduino Nano – Display LCD e CDI
- Painel de Chaves e LEDs para Microsoft Flight Simulator 2020 com Arduino
- Transforme seu Teclado MIDI em Tutor de Piano Inteligente com Arduino, LEDs e MuseScore
- Controlando Matriz de LED 8×8 com Arduino Uno: Guia Passo a Passo
- Sistema Inteligente de Monitoramento de Temperatura para Escolas: Preciso, Tempo Real e Seguro
- Biblioteca Eficiente de Porta IO de 8 Bits para Arduino – Expanda o Controle Digital
- Shield TFT 2,8" para Arduino Nano – Display SPI 320×240 de Alto Desempenho
- Circuito de Entrada Analógica Isolada para Arduino
- Construa uma Calculadora Arduino com Display LCD 16x2 e Teclado
- Kit de Robô de Navegação Interna Inteligente para Projetos Arduino