久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 9108|回復(fù): 12
打印 上一主題 下一主題
收起左側(cè)

單片機(jī)矩陣鍵盤掃描驅(qū)動(dòng)程序與電路分析

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:446156 發(fā)表于 2021-11-15 14:47 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
矩陣鍵盤的掃描原理很多教材都介紹過,在這里再贅述一遍。
以4X4鍵盤為例,首先按照下圖制作電路。

然后將HOR1-HOR4連接到單片機(jī)的輸入引腳上去;LON1-LON4連接到單片機(jī)的開漏輸出引腳上去,注意這4個(gè)引腳必須設(shè)置為開漏模式!
程序上首先將LON1所連接的IO輸出低電平其余3個(gè)IO輸出高電平,同時(shí)檢測(cè)HOR1-HOR4的電平來獲取K1-K4的按鍵狀態(tài);然后將LON2所連接的IO輸出低電平其余3個(gè)IO輸出高電平,同時(shí)檢測(cè)HOR1-HOR4的電平來獲取K5-K8的按鍵狀態(tài);依次類推。
但是這個(gè)電路是有BUG的,比如同時(shí)按下K1、K5和K6,當(dāng)LON1為低電平的時(shí)HOR1檢測(cè)到是低電平?jīng)]有問題;因?yàn)镵2沒有被按下所以我們希望HOR2是高電平,但是由于K1、K5、K6同時(shí)按下電流從VCC通過R2再通過K6再通過K5再通過K1流到LON1,所以實(shí)際上HOR2也是低電平這時(shí)候程序就認(rèn)為K2被按下了導(dǎo)致出錯(cuò)。


解決這個(gè)問題很簡(jiǎn)單只需要在合適的位置加一個(gè)二極管,利用其單向?qū)щ娦宰钃蹼娏骺缌辛鲃?dòng)就行了。


好了,接下來是單片機(jī)代碼時(shí)間
  1. #ifndef __Key_matrix_H
  2. #define __Key_matrix_H

  3. #include "gpio.h"
  4. #include "gpio_bool.h"

  5. /*務(wù)必把這4個(gè)輸出IO設(shè)置為上拉輸入*/
  6. #define KEY_HOR1 PAin(7)
  7. #define KEY_HOR2 PAin(6)
  8. #define KEY_HOR3 PAin(5)
  9. #define KEY_HOR4 PAin(4)
  10. /*務(wù)必把這4個(gè)輸出IO設(shè)置為開漏*/
  11. #define KEY_LON1 PBout(0)
  12. #define KEY_LON2 PCout(5)
  13. #define KEY_LON3 PCout(4)
  14. #define KEY_LON4 PCout(3)

  15. #define KEY_PRESS_TIME 20//消抖常數(shù)
  16. #define KEY_LONG_PRESS_TIME 3000//單個(gè)按鍵長(zhǎng)按閾值3s
  17. /*通過讀取(只讀)這三個(gè)變量即可獲得按鍵的單按、長(zhǎng)按和組合鍵信息*/
  18. extern volatile uint16_t Key_Phy_Num;
  19. extern volatile uint8_t Key_Pulse_Num;
  20. extern volatile uint16_t Key_LP_Num;

  21. typedef enum
  22. {
  23.         KPL_DISABLE=0,
  24.         KPL_ENABLE
  25. }K_L_P;//按鍵的長(zhǎng)按狀態(tài)
  26. typedef struct
  27. {
  28.         K_L_P KEY_LONG_PRESS;
  29.         uint16_t KeyOpenCount;
  30.         uint8_t KOC_EN;
  31.         uint16_t KeyCloseCount;
  32.         uint8_t KCC_EN;
  33. }Key_Para;

  34. exter Key_Par Key_1,Key_2,Key_3,Key_4,Key_5,Key_6,Key_7,Key_8,Key_9,Key_10,Key_11,Key_12,Key_13,Key_14,Key_15,Key_16;

  35. void Clear_Key_Pulse_Num(void);//當(dāng)讀取完Key_Pulse_Num后調(diào)用
  36. void KeyCount_Run(void);//在1ms滴答里調(diào)用
  37. void Key_Scan(void);//大循環(huán)或者滴答里邊都行

  38. #endif
復(fù)制代碼
  1. #include "Key_matrix.h"

  2. Key_Par Key_1,Key_2,Key_3,Key_4,Key_5,Key_6,Key_7,Key_8,Key_9,Key_10,Key_11,Key_12,Key_13,Key_14,Key_15,Key_16;
  3. volatile uint16_t Key_Phy_Num=0;  //Key_Phy_Num每一個(gè)bit代表一個(gè)按鍵的狀態(tài)
  4. volatile uint8_t Key_Pulse_Num=0;//當(dāng)某一個(gè)按鍵從按下到彈起的過程中(非長(zhǎng)按)始終只有該按鍵被操作,則Key_Pulse_Num被修改為該鍵的序號(hào)
  5. volatile uint16_t Key_LP_Num=0;   //Key_LP_Num每一個(gè)bit代表一個(gè)按鍵的長(zhǎng)按狀態(tài)
  6. uint8_t KeyCom=0;//組合鍵是否出現(xiàn)

  7. static void Key_Num_Read(Key_Para* Key,uint16_t KPN,uint8_t Pulse,uint8_t Key_Hor)
  8. {
  9.         if(Key_Hor == 0)
  10.         {
  11.                 Key->KOC_EN=0;//按鍵按下立即清除(松開)計(jì)數(shù)
  12.                 if(Key->KeyCloseCount > KEY_PRESS_TIME)
  13.                 {
  14.                         /*消抖方法為檢測(cè)到按鍵被(持續(xù))按下超過20ms*/
  15.                         Key_Phy_Num|=KPN;//消抖完畢后記錄被按下的按鍵的鍵值
  16.                         if(Key->KeyCloseCount > KEY_LONG_PRESS_TIME)
  17.                         {
  18.                                 /*檢測(cè)到按鍵被(持續(xù))按下超過3秒*/
  19.                                 Key->KEY_LONG_PRESS=KPL_ENABLE;
  20.                                 Key_LP_Num|=KPN;
  21.                                 Key->KCC_EN=0;
  22.                         }
  23.                         else
  24.                         {
  25.                                 /*時(shí)間不夠啟動(dòng)計(jì)數(shù)*/
  26.                                 Key->KCC_EN=1;
  27.                         }
  28.                 }
  29.                 else
  30.                 {
  31.                         /*時(shí)間不夠啟動(dòng)計(jì)數(shù)*/
  32.                         Key->KCC_EN=1;
  33.                 }
  34.         }
  35.         else
  36.         {
  37.                 Key->KCC_EN=0;//按鍵松開立即清除(按下)計(jì)數(shù)
  38.                 if(Key->KeyOpenCount > KEY_PRESS_TIME)
  39.                 {
  40.                         if((Key_Phy_Num==KPN)&&(KeyCom==0)&&(Key->KEY_LONG_PRESS!=KPL_ENABLE))
  41.                         {
  42.                                 //按鍵被按下過&&非長(zhǎng)按&&不是在組合鍵周期,該按鍵釋放時(shí)發(fā)出生命周期為直到被讀取或者直到有新按鍵被按下的脈沖
  43.                                 Key_Pulse_Num=Pulse;
  44.                         }
  45.                          //清除該位
  46.                          Key_Phy_Num&=(~KPN);
  47.                          Key_LP_Num&=(~KPN);
  48.                         /*檢測(cè)到(持續(xù))松開20ms*/
  49.                         Key->KEY_LONG_PRESS=KPL_DISABLE;
  50.                         Key->KOC_EN=0;
  51.                 }
  52.                 else
  53.                 {
  54.                         Key->KOC_EN=1;
  55.                 }
  56.         }
  57. }
  58. /********************************************************/
  59. static void Key_Count(Key_Para *Key)
  60. {
  61.         if(Key->KOC_EN==0)
  62.         {
  63.                 Key->KeyOpenCount=0;
  64.         }
  65.         else if(Key->KeyOpenCount>=50000)
  66.         {
  67.                 Key->KeyOpenCount=50000;
  68.         }
  69.         else
  70.         {
  71.                 Key->KeyOpenCount++;
  72.         }

  73.         if(Key->KCC_EN==0)
  74.         {
  75.                 Key->KeyCloseCount=0;
  76.         }
  77.         else if(Key->KeyCloseCount>=50000)
  78.         {
  79.                 Key->KeyCloseCount=50000;
  80.         }
  81.         else
  82.         {
  83.                 Key->KeyCloseCount++;
  84.         }
  85. }
  86. /********************************************************/
  87. void Clear_Key_Pulse_Num(void)
  88. {
  89.         Key_Pulse_Num=0;
  90. }
  91. /********************************************************/
  92. void KeyCount_Run(void)
  93. {
  94.         Key_Count(&Key_1);
  95.         Key_Count(&Key_2);
  96.         Key_Count(&Key_3);
  97.         Key_Count(&Key_4);
  98.         Key_Count(&Key_5);
  99.         Key_Count(&Key_6);
  100.         Key_Count(&Key_7);
  101.         Key_Count(&Key_8);
  102.         Key_Count(&Key_9);
  103.         Key_Count(&Key_10);
  104.         Key_Count(&Key_11);
  105.         Key_Count(&Key_12);
  106.         Key_Count(&Key_13);
  107.         Key_Count(&Key_14);
  108.         Key_Count(&Key_15);
  109.         Key_Count(&Key_16);
  110. }
  111. /********************************************************/
  112. static void Recognition_KeyCombination(void)
  113. {
  114.         uint8_t i=0,j=0;
  115.         uint16_t Data=0;
  116.         
  117.         Data=Key_Phy_Num;
  118.         for(i=0;i<16;i++)
  119.         {
  120.                 if(Data&0x8000)
  121.                 {
  122.                         j++;
  123.                 }
  124.                 Data<<=1;
  125.         }
  126.         /*發(fā)現(xiàn)多個(gè)bit為1,那指定多個(gè)按鍵按下了*/
  127.         if(j>1)
  128.         {
  129.                 KeyCom=1;
  130.         }
  131.         /*一切歸于平靜,又是一個(gè)因果循環(huán)*/
  132.         if(Key_Phy_Num==0x0)
  133.         {
  134.                 KeyCom=0;
  135.         }
  136. }
  137. /********************************************************/
  138. void Key_Scan(void)
  139. {        
  140.   static uint8_t ScanCount=0;
  141.   
  142.   Recognition_KeyCombination();
  143.   switch(ScanCount)
  144.   {
  145.     case 0:
  146.     {
  147.       KEY_LON1=0;KEY_LON2=1;KEY_LON3=1;KEY_LON4=1;
  148.       Key_Num_Read(&Key_1,(uint16_t)0x0001   ,1,KEY_HOR1);
  149.       Key_Num_Read(&Key_2,(uint16_t)0x0001<<1,2,KEY_HOR2);
  150.       Key_Num_Read(&Key_3,(uint16_t)0x0001<<2,3,KEY_HOR3);
  151.       Key_Num_Read(&Key_4,(uint16_t)0x0001<<3,4,KEY_HOR4);
  152.       KEY_LON1=1;KEY_LON2=0;KEY_LON3=1;KEY_LON4=1;
  153.       ScanCount++;
  154.     }break;
  155.     case 1:
  156.     {
  157.       KEY_LON1=1;KEY_LON2=0;KEY_LON3=1;KEY_LON4=1;
  158.       Key_Num_Read(&Key_5,(uint16_t)0x0001<<4,5,KEY_HOR1);
  159.       Key_Num_Read(&Key_6,(uint16_t)0x0001<<5,6,KEY_HOR2);
  160.       Key_Num_Read(&Key_7,(uint16_t)0x0001<<6,7,KEY_HOR3);
  161.       Key_Num_Read(&Key_8,(uint16_t)0x0001<<7,8,KEY_HOR4);
  162.       KEY_LON1=1;KEY_LON2=1;KEY_LON3=0;KEY_LON4=1;
  163.       ScanCount++;
  164.     }break;
  165.     case 2:
  166.     {
  167.       KEY_LON1=1;KEY_LON2=1;KEY_LON3=0;KEY_LON4=1;
  168.       Key_Num_Read(&Key_9 ,(uint16_t)0x0001<<8 , 9,KEY_HOR1);
  169.       Key_Num_Read(&Key_10,(uint16_t)0x0001<<9 ,10,KEY_HOR2);
  170.       Key_Num_Read(&Key_11,(uint16_t)0x0001<<10,11,KEY_HOR3);
  171.       Key_Num_Read(&Key_12,(uint16_t)0x0001<<11,12,KEY_HOR4);
  172.       KEY_LON1=1;KEY_LON2=1;KEY_LON3=1;KEY_LON4=0;
  173.       ScanCount++;
  174.     }break;
  175.     case 3:
  176.     {
  177.       KEY_LON1=1;KEY_LON2=1;KEY_LON3=1;KEY_LON4=0;
  178.       Key_Num_Read(&Key_13,(uint16_t)0x0001<<12,13,KEY_HOR1);
  179.       Key_Num_Read(&Key_14,(uint16_t)0x0001<<13,14,KEY_HOR2);
  180.       Key_Num_Read(&Key_15,(uint16_t)0x0001<<14,15,KEY_HOR3);
  181.       Key_Num_Read(&Key_16,(uint16_t)0x0001<<15,16,KEY_HOR4);
  182.       KEY_LON1=0;KEY_LON2=1;KEY_LON3=1;KEY_LON4=1;
  183.       ScanCount=0;
  184.     }break;
  185.     default:
  186.     {
  187.       ScanCount=0;
  188.     }break;
  189.   }
  190. }
復(fù)制代碼




評(píng)分

參與人數(shù) 1黑幣 +80 收起 理由
admin + 80 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏18 分享淘帖 頂9 踩1
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:859897 發(fā)表于 2021-11-24 09:53 | 只看該作者
優(yōu)秀啊
回復(fù)

使用道具 舉報(bào)

板凳
ID:989232 發(fā)表于 2021-12-14 21:09 來自手機(jī) | 只看該作者
牛啊,確實(shí)不錯(cuò)
回復(fù)

使用道具 舉報(bào)

地板
ID:872412 發(fā)表于 2022-3-1 11:54 | 只看該作者
矩陣代碼需要寫這么多么,寫過一次記得沒幾句
回復(fù)

使用道具 舉報(bào)

5#
ID:214914 發(fā)表于 2022-3-20 20:11 | 只看該作者
講的很好,通俗易懂
回復(fù)

使用道具 舉報(bào)

6#
ID:1014835 發(fā)表于 2022-4-2 11:52 | 只看該作者
矩陣代碼需要寫這么多么,寫過一次記得沒幾句
回復(fù)

使用道具 舉報(bào)

7#
ID:1015352 發(fā)表于 2022-4-3 11:17 | 只看該作者
so nice
回復(fù)

使用道具 舉報(bào)

8#
ID:1064915 發(fā)表于 2023-8-28 15:04 | 只看該作者
在51用,程序怎么改
回復(fù)

使用道具 舉報(bào)

9#
ID:371734 發(fā)表于 2024-3-15 21:35 | 只看該作者
牛啊,確實(shí)不錯(cuò)
回復(fù)

使用道具 舉報(bào)

10#
ID:446156 發(fā)表于 2024-11-4 08:21 | 只看該作者
關(guān)于驅(qū)動(dòng)如何修改成51用,第一搞一個(gè)1ms的中斷,用定時(shí)器也行在大循環(huán)里記個(gè)數(shù)模擬1ms周期也行不需要太準(zhǔn)確。第二把8個(gè)IO的宏改成51的IO,比如把#define KEY_HOR1 PAin(7)改成#define KEY_HOR1 P1^0;并按照注釋來配置輸入輸出狀態(tài)。第三把uint8_t改成unsigned char,uint16_t改成unsigned int。第四把#include "gpio.h"#include "gpio_bool.h"刪掉換上51的頭文件
回復(fù)

使用道具 舉報(bào)

11#
ID:349276 發(fā)表于 2024-11-6 10:14 | 只看該作者
學(xué)習(xí)來著,空了研究一下。
回復(fù)

使用道具 舉報(bào)

12#
ID:446156 發(fā)表于 2025-3-11 09:24 | 只看該作者
op5726170 發(fā)表于 2022-3-1 11:54
矩陣代碼需要寫這么多么,寫過一次記得沒幾句

這么多年了,我忍住不懟你。矩陣驅(qū)動(dòng)確實(shí)可以寥寥幾行就能實(shí)現(xiàn),但是你寫的那玩意有幾個(gè)功能?估計(jì)連消抖都沒有,更別說隨意擴(kuò)展、跨平臺(tái)移植、識(shí)別長(zhǎng)短按以及松手后的事件觸發(fā)
回復(fù)

使用道具 舉報(bào)

13#
ID:349276 發(fā)表于 2025-3-17 15:04 | 只看該作者
qinlu123 發(fā)表于 2025-3-11 09:24
這么多年了,我忍住不懟你。矩陣驅(qū)動(dòng)確實(shí)可以寥寥幾行就能實(shí)現(xiàn),但是你寫的那玩意有幾個(gè)功能?估計(jì)連消抖 ...

嘿嘿,還可以搞組合鍵
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: m豆传媒在线链接观看 | 2021狠狠干| 97高清国语自产拍 | 91看片网 | 日韩av福利在线观看 | 美女黄频 | 久久久久一区二区三区 | 欧美v在线观看 | 久久极品| 蜜臀久久99精品久久久久野外 | 91久久久www播放日本观看 | 国产精品久久久久久久久久妞妞 | 久久久国产一区二区三区四区小说 | 亚洲一区不卡在线 | 国产精品久久久久久久久 | 中文精品久久 | 国产成人区 | 视频在线亚洲 | 亚洲精品免费在线观看 | 国产1区2区 | 欧美日在线| 久久久久久高潮国产精品视 | 国产欧美视频一区 | 精品一区二区电影 | 免费看国产片在线观看 | 色综合激情 | 国产精品久久久久久亚洲调教 | 蜜桃在线一区二区三区 | 欧美不卡在线 | 欧美日韩成人在线 | 国产精品一区视频 | 久久av一区二区三区 | 国产精品久久久久久妇女6080 | 嫩草视频在线看 | 黑色丝袜三级在线播放 | 美女福利网站 | 欧美日本亚洲 | 亚洲国产精品久久久久秋霞不卡 | 久久亚洲一区 | 久久久精品一区二区三区 | 国产毛片视频 |