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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

51單片機獨立按鍵程序 實現長按、短按功能

  [復制鏈接]
跳轉到指定樓層
樓主
ID:743654 發表于 2021-9-30 11:26 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
獨立按鍵 通過定時器實現長按、短按功能:

程序每條語句都附帶注釋,易理解,方便移植。

本人親測有效!

單片機源程序如下:
  1. /*************************************************************************************
  2. 實驗現象:下載程序后按下K1按鍵可以對led_0/led_1小燈狀態取反
  3.            短按控制led_0;長按控制led_1                                                  
  4. *************************************************************************************
  5. */

  6. #include "reg52.h"               //此文件中定義了單片機的一些特殊功能寄存器

  7. typedef unsigned int u16;          //對數據類型進行聲明定義
  8. typedef unsigned char u8;

  9. bit press_flag; //按鍵標志位
  10. u16 count;      //計數器標志位
  11. sbit k1=P3^1;         //定義P31口是k1
  12. sbit led_0=P2^0; //定義P20口是led_0
  13. sbit led_1=P2^1; //定義P20口是led_1

  14. void Timer0Init()
  15. {
  16.         TMOD|=0X01;//選擇為定時器0模式,工作方式1,僅用TR0打開啟動。

  17.         TH0=0XFC;        //給定時器賦初值,定時1ms
  18.         TL0=0X18;       
  19.         ET0=1;         //打開定時器0中斷允許
  20.         EA=1;         //打開總中斷
  21.         TR0=1;//打開定時器                       
  22. }

  23. void Timer0() interrupt 1
  24. {
  25.         TH0=0XFC;        //給定時器賦初值,定時1ms
  26.         TL0=0X18;
  27.         count++;  //計數器累加
  28. }


  29. /*******************************************************************************
  30. * 函 數 名         : delay
  31. * 函數功能                   : 延時函數,i=1時,大約延時10us
  32. *******************************************************************************/
  33. void delay(u16 i)
  34. {
  35.         while(i--);       
  36. }

  37. /*******************************************************************************
  38. * 函 數 名         : keypros
  39. * 函數功能                   : 按鍵處理函數,判斷按鍵K1是否按下
  40. *******************************************************************************/
  41. void keypros()
  42. {
  43.         if(k1==0)                     //檢測按鍵K1是否按下
  44.         {       
  45.                 delay(1000);   //消除抖動 一般大約10ms
  46.                 if(k1==0)             //再次判斷按鍵是否按下
  47.                 {
  48.                   press_flag=1; //按鍵標志位
  49.                   TR0=1;        //打開中斷
  50.                   while(!k1);   //按鍵松手檢測
  51.                   TR0=0;        //關閉中斷
  52.                 }
  53.            if(press_flag)  //若有按鍵
  54.           {
  55.             if(count>=1500) //長按>=1.5s
  56.             {
  57.               led_1=~led_1;        //led_1燈狀態取反 ,此處可以換成別的處理事件
  58.              }
  59.             else            //短按<1.5s
  60.             {
  61.               led_0=~led_0;         //led_0燈狀態取反 ,此處可以換成別的處理事件
  62.             }
  63.             count=0;               //計數器清零
  64.             press_flag=0;        //按鍵標志位清零
  65.           }                
  66.         }
  67. }

  68. /*******************************************************************************
  69. * 函 數 名       : main
  70. * 函數功能                 : 主函數
  71. * 輸    入       : 無
  72. * 輸    出             : 無
  73. *******************************************************************************/
  74. void main()
  75. {       
  76.         Timer0Init();//定時器初始化
  77.         led_0=1;     //led_0熄滅
  78.         led_1=1;     //led_1熄滅
  79.         while(1)     //主循環
  80.         {       
  81.           keypros();  //按鍵處理函數       
  82.         }               
  83. }
復制代碼


評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

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

使用道具 舉報

沙發
ID:1042234 發表于 2022-8-17 10:32 | 只看該作者
好像不太對 第一次短按會判斷為長按
回復

使用道具 舉報

板凳
ID:1039671 發表于 2022-8-17 16:34 | 只看該作者
stcmcu2 發表于 2022-8-17 10:32
好像不太對 第一次短按會判斷為長按

做了實驗,第一次開機LED1會亮,仔細分析了下代碼,在定時器初始化里面把TR0=1改為TR0=0,就可以解決這個問題。然后感覺有一點還是不完美,就是按鍵長按不松開LED1不會點亮,需要釋放按鍵才能點亮。
回復

使用道具 舉報

地板
ID:161164 發表于 2022-8-17 17:32 | 只看該作者
stcmcu2 發表于 2022-8-17 10:32
好像不太對 第一次短按會判斷為長按

26行 改為 TR0 = 0;
但不建議用長時間的阻塞式消抖/while(!K1)
回復

使用道具 舉報

5#
ID:814525 發表于 2022-8-17 20:17 | 只看該作者
一看到while(!k1)這句,就沒有研究的價值。
回復

使用道具 舉報

6#
ID:1042234 發表于 2022-8-18 08:42 | 只看該作者
lkc8210 發表于 2022-8-17 17:32
26行 改為 TR0 = 0;
但不建議用長時間的阻塞式消抖/while(!K1)

雙擊的怎么樣去操作
回復

使用道具 舉報

7#
ID:161164 發表于 2022-8-18 10:00 | 只看該作者
  1. /*************************************************************************************
  2. 實驗現象:下載程序后按下K1按鍵可以對led_0/led_1小燈狀態取反
  3.            短按控制led_0;長按控制led_1
  4. *************************************************************************************
  5. */

  6. #include "reg52.h"               //此文件中定義了單片機的一些特殊功能寄存器

  7. typedef unsigned int u16;          //對數據類型進行聲明定義
  8. typedef unsigned char u8;

  9. u16 count = 0;      //計數器標志位
  10. u8 KeyVal = 0;//按鍵標志位
  11. sbit k1=P3^1;         //定義P31口是k1
  12. sbit led_0=P2^0; //定義P20口是led_0
  13. sbit led_1=P2^1; //定義P20口是led_1
  14. bit Flag_1ms = 0;//1ms標志位
  15. void Timer0Init()
  16. {
  17.         TMOD|=0X01;//選擇為定時器0模式,工作方式1,僅用TR0打開啟動。

  18.         TH0=0XFC;        //給定時器賦初值,定時1ms
  19.         TL0=0X18;
  20.         ET0=1;         //打開定時器0中斷允許
  21.         EA=1;         //打開總中斷
  22.         TR0=1;//打開定時器
  23. }

  24. void Timer0() interrupt 1
  25. {
  26.         TH0=0XFC;        //給定時器賦初值,定時1ms
  27.         TL0=0X18;
  28.         Flag_1ms = 1;
  29. }

  30. /*******************************************************************************
  31. * 函 數 名         : keypros
  32. * 函數功能                   : 按鍵處理函數,判斷按鍵K1是否按下
  33. *******************************************************************************/
  34. void keypros()
  35. {
  36.         if(Flag_1ms==1)
  37.         {
  38.                 Flag_1ms = 0;
  39.                 if(k1==0)             //判斷按鍵是否按下
  40.                 {
  41.                         if(count<0xFFFF)count++;
  42.                         if(count==1500)
  43.                         {
  44.                                 KeyVal = 10;
  45.                         }
  46.                 }
  47.                 else
  48.                 {
  49.                         if((count>= 20) && (count<1500))
  50.                         {
  51.                                 KeyVal = 1;
  52.                         }
  53.                         count=0;
  54.                 }
  55.                 if(KeyVal > 0)  //若有按鍵
  56.                 {
  57.                         if(KeyVal==10) //長按>=1.5s
  58.                         {
  59.                                 led_1=~led_1;        //led_1燈狀態取反 ,此處可以換成別的處理事件
  60.                         }
  61.                         else            //短按<1.5s
  62.                         {
  63.                                 led_0=~led_0;         //led_0燈狀態取反 ,此處可以換成別的處理事件
  64.                         }
  65.                         KeyVal=0;
  66.                 }
  67.         }
  68. }

  69. /*******************************************************************************
  70. * 函 數 名       : main
  71. * 函數功能                 : 主函數
  72. * 輸    入       : 無
  73. * 輸    出             : 無
  74. *******************************************************************************/
  75. void main()
  76. {
  77.         Timer0Init();//定時器初始化
  78.         led_0=1;     //led_0熄滅
  79.         led_1=1;     //led_1熄滅
  80.         while(1)     //主循環
  81.         {
  82.                 keypros();  //按鍵處理函數
  83.         }
  84. }
復制代碼


回復

使用道具 舉報

8#
ID:161164 發表于 2022-8-18 10:22 | 只看該作者
stcmcu2 發表于 2022-8-18 08:42
雙擊的怎么樣去操作
  1. /*************************************************************************************
  2. 實驗現象:下載程序后按下K1按鍵可以對led_0/led_1小燈狀態取反
  3.            短按控制led_0;長按控制led_1
  4. *************************************************************************************
  5. */

  6. #include "reg52.h"               //此文件中定義了單片機的一些特殊功能寄存器

  7. typedef unsigned int u16;          //對數據類型進行聲明定義
  8. typedef unsigned char u8;

  9. u16 PressDelay = 0;     //按下計數器標志位
  10. u16 ReleaseDelay = 0;   //放開計數器標志位
  11. u8 KeyVal = 0;                        //按鍵標志位
  12. u8 ClickCount = 0;                //按鍵次數
  13. sbit k1=P3^2;                 //定義P32口是k1
  14. sbit led_0=P2^0;                 //定義P20口是led_0
  15. sbit led_1=P2^1;                 //定義P20口是led_1
  16. bit Flag_1ms = 0;                //1ms標志位
  17. void Timer0Init()
  18. {
  19.         TMOD|=0X01;//選擇為定時器0模式,工作方式1,僅用TR0打開啟動。

  20.         TH0=0XFC;       //給定時器賦初值,定時1ms
  21.         TL0=0X18;
  22.         ET0=1;                 //打開定時器0中斷允許
  23.         EA=1;                 //打開總中斷
  24.         TR0=1;                        //打開定時器
  25. }

  26. void Timer0() interrupt 1
  27. {
  28.         TH0=0XFC;        //給定時器賦初值,定時1ms
  29.         TL0=0X18;
  30.         Flag_1ms = 1;         //1ms標志位
  31. }

  32. /*******************************************************************************
  33. * 函 數 名         : keypros
  34. * 函數功能                   : 按鍵處理函數,判斷按鍵K1是否按下
  35. *******************************************************************************/
  36. void keypros()
  37. {
  38.         if(Flag_1ms==1)
  39.         {
  40.                 Flag_1ms = 0;
  41.                 if(k1==0)             //判斷按鍵是否按下
  42.                 {
  43.                         if(PressDelay<0xFFFF)PressDelay++;
  44.                         if(PressDelay==20)//20ms消抖
  45.                         {
  46.                                 ClickCount++;
  47.                         }
  48.                         if(PressDelay==1500)
  49.                         {
  50.                                 KeyVal = 10;
  51.                         }
  52.                         ReleaseDelay = 0;
  53.                 }
  54.                 else
  55.                 {
  56.                         if(ReleaseDelay<0xFF)ReleaseDelay++;
  57.                         if(ReleaseDelay==200)
  58.                         if(PressDelay<1500)
  59.                         {
  60.                                 KeyVal = ClickCount;
  61.                                 ClickCount = 0;
  62.                         }
  63.                         PressDelay=0;
  64.                 }
  65.                 if(KeyVal > 0)  //若有按鍵
  66.                 {
  67.                         if(KeyVal==10) //長按>=1.5s
  68.                         {
  69.                                 led_1=~led_1;        //led_1燈狀態取反 ,此處可以換成別的處理事件
  70.                         }
  71.                         else if(KeyVal==1)
  72.                         {
  73.                                 led_0=0;
  74.                         }
  75.                         else if(KeyVal==2)
  76.                         {
  77.                                 led_0=1;
  78.                         }
  79.                         KeyVal=0;
  80.                 }
  81.         }
  82. }

  83. /*******************************************************************************
  84. * 函 數 名       : main
  85. * 函數功能                 : 主函數
  86. * 輸    入       : 無
  87. * 輸    出             : 無
  88. *******************************************************************************/
  89. void main()
  90. {
  91.         Timer0Init();//定時器初始化
  92.         led_0=1;     //led_0熄滅
  93.         led_1=1;     //led_1熄滅
  94.         while(1)     //主循環
  95.         {
  96.                 keypros();  //按鍵處理函數
  97.         }
  98. }
復制代碼


回復

使用道具 舉報

9#
ID:119977 發表于 2022-8-18 10:31 | 只看該作者
delay(1000);   //消除抖動 一般大約10ms   //一般我看到用延時消抖我都覺得水平一般   
回復

使用道具 舉報

10#
ID:1042234 發表于 2022-8-18 15:01 | 只看該作者

1.按鈕長按松開的時候會誤判為短按
2.雙擊的時候第二下如果時間長一點的話會誤判為長按
回復

使用道具 舉報

11#
ID:1042234 發表于 2022-8-18 15:11 | 只看該作者

你好  實際在測試的時候發現 1.按鈕長按抬起的時候會誤判為短按
2.雙擊的時候第二下長按的時候會誤判為長按  
回復

使用道具 舉報

12#
ID:161164 發表于 2022-8-18 17:26 | 只看該作者
stcmcu2 發表于 2022-8-18 15:01
1.按鈕長按松開的時候會誤判為短按
2.雙擊的時候第二下如果時間長一點的話會誤判為長按
  1. void keypros()
  2. {
  3.         if(Flag_1ms==1)
  4.         {
  5.                 Flag_1ms = 0;
  6.                 if(k1==0)             //判斷按鍵是否按下
  7.                 {
  8.                         if(PressDelay<0xFFFF)PressDelay++;
  9.                         if(PressDelay==20)//20ms消抖
  10.                         {
  11.                                 ClickCount++;
  12.                         }
  13.                                                 if(ClickCount<2)//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  14.                                                         if(PressDelay==1500)
  15.                                                         {
  16.                                                                         KeyVal = 10;
  17.                                                                         ClickCount = 0;//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  18.                                                         }
  19.                         ReleaseDelay = 0;
  20.                 }
  21.                 else
  22.                 {
  23.                         if(ReleaseDelay<0xFF)ReleaseDelay++;
  24.                         if(ReleaseDelay==200)
  25.                                                         if(ClickCount)//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  26.                                                         {
  27.                                                                         KeyVal = ClickCount;
  28.                                                                         ClickCount = 0;
  29.                                                         }
  30.                         PressDelay=0;
  31.                 }
  32.                 if(KeyVal > 0)  //若有按鍵
  33.                 {
  34.                         if(KeyVal==10) //長按>=1.5s
  35.                         {
  36.                                 led_1=~led_1;        //led_1燈狀態取反 ,此處可以換成別的處理事件
  37.                         }
  38.                         else if(KeyVal==1)
  39.                         {
  40.                                 led_0=0;
  41.                         }
  42.                         else if(KeyVal==2)
  43.                         {
  44.                                 led_0=1;
  45.                         }
  46.                         KeyVal=0;
  47.                 }
  48.         }
  49. }
復制代碼


回復

使用道具 舉報

13#
ID:1042234 發表于 2022-8-19 09:36 | 只看該作者

有時間我試一試 效果
回復

使用道具 舉報

14#
ID:1039671 發表于 2022-8-19 10:03 | 只看該作者

這個好,長按不需要松手就可以完成動作,收藏了
回復

使用道具 舉報

15#
ID:1042234 發表于 2022-8-19 11:30 | 只看該作者

短按 抬起  ok
雙擊 抬起ok
長按 ok
回復

使用道具 舉報

16#
ID:699774 發表于 2022-8-19 12:38 | 只看該作者
hewayking 發表于 2022-8-18 10:31
delay(1000);   //消除抖動 一般大約10ms   //一般我看到用延時消抖我都覺得水平一般

確實真正寫程序誰會用delay讓mcu死在這里循環等待呢
回復

使用道具 舉報

17#
ID:1093578 發表于 2023-9-14 20:21 | 只看該作者

試了一下,確實OK
回復

使用道具 舉報

18#
ID:320250 發表于 2023-9-15 12:58 | 只看該作者
用定時器來檢測,有點浪費
回復

使用道具 舉報

19#
ID:1093578 發表于 2023-9-16 10:11 | 只看該作者
瘋城浪子 發表于 2023-9-15 12:58
用定時器來檢測,有點浪費

我很疑惑,他這個功能實現是OK的,但是TR0=1 打開后,再也沒關閉。定時器一直在跑,有什么弊端?
回復

使用道具 舉報

20#
ID:1093740 發表于 2023-9-16 17:21 | 只看該作者

這個COUNT延時,是不是還得算上程序運行時間了。額。應該沒啥影響吧。
回復

使用道具 舉報

21#
ID:1093740 發表于 2023-9-16 17:22 | 只看該作者
Tony5658 發表于 2023-9-16 10:11
我很疑惑,他這個功能實現是OK的,但是TR0=1 打開后,再也沒關閉。定時器一直在跑,有什么弊端?

這定時器一直跑,沒啥影響啊
回復

使用道具 舉報

22#
ID:1119741 發表于 2024-6-17 17:12 | 只看該作者
有處理兩個按鍵的嘛
回復

使用道具 舉報

23#
ID:161164 發表于 2024-6-18 11:54 | 只看該作者
mxf153163 發表于 2024-6-17 17:12
有處理兩個按鍵的嘛

有,加一些判斷和標志位
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: av中文字幕在线 | 欧美日韩在线观看一区 | 一区二区三区在线看 | 国产农村妇女精品一二区 | 国产欧美日韩精品在线观看 | 亚洲精品一区二区三区中文字幕 | 青青艹在线视频 | 国产美女精品视频 | 国产中文字幕网 | 国产999精品久久久 日本视频一区二区三区 | 欧美福利在线 | 久久精品视频免费看 | 国产精品美女www | 精品国产欧美一区二区 | 日韩精品av一区二区三区 | 中文字幕在线一区 | 久久久久国产一区二区三区 | 本道综合精品 | 欧美激情一区 | 一级欧美黄色片 | 色综合久久天天综合网 | 亚洲一区二区三区免费在线观看 | 亚洲高清在线观看 | 一区二区高清 | 日韩精品一区二区三区在线播放 | 久久一级 | 午夜影院在线观看免费 | 亚洲 欧美 另类 综合 偷拍 | 日韩精品一区二区三区在线播放 | 亚洲一区二区在线免费观看 | 久久成人国产精品 | 色吊丝2 | 在线看亚洲| 日本三级日产三级国产三级 | av第一页| 亚洲欧美国产精品久久 | 黄色高清视频 | 日韩1区| 国产一区二区三区四区三区四 | 天堂一区二区三区四区 | 精品国产网 |