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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 15193|回復: 16
打印 上一主題 下一主題
收起左側

單片機用ADC+電阻掃描鍵盤的源程序和原理圖

  [復制鏈接]
跳轉到指定樓層
樓主
這是我的ADC掃描鍵盤程序,附原理圖,用stc單片機自帶的ad和一些電阻構成的簡單電路,實現了16個ad的按鍵.


單片機源程序如下:
  1. /*************  本程序功能說明  **************

  2. 用STC的MCU的IO方式控制74HC595驅動8位數碼管。

  3. 顯示效果為: 數碼時鐘.

  4. 使用Timer0的16位自動重裝來產生1ms節拍,程序運行于這個節拍下, 用戶修改MCU主時鐘頻率時,自動定時于1ms.

  5. 左邊4位LED顯示時間(小時,分鐘), 右邊最后兩位顯示按鍵值.

  6. ADC按鍵鍵碼為1~16.

  7. 按鍵只支持單鍵按下, 不支持多鍵同時按下, 那樣將會有不可預知的結果.

  8. 鍵按下超過1秒后,將以10鍵/秒的速度提供重鍵輸出. 用戶只需要檢測KeyCode是否非0來判斷鍵是否按下.

  9. 調整時間鍵:
  10. 鍵碼1: 小時+.
  11. 鍵碼2: 小時-.
  12. 鍵碼3: 分鐘+.
  13. 鍵碼4: 分鐘-.


  14. ******************************************/


  15. #include    "reg51.h"
  16. #include    "intrins.h"

  17. #define     MAIN_Fosc       11059200L   //定義主時鐘

  18. typedef     unsigned char   u8;
  19. typedef     unsigned int    u16;
  20. typedef     unsigned long   u32;

  21. sfr TH2  = 0xD6;
  22. sfr TL2  = 0xD7;
  23. sfr IE2   = 0xAF;
  24. sfr INT_CLKO = 0x8F;
  25. sfr AUXR = 0x8E;
  26. sfr AUXR1 = 0xA2;
  27. sfr P_SW1 = 0xA2;
  28. sfr P_SW2 = 0xBA;
  29. sfr S2CON = 0x9A;
  30. sfr S2BUF = 0x9B;

  31. sfr ADC_CONTR = 0xBC;   //帶AD系列
  32. sfr ADC_RES   = 0xBD;   //帶AD系列
  33. sfr ADC_RESL  = 0xBE;   //帶AD系列
  34. sfr P1ASF = 0x9D;   //只寫,模擬輸入(AD或LVD)選擇

  35. sfr P4   = 0xC0;
  36. sfr P5   = 0xC8;
  37. sfr P6   = 0xE8;
  38. sfr P7   = 0xF8;
  39. sfr P1M1 = 0x91;    //PxM1.n,PxM0.n     =00--->Standard,    01--->push-pull
  40. sfr P1M0 = 0x92;    //                  =10--->pure input,  11--->open drain
  41. sfr P0M1 = 0x93;
  42. sfr P0M0 = 0x94;
  43. sfr P2M1 = 0x95;
  44. sfr P2M0 = 0x96;
  45. sfr P3M1 = 0xB1;
  46. sfr P3M0 = 0xB2;
  47. sfr P4M1 = 0xB3;
  48. sfr P4M0 = 0xB4;
  49. sfr P5M1 = 0xC9;
  50. sfr P5M0 = 0xCA;
  51. sfr P6M1 = 0xCB;
  52. sfr P6M0 = 0xCC;
  53. sfr P7M1 = 0xE1;
  54. sfr P7M0 = 0xE2;

  55. sbit P00 = P0^0;
  56. sbit P01 = P0^1;
  57. sbit P02 = P0^2;
  58. sbit P03 = P0^3;
  59. sbit P04 = P0^4;
  60. sbit P05 = P0^5;
  61. sbit P06 = P0^6;
  62. sbit P07 = P0^7;
  63. sbit P10 = P1^0;
  64. sbit P11 = P1^1;
  65. sbit P12 = P1^2;
  66. sbit P13 = P1^3;
  67. sbit P14 = P1^4;
  68. sbit P15 = P1^5;
  69. sbit P16 = P1^6;
  70. sbit P17 = P1^7;
  71. sbit P20 = P2^0;
  72. sbit P21 = P2^1;
  73. sbit P22 = P2^2;
  74. sbit P23 = P2^3;
  75. sbit P24 = P2^4;
  76. sbit P25 = P2^5;
  77. sbit P26 = P2^6;
  78. sbit P27 = P2^7;
  79. sbit P30 = P3^0;
  80. sbit P31 = P3^1;
  81. sbit P32 = P3^2;
  82. sbit P33 = P3^3;
  83. sbit P34 = P3^4;
  84. sbit P35 = P3^5;
  85. sbit P36 = P3^6;
  86. sbit P37 = P3^7;
  87. sbit P40 = P4^0;
  88. sbit P41 = P4^1;
  89. sbit P42 = P4^2;
  90. sbit P43 = P4^3;
  91. sbit P44 = P4^4;
  92. sbit P45 = P4^5;
  93. sbit P46 = P4^6;
  94. sbit P47 = P4^7;
  95. sbit P50 = P5^0;
  96. sbit P51 = P5^1;
  97. sbit P52 = P5^2;
  98. sbit P53 = P5^3;
  99. sbit P54 = P5^4;
  100. sbit P55 = P5^5;
  101. sbit P56 = P5^6;
  102. sbit P57 = P5^7;



  103. #define Timer0_Reload   (65536UL -(MAIN_Fosc / 1000))       //Timer 0 中斷頻率, 1000次/秒

  104. #define DIS_DOT     0x20
  105. #define DIS_BLACK   0x10
  106. #define DIS_        0x11




  107. u8 code t_display[]={                       //標準字庫
  108. //   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
  109.     0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
  110. //black  -     H    J    K    L    N    o   P    U     t    G    Q    r   M    y
  111.     0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
  112.     0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46};    //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1

  113. u8 code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};      //位碼


  114. sbit    P_HC595_SER   = P4^0;   //pin 14    SER     data input
  115. sbit    P_HC595_RCLK  = P5^4;   //pin 12    RCLk    store (latch) clock
  116. sbit    P_HC595_SRCLK = P4^3;   //pin 11    SRCLK   Shift data clock


  117. u8  LED8[8];        //顯示緩沖
  118. u8  display_index;  //顯示位索引
  119. bit B_1ms;          //1ms標志

  120. u8  ADC_KeyState,ADC_KeyState1,ADC_KeyState2,ADC_KeyState3; //鍵狀態
  121. u8  ADC_KeyHoldCnt; //鍵按下計時
  122. u8  KeyCode;    //給用戶使用的鍵碼, 1~16有效
  123. u8  cnt10ms;

  124. u8  hour,minute,second; //RTC變量
  125. u16 msecond;

  126. void    CalculateAdcKey(u16 adc);
  127. u16     Get_ADC10bitResult(u8 channel); //channel = 0~7
  128. void    DisplayRTC(void);
  129. void    RTC(void);




  130. /**********************************************/
  131. void main(void)
  132. {
  133.     u8  i;
  134.     u16 j;

  135.     P0M1 = 0;   P0M0 = 0;   //設置為準雙向口
  136.     P1M1 = 0;   P1M0 = 0;   //設置為準雙向口
  137.     P2M1 = 0;   P2M0 = 0;   //設置為準雙向口
  138.     P3M1 = 0;   P3M0 = 0;   //設置為準雙向口
  139.     P4M1 = 0;   P4M0 = 0;   //設置為準雙向口
  140.     P5M1 = 0;   P5M0 = 0;   //設置為準雙向口
  141.     P6M1 = 0;   P6M0 = 0;   //設置為準雙向口
  142.     P7M1 = 0;   P7M0 = 0;   //設置為準雙向口
  143.    
  144.     display_index = 0;
  145.     P1ASF = 0x10;       //P1.4做ADC
  146.     ADC_CONTR = 0xE0;   //90T, ADC power on
  147.    
  148.     AUXR = 0x80;    //Timer0 set as 1T, 16 bits timer auto-reload,
  149.     TH0 = (u8)(Timer0_Reload / 256);
  150.     TL0 = (u8)(Timer0_Reload % 256);
  151.     ET0 = 1;    //Timer0 interrupt enable
  152.     TR0 = 1;    //Tiner0 run
  153.     EA = 1;     //打開總中斷
  154.    
  155.     for(i=0; i<8; i++)  LED8[i] = 0x10; //上電消隱

  156.     hour   = 12;    //初始化時間值
  157.     minute = 0;
  158.     second = 0;
  159.     DisplayRTC();

  160.     ADC_KeyState  = 0;
  161.     ADC_KeyState1 = 0;
  162.     ADC_KeyState2 = 0;
  163.     ADC_KeyState3 = 0;  //鍵狀態
  164.     ADC_KeyHoldCnt = 0; //鍵按下計時
  165.     KeyCode = 0;    //給用戶使用的鍵碼, 1~16有效
  166.     cnt10ms = 0;

  167.     while(1)
  168.     {
  169.         if(B_1ms)   //1ms到
  170.         {
  171.             B_1ms = 0;
  172.             if(++msecond >= 1000)   //1秒到
  173.             {
  174.                 msecond = 0;
  175.                 RTC();
  176.                 DisplayRTC();
  177.             }
  178.             if(msecond == 500)  DisplayRTC();   //小時后的小數點做秒閃

  179.             if(++cnt10ms >= 10) //10ms讀一次ADC
  180.             {
  181.                 cnt10ms = 0;
  182.                 j = Get_ADC10bitResult(4);  //參數0~7,查詢方式做一次ADC, 返回值就是結果, == 1024 為錯誤
  183.                 if(j < 1024)    CalculateAdcKey(j); //計算按鍵
  184.                         
  185.             }

  186.             if(KeyCode > 0)     //有鍵按下
  187.             {
  188.                 LED8[6] = KeyCode / 10; //顯示鍵碼
  189.                 LED8[7] = KeyCode % 10; //顯示鍵碼

  190.                 if(KeyCode == 1)    //hour +1
  191.                 {
  192.                     if(++hour >= 24)    hour = 0;
  193.                     DisplayRTC();
  194.                 }
  195.                 if(KeyCode == 2)    //hour -1
  196.                 {
  197.                     if(--hour >= 24)    hour = 23;
  198.                     DisplayRTC();
  199.                 }
  200.                 if(KeyCode == 3)    //minute +1
  201.                 {
  202.                     second = 0;
  203.                     if(++minute >= 60)  minute = 0;
  204.                     DisplayRTC();
  205.                 }
  206.                 if(KeyCode == 4)    //minute -1
  207.                 {
  208.                     second = 0;
  209.                     if(--minute >= 60)  minute = 59;
  210.                     DisplayRTC();
  211.                 }

  212.                 KeyCode = 0;
  213.             }

  214.         }
  215.     }
  216. }
  217. /**********************************************/



  218. /********************** 顯示時鐘函數 ************************/
  219. void    DisplayRTC(void)
  220. {
  221.     if(hour >= 10)  LED8[0] = hour / 10;
  222.     else            LED8[0] = DIS_BLACK;
  223.     LED8[1] = hour % 10;
  224.     LED8[2] = minute / 10;
  225.     LED8[3] = minute % 10;
  226.     if(msecond >= 500)      LED8[1] |= DIS_DOT; //小時后的小數點做秒閃
  227. }

  228. /********************** RTC演示函數 ************************/
  229. void    RTC(void)
  230. {
  231.     if(++second >= 60)
  232.     {
  233.         second = 0;
  234.         if(++minute >= 60)
  235.         {
  236.             minute = 0;
  237.             if(++hour >= 24)    hour = 0;
  238.         }
  239.     }
  240. }


  241. //========================================================================
  242. // 函數: u16    Get_ADC10bitResult(u8 channel)
  243. // 描述: 查詢法讀一次ADC結果.
  244. // 參數: channel: 選擇要轉換的ADC.
  245. // 返回: 10位ADC結果.
  246. // 版本: V1.0, 2012-10-22
  247. //========================================================================
  248. u16 Get_ADC10bitResult(u8 channel)  //channel = 0~7
  249. {
  250.     ADC_RES = 0;
  251.     ADC_RESL = 0;

  252.     ADC_CONTR = (ADC_CONTR & 0xe0) | 0x08 | channel;    //start the ADC
  253.     _nop_();
  254.     _nop_();
  255.     _nop_();
  256.     _nop_();

  257.     while((ADC_CONTR & 0x10) == 0)  ;   //wait for ADC finish
  258.     ADC_CONTR &= ~0x10;     //清除ADC結束標志
  259.     return  (((u16)ADC_RES << 2) | (ADC_RESL & 3));
  260. }

  261. /***************** ADC鍵盤計算鍵碼 *****************************
  262. 電路和軟件算法設計: Coody
  263. 本ADC鍵盤方案在很多實際產品設計中, 驗證了其穩定可靠, 即使按鍵使用導電膜,都很可靠.
  264. 16個鍵,理論上各個鍵對應的ADC值為 (1024 / 16) * k = 64 * k, k = 1 ~ 16, 特別的, k=16時,對應的ADC值是1023.
  265. 但是實際會有偏差,則判斷時限制這個偏差, ADC_OFFSET為+-偏差, 則ADC值在 (64*k-ADC_OFFSET) 與 (64*k+ADC_OFFSET)之間為鍵有效.
  266. 間隔一定的時間,就采樣一次ADC,比如10ms.
  267. 為了避免偶然的ADC值誤判, 或者避免ADC在上升或下降時誤判, 使用連續3次ADC值均在偏差范圍內時, ADC值才認為有效.
  268. 以上算法, 能保證讀鍵非常可靠.
  269. **********************************************/
  270. #define ADC_OFFSET  16
  271. void    CalculateAdcKey(u16 adc)
  272. {
  273.     u8  i;
  274.     u16 j;
  275.    
  276.     if(adc < (64-ADC_OFFSET))
  277.     {
  278.         ADC_KeyState = 0;   //鍵狀態歸0
  279.         ADC_KeyHoldCnt = 0;
  280.     }
  281.     j = 64;
  282.     for(i=1; i<=16; i++)
  283.     {
  284.         if((adc >= (j - ADC_OFFSET)) && (adc <= (j + ADC_OFFSET)))  break;  //判斷是否在偏差范圍內
  285.         j += 64;
  286.     }
  287.     ADC_KeyState3 = ADC_KeyState2;
  288.     ADC_KeyState2 = ADC_KeyState1;
  289.     if(i > 16)  ADC_KeyState1 = 0;  //鍵無效
  290.     else                        //鍵有效
  291.     {
  292.         ADC_KeyState1 = i;
  293.         if((ADC_KeyState3 == ADC_KeyState2) && (ADC_KeyState2 == ADC_KeyState1) &&
  294.            (ADC_KeyState3 > 0) && (ADC_KeyState2 > 0) && (ADC_KeyState1 > 0))
  295.         {
  296.             if(ADC_KeyState == 0)   //第一次檢測到
  297.             {
  298.                 KeyCode  = i;   //保存鍵碼
  299.                 ADC_KeyState = i;   //保存鍵狀態
  300.                 ADC_KeyHoldCnt = 0;
  301.             }
  302.             if(ADC_KeyState == i)   //連續檢測到同一鍵按著
  303.             {
  304.                 if(++ADC_KeyHoldCnt >= 100) //按下1秒后,以10次每秒的速度Repeat Key
  305.                 {
  306. ……………………

  307. …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼

所有資料51hei提供下載:
ADC鍵盤.zip (3.92 KB, 下載次數: 220)



分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏5 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:140183 發表于 2017-6-29 05:40 | 只看該作者
很好的資料.多謝分享!
回復

使用道具 舉報

板凳
ID:274730 發表于 2018-1-11 11:33 | 只看該作者
謝謝分享謝謝分享,,,,,,,,,,,,,
回復

使用道具 舉報

地板
ID:117047 發表于 2018-3-12 12:18 | 只看該作者
感謝分享!!!
回復

使用道具 舉報

5#
ID:66287 發表于 2018-3-14 10:14 | 只看該作者
程序設計合理,編制簡潔,謝謝分享!
回復

使用道具 舉報

6#
ID:339788 發表于 2018-6-25 00:21 | 只看該作者
謝謝樓主
回復

使用道具 舉報

7#
ID:374681 發表于 2018-7-19 11:19 | 只看該作者

謝謝樓主
回復

使用道具 舉報

8#
ID:446645 發表于 2019-2-27 15:55 | 只看該作者
很好的資料.多謝分享!
回復

使用道具 舉報

9#
ID:151689 發表于 2019-5-12 13:58 | 只看該作者
老大可以下載嗎?
回復

使用道具 舉報

10#
ID:525189 發表于 2019-8-23 09:56 | 只看該作者
不錯的資料,謝謝分享!
回復

使用道具 舉報

11#
ID:602985 發表于 2019-8-23 10:26 | 只看該作者
謝謝分享!
回復

使用道具 舉報

12#
ID:151348 發表于 2020-4-2 10:24 | 只看該作者
可用,已經成功移植
回復

使用道具 舉報

13#
ID:292359 發表于 2020-6-10 17:08 | 只看該作者
感謝分享,正在搞ADC多鍵去switch不同的功能區,代替原來的獨立鍵盤,還沒搞定T0去掃
回復

使用道具 舉報

14#
ID:775405 發表于 2020-6-10 19:35 | 只看該作者
這資料不錯啊,謝謝分享
回復

使用道具 舉報

15#
ID:716797 發表于 2020-6-16 12:40 | 只看該作者
謝謝樓主無私分享、
回復

使用道具 舉報

16#
ID:774633 發表于 2020-6-17 08:38 | 只看該作者
利用一個ADC口,就實現多按鍵掃描,唯獨不能識別同時按。不過很好了。謝謝分享
回復

使用道具 舉報

17#
ID:65956 發表于 2020-6-17 08:50 | 只看該作者
感謝分享思路,但我個人建議大家在作時,那些電阻可配大點,這樣每個按鍵值之間的差別會大點,方便程序對按鍵值的判斷范圍寬點,減少誤判
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 久久在线精品 | 精品国产乱码久久久久久牛牛 | 色橹橹欧美在线观看视频高清 | 紧缚调教一区二区三区视频 | 淫片专区| 91久久国产综合久久 | 亚洲一区二区综合 | 久久伊人影院 | 97偷拍视频| 日本天堂视频 | 日韩一区二区av | 欧美精品在线一区 | 欧美专区日韩专区 | 久久高清 | www.青娱乐| 午夜欧美日韩 | 观看毛片 | 免费国产一区 | 亚洲欧美国产毛片在线 | 国产精品色 | 99久久夜色精品国产亚洲96 | 亚洲视频免费观看 | 在线免费观看色 | 爱草视频 | 亚洲视频一区在线 | 99久久精品国产一区二区三区 | 青青草网| 欧美1—12sexvideos | 日韩欧美在线视频观看 | 精品一区在线 | 日韩高清www| 中国美女一级黄色片 | 日本一二三区电影 | 午夜a√| 欧美xxxx色视频在线观看免费 | 手机av免费在线 | 亚洲午夜av久久乱码 | 人人人人干 | 国产a视频| 毛片免费看的 | 国产成人久久av免费高清密臂 |