標(biāo)題: 51單片機(jī)獨(dú)立按鍵程序 實(shí)現(xiàn)長按、短按功能 [打印本頁]

作者: cheney03    時(shí)間: 2021-9-30 11:26
標(biāo)題: 51單片機(jī)獨(dú)立按鍵程序 實(shí)現(xiàn)長按、短按功能
獨(dú)立按鍵 通過定時(shí)器實(shí)現(xiàn)長按、短按功能:

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

本人親測(cè)有效!

單片機(jī)源程序如下:
  1. /*************************************************************************************
  2. 實(shí)驗(yàn)現(xiàn)象:下載程序后按下K1按鍵可以對(duì)led_0/led_1小燈狀態(tài)取反
  3.            短按控制led_0;長按控制led_1                                                  
  4. *************************************************************************************
  5. */

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

  7. typedef unsigned int u16;          //對(duì)數(shù)據(jù)類型進(jìn)行聲明定義
  8. typedef unsigned char u8;

  9. bit press_flag; //按鍵標(biāo)志位
  10. u16 count;      //計(jì)數(shù)器標(biāo)志位
  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;//選擇為定時(shí)器0模式,工作方式1,僅用TR0打開啟動(dòng)。

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

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


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

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

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



作者: stcmcu2    時(shí)間: 2022-8-17 10:32
好像不太對(duì) 第一次短按會(huì)判斷為長按
作者: mirenhuan    時(shí)間: 2022-8-17 16:34
stcmcu2 發(fā)表于 2022-8-17 10:32
好像不太對(duì) 第一次短按會(huì)判斷為長按

做了實(shí)驗(yàn),第一次開機(jī)LED1會(huì)亮,仔細(xì)分析了下代碼,在定時(shí)器初始化里面把TR0=1改為TR0=0,就可以解決這個(gè)問題。然后感覺有一點(diǎn)還是不完美,就是按鍵長按不松開LED1不會(huì)點(diǎn)亮,需要釋放按鍵才能點(diǎn)亮。
作者: lkc8210    時(shí)間: 2022-8-17 17:32
stcmcu2 發(fā)表于 2022-8-17 10:32
好像不太對(duì) 第一次短按會(huì)判斷為長按

26行 改為 TR0 = 0;
但不建議用長時(shí)間的阻塞式消抖/while(!K1)
作者: 張?zhí)鞄?nbsp;   時(shí)間: 2022-8-17 20:17
一看到while(!k1)這句,就沒有研究的價(jià)值。
作者: stcmcu2    時(shí)間: 2022-8-18 08:42
lkc8210 發(fā)表于 2022-8-17 17:32
26行 改為 TR0 = 0;
但不建議用長時(shí)間的阻塞式消抖/while(!K1)

雙擊的怎么樣去操作
作者: lkc8210    時(shí)間: 2022-8-18 10:00
  1. /*************************************************************************************
  2. 實(shí)驗(yàn)現(xiàn)象:下載程序后按下K1按鍵可以對(duì)led_0/led_1小燈狀態(tài)取反
  3.            短按控制led_0;長按控制led_1
  4. *************************************************************************************
  5. */

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

  7. typedef unsigned int u16;          //對(duì)數(shù)據(jù)類型進(jìn)行聲明定義
  8. typedef unsigned char u8;

  9. u16 count = 0;      //計(jì)數(shù)器標(biāo)志位
  10. u8 KeyVal = 0;//按鍵標(biāo)志位
  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標(biāo)志位
  15. void Timer0Init()
  16. {
  17.         TMOD|=0X01;//選擇為定時(shí)器0模式,工作方式1,僅用TR0打開啟動(dòng)。

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

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

  30. /*******************************************************************************
  31. * 函 數(shù) 名         : keypros
  32. * 函數(shù)功能                   : 按鍵處理函數(shù),判斷按鍵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燈狀態(tài)取反 ,此處可以換成別的處理事件
  60.                         }
  61.                         else            //短按<1.5s
  62.                         {
  63.                                 led_0=~led_0;         //led_0燈狀態(tài)取反 ,此處可以換成別的處理事件
  64.                         }
  65.                         KeyVal=0;
  66.                 }
  67.         }
  68. }

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



作者: lkc8210    時(shí)間: 2022-8-18 10:22
stcmcu2 發(fā)表于 2022-8-18 08:42
雙擊的怎么樣去操作
  1. /*************************************************************************************
  2. 實(shí)驗(yàn)現(xiàn)象:下載程序后按下K1按鍵可以對(duì)led_0/led_1小燈狀態(tài)取反
  3.            短按控制led_0;長按控制led_1
  4. *************************************************************************************
  5. */

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

  7. typedef unsigned int u16;          //對(duì)數(shù)據(jù)類型進(jìn)行聲明定義
  8. typedef unsigned char u8;

  9. u16 PressDelay = 0;     //按下計(jì)數(shù)器標(biāo)志位
  10. u16 ReleaseDelay = 0;   //放開計(jì)數(shù)器標(biāo)志位
  11. u8 KeyVal = 0;                        //按鍵標(biāo)志位
  12. u8 ClickCount = 0;                //按鍵次數(shù)
  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標(biāo)志位
  17. void Timer0Init()
  18. {
  19.         TMOD|=0X01;//選擇為定時(shí)器0模式,工作方式1,僅用TR0打開啟動(dòng)。

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

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

  32. /*******************************************************************************
  33. * 函 數(shù) 名         : keypros
  34. * 函數(shù)功能                   : 按鍵處理函數(shù),判斷按鍵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燈狀態(tài)取反 ,此處可以換成別的處理事件
  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. * 函 數(shù) 名       : main
  85. * 函數(shù)功能                 : 主函數(shù)
  86. * 輸    入       : 無
  87. * 輸    出             : 無
  88. *******************************************************************************/
  89. void main()
  90. {
  91.         Timer0Init();//定時(shí)器初始化
  92.         led_0=1;     //led_0熄滅
  93.         led_1=1;     //led_1熄滅
  94.         while(1)     //主循環(huán)
  95.         {
  96.                 keypros();  //按鍵處理函數(shù)
  97.         }
  98. }
復(fù)制代碼



作者: hewayking    時(shí)間: 2022-8-18 10:31
delay(1000);   //消除抖動(dòng) 一般大約10ms   //一般我看到用延時(shí)消抖我都覺得水平一般   
作者: stcmcu2    時(shí)間: 2022-8-18 15:01
lkc8210 發(fā)表于 2022-8-18 10:22

1.按鈕長按松開的時(shí)候會(huì)誤判為短按
2.雙擊的時(shí)候第二下如果時(shí)間長一點(diǎn)的話會(huì)誤判為長按
作者: stcmcu2    時(shí)間: 2022-8-18 15:11
lkc8210 發(fā)表于 2022-8-18 10:22

你好  實(shí)際在測(cè)試的時(shí)候發(fā)現(xiàn) 1.按鈕長按抬起的時(shí)候會(huì)誤判為短按
2.雙擊的時(shí)候第二下長按的時(shí)候會(huì)誤判為長按  
作者: lkc8210    時(shí)間: 2022-8-18 17:26
stcmcu2 發(fā)表于 2022-8-18 15:01
1.按鈕長按松開的時(shí)候會(huì)誤判為短按
2.雙擊的時(shí)候第二下如果時(shí)間長一點(diǎn)的話會(huì)誤判為長按
  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燈狀態(tài)取反 ,此處可以換成別的處理事件
  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. }
復(fù)制代碼



作者: stcmcu2    時(shí)間: 2022-8-19 09:36
lkc8210 發(fā)表于 2022-8-18 17:26

有時(shí)間我試一試 效果
作者: mirenhuan    時(shí)間: 2022-8-19 10:03
lkc8210 發(fā)表于 2022-8-18 10:00

這個(gè)好,長按不需要松手就可以完成動(dòng)作,收藏了
作者: stcmcu2    時(shí)間: 2022-8-19 11:30
lkc8210 發(fā)表于 2022-8-18 17:26

短按 抬起  ok
雙擊 抬起ok
長按 ok
作者: liu9808    時(shí)間: 2022-8-19 12:38
hewayking 發(fā)表于 2022-8-18 10:31
delay(1000);   //消除抖動(dòng) 一般大約10ms   //一般我看到用延時(shí)消抖我都覺得水平一般

確實(shí)真正寫程序誰會(huì)用delay讓mcu死在這里循環(huán)等待呢
作者: Tony5658    時(shí)間: 2023-9-14 20:21
lkc8210 發(fā)表于 2022-8-18 17:26

試了一下,確實(shí)OK
作者: 瘋城浪子    時(shí)間: 2023-9-15 12:58
用定時(shí)器來檢測(cè),有點(diǎn)浪費(fèi)
作者: Tony5658    時(shí)間: 2023-9-16 10:11
瘋城浪子 發(fā)表于 2023-9-15 12:58
用定時(shí)器來檢測(cè),有點(diǎn)浪費(fèi)

我很疑惑,他這個(gè)功能實(shí)現(xiàn)是OK的,但是TR0=1 打開后,再也沒關(guān)閉。定時(shí)器一直在跑,有什么弊端?
作者: weilemin123    時(shí)間: 2023-9-16 17:21
lkc8210 發(fā)表于 2022-8-18 10:00

這個(gè)COUNT延時(shí),是不是還得算上程序運(yùn)行時(shí)間了。額。應(yīng)該沒啥影響吧。
作者: weilemin123    時(shí)間: 2023-9-16 17:22
Tony5658 發(fā)表于 2023-9-16 10:11
我很疑惑,他這個(gè)功能實(shí)現(xiàn)是OK的,但是TR0=1 打開后,再也沒關(guān)閉。定時(shí)器一直在跑,有什么弊端?

這定時(shí)器一直跑,沒啥影響啊
作者: mxf153163    時(shí)間: 2024-6-17 17:12
有處理兩個(gè)按鍵的嘛
作者: lkc8210    時(shí)間: 2024-6-18 11:54
mxf153163 發(fā)表于 2024-6-17 17:12
有處理兩個(gè)按鍵的嘛

有,加一些判斷和標(biāo)志位




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1