在電路中開關的種類很多,主要的功能是接通和斷開,開關打開時為接通,此時電流會流通,我們稱之為(ON),開關斷開時會開路,此時電流不會流通,我們稱之為(OFF)。開關的種類有很多,例如:機械開關、指撥開關、按鍵開關,可以上網查詢各個開關的模樣與電路圖的表示方法,蠻好分辨的。
一般微控制器數位輸入腳位的接法分別為上拉電阻(Pull-Up)與下拉電阻(Pull-Down)。第一張圖:下拉電阻(Pull-Down)接法+5V
│
[按鈕]
│
Pin7 ← 連接到數位輸入腳(如 sw=7)
│
[10K] ← 電阻(例如 10KΩ)
│
GND
工作原理:
Pin7
讀到的是 LOW (0)。Pin7
讀到的是 HIGH (1)。第二張圖:上拉電阻(Pull-Up)接法
+5V
│
[10K] ← 電阻(例如 10KΩ)
│
Pin7 ← 連接到數位輸入腳(如 sw=7)
│
[按鈕]
│
GND
工作原理:
Pin7
預設為 HIGH (1)。Pin7
直接接到 GND,讀到的是 LOW (0)。好,現在幫我將接線用成下圖(下拉電阻(Pull-Down)接法):
const int sw = 7;
const int led = 12;
void setup()
{
pinMode(sw, INPUT);
pinMode(led, OUTPUT);
}
void loop()
{
if(digitalRead(sw) == HIGH){
delay(20);
digitalWrite(led, HIGH);
}
else{
digitalWrite(led, LOW);
}
}
delay(20)
,但它並不是真正意義上的「去彈跳」(debounce);更準確地說,這只能算是插入一段延時,並沒有在延時之後再次檢查按鈕是否仍維持在同一狀態。所以真正的軟體去彈跳流程為何?
改進的程式碼如下所示:
const int sw = 7;
const int led = 12;
const int deBounceDelay = 20;
void setup() {
pinMode(sw, INPUT);
pinMode(led, OUTPUT);
}
void loop() {
// 偵測按鈕是否被按下
if (digitalRead(sw) == HIGH) {
// 按下後先等待 debounce 延時
delay(deBounceDelay);
// 再次確認按鈕是否仍然處於按下狀態
if (digitalRead(sw) == HIGH) {
// 如果確定按下,則點亮 LED
digitalWrite(led, HIGH);
// 進入等待狀態,直到按鈕鬆開
while (digitalRead(sw) == HIGH)
;
// 等待按鈕釋放(鬆開)後,再做一次 debounce
delay(deBounceDelay);
if (digitalRead(sw) == LOW) {
// 確認鬆開後,熄滅 LED
digitalWrite(led, LOW);
}
}
}
}
這段程式碼:
while(digitalRead(sw) == HIGH)
;
的意思是:只要 digitalRead(sw) 回傳 HIGH,程式就會一直在這個迴圈中「忙等待」(busy-wait),直到按鈕狀態改變,不再是 HIGH。這種寫法可以讓程式暫停在這裡,不執行後面的程式碼,直到按鈕被放開。
如若今天我想要利用按鈕來控制的行為是: 按鈕按下後放開,切換狀態的話,我們可以這樣實現:
const int sw = 7;
const int led = 12;
const int deBounceDelay = 20;
int lesStatus = LOW;
void setup()
{
pinMode(sw, INPUT);
pinMode(led, OUTPUT);
}
void loop()
{
if(digitalRead(sw) == HIGH){
delay(deBounceDelay);
while(digitalRead(sw) == HIGH)
;
lesStatus = !lesStatus;
digitalWrite(led, lesStatus);
}
}
好,在Arduino中,其內部有上拉電阻,「上拉電阻」的概念是用來穩定數位輸入腳的電平,避免在開關(如按鈕)未接通時輸入腳懸空,從而受到干擾產生不穩定的讀數。
上拉電阻的接法如下:
+5V
│
[10K] ← 上拉電阻(例如 10KΩ)
│
Pin7 ← 連接到數位輸入腳(如 sw=7)
│
[按鈕]
│
GND
想要使用Arduino 的內建上拉電阻,只需將腳位設為
pinMode(sw, INPUT_PULLUP);
好,現在我們來改寫本章節的範例3:
首先改變接線關係:
再來修改程式碼:
const int sw = 7;
const int led = 12;
const int deBounceDelay = 20;
int ledStatus = LOW;
void setup() {
pinMode(sw, INPUT_PULLUP); // 使用內建上拉電阻
pinMode(led, OUTPUT);
}
void loop() {
// 當按鈕被按下時,digitalRead(sw) 會讀取到 LOW
if (digitalRead(sw) == LOW) {
delay(deBounceDelay); // 延時以消除彈跳
// 等待按鈕釋放,即讀值變成 HIGH
while (digitalRead(sw) == LOW)
;
ledStatus = !ledStatus; // 切換 LED 狀態
digitalWrite(led, ledStatus); // 更新 LED 輸出
}
}
電話鍵盤通常採用矩陣式排列,例如 3×4 的鍵盤
在tinkercad中,已經幫你標記好接線的關係了,如下圖:
好,這邊簡單示範如何掃描指定按鈕的讀值,策略是使用兩個迴圈,外層迴圈負責掃描列,內層迴圈負責掃描行(檢查哪一按鈕被壓下)。
好,首先請跟我把麵包版接好,如下圖:
再來,程式碼如下所示:
const byte ROWS = 4; // 四列
const byte COLS = 4; // 四行
const int buzzPin = 3; // 蜂鳴器接腳
// 鍵盤行與列的 Arduino 腳位設定
byte rowPins[ROWS] = {4, 5, 6, 7}; // 連接鍵盤的列腳位
byte colPins[COLS] = {8, 9, 10, 11}; // 連接鍵盤的行腳位
// 鍵盤上各按鍵對應的字元
char keys[ROWS][COLS] = {
{'1','2','3', 'A'},
{'4','5','6', 'B'},
{'7','8','9', 'C'},
{'*','0','#', 'D'}
};
const int deBounceDelay = 20; // 去彈跳延時(毫秒)
void setup(){
Serial.begin(9600);
// 設定所有 rowPins 為輸出,預設拉 HIGH
for (int i = 0; i < ROWS; i++){
pinMode(rowPins[i], OUTPUT);
digitalWrite(rowPins[i], HIGH);
}
// 設定所有 colPins 為輸入,啟用內建上拉
for (int i = 0; i < COLS; i++){
pinMode(colPins[i], INPUT_PULLUP);
}
// 設定蜂鳴器腳位為輸出
pinMode(buzzPin, OUTPUT);
}
// getKey() 函式:掃描矩陣鍵盤,若有按下則回傳該鍵字元,否則回傳 '\0'
char getKey() {
for (int r = 0; r < ROWS; r++) {
// 將當前列拉低
digitalWrite(rowPins[r], LOW);
// 掃描所有行
for (int c = 0; c < COLS; c++){
// 因為使用內建上拉電阻,按下時該行會變成 LOW
if (digitalRead(colPins[c]) == LOW) {
delay(deBounceDelay); // debounce 延時
if (digitalRead(colPins[c]) == LOW) { // 再次確認仍然按下
// 等待按鍵釋放
while (digitalRead(colPins[c]) == LOW) {
;
}
// 將該列恢復 HIGH 後,回傳對應字元
digitalWrite(rowPins[r], HIGH);
return keys[r][c];
}
}
}
// 恢復該列為 HIGH
digitalWrite(rowPins[r], HIGH);
}
return '\0'; // 沒有按鍵按下時回傳空字元
}
void loop(){
char key = getKey(); // getKey() 掃描鍵盤
if (key != '\0') { // 若有鍵按下
Serial.print("Press: ");
Serial.println(key);
// 控制蜂鳴器嗶一聲:蜂鳴 100 毫秒
digitalWrite(buzzPin, HIGH);
delay(100);
digitalWrite(buzzPin, LOW);
}
}
getKey()
函式
'\0'
。本頻道持續更新中(內容涵蓋前端程式設計入門、大學必備程式設計入門、電子系專業課程入門、數學微積分題解)如果身旁有相關科系的學生,不妨推薦一下喔~
相信這裡會是家教或線上課程之外,高中、大學生系統性綜合學習的好選擇。
最後感謝您的觀看!