标题: 51单片机识别 "单击.双击.长按"-我写的代码相信你能读懂 [打印本页]

作者: Kxuan163    时间: 2024-11-17 12:22
标题: 51单片机识别 "单击.双击.长按"-我写的代码相信你能读懂
//51单片机识别 "单击.双击.长按" 代码
//作者:Kxuan163
//程序功能:检测按钮的按下弹起次数,以识别"单击.双击.长按"
//MCU: STC89c52RC        晶振 11.0592MHZ
//Proteus8仿真通过;51开发板实验通过。

#include<reg52.h>   
#include<stdlib.h>  
sbit button =P1^2;    //按钮连接的单片机引脚
sbit LED1 =P2^7;             //单击则LED1亮
sbit LED2 =P2^4;      //双击则LED2亮
sbit LED3 =P2^0;      //长按则LED3亮
unsigned char count;  //T0计数溢出中断次数
unsigned char finish; //T0计时一轮结束标志
unsigned char read;   //读取P1^2引脚电平的变量
unsigned char dn;     //读得P1^2引脚低电平次数
unsigned char up;     //button弹起次数

//延时函数,入口参数ms为延时的毫秒数/////
void delayms(unsigned int ms)
{         unsigned char i;
        while(ms--)
        { for(i = 0; i < 120; i++); }                                       
} //////////////////////////////////////

//主函数
void main(void)         
{
  //T0 初始化 //////////////////////////
         TMOD=0x01;              //使用定时器T0的模式1
    TH0=(65536-46083)/256;  //定时器T0的高8位设置初值
    TL0=(65536-46083)%256;  //定时器T0的低8位设置初值
    EA=1;                   //开总中断
    ET0=1;                  //T0中断允许
  //////////////////////////////////////

  while(1)
   {
    LED1 =1; LED2=1; LED3=1;
    dn =0; up=0; count =0; finish =0;

    TR0=1;              //启动T0计时
    while(finish !=1 )  //在设定的T0计时段内循环检测
     {
      read =button;            //读取P1^2引脚电平
          if (read == 0) delayms(10); //延时10毫秒消热抖动         

          if (button == 0)
            {dn ++; read =button;} //读得P1^2低电平次数累加

          if (read ==0 && button ==1) up ++;//弹起次数累加
         } //end of while(finish !=1 )

    // T0计时一轮结束,进行识别:
        TR0 =0;
    if (dn >=1 && up ==1 )       //弹起1次,即单击               
              { LED1 =0; delayms(1000);} //LED1亮

    if (dn >=2 && up ==2 )            //弹起2次,即双击               
       { LED2=0; delayms(1000);}  //LED2亮

        if (dn>=20 && up==0 )        //持续未弹起,即长按     
              { LED3=0; delayms(1000);}  //LED3亮         
         
   } //end of while(1)
} //end of main()  


//函数:定时器T0的中断服务 ////////////////
void Time0(void ) interrupt 1 using 1
  {
    count++;            //T0计数溢出中断次数累加
    if(count==20)  //若T0计数溢出次数累计达设定值
          {count =0; finish =1;} //一轮计时结束                          

         TH0=(65536-46083)/256;  
        TL0=(65536-46083)%256;  
  } ///////////////////////////////////////






作者: lkc8210    时间: 2024-11-17 22:13
看到while+delayms就知道不用看懂也可以

作者: Kxuan163    时间: 2024-11-17 23:50
lkc8210 发表于 2024-11-17 22:13
看到while+delayms就知道不用看懂也可以

谢谢跟帖!
我尝试过用此算法,将代码略加修改即可识别三击...
作者: qsssuv    时间: 2024-11-18 11:45
http://www.51hei.com/bbs/dpj-238107-1.html
作者: STC庄伟    时间: 2024-11-19 08:51
你用AI8051U的 支持USB下载  兼容89C52的  
作者: Kxuan163    时间: 2024-11-19 11:39
STC庄伟 发表于 2024-11-19 08:51
你用AI8051U的 支持USB下载  兼容89C52的

谢谢庄伟先生建议,我亦正有此意。
作者: 赵八百    时间: 2024-11-19 16:52
你这个delay10ms不要这样写,你1ms近义词中断,20ms扫描一次就已经消抖了,
作者: Kxuan163    时间: 2024-11-20 10:49
发表于 2024-11-19 16:52
你这个delay10ms不要这样写,你1ms近义词中断,20ms扫描一次就已经消抖了,

delayms(10); //延时10毫秒消热抖动   ------这行代码无问题。有 书为依据
作者: xujibicool    时间: 2024-11-20 21:16
你都用定时器,还搞个delay 带坏朋友
作者: Kxuan163    时间: 2024-11-21 11:59
发表于 2024-11-20 21:16
你都用定时器,还搞个delay

定时器中断方式计时, delayms()软件方式计时,  各有各的用途。你未完全读懂。
作者: dj3365191    时间: 2024-11-21 17:22
有时候按两次还是LED1亮,程序修改哪里才能避免这种情况发生
作者: Kxuan163    时间: 2024-11-22 12:15
dj3365191 发表于 2024-11-21 17:22
有时候按两次还是LED1亮,程序修改哪里才能避免这种情况发生

你是用proteus仿真吗?  晶振是否 11.0592MHZ?
我刚刚为解答你的问题,试修改代码,再次仿真成功。
原代码   if (read == 0) delayms(10);  //延时10毫秒消热抖动
修改为   if (read == 0) delayms(5);    //延时 5毫秒消热抖动
作者: zhangdong533    时间: 2025-4-2 01:10
程序功能:检测按钮的按下弹起次数,以识别"单击.双击.长按"。。学习了




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1