极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2514|回复: 1

用ADC读取按键

[复制链接]
发表于 2019-7-29 11:37:26 | 显示全部楼层 |阅读模式
写了一个用ADC读取按键的方法,分享给大家
https://www.arduino.cn/thread-90698-1-1.html
回复

使用道具 举报

发表于 2019-9-1 15:22:29 | 显示全部楼层
本帖最后由 shouzama 于 2019-9-1 15:39 编辑

我在去年也有做一個專題,那個專題要用4*4的矩陣按鍵

為了用最少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 剛好合適 )

這個程式只是用來讀取矩陣按鈕,算是該專題全面進行
前的功能測試,後來改成副程式只是讓它在專題主程式
中比較好呼叫處理而已
  1. /*
  2. 4*4 按鍵讀取測試程式,2018.09.27 作成
  3. 接腳 1:+5.00V 1023
  4. 接腳 2:+3.75V 767
  5. 接腳 3:+2.48V 507
  6. 接腳 4:+1.23V 251
  7. 依次讀取 A,B,C,D 腳位是否有穩定的輸入電壓(連讀2次間隔 GAP_TIME),
  8. 依讀取的位置(A~D)及讀到的電壓來判斷是哪個按鍵被按下,顯示於MONITOR內

  9. 2018.09.29 改版:以副程式呼叫,掃瞄讀取按鍵值並回傳,追加按鍵按住不放判斷
  10. */

  11. #define MISS 5          //讀取值的可容許公差(+/-)

  12. #define BUZZER 3        //定義蜂鳴器接腳為 3
  13. #define BZ_TIMER 30     //按鍵回饋的響音長度
  14. #define GAP_TIME 5      //連續讀取按鍵的間隔時間
  15. #define SCAN_TIME 100   //按鍵回應時間

  16. int SCAN_LINE = 0;                                            //內定由 1 縱列開始掃瞄(再往2,3,A縱列)
  17. int SCAN[4] = { A5, A4, A6, A7 };                             //設定掃瞄縱列(輸入埠順序)
  18. int MAX[4] = { 1023+MISS, 767+MISS, 507+MISS, 251+MISS };     //設定上限陣列
  19. int MID[4] = { 0, 1, 2, 3 };                                  //指向按鍵排(0=橫排1,1=橫排4,2=橫排7,3=橫排0)
  20. int MIN[4] = { 1023-MISS, 767-MISS, 507-MISS, 251-MISS };     //設定下限陣列
  21. int K_VALUE[3] = { 0,0,0 };                                   //定義按鍵讀值 3 筆
  22. unsigned long KEY_PRESS_TIME = 0;                             //記錄此次按鍵時間

  23. //設定按鍵陣列 KEY[縱列][橫排] 指向的特定按鍵值
  24. int KEY[4][4] = { { 1,2,3,10 }, { 4,5,6,11 }, { 7,8,9,12 }, { 0,15,14,13 } };


  25. int READ_KEY()
  26. //無輸入引數,讀取 4*4 按鍵狀態並回傳 1 短整數的按鍵值:(16=該掃瞄列無按鍵被按下,0~15="0"~"F")
  27. {
  28.   int RESULT = 16;                          //回傳值,內定 16 (無按鍵按下)
  29.   //連續 3 次讀電壓值
  30.   for ( int I = 0; I<3; I++ )
  31.   {
  32.     K_VALUE[I] = analogRead( SCAN[SCAN_LINE] );   //讀取輸入值(0~1023)
  33.     if ( K_VALUE[I] <= MAX[0] && K_VALUE[I] >= MIN[0] )
  34.       K_VALUE[I] = MID[0];                        //若符合 1023 電壓範圍,則將電壓值轉成按鍵排值0
  35.     else
  36.       if ( K_VALUE[I] <= MAX[1] && K_VALUE[I] >= MIN[1] )
  37.         K_VALUE[I] = MID[1];                      //若符合 767 電壓範圍,則將電壓值轉成按鍵排值1
  38.       else
  39.         if ( K_VALUE[I] <= MAX[2] && K_VALUE[I] >= MIN[2] )
  40.           K_VALUE[I] = MID[2];                    //若符合 507 電壓範圍,則將電壓值轉成按鍵排值2
  41.         else
  42.           if ( K_VALUE[I] <= MAX[3] && K_VALUE[I] >= MIN[3] )
  43.             K_VALUE[I] = MID[3];                  //若符合 251 電壓範圍,則將電壓值轉成按鍵排值3
  44.           else
  45.             K_VALUE[I] = I+4;                     //若不符電壓範圍(浮動電壓)則將排值設為 I+4 (不存在&不會相同的排值)
  46.     delay( GAP_TIME );                            //暫停,繼續讀下一次(共讀3次)
  47.   }
  48.   //判斷是否穩定(3 筆讀值需相同),若穩定,特定出按鍵別("0"~"F")
  49.   if ( K_VALUE[0] == K_VALUE[1] && K_VALUE[0] == K_VALUE[2] )
  50.     RESULT = KEY[SCAN_LINE][K_VALUE[0]];    //依掃瞄線別 SCAN_LINE 及電壓讀值 K_VALUE[0] 特定出被按下的按鍵
  51.   
  52.   return RESULT;                        //傳回按鍵值(0~16)
  53. }


  54. void setup()
  55. {
  56.   pinMode(BUZZER, OUTPUT);              //指定蜂鳴器為輸出用
  57.   //初始化串列通訊並指定速率(BPS):
  58.   Serial.begin(9600);
  59. }

  60. void loop()
  61. {
  62. START:
  63.   
  64.   SCAN_LINE++;                          //切往下一掃瞄縱列(0→3=1→A)
  65.   if ( SCAN_LINE == 4 )                 //限制掃瞄縱列範圍0~3
  66.     SCAN_LINE = 0;
  67.   
  68.   int NEW_KEY = READ_KEY();             //讀取按鍵值

  69.   if ( NEW_KEY != 16 )                  //若有正確&穩定的新回傳按鍵值
  70.   {
  71.     if ( (millis()-KEY_PRESS_TIME) < SCAN_TIME )  //若前後按鍵時間短則以按鍵未放開處理
  72.     {  
  73.       KEY_PRESS_TIME = millis();        //更新按鍵時間
  74.       goto START;                       //重新掃瞄按鍵
  75.     }

  76.     Serial.print( NEW_KEY );            //顯示按鍵值&換列
  77.     Serial.print( "\n" );
  78.     digitalWrite( BUZZER, HIGH );       //響音
  79.     delay( BZ_TIMER );
  80.     digitalWrite( BUZZER, LOW );
  81.     KEY_PRESS_TIME = millis();          //記錄此次按鍵時間
  82.   }

  83. }
复制代码


回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2020-7-15 17:05 , Processed in 0.047265 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表