今天要介紹的是arduino裡的鍵盤元件-keypad~
這個是模擬器裡的keypad,有16個鍵。
先介紹底下的引腳,總共有八個,從左邊往右來看,分別為ROW1、ROW2、ROW3、ROW4、COL1、COL2、COL3、COL4。
那這個keypad順序跟我們在C中學到的陣列是一樣的,ROW1是最上面的列、COL1是最左邊的行,依序往下、往右。
那這八個引腳,要分別接上八個不同的數位腳位,之後寫程式碼執行時會要寫入這八個引腳接到哪個角位。
那在使用keypad前,要先載他的函式庫~叫做Keypad。
然後是接上keypad,這裡我接的腳位是D13~D6。
接著是一些使用keypad的設定:
keypad共有4個Row、4個Column,所以我先設兩個常數,分別表示Row及Column的數量:
const int ROWS = 4; //row數量
const int COLS = 4; //column數量
然後設立一個4*4大小的陣列,用來表示此keypad中每一個鍵所代表的值:
char keys[ROWS][COLS] =
{
{'1','2','3','A'}, //第一個ROW
{'4','5','6','B'}, //第二個ROW
{'7','8','9','C'}, //第三個ROW
{'*','0','#','D'} //第四個ROW
};
那這個每一個按鍵的值,不一定需要跟按鍵上印的字一樣,就依照自己的需求去給值就可以了;我也可以在這16個鍵上,依序給A、B、C、D、E、F、…。
然後還記得前面的時候有先接keypad的線嗎~接著就要來寫入接的腳位了,根據剛剛的接線來寫入。
uint8_t rowPins[ROWS] = {13,12,11,10}; //ROW由上到下接的腳位(R1,R2,R3,R4)
uint8_t colPins[COLS] = {9,8,7,6}; //COL由左到右接的腳位(C1,C2,C3,C4)
這邊來解釋一下uint8_t是什麼意思,u是unsigned,int就是integer,8就是位元數,t是typedef,所以uint8_t就是指宣告一個無號整數,有8位,所以值的範圍是0~255。
那keypad的基本設定都設定好了,接著就是輸入的部分,也就是傳送按下的鍵所代表的值到開發板中。
Keypad keypad = Keypad(makeKeymap(keys),rowPins,colPins,ROWS,COLS);
這邊使用到Keypad函式庫中的function,用來處理鍵盤的輸入。
先宣告一個變數為keypad,他的type為Keypad,keypad的值會是Keypad這個function的結果。
接著來看Keypad的每一個參數意思~
makeKeymap()是一個function,他會將一個二維陣列轉化成一個鍵盤的樣子,那括號內放入的變數就是我們先前宣告好的4*4陣列,也就是表示keypad每一個鍵的意思的那個陣列;makeKeymap(keys)執行好後,就會告訴Keypad這個鍵盤矩陣每一個按鍵的位子以及他所代表的值。
那如果是希望按下某個鍵後能產生什麼功能,只要定義好後,makeKeymap也會將此功能傳入Keypad中。
接著是rowPins及colPins,也是剛剛定義過的一維陣列,這兩個陣列負責告訴Keypad,鍵盤接到了開發板中的哪八個腳位。
最後是ROWS及COLS,這兩個則是向Keypad表達這個鍵盤有幾個row、幾個column。
那目前這些定義都不用寫在setup或loop裡,就像是寫C時定義全域變數或寫function一樣。
在keypad的部分,setup是不用特別處理他的初始化,所以單純只使用keypad的話,setup應該是可以為空。
接著就是loop執行的部分。
void loop()
{
char key = keypad.getKey();
if( key != NO_KEY ){
lcd.print(key);
}
}
在這個loop裡,我要在lcd印上我剛剛在keypad按了哪個鍵。
在Keypad函式庫中,可以透過getkey()來取得剛剛按的值;我將getkey()的回傳值儲存在key這個變數中。
那如果按下後沒有得到任何的值,getkey()就會回傳「NO_KEY」,所以如果key儲存的值不等於NO_KEY,就表示有按鈕被按、且值傳送到key儲存,然後印到lcd中。
好啦~那keypad的基本設定跟操作都介紹完了~
接下來是簡單的操作,在按下keypad後,我要lcd輸出我在鍵盤按下了什麼鍵:
#include <LiquidCrystal.h>
#include <Keypad.h>
LiquidCrystal lcd(19,18,17,16,15,14);
const int ROWS = 4;
const int COLS = 4;
char keys[ROWS][COLS] =
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
uint8_t rowPins[ROWS] = {13,12,11,10};
uint8_t colPins[COLS] = {9,8,7,6};
Keypad keypad = Keypad(makeKeymap(keys),rowPins,colPins,ROWS,COLS);
void setup()
{
Serial.begin(9600);
lcd.begin(16,2);
}
void loop()
{
char key = keypad.getKey();
if( key != NO_KEY ){
lcd.print(key);
delay(1000);
}
lcd.clear();
}
接線的部分則是:
當我按下keypad的其中一個鍵,lcd就會顯示我按的鍵是哪一個,顯示一秒後就消失。
那因為我要求lcd要顯示1秒,所以在這顯示的1秒內,如果按其他鍵,是不會有反應的,得等1秒結束。
寫一下改良版:
void loop()
{
char key = keypad.getKey();
if( key != NO_KEY ){
lcd.clear(); //清空畫面
lcd.print(key);
}
}
跟上一個的差別是,把delay移除、在lcd印字前先清空畫面。
有沒有清空畫面的差異是,如果有清空,則每一次按下按鈕時,值都會固定顯示在左上第一格。
那如果沒有清空畫面,按下的值就會一直存在,所以再按下其他按鈕時,字會接著印在後面。
那接著來點lcd的小補充。
如果按照上述的程式碼,我按了16個鍵後,第一排滿了,接下來再按任何的數值,畫面都不會有改變。
那如果我希望第一排滿了之後,改印在第二排,就要來做點設定:
int cnt = 0;
void loop()
{
char key = keypad.getKey();
if( key != NO_KEY ){
cnt += 1;
if( cnt == 17 ){
lcd.setCursor(0,1);
}
lcd.print(key);
}
}
我新增了一個cnt,負責計數目前按了幾個鍵;當按到第17個鍵,就表示要換到下一行,所以就將cursor移到(0,1)的位子,這樣就會在第一排滿了之後,接這印在第二排了。
我本來寫成if(cnt > = 17 ),但這樣就是17之後每次游標都會停留在(0,1)的地方XD
喔對,如果沒有換行,那按到第41個鍵時,就會印到第二排囉~因為其實這個LCD板子每一排都有40個位子,會顯示出來的卻只有16格。
那今天就先這樣~keypad是一個很神奇的東西吧XD