Arduino 64-toets Prototoetsenbord Matrix – Bouw een Aangepast Toetsenbord met Shift Registers
Onderdelen en benodigdheden
| Arduino UNO | × | 1 |
| 1N4148 – Algemeen Doel Snelle Schakeldiode | × | 64 |
| Tactiele Schakelaar, Bovenbediend | × | 64 |
| Pin headers | × | 1 |
| 74HC595 Shift Register | × | 1 |
Benodigde tools en machines
- Soldeerbout (standaard)
Apps en online services
- Arduino IDE
Over dit project

Update: Ik heb de code verbeterd, zie "Update" aan het einde.
Ik werk momenteel aan een project dat een geïntegreerd toetsenbord zal hebben, wat een probleem opleverde: hoe sluit ik een toetsenbord in het ontwikkelbord-prototype in? Ik kan geen USB-toetsenbord of bestaand Arduino-gebaseerd toetsenbord gebruiken, omdat het toetsenbord in het echte project direct verbonden is met de microcontroller die alle andere functies afhandelt. Daarom ontwierp ik deze basis PCB-gebaseerde 64-toets prototypetoetsenbordmatrix.
Deze PCB bevat geen IC's (geïntegreerde circuits). De rijen en kolommen van de toetsenbordmatrix zijn direct verbonden met de pin-headers zodat het toetsenbord aangesloten kan worden op een Arduino of een andere microcontroller. Het is perfect voor het prototypen van je projecten die een geïntegreerd toetsenbord zullen bevatten.
Ik heb gedetailleerd, zwaar gecommentarieerde code opgenomen om dit met elk Arduino-compatibel ontwikkelbord te laten werken dat voldoende I/O-pinnen beschikbaar heeft – 11 pinnen zijn vereist. Het toetsenbord heeft 64 toetsen, inclusief modifiers voor shift, caps, ctrl, alt, fn en "special". Er zijn ook zes extra toetsen die voor wat je wilt gebruikt kunnen worden. Elke enkele toets zijn functies kunnen individueel gedefinieerd worden, inclusief de functie van elke toets wanneer een modifier actief is. Meiner mening na is dit aanzienlijk nuttiger dan bestaande toetsenbordcode die je mogelijkheid om toetsgedrag aan te passen streng beperkt.
De meegeleverde code print tekst naar Serial. Dit kan eenvoudig gewijzigd worden als je de tekst ergens anders heen wilt sturen.
Een Opmerking Over Programmagrootte:
De code die ik aanbied is vrij groot, omdat het geen enkele bestaande bibliotheek gebruikt. Ik schreef deze code volledig vanaf nul om de aanpasbaarheid te ermöglichen die ik nodig had. Op een Arduino UNO gebruikt dit 9100 bytes (28%) van de programmageheugenruimte en gebruiken globale variabelen 394 bytes (19%) van het dynamische geheugen.
Mijn code zou waarschijnlijk efficiënter kunnen zijn en er zijn zeker kleinere bibliotheken en sketches voor toetsenborden, maar dit is de enige manier die ik kon bedenken om volledige flexibiliteit over elke toets met elke modifier te bieden. Het houdt ook rekening met realistisch toetsenbordgebruik. Bijvoorbeeld, met mijn code resulteert het indrukken van de Shift-toets terwijl Caps Lock ingeschakeld is in een kleine letter zoals het hoort. Standaard doet het indrukken van de FN-toets terwijl ESC ingedrukt wordt niets. Maar dat gedrag is volledig aanpasbaar, dus je kunt het veranderen zoals je wilt.
Benodigdheden:
- De aangepaste PCB
- 6x6x5mm tactiele momentane drukknoppen (x64)
- 1N4148 schakeldiodes (x64)
- 1x8 pin headers, female of male (x2)
- 74HC595 shift register
- Draadbruggen
- Experimenteerbord
- Arduino Uno of elk Arduino-compatibel microcontroller-ontwikkelbord
Stap 1: Hoe een toetsenbordmatrix werkt


Waarom is een toetsenbordmatrix noodzakelijk?
Dit toetsenbord heeft 64 toetsen. Als je elk van die knoppen direct met je ontwikkelboard zou verbinden, zou je 64 I/O-pinnen nodig hebben. Dat is veel pinnen en meer dan de meeste ontwikkelborden beschikbaar hebben. Om dat terug te brengen naar een veel redelijker aantal kunnen we een toetsenbordmatrix gebruiken, wat alleen een aantal pinnen vereist gelijk aan de wortel (afgerond naar boven) van het aantal toetsen.
Een toetsenbordmatrix is zo ingesteld dat elke toetsenschakelaar in een rij verbonden is en elke toetsenschakelaar in een kolom verbonden is. Als we willen zien welke toetsen ingedrukt zijn, "activeren" we de eerste rij en controleren we vervolgens elke kolom. Als een bepaalde kolom actief is, weten we dat de toets in die kolom en rij 1 is ingedrukt. We deactiveren dan rij 1 en activeren rij 2, en controleren weer alle kolommen. Nadat alle rijen geactiveerd zijn, beginnen we gewoon weer bij de eerste rij.
Hoe we de toetsenbordmatrix scannen:
Omdat we met een microcontroller werken, betekent "activeren" dat we die rij op LOW of HIGH zetten. In dit geval zetten we de rij op LOW omdat we de ingebouwde pull-up weerstanden van de microcontroller op onze kolom-ingangspinnen gebruiken. Zonder een pull-up of pull-down weerstand zal een ingangspin onvoorspelbaar reageren als gevolg van interferentie, wat valse toetsaanslagen registreert.
De ATmega328P-microcontroller die in de Arduino UNO gebruikt wordt, heeft geen ingebouwde pull-down-weerstanden, alleen pull-up-weerstanden. Dus we gebruiken die. De pull-up-weerstanden verbinden elke ingangspin met 5V, zodat ze altijd HIGH lezen totdat een knop wordt ingedrukt.
Alle rijen staan ook normaal op HIGH, wat voorkomt dat de kolompinnen verbonden worden met de rijenpinnen of een knop nu ingedrukt is of niet. Maar wanneer we een rij willen controleren, kunnen we die rij op LOW zetten. Als een knop in die rij is ingedrukt, biedt dit een pad voor de ingangspin om naar de ground getrokken te worden – wat resulteert in die kolom nu als LOW wordt gelezen.
Kortom: we zetten een rij op LOW en controleren welke kolompinnen nu LOW lezen. Die overeenkomen met ingedrukte knoppen. Dit proces gebeurt zeer snel, dus we kunnen het hele toetsenbord vaak per seconde scannen. Mijn code beperkt dit tot 200 keer per seconde, wat prestaties, debouncing en het vastleggen van elke toetsaanslag in evenwicht brengt.
Diodes, ghosting en n-key rollover:
De dioden in de schakeling zijn er om ongewenste toetsaanslagen te voorkomen wanneer bepaalde toetsencombinaties ingedrukt worden. Diodes laten stroom alleen in één richting vloeien, wat ghosting voorkomt. Als we geen dioden zouden gebruiken, dan zou het indrukken van bepaalde toetsen een andere niet-ingedrukte toets kunnen laten registreren, omdat stroom door de aangrenzende schakelaars vloeit. Dit wordt getoond in de vereenvoudigde afbeelding waar het indrukken van drie aangrenzende toetsen de toets in de vierde hoek doet registreren zelfs als hij niet is ingedrukt. De dioden voorkomen dat en maken "n-key rollover" mogelijk, wat betekent dat we zoveel toetsen in welke combinatie dan ook kunnen indrukken zonder problemen.
Pinnen besparen met een shift register:
De scherpe lezers onder jullie hebben waarschijnlijk gemerkt dat ik zei dat een toetsenbordmatrix een aantal pinnen vereist gelijk aan de wortel van het aantal toetsen, maar dat ik ook zei dat mijn toetsenbordontwerp slechts 11 pinnen vereist. Het zou 16 moeten zijn, toch? Nee, want we gebruiken een 74HC595 shift register. Deze shift register laat ons toe om slechts drie van de I/O-pinnen van de Arduino te gebruiken om maximaal acht uitgangspinnen te besturen. Die drie pinnen laten ons een byte (acht bits) naar het shift register sturen, dat de acht uitgangspinnen op HIGH of LOW zet. Door het shift register te gebruiken voor de uitgangsrijpinnen, besparen we 5 complete I/O-pinnen!
"Waarom niet ook een shift register voor de ingangspinnen gebruiken?" vraag je je af. Het simpelste antwoord is dat invoer een ander type shift register vereist en ik had dat type niet bij de hand. Maar het gebruik van een shift register voor invoer vercompliceert ook hoe we de kolommen lezen en kan problemen veroorzaken met ruis en "debouncing". Kortom, het is een hoofdpijn die ik in dit geval niet nodig had.
schematic.pdf
Stap 2: PCB-ontwerp



Schema-ontwerp
Nu je begrijpt hoe een toetsenbordmatrix werkt, zou mijn PCB-ontwerp duidelijk moeten zijn. Ik ontwierp de PCB in KiCAD (sorry Eagle-rechters) en begon met het schema. Ik plaatste simpelweg een knopsymbool en een diodesymbool, kopieerde en plakte die tot ik mijn raster van 64 toetsen had. Daarna voegde ik twee 1x8 pin-header-symbolen toe, één voor de rijen en één voor de kolommen. Een kant van de knoppen was in kolommen verbonden en de andere kant in rijen.
De volgende stap was het toewijzen van PCB-footprints aan elk van die schematicsymbolen. De inbegrepen footprint-bibliotheek van KiCAD had de benodigde footprints ingebouwd. Bij het ontwerpen van je eigen PCB's moet je heel voorzichtig zijn om de juiste footprints te kiezen, want dat zijn de dingen die daadwerkelijk op je PCB terechtkomen. Er zijn veel componenten met zeer vergelijkbare footprints, maar met iets andere pitches ofzo. Zorg dat je die kiest die overeenkomen met je echte componenten.
Footprints en pinnummers
Let met name op de pinnummers. KiCAD heeft een rare kwestie waarbij de pinnummers van het schematicsymbool van de diode niet overeenkomen met de pinnummers van de footprint. Dit resulteert in omgekeerde dioden, wat een ernstig probleem is gezien hun polariteit. Ik had die fout niet opgemerkt en moest de eerste batch PCB's die ik bestelde weggooien. Om dit probleem op de tweede revisie op te lossen, moest ik een aangepaste diode-footprint maken met de pinnummers omgewisseld.
PCB-layout
Met het schema klaar en footprints toegewezen, ging ik over naar de echte PCB-layout. De bordkontuur werd gemaakt in Autodesk Fusion 360, geëxporteerd als DXF en vervolgens in KiCAD geïmporteerd op de Edge Cuts-laag. Het grootste deel van het werk daarna was het rangschikken van de knoppen zodat ze een layout hadden die lijkt op een normaal toetsenbord.
Daarna werden alle sporen gerouteerd. Omdat de echte knoppenlayout niet overeenkomt met de nette en ordelijke matrix in het schema, werd dit deel een beetje rommelig en moest ik in sommige plekken vias gebruiken. Vias laten je een spoor van de ene laag naar de andere routeren, wat erg handig is als je een 2-laags bord met veel overlappende sporen gebruikt. Tot slot voegde ik gevulde gebieden toe, omdat dat een goede gewoonte is.
PCB-fabricage
Met het bord ontworpen, plotte ik simpelweg alle lagen en voegde ze toe aan een zip-map. Die map wordt hier aangeboden en kan direct geüpload worden naar een PCB-fabricagedienst zoals JLCPCB.
Hier is de link naar de PCB Gerber-bestanden: https://drive.google.com/file/d/10YriLLtghV0Sb84Wm...
Stap 3: PCB-assemblage

Dit is de makkelijkste, maar meest saaie stap in het hele project. Soldeer gewoon alle componenten op hun plaats. Ze zijn alle doorgangsgaten-componenten en makkelijk te solderen. Let met name op de oriëntatie van de dioden. De markering op de dioden moet overeenkomen met de markeringen op de PCB.
In mijn ervaring was het makkelijkst om de PCB vast te zetten met een derde hand en eerst alle dioden te plaatsen. Daarna het bord omdraaien en ze allemaal solderen, dan de pootjes afknippen. Daarna alle knoppen plaatsen en die solderen. Vervolgens de pin-headers solderen. Je kunt female of male pin-headers gebruiken, dat is volledig aan jou. Als je male headers gebruikt en ze onder het bord plaatst, is de afstand correct om ze direct in een experimenteerbord te steken.
Stap 4: Verbind het toetsenbord met je Arduino



De bedrading ziet er ingewikkeld uit, maar is het niet als je goed oplet waar alles naartoe gaat.
Acht draadbruggen gaan van de kolom-header direct in de volgende Arduino-pinnen:
- Kolom 1 > A0
- Kolom 2 > A1
- Kolom 3 > A2
- Kolom 4 > A3
- Kolom 5 > A4
- Kolom 6 > A5
- Kolom 7 > 5
- Kolom 8 > 6
Plaats daarna de 74HC595 shift register op je experimenteerbord over de middenbreuk. Let op de oriëntatie van de chip! De stip duidt pin 1 aan.
Bekijk het bedradingsschema om te zien waar de 5V- en Ground-verbindingen gaan. De shift register heeft twee pinnen verbonden met 5V en twee pinnen met Ground.
Er zijn slechts drie draden nodig om de shift register met de Arduino te verbinden. Zij zijn:
- Shift (Clock) 11 > 4
- Shift (Latch) 12 > 3
- Shift (Data) 14 > 2
Vanwege een rare reden zijn de uitgangspinnen van de shift register op een contra-intuïtieve manier gerangschikt. Let goed op het shift register pinout-diagram bij het verbinden van die met je rijenpinnen. Zij zijn:
- Rij 1 > Shift (Q0) 15
- Rij 2 > Shift (Q1) 1
- Rij 3 > Shift (Q2) 2
- Rij 4 > Shift (Q3) 3
- Rij 5 > Shift (Q4) 4
- Rij 6 > Shift (Q5) 5
- Shift 7 > Shift (Q6) 6
- Shift 8 > Shift (Q7) 7
Niets is verbonden met Arduino-pin 0 of 1, omdat die ook voor de seriële poort gebruikt worden en conflicten veroorzaken.
Stap 5: Flash de Arduino-code

Flash je Arduino met de hier geleverde code. Er is niets speciaals aan, upload de code zoals je dat bij elk ander Arduino-project zou doen.
Alles in de code heeft gedetailleerde commentaren die je kendoor kunt lezen, dus ik ga hier niet diep op in. Basisweg worden de pinnen ingesteld als in- en uitgangen. De hoofdloop bevat alleen een timerfunctie. Elke 5ms roept het de functie aan om het toetsenbord te scannen. Die functie roept een aparte functie aan om het shift register in te stellen voordat de kolommen gecontroleerd worden. Ingedrukte toetsen printen hun waarde naar Serial.
Als je wilt wijzigen wat er geprint wordt wanneer je een toets indrukt, verander gewoon de Serial.print("_"); in de if-statement die overeenkomt met de voorwaarde. Je kunt bijvoorbeeld instellen wat er geprint wordt als je FN ingedrukt houdt en N indrukt. Hetzelfde geldt voor elke andere toets met elke modifier.
Veel toetsen doen in deze code helemaal niets, omdat het alleen naar Serial print. Dat betekent dat de backspace-toets geen effect heeft, omdat je niet uit de Serial Monitor kunt wissen – die data is al ontvangen. Je bent echter vrij om dat te veranderen als je wilt.
Het toetsenbord gebruiken met je eigen projecten
Het is leuk om naar serial te printen, maar dat is niet echt het punt van dit toetsenbord. Het doel van dit toetsenbord is voor het prototypen van complexere projecten. Daarom is het gemakkelijk om de functionaliteit aan te passen. Als je bijvoorbeeld de getypte tekst naar een OLED-scherm wilt printen, kun je simpelweg elke Serial.print( vervangen door display.print( of wat je specifieke display vereist. Het Vervang Alles-hulpmiddel van de Arduino IDE is geweldig om die allemaal in één keer te vervangen.
Bedankt voor het lezen en ik hoop dat dit toetsenbord je helpt met je projecten!
ProtoKeyboardV1.1-Shifted.ino
1/30/21 Update:
Deze nieuwe code is volledig herschreven en presteert beter dan de oorspronkelijke code. Dit werd voornamelijk gedaan om een probleem met mijn algoritme op te lossen dat ervoor zorgde dat karakters niet elke keer werden ingevoerd wanneer een toets werd ingedrukt. De oorspronkelijke code controleerde of een bepaalde toets niet de laatste ingedrukte toets was. Dit veroorzaakte een probleem als 2 of meer toetsen ingedrukt gehouden werden, wat zou leiden tot iets als "fgfgfgfgfgfgfgfgfgfg" wordt ingevoerd. Dit verhinderde ook dat je dezelfde toets heel snel herhaald kon typen, zoals de twee m's in het woord "bummer".
De nieuwe code lost beide problemen op en is ook eleganter. In plaats van bij te houden welke toets als laatste was ingedrukt, controleren we de staat van het hele toetsenbord en vergelijken we die met de hele toetsenbordstaat in de vorige lus. Dit betekent dat de lus veel sneller kan draaien, en je kunt ook dezelfde toets heel snel herhaald typen. De prestaties zijn dramatisch verbeterd. Alle karakters staan ook in arrays bovenaan, zodat je ze makkelijk kunt vinden en wijzigen. Er zijn onafhankelijke arrays voor elke modifier. De code is ook veel korter.
Het enige nadeel van deze nieuwe aanpak is dat het meer dynamisch geheugen gebruikt – hoewel het aanzienlijk minder programmageheugen gebruikt. Op een Arduino Uno gebruikt het nu: 3532 bytes (10%) van de programmageheugenruimte en 605 bytes (29%) van het dynamische geheugen.
Als extra bonus werkt deze code net zo goed op snelle microcontrollers als de ARM Cortex-M4. De intervaltimer om het toetsenbord te controleren is in microseconden, dus het zal op elk board hetzelfde presteren. Je kunt ook eenvoudig aanpassen hoe vaak het toetsenbord gecontroleerd wordt. Standaard draait het één lus elke 500 microseconden. Het duurt 8 lussen om het toetsenbord te controleren, voor een totaal van 4000 microseconden (4 milliseconden, of 250 keer per seconde) – hoewel het langer kan duren als de microcontroller niet snel genoeg is om de code zo snel uit te voeren.
Code
ProtoKeyboardV1.1-Shifted.ino Arduino
Geen preview (alleen download).
ProtoKeyboardV1-Bits.ino Arduino
/* Sketch voor Prototyping Keyboard V1.2
* door Cameron Coward 1/30/21
*
* Getest op Arduino Uno. Vereist aangepaste PCB
* en een 74HC595 shift register.
*
* Meer info: https://www.hackster.io/cameroncoward/64-key-prototyping-keyboard-matrix-for-arduino-4c9531 */
const int rowData = 2; // shift register Data pin voor rijen
const int rowLatch = 3; // shift register Latch pin voor rijen
const int rowClock = 4; // shift register Clock pin voor rijen
// dit zijn onze kolom-ingangspinnen. Pin 0 en Pin 1 worden niet gebruikt,
// omdat ze problemen veroorzaken (vermoedelijk omdat ze TX en RX zijn)
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 is de vereiste shift register byte voor elke rij, rowState zal ingedrukte toetsen voor elke rij bevatten
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};
// ASCII-codes voor toetsen zonder modifiers ingedrukt. Modifiers zijn NULL (0),
// omdat we die apart controleren en hun waarden niet geprint hoeven te worden.
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
};
// ASCII-codes voor toetsen met shift ingedrukt EN caps actief
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
};
// ASCII-codes voor toetsen met shift ingedrukt.
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
};
// ASCII-codes voor toetsen met ctrl ingedrukt.
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, 32, 0, 0, 0, 0, 0, 0, 0
};
// ASCII-codes voor toetsen met spcl ingedrukt.
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, 0
};
// ASCII-codes voor toetsen met alt ingedrukt.
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
};
// ASCII-codes voor toetsen met fn ingedrukt.
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
};
// ASCII-codes voor toetsen met caps actief
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; // slaat laatste keer op dat toetsenbord gecheckt werd
// de volgende variabele is een long omdat de tijd, gemeten in milliseconden,
// snel een groter wordt dan in een int opgeslagen kan worden.
long keyboardInterval = 500; // interval om toetsenbord te checken (microseconden)
int rowToCheck = 0; // We checken één rij per lus van checkKeyboard(), dit gecombineerd met keyboardInterval
// geeft de shiftRegister tijd om volledig te updaten tussen rij-controles
bool caps = false; // is caps lock aan?
bool shift = false; // is linker of rechter shift ingedrukt?
bool capsShift = false; // zijn shift EN caps actief?
bool ctrl = false; // is de ctrl-toets ingedrukt?
bool spcl = false; // is de spcl-toets ingedrukt?
bool alt = false; // is de alt-toets ingedrukt?
bool fn = false; // is de function-toets ingedrukt?
void setup() {
Serial.begin(9600);
// stel alle kolompinnen in als inputs met interne pull-up weerstanden
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);
// de outputs die nodig zijn om de 74HC595 shift register te besturen
pinMode(rowLatch, OUTPUT);
pinMode(rowClock, OUTPUT);
pinMode(rowData, OUTPUT);
updateShiftRegister(B11111111); // zorg dat shift register begint met alle HIGH
}
void loop() {
mainTimer();
}
void mainTimer() {
unsigned long currentMicros = micros(); // hoeveel microseconden draait de Arduino al?
if(currentMicros - previousKeyboardMicros > keyboardInterval) {
// als verstreken tijd sinds laatste check het interval overschrijdt
// sla de laatste keer op dat het toetsenbord gecheckt werd
previousKeyboardMicros = currentMicros;
checkKeyboard(); // check alle toetsen en print resultaten naar serial
}
}
void updateShiftRegister(byte row) {
// deze functie stelt de shift register in volgens de byte die doorgegeven werd
digitalWrite(rowLatch, LOW); // zet latch op LOW zodat we een hele byte tegelijk kunnen schrijven
shiftOut(rowData, rowClock, MSBFIRST, row); // schrijf die byte
digitalWrite(rowLatch, HIGH); // zet latch terug op HIGH zodat shift register stabiel blijft tot volgende verandering
}
void checkKeyboard() {
// stel de shift register in op de byte-waarde van de huidige rij, uit het shiftRow[] byte-array
updateShiftRegister(shiftRow[rowToCheck]);
// Check elke kolom
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); }
// zet alle shift register pinnen op HIGH, dit houdt waarden tegen dat ze "bloeien" naar de volgende lus
updateShiftRegister(B11111111);
rowToCheck = rowToCheck + 1; // ga naar volgende rij
// na controleren van de 8e rij, check de statussen (toetsaanslagen) en begin weer bij de 1e rij
if (rowToCheck > 7 ) {
checkPressedKeys();
rowToCheck = 0;
}
}
void checkPressedKeys() {
// check of een van de shift-toetsen ingedrukt is
if (bitRead(rowState[5], 1) | bitRead(rowState[6], 4)) { shift = true; } else { shift = false; }
// check of een van de ctrl-toetsen ingedrukt is
if (bitRead(rowState[6], 5) | bitRead(rowState[7], 3)) { ctrl = true; } else { ctrl = false; }
// check of een van de spcl-toetsen ingedrukt is
if (bitRead(rowState[6], 6) | bitRead(rowState[7], 2)) { spcl = true; } else { spcl = false; }
// check of een van de alt-toetsen ingedrukt is
if (bitRead(rowState[6], 7) | bitRead(rowState[7], 1)) { alt = true; } else { alt = false; }
// check of FN-toets ingedrukt is
if (bitRead(rowState[7], 4)) { fn = true; } else { fn = false; }
// check of caps actief is en shift ingedrukt
if (shift == true && caps == true) { capsShift = true; } else { capsShift = false; }
for (int i = 8; i >= 0; i--) { // itereer door elke rij
for (int j = 7; j >= 0; j--) { // itereer door elke bit in die rij
bool newBit = bitRead(rowState[i], j); // check de staat van die bit
bool prevBit = bitRead(prevRowState[i], j); // check de vorige staat van die bit
if ((newBit == 1) && (prevBit == 0)) { // laat toetsaanslag alleen toe als staat veranderd is naar true
int thisChar = (i * 8) + j; // bereken welke positie in char-array te selecteren
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); } // zet vorige bitstaat op true als toets ingedrukt
else { bitClear(prevRowState[i], j); } // zet vorige bitstaat op false als toets niet ingedrukt, zodat het weer ingedrukt kan worden
}
}
}
void processKey(char receivedKey) {
if (receivedKey == 7) { // check voor speciale functies op dezelfde manier als caps (voeg nieuwe "else if" statements toe)
caps = !caps;
} else {
Serial.print(receivedKey); // als char niet overeenkomt met een speciale functie, print die char gewoon
}
}
Aangepaste onderdelen en behuizingen
Upload het hele .zip-bestand naar je PCB-fabricagedienst
keyplots_4xipOSLHzg.zip
Schema's
Productieproces
- Arduino Nano Flight Simulator 2020 Bedieningspaneel – LCD & CDI Display
- Arduino-gebaseerd schakelaar- & LED-paneel voor Microsoft Flight Simulator 2020
- Verander je MIDI-toetsenbord in een slimme pianotutor met Arduino, LEDs en MuseScore
- Een 8×8 LED-matrix beheersen met Arduino Uno: Stap-voor-stap handleiding
- Slim Temperatuurmonitoring Systeem voor Scholen: Nauwkeurig, Real-time en Beveiligd
- Efficiënte 8-bit IO-poort bibliotheek voor Arduino – Uitbreiding digitale controle
- Hoogwaardige 2,8″ TFT Shield voor Arduino Nano – 320×240 SPI Display
- Geïsoleerde analoge ingangsschakeling voor Arduino bouwen
- Arduino rekenmachine bouwen met 16x2 LCD en keypad
- DC-motorbeheersing onder de knie: Expert Tips & Trucs met PID-regeling
- Slim Indoor Navigatie Robot Kit voor Arduino Projecten