這是一個簡單的 PCB 鍵盤,您可以輕松地將其用于您的 Arduino 項目。
我目前正在做一個將有一個集成鍵盤的項目,做的時候碰上了一個問題:我如何在開發板原型中包含一個鍵盤?我不能使用 USB 鍵盤或現有的基于 Arduino 的鍵盤,因為實際項目中的鍵盤直接連接到處理所有其他功能的微控制器。所以我設計了這個基本的基于 PCB 的 64 鍵原型鍵盤矩陣。
此 PCB 不包含任何 IC 。鍵盤矩陣的行和列直接連接到排針,以便鍵盤可以連接到 Arduino 或任何其他微控制器。它非常適合對包含集成鍵盤的項目進行原型設計。
項目需要包含詳細的、大量注釋的代碼,以使其與任何具有足夠 I/O 引腳可用的 Arduino 兼容開發板一起工作——需要 11 個引腳。鍵盤有 64 個鍵,包括 shift、caps、ctrl、alt、fn 和“special”的修飾符。還有六個額外的鍵可用于定制您喜歡的任何內容。可以單獨定義每個鍵的功能,包括激活修飾符時每個鍵的功能。在我看來,這比現有的鍵盤代碼更有用,后者嚴重限制了您自定義按鍵行為的能力。
提供的代碼會將文本打印到 Serial。如果您希望文本轉到其他地方,則可以輕松更改此設置。
關于程序大小的說明:
項目代碼非常大,因為它不使用任何現有的庫。我完全從頭開始編寫這段代碼,以實現我需要的可定制性。在 Arduino UNO 上,這將使用 9100 字節 (28%) 的程序存儲空間,全局變量使用 394 字節 (19%) 的動態內存。
我的代碼可能會更高效,并且鍵盤的庫和草圖肯定更小,但這是我可以設計的唯一方法,可以為每個修飾符的每個鍵提供完全的靈活性。它還考慮了現實世界的鍵盤使用情況。例如,我的代碼在啟用 Caps Lock 的情況下按 Shift 鍵將生成應有的小寫字母。默認情況下,按住 FN 鍵的同時按 ESC 不會執行任何操作。但是這種行為是完全可定制的,所以你可以隨意改變它。
所需:
定制PCB
6x6x5mm 觸覺瞬時按鈕(x64)
1N4148 開關二極管(x64)
1x8 排針,母頭或公頭(x2)
74HC595移位寄存器
跳線
面包板
Arduino Uno或任何與 Arduino 兼容的微控制器開發板
第 1 步:鍵盤矩陣的工作原理
為什么需要鍵盤矩陣?
這個鍵盤有 64 個鍵。如果您要將這些按鈕中的每一個都直接連接到您的開發板,則需要 64 個 I/O 引腳。那是很多引腳,比大多數開發板都可用。為了將它降低到一個更合理的數字,我們可以使用鍵盤矩陣,它只需要與鍵數的平方根(向上取整)相等的引腳數。
設置了鍵盤矩陣,因此連接了行中的每個鍵開關,并且連接了列中的每個鍵開關。當我們想查看按下了哪些鍵時,我們“激活”第一行,然后檢查每一列。如果特定列處于活動狀態,我們就知道該列和第 1 行中的鍵已被按下。然后我們停用第 1 行并激活第 2 行,然后再次檢查所有列。在所有行都被激活后,我們只需從第一行重新開始。
如何掃描鍵盤矩陣:
因為我們使用的是微控制器,所以“激活”意味著將該行設置為 LOW 或 HIGH。在這種情況下,我們將行設置為低,因為我們在列輸入引腳上使用了微控制器的內置上拉電阻。如果沒有上拉或下拉電阻,輸入引腳將因接口而做出不可預測的反應,這將記錄錯誤的按鈕按下。
Arduino UNO 中使用的 ATmega328P 微控制器沒有任何內置下拉電阻,只有上拉電阻。所以我們正在使用這些。上拉電阻將每個輸入引腳連接到 5V,確保在按下按鈕之前它們始終讀取為高電平。
所有的行通常也設置為 HIGH,這可以防止列引腳連接到行引腳,無論是否按下按鈕。但是當我們準備好檢查一行時,我們可以將該行設置為 LOW 。如果按下該行中的按鈕,這將為輸入引腳提供一個被拉到地的路徑——導致該列現在讀取為 LOW 。
因此,總而言之:我們將一行設置為 LOW,然后檢查哪些列引腳現在讀取 LOW。這些對應于按下的按鈕。這個過程發生得非常快,因此我們可以每秒多次掃描整個鍵盤。我的代碼將其限制為每秒 200 次,以平衡性能、彈跳和確保每個按鍵都被捕獲。
二極管、重影和 n 鍵翻轉:
當按住某些按鈕組合時,電路中的二極管可以防止意外按鍵。二極管只允許電流沿一個方向流動,從而防止重影。如果我們不使用二極管,那么按下某些鍵可能會導致另一個未按下的鍵被注冊,因為電流流過相鄰的開關。這在簡化的圖形中顯示,其中按下任何三個相鄰的鍵都會導致第四個角的鍵被注冊,即使它沒有被按下。二極管可以防止這種情況并啟用“n鍵翻轉”,這意味著我們可以按我們想要的任何組合按我們想要的任意數量的鍵,而不會出現任何問題。
用移位寄存器保存引腳:
精明的你們可能注意到我說鍵盤矩陣需要的引腳數等于鍵數的平方根,但我也說過我的鍵盤設計只需要 11 個引腳。應該是16吧?不,因為我們使用的是 74HC595 移位寄存器。這個移位寄存器讓我們只使用 Arduino 的三個 I/O 引腳來控制多達八個輸出引腳。這三個引腳讓我們向移位寄存器發送一個字節(八位),它將其八個輸出引腳設置為高電平或低電平。通過對輸出行引腳使用移位寄存器,我們節省了 5 個完整的 I/O 引腳!
“那么為什么不對輸入引腳也使用移位寄存器呢?” 你問。最簡單的答案是輸入需要不同類型的移位寄存器,而我手頭沒有那種類型。但是使用移位寄存器進行輸入也會使我們讀取列的方式復雜化,并可能導致噪聲和“彈跳”問題。我只想說在這種情況下我不需要承擔這個頭疼的事。
第 2 步:PCB 設計
原理圖設計
現在您了解了鍵盤矩陣的工作原理,我的 PCB 設計應該很簡單。我在 KiCAD 中設計了 PCB,并從原理圖開始。我只是放置了一個按鈕符號和一個二極管符號,然后復制并粘貼它們,直到我擁有 64 個鍵的網格。然后我添加了兩個 1x8 針頭符號,一個用于行,一個用于列。按鈕的一側連接成列,按鈕的另一側連接成行。
下一步是將 PCB 封裝分配給每個原理圖符號。KiCAD 包含的封裝庫內置了必要的封裝。當您設計自己的 PCB 時,您必須非常小心地選擇正確的封裝,因為這些實際上最終會出現在您的 PCB 上。有許多組件具有非常相似的足跡,但間距或其他方面略有不同。確保選擇與您的實際組件相匹配的組件。
封裝和引腳編號
請特別注意引腳編號。KiCAD 有一個奇怪的問題,即原理圖二極管符號引腳編號與封裝引腳編號不匹配。這導致二極管反向,考慮到它們的極性,這是一個嚴重的問題,必須創建一個自定義二極管封裝并交換引腳號。
PCB布局
完成原理圖并分配足跡后,我開始進行實際的 PCB 布局。電路板輪廓在 Autodesk Fusion 360 中創建,導出為 DXF,然后在 Edge Cuts 圖層上導入 KiCAD。之后的大部分工作只是簡單地排列按鈕,使它們的布局類似于普通鍵盤。
PCB制造
設計好電路板后,我簡單地繪制了所有層并將它們添加到一個 zip 文件夾中。該文件夾在此處提供,可以直接上傳到 JLCPCB 等 PCB 制造服務。
第 3 步:PCB 組裝
這是整個項目中最簡單但最繁瑣的一步。只需將所有組件焊接到位。它們都是通孔元件,易于焊接。特別注意二極管的方向。二極管上的標記應與 PCB 上的標記相匹配。
根據我的經驗,最簡單的方法是用第三只手將 PCB 固定到位,然后將所有二極管先放入。然后翻轉電路板并將它們全部焊接,然后夾住引線。然后放置所有按鈕并焊接它們。然后將排針焊接到位。您可以使用母頭或公頭排針,這完全取決于您。如果你使用公頭然后放在板子下面,間距是正確的,可以將它們直接粘在面包板上。
第 4 步:將鍵盤連接到您的 Arduino
接線看起來很復雜,但是當您注意到細節時,它其實并沒有那么糟糕。
八根跳線將從列標題直接進入以下 Arduino 引腳:
第 1 列 》 A0
第 2 欄 》 A1
第 3 欄 》 A2
第 4 欄 》 A3
第 5 欄 》 A4
第 6 欄 》 A5
第 7 欄 》 5
第 8 欄 》 6
接下來,將 74HC595 移位寄存器放在面包板上,橫跨中間休息處。注意芯片的方向,圓點表示引腳 1。
查看接線圖,了解 5V 和接地連接的位置。移位寄存器有兩個連接到 5V 的引腳和兩個接地的引腳。
只需三根線即可將移位寄存器連接到 Arduino。他們是:
Shift(時鐘)11 》 4
Shift(閂鎖)12 》 3
Shift(數據)14 》 2
出于某種原因,移位寄存器的輸出引腳以違反直覺的方式排列。將移位寄存器連接到行引腳時,請特別注意移位寄存器引腳圖。他們是:
第 1 行 》 Shift (Q0) 15
第 2 行 》 Shift (Q1) 1
第 3 行 》 Shift (Q2) 2
第 4 行 》 Shift (Q3) 3
第 5 行 》 Shift (Q4) 4
第 6 行 》 Shift (Q5) 5
Shift 7 》 Shift (Q6) 6
Shift 8 》 Shift (Q7) 7
沒有任何東西連接到 Arduino 0 或 1 引腳,因為它們也用于串行端口并導致沖突。
第 5 步:刷新 Arduino 代碼
這一步沒有什么特別之處,只需像使用任何其他 Arduino 項目一樣上傳代碼即可。
代碼中的所有內容都有詳細的注釋,您可以閱讀,因此我不會在這里詳細介紹。基本上,引腳設置為輸入和輸出。主循環只包含一個計時器功能。每5ms,它調用函數掃描鍵盤。在檢查每一列之前,該函數調用一個單獨的函數來設置移位寄存器。按下的鍵將其值打印到串行。
如果要更改按鍵時打印的內容,只需更改Serial.print(“_”); 在與條件相對應的 if 語句中。例如,您可以設置按住 FN 并按 N 時打印的內容。對于每個其他帶有每個修飾符的鍵也是如此。
許多鍵在這段代碼中根本不做任何事情,因為它只是打印到串行。這意味著退格鍵不起作用,因為您無法從串行監視器中刪除該數據已經收到。但是,如果您愿意,可以隨意使用更改。
在項目中使用鍵盤
打印到串口很好,但這并不是這個鍵盤的真正意義。該鍵盤的目的是為更復雜的項目制作原型。這就是為什么很容易改變功能的原因。例如,如果您想將鍵入的文本打印到 OLED 屏幕上,您可以簡單地將每個Serial.print(替換為display.print(或您的特定顯示器需要的任何內容。Arduino IDE 的Replace All工具非常適合替換所有這些一步到位。
ProtoKeyboardV1-Bits.ino:
/* ? ?Sketch for Prototyping Keyboard V1.2
?* ? ?by Cameron Coward 1/30/21
?* ? ?
?* ? ?Tested on Arduino Uno. Requires custom PCB
?* ? ?and a 74HC595 shift register.
?* ? ?
?* ? ?More info: https://www.hackster.io/cameroncoward/64-key-prototyping-keyboard-matrix-for-arduino-4c9531
?*/
const int rowData = 2; // shift register Data pin for rows
const int rowLatch = 3; // shift register Latch pin for rows
const int rowClock = 4; // shift register Clock pin for rows
// these are our column input pins. Pin 0 and Pin 1 are not used,
// because they cause issues (presumably because they're TX and 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 is the required shift register byte for each row, rowState will contain pressed keys for each row
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 for keys with no modifiers pressed. Modifiers are NULL (0),
// because we will check those separately and their values should not be printed.
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 for keys with shift pressed AND caps is active
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 for keys with shift pressed.
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 for keys with ctrl pressed.
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 for keys with spcl pressed.
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
};
// ASCII codes for keys with alt pressed.
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
};
// ASCII codes for keys with fn pressed.
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
};
// ASCII codes for keys with caps is active
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; ? ? ? ?// will store last time keyboard was checked
?
// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long keyboardInterval = 500; ? ? ? ? ? // interval at which to check keyboard (microseconds)
int rowToCheck = 0; // We check one row per loop of checkKeyboard(), this combined with keyboardInterval?
? ? ? ? ? ? ? ? ? ? // gives the shiftRegister time to fully update between row checks
bool caps = false; ?// is caps lock on?
bool shift = false; // is either left or right shift pressed?
bool capsShift = false; // are shift AND caps active?
bool ctrl = false; // is the ctrl key pressed?
bool spcl = false; ?// is the spcl key pressed?
bool alt = false; // is the alt key pressed?
bool fn = false; ?// is the function key pressed?
void setup() {
? Serial.begin(9600);
? // setup all column pin as inputs with internal pullup resistors
? 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);
? // the outputs needed to control the 74HC595 shift register
? pinMode(rowLatch, OUTPUT);
? pinMode(rowClock, OUTPUT);
? pinMode(rowData, OUTPUT);
? updateShiftRegister(B11111111); // make sure shift register starts at all HIGH
}
void loop() {
?mainTimer();
}
void mainTimer() {
? unsigned long currentMicros = micros(); // how many microseconds has the Arduino been running?
??
? if(currentMicros - previousKeyboardMicros > keyboardInterval) { // if elapsed time since last check exceeds the interval
? ? // save the last time the keyboard was checked
? ? previousKeyboardMicros = currentMicros; ??
?
? ? checkKeyboard(); // check all of the keys and print out the results to serial
? }
}
void updateShiftRegister(byte row) {
? //this function sets the shift register according to the byte that was passed to it
?
? digitalWrite(rowLatch, LOW); // set latch to low so we can write an entire byte at once
? shiftOut(rowData, rowClock, MSBFIRST, row); ?// write that byte
? digitalWrite(rowLatch, HIGH); // set latch back to high so it shift register will remain stable until next change
}
void checkKeyboard() {
? // set the shift register to the current row's byte value, from the shiftRow[] byte array
? updateShiftRegister(shiftRow[rowToCheck]);
? // Check each column
? 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);
? }
? // set all shift register pins to HIGH, this keeps values from "bleeding" over to the next loop
? updateShiftRegister(B11111111);
? rowToCheck = rowToCheck + 1; // iterate to next row
? // after checking the 8th row, check the states (button presses) and then start over on the 1st row
? if (rowToCheck > 7 ) {
? ? checkPressedKeys();
? ? rowToCheck = 0;
? }
}
void checkPressedKeys() {
? // check if either shift key is pressed
? if (bitRead(rowState[5], 1) | bitRead(rowState[6], 4)) {
? ? shift = true;
? } else {
? ? shift = false;
? }
? // check if either ctrl key is pressed
? if (bitRead(rowState[6], 5) | bitRead(rowState[7], 3)) {
? ? ctrl = true;
? } else {
? ? ctrl = false;
? }
? // check if either spcl key is pressed
? if (bitRead(rowState[6], 6) | bitRead(rowState[7], 2)) {
? ? spcl = true;
? } else {
? ? spcl = false;
? }
? // check if either alt key is pressed
? if (bitRead(rowState[6], 7) | bitRead(rowState[7], 1)) {
? ? alt = true;
? } else {
? ? alt = false;
? }
? // check if FN key is pressed
? if (bitRead(rowState[7], 4)) {
? ? fn = true;
? } else {
? ? fn = false;
? }
? // check caps is active and shift is pressed
? if (shift == true && caps == true) {
? ? capsShift = true;
? } else {
? ? capsShift = false;
? }
??
? for (int i = 8; i >= 0; i--) { ? ? ? ? ? ? ? ? ? ?// iterate through each row
? ? for (int j = 7; j >= 0; j--) { ? ? ? ? ? ? ? ? ?// iterate through each bit in that row
? ? ??
? ? ? bool newBit = bitRead(rowState[i], j); ? ? ? ? ? ? // check the state of that bit
? ? ? bool prevBit = bitRead(prevRowState[i], j); ? ? ? ? // check the previous state of that bit
? ? ??
? ? ? if ((newBit == 1) && (prevBit == 0)) { ? ? ? ? ? ? ? ? ? ? ? // only allows button press if state has changed to true
? ? ? ? ? int thisChar = (i * 8) + j; ? ? ? ? ? ? ? // calculate which position in char array to select
? ? ? ? ? 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); ? ? // set previous bit state to true if a key is pressed
? ? ? } else {
? ? ? ? ? bitClear(prevRowState[i], j); ? // set previous bit state to false if key isn't pressed, so it can be pressed again
? ? ? }
? ? }
? }
}
void processKey(char receivedKey) {
? if (receivedKey == 7) { ? ? ? ? ? ? ? ? // check for special functions in the same way as caps (add new "else if" statements)
? ? caps = !caps;
? } else {
? ? Serial.print(receivedKey); ? ? ? ? ? ?// if char does not correspond to a special function, simply print that char
? }
}
評論
查看更多