用ADC读取按键
写了一个用ADC读取按键的方法,分享给大家https://www.arduino.cn/thread-90698-1-1.html 本帖最后由 shouzama 于 2019-9-1 15:39 编辑
我在去年也有做一個專題,那個專題要用4*4的矩陣按鍵
https://img.pcstore.com.tw/~prod/M07530108_big.jpg?P=1560388092
為了用最少I/O來做按鍵讀取功能,也稍微想了一下,依照
一般掃瞄方式就像您說的需要 4掃瞄線+4讀取線=8 個
PORT,後來我是用 4 個 ADC PORT 來達成,原理跟您的
類似,但我的做法在硬體上比較簡單,細部則交給軟體去
處理
比方說雜訊濾除,我沒用任何電路去做,但軟體要負責
判斷是雜訊或是真正按鈕,彈跳處理也是軟體來做,分壓
則很簡單用 4 顆 1Kohm 電阻將 5V 分成四等份:
1.23V、2.48V、3.75V、5V ,再將這些分壓接到矩陣
按鍵的掃瞄端,輸出端則接到 A4、A5、A6、A7
(A6 A7是 PRO MINI 才有的 ADC,它們不能當OUTPUT,
拿來做 INPUT 剛好合適 )
這個程式只是用來讀取矩陣按鈕,算是該專題全面進行
前的功能測試,後來改成副程式只是讓它在專題主程式
中比較好呼叫處理而已
/*
4*4 按鍵讀取測試程式,2018.09.27 作成
接腳 1:+5.00V 1023
接腳 2:+3.75V 767
接腳 3:+2.48V 507
接腳 4:+1.23V 251
依次讀取 A,B,C,D 腳位是否有穩定的輸入電壓(連讀2次間隔 GAP_TIME),
依讀取的位置(A~D)及讀到的電壓來判斷是哪個按鍵被按下,顯示於MONITOR內
2018.09.29 改版:以副程式呼叫,掃瞄讀取按鍵值並回傳,追加按鍵按住不放判斷
*/
#define MISS 5 //讀取值的可容許公差(+/-)
#define BUZZER 3 //定義蜂鳴器接腳為 3
#define BZ_TIMER 30 //按鍵回饋的響音長度
#define GAP_TIME 5 //連續讀取按鍵的間隔時間
#define SCAN_TIME 100 //按鍵回應時間
int SCAN_LINE = 0; //內定由 1 縱列開始掃瞄(再往2,3,A縱列)
int SCAN = { A5, A4, A6, A7 }; //設定掃瞄縱列(輸入埠順序)
int MAX = { 1023+MISS, 767+MISS, 507+MISS, 251+MISS }; //設定上限陣列
int MID = { 0, 1, 2, 3 }; //指向按鍵排(0=橫排1,1=橫排4,2=橫排7,3=橫排0)
int MIN = { 1023-MISS, 767-MISS, 507-MISS, 251-MISS }; //設定下限陣列
int K_VALUE = { 0,0,0 }; //定義按鍵讀值 3 筆
unsigned long KEY_PRESS_TIME = 0; //記錄此次按鍵時間
//設定按鍵陣列 KEY[縱列][橫排] 指向的特定按鍵值
int KEY = { { 1,2,3,10 }, { 4,5,6,11 }, { 7,8,9,12 }, { 0,15,14,13 } };
int READ_KEY()
//無輸入引數,讀取 4*4 按鍵狀態並回傳 1 短整數的按鍵值:(16=該掃瞄列無按鍵被按下,0~15="0"~"F")
{
int RESULT = 16; //回傳值,內定 16 (無按鍵按下)
//連續 3 次讀電壓值
for ( int I = 0; I<3; I++ )
{
K_VALUE = analogRead( SCAN ); //讀取輸入值(0~1023)
if ( K_VALUE <= MAX && K_VALUE >= MIN )
K_VALUE = MID; //若符合 1023 電壓範圍,則將電壓值轉成按鍵排值0
else
if ( K_VALUE <= MAX && K_VALUE >= MIN )
K_VALUE = MID; //若符合 767 電壓範圍,則將電壓值轉成按鍵排值1
else
if ( K_VALUE <= MAX && K_VALUE >= MIN )
K_VALUE = MID; //若符合 507 電壓範圍,則將電壓值轉成按鍵排值2
else
if ( K_VALUE <= MAX && K_VALUE >= MIN )
K_VALUE = MID; //若符合 251 電壓範圍,則將電壓值轉成按鍵排值3
else
K_VALUE = I+4; //若不符電壓範圍(浮動電壓)則將排值設為 I+4 (不存在&不會相同的排值)
delay( GAP_TIME ); //暫停,繼續讀下一次(共讀3次)
}
//判斷是否穩定(3 筆讀值需相同),若穩定,特定出按鍵別("0"~"F")
if ( K_VALUE == K_VALUE && K_VALUE == K_VALUE )
RESULT = KEY]; //依掃瞄線別 SCAN_LINE 及電壓讀值 K_VALUE 特定出被按下的按鍵
return RESULT; //傳回按鍵值(0~16)
}
void setup()
{
pinMode(BUZZER, OUTPUT); //指定蜂鳴器為輸出用
//初始化串列通訊並指定速率(BPS):
Serial.begin(9600);
}
void loop()
{
START:
SCAN_LINE++; //切往下一掃瞄縱列(0→3=1→A)
if ( SCAN_LINE == 4 ) //限制掃瞄縱列範圍0~3
SCAN_LINE = 0;
int NEW_KEY = READ_KEY(); //讀取按鍵值
if ( NEW_KEY != 16 ) //若有正確&穩定的新回傳按鍵值
{
if ( (millis()-KEY_PRESS_TIME) < SCAN_TIME )//若前後按鍵時間短則以按鍵未放開處理
{
KEY_PRESS_TIME = millis(); //更新按鍵時間
goto START; //重新掃瞄按鍵
}
Serial.print( NEW_KEY ); //顯示按鍵值&換列
Serial.print( "\n" );
digitalWrite( BUZZER, HIGH ); //響音
delay( BZ_TIMER );
digitalWrite( BUZZER, LOW );
KEY_PRESS_TIME = millis(); //記錄此次按鍵時間
}
}
页:
[1]