找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4522|回复: 16
收起左侧

单片机实用按键模块,没有延时语句、while()语句,可以直接复制使用与其他程序不冲突

  [复制链接]
ID:491577 发表于 2021-6-7 12:30 | 显示全部楼层 |阅读模式
本帖最后由 hhh402 于 2021-6-13 12:55 编辑

单片机实用按键模块,没有延时语句、while()语句,资源占用小。可以直接复制使用与其他程序不冲突。
使用时只需要直接引用全局变量key1和key2就可以。举例:
1、k1按键按下LED1亮,再次按下LED1灭,
if(key1==1)        //k1按键按下
{
   key1=0;//必须软件清零!!!
   LED1=~LED1;
}

2、k2按键按下LED1亮,K2长按LED1灭,
if(key1==2) //k2按键按下
{
   key1=0;//必须软件清零!!!
   LED1=0; //0开1关
}
if(key1==20) //k按键长按
{
   key1=0;//必须软件清零!!!
   LED1=1; //0开1关
}

3、k3按键按下LED1亮,K4按下LED1灭,
if(key1==3) //k3按键按下
{
   key1=0;//必须软件清零!!!
   LED1=0; //0开1关
}
if(key1==4) //k4按键按下
{
   key1=0;//必须软件清零!!!
   LED1=1; //0开1关
}

4、K3按下一次,数据m 增加1,长按k3两秒以上每隔500ms数据m 增加10;K4按下一次,数据m 减少1,长按k4两秒以上每隔500ms数据m 减少10;
if(key1==3) //k3按键按下
{
   key1=0;//必须软件复位
   m++; //数据m 增加1
}
if(key2==3) //k3按键按下两秒以上,注意key2不需要清零,key1必须清零!!!
{
   if(ms1>2000&&ms1%500==0) m=m+10; //长按k3两秒以上每隔500ms数据m 增加10,ms1是毫秒变量,需要放在定时器1ms中断中自加,ms1++;
}
else ms1=0;        //复位

if(key1==4) //k4按键按下
{
   key1=0;//必须软件复位
   m--; //数据m -1
}
if(key2==4) //k4按键按下两秒以上 ,注意key2不需要清零,key1必须清零!!!
{
   if(ms2>2000&&ms2%500==0)  m=m-10; //长按k4两秒以上每隔500ms,ms2是毫秒变量,需要放在定时器1ms中断中自加,ms2++;
}
else ms2=0;//复位

//下面是完整程序代码:
#include "stc8.h"
#include "intrins.h"
#define u8  unsigned char
#define u16 unsigned int
sbit k1=P0^0;//按键1,四个按键可以是任意I/O口。按键按下时k1=0,按键释放k1=1
sbit k2=P0^1;//按键2
sbit k1=P0^2;//按键3
sbit k1=P0^3;//按键4
sbit LED1=P1^0;//LED1

//u8 key1[4];//按键变量数组,4个按键互不影响,如果用key1,一次只能够按一个按键,不允许同时按键。
u8 key1;//按键变量1,输出按键单击,长按。每单击或长按一次只输出一次,由调用函数清零。//key1=1/2/3/4是对应的按键单击,key1=10、20、30、40是对应的按键长按。key1=0表示没有按键按下。
//key1主要用途是:判断某一个按键是单击还是长按.注意调用函数需要将key1清零!!!
//u8 key2[4];//按键变量数组,4个按键互不影响,如果用key2,一次只能够按一个按键,不允许同时按键。
u8 key2;//按键变量2,输出按键单击,每10ms输出一次,key1=1/2/3/4是对应的按键单击。
//key2主要用途是:长按按键时快速增加或减少数值。
u16 ms1,ms2;//毫秒计时
u16 m;//
void key() //按键处理模块,需要放在10ms中断中运行!!!
/* 说明:1、按键单击,指按下100-1000ms内释放,加入时间限制是为了防止干扰。
             2、按键长按,指按下3-10s内释放,加入时间限制是为了防止干扰。
              3、函数运行后,按键值保存在key1、key2。用户直接调用key1、key2即可。

*/
{
  //静态变量,必须要static
  u16 static kgr[4];    //必须要static,抗干扰时间数组
  u8  static kanggr[4]; //中间变量1
  u8  static anjtem[4]; //按键释放中间变量。
  u8 i;
  u8 L_anj[4];
  L_anj[0]=k1;
  L_anj[1]=k2;
  L_anj[2]=k3;
  L_anj[3]=k4;
  for(i=0;i<3;i++)  //4个按键处理,key1,
   {
         if(L_anj[ i]==0)        //按键按下                                       
          { if(kanggr[ i]==0)        //中间变量1,与下面互锁
             { kgr[ i]=0;                //抗干扰时间清零,每次按键只写1次。
               kanggr[ i]=1;         //中间变量1
               anjtem[ i]=1;         //按键释放中间变量。与下面互锁
             }

           if(anjtem[ i]==1)
           {
                  kgr[ i]++;//10毫秒计时。
                  if(kgr[ i]>1000) //按键按下大于10秒,强制复位,防止误按。
                   { anjtem[ i]=0; //按键释放中间变量。与上面互锁
                     kgr[ i]=0;
//                  key1[ i]=0;//数组,4个按键独立
                   }
           }
         }

     else    //按键释放
     { kanggr[ i]=0;           //中间变量1,与上面互锁
           if(kgr[ i]>9&&kgr[ i]<99) //按键间隔100--1000毫秒才有效,防止电磁干扰。时间可以修改
                 key1=i+1;   //单击,按键间隔100--1000毫秒,每次释放只写1次。一次只能够按一个按键,不允许同时按键。
           //key1[ i]=i+1;//数组,4个按键独立
           else if(kgr[ i]>300&&kgr[ i]<1000) //按键间隔3000--10000毫秒才有效,防止电磁干扰。时间可以修改
                 key1=(i+1)*10;//长按,按键间隔3--10秒,每次释放只写1次。
           //key1[ i]=(i+1)*10;//数组,4个按键独立
     }
  }

//下面是处理:key2是有按键按下就输出键值。        
    for(i=0;i<3;i++)
         { if(L_anj[ i]==0)
           key2=i+1;//一次只能够按一个按键,不允许同时按键。
         //key2[ i]=i+1;//数组,4个按键独立.
         }
}


void timer0() interrupt 1                 //计时器T0中断1ms。
{
  //静态变量,必须要static
  u8  static time=0;   //毫秒变量。
  time++;//毫秒计时。
  if(time>9) //10ms运行一次按键处理函数,不需要防抖程序。
  {
       time=0;
        key();//按键处理模块,需要放在10ms中断中运行!!!
  }
//下面的语句不是按键模块需要的,可以删除。
    ms1++;ms2++;//毫秒计时
}

void main()
{
//1毫秒@12.000MHz,下面是STC单片机定时器0代码,如果是别的单片机请根据手册修改
        AUXR |= 0x80;                //定时器时钟1T模式
        TMOD &= 0xF0;                //设置定时器模式
        TL0 = 0x20;                //设置定时初值,1毫秒@12.000MHz
        TH0 = 0xD1;                //设置定时初值,1毫秒@12.000MHz
        TF0 = 0;                //清除TF0标志        
        ET0 = 1;        //使能定时器中断
       EA = 1;                    //打开总中断
        TR0 = 1;                //定时器0开始计时
while(1)
  {
//1、k1按键按下LED1亮,再次按下LED1灭,
    if(key1==1)        //k1按键按下
     {
       key1=0;//必须软件清零!!!
       LED1=~LED1;
     }

//2、k2按键按下LED1亮,K2长按LED1灭,
    if(key1==2) //k2按键按下
     {
       key1=0;//必须软件清零!!!
       LED1=0; //0开1关
     }
   if(key1==20) //k按键长按
     {
       key1=0;//必须软件清零!!!
       LED1=1; //0开1关
     }

//3、k3按键按下LED1亮,K4按下LED1灭,
   if(key1==3) //k3按键按下
    {
      key1=0;//必须软件清零!!!
      LED1=0; //0开1关
    }
   if(key1==4) //k4按键按下
    {
      key1=0;//必须软件清零!!!
      LED1=1; //0开1关
    }

//4、K3按下一次,数据m 增加1,长按k3两秒以上每隔500ms数据m 增加10;K4按下一次,数据m 减少1,长按k4两秒以上每隔500ms数据m 减少10;
//m的范围:0-60000
   if(key1==3) //k3按键按下
    {
      key1=0;//必须软件清零!!!
      if(m<60000) m++; //数据m 增加1
    }
   if(key2==3) //k3按键按下两秒以上,注意key2不需要清零,key1必须清零!!!
    {
      if(ms1>2000&&ms1%500==0)
           {if(m<=59990) m=m+10;} //长按k3两秒以上每隔500ms数据m 增加10,ms1是毫秒变量,需要放在定时器1ms中断中自加,ms1++;
    }
   else ms1=0;        //复位

   if(key1==4) //k4按键按下
    {
      key1=0;//必须软件复位
      if(m>0) m--; //数据m -1
    }
   if(key2==4) //k4按键按下两秒以上 ,注意key2不需要清零,key1必须清零!!!
    {
      if(ms2>2000&&ms2%500==0)
          {if(m>9)  m=m-10;} //长按k4两秒以上每隔500ms,ms2是毫秒变量,需要放在定时器1ms中断中自加,ms2++;
    }
   else ms2=0;//复位
}
}


评分

参与人数 2黑币 +60 收起 理由
x84s09t28 + 10 赞一个!
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:491577 发表于 2021-6-7 15:52 | 显示全部楼层
本帖最后由 hhh402 于 2021-6-13 12:56 编辑

这是按键检测模块函数:要认真看才能够理解。
void key() //按键处理模块,需要放在10ms中断中运行!!!
/* 说明:1、按键单击,指按下100-1000ms内释放,加入时间限制是为了防止干扰。
             2、按键长按,指按下3-10s内释放,加入时间限制是为了防止干扰。
             3、函数运行后,按键值保存在key1、key2。用户直接调用key1、key2即可。
*/
{
  u16 static kgr[4];    //必须要static,抗干扰时间数组
  u8  static kanggr[4]; //中间变量1
  u8  static anjtem[4]; //按键释放中间变量。
  u8 i;
  u8 L_anj[4];
  L_anj[0]=k1;
  L_anj[1]=k2;
  L_anj[2]=k3;
  L_anj[3]=k4;
  for(i=0;i<3;i++)  //4个按键处理,key1,
   {
         if(L_anj[ i]==0)        //按键按下                                       
          { if(kanggr[ i]==0)        //中间变量1,与下面互锁
             { kgr[ i]=0;                //抗干扰时间清零,每次按键只写1次。
               kanggr[ i]=1;         //中间变量1
               anjtem[ i]=1;         //按键释放中间变量。与下面互锁
            }

           if(anjtem[ i]==1)
           {
                  kgr[ i]++;//10毫秒计时。
                  if(kgr[ i]>1000) //按键按下大于10秒,强制复位,防止误按。
                   { anjtem[ i]=0; //按键释放中间变量。与上面互锁
                     kgr[ i]=0;
                   }
           }
         }

     else    //按键释放
     { kanggr[ i]=0;           //中间变量1,与上面互锁
           if(kgr[ i]>9 && kgr[ i]<99) //按键间隔100--1000毫秒才有效,防止电磁干扰。时间可以修改
                 key1=i+1;   //单击,按键间隔100--1000毫秒,每次释放只写1次。一次只能够按一个按键,不允许同时按键。
           else if(kgr[ i]>300 && kgr[ i]<1000) //按键间隔3000--10000毫秒才有效,防止电磁干扰。时间可以修改
                 key1=(i+1)*10;//长按,按键间隔3--10秒,每次释放只写1次。
     }
  }

//下面是处理:key2是有按键按下就输出键值。        
    for(i=0;i<3;i++)
         { if(L_anj[ i]==0)
           key2=i+1;//一次只能够按一个按键,不允许同时按键。
         }
}

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:299626 发表于 2021-6-7 17:15 | 显示全部楼层
本帖最后由 nqwang 于 2021-6-7 17:46 编辑

mark下,好东西,节省资源的按键处理,但是建议做个完整的工程这样好些。
回复

使用道具 举报

ID:229641 发表于 2021-6-7 23:30 来自手机 | 显示全部楼层
有完整的没我白嫖一下…
回复

使用道具 举报

ID:820198 发表于 2021-6-8 08:18 | 显示全部楼层
感谢分享, 有完整工程例子学习吗
回复

使用道具 举报

ID:491577 发表于 2021-6-8 09:55 | 显示全部楼层
最上面就是完整的程序,只需要改一下IO口设置,直接复制就可以用,与别的程序没有冲突,没有延时语句,while语句,资源占用很小。
回复

使用道具 举报

ID:491577 发表于 2021-6-8 09:58 | 显示全部楼层
注意:1、必须定义全局变量key1、key2。
          2、按键处理模块,需要放在10ms中断中运行!!!
          3、直接调用key1、key2就好。
回复

使用道具 举报

ID:914666 发表于 2021-6-10 04:57 | 显示全部楼层
要是客户一起按了按键怎么办啊?
回复

使用道具 举报

ID:491577 发表于 2021-6-10 10:13 | 显示全部楼层
用key1传递键值是不支持同时按键的,如果同时按键了会返回最后释放按键的键值,如果想四个按键独立互不影响可以使用数组key1[],程序里面有代码,已经注销了,自己修改一下就可以用。这个程序最大的特点是没有延时语句,while语句,不会阻塞别的程序,直接复制粘贴就可以使用了。
回复

使用道具 举报

ID:428114 发表于 2021-6-10 14:09 | 显示全部楼层
放在中断里,是一种手法,当然不再需要延时语句了,和程序没有关系.
回复

使用道具 举报

ID:162733 发表于 2021-6-12 21:38 | 显示全部楼层
上面的程序只有key2可以读出数值,key1始终无法读出数值
回复

使用道具 举报

ID:491577 发表于 2021-6-13 12:59 | 显示全部楼层
本帖最后由 hhh402 于 2021-6-15 12:16 编辑
x84s09t28 发表于 2021-6-12 21:38
上面的程序只有key2可以读出数值,key1始终无法读出数值

程序有点错误,按键检测程序中,ket1=0;这一句要去掉就可以了,最上面的程序我已经改好了,你再试试。其实原程序也是可以用的,key1的值只保存10ms就会变为0了,人眼是看不到key1的变化,但是10ms时间足够了,程序不会出错。
回复

使用道具 举报

ID:162733 发表于 2021-7-1 23:34 | 显示全部楼层
hhh402 发表于 2021-6-13 12:59
程序有点错误,按键检测程序中,ket1=0;这一句要去掉就可以了,最上面的程序我已经改好了,你再试试。其 ...

刚试过了程序,在你的key()程序中,else //按键释放,这个地方需要改成else if(kanggr[i ]==1)  //按键释放;否则的话,按键只有第一次按下有用,后面就不能用了
回复

使用道具 举报

ID:491577 发表于 2021-7-10 11:53 | 显示全部楼层
“按键只有第一次按下有用,后面就不能用了”,就是要这样的效果。等到按键释放后才会归位。每一次按键按下、释放只会输出一次键值,这样才方便程序调用。
回复

使用道具 举报

ID:579174 发表于 2021-8-4 14:20 | 显示全部楼层
程序小白,下来学习了,感谢分享!
回复

使用道具 举报

ID:845675 发表于 2021-8-11 19:08 来自手机 | 显示全部楼层
楼主,你这个模块怎么在我的AT89S51上不能正常使用啊
回复

使用道具 举报

ID:491577 发表于 2021-8-12 10:00 | 显示全部楼层
这是STC8单片机的程序,用在其他单片机需要修改定时器0部分。按照手册修改。
void main()
{
//1毫秒@12.000MHz,下面是STC单片机定时器0代码,如果是别的单片机请根据手册修改
        AUXR |= 0x80;                //定时器时钟1T模式
        TMOD &= 0xF0;                //设置定时器模式
        TL0 = 0x20;                //设置定时初值,1毫秒@12.000MHz
        TH0 = 0xD1;                //设置定时初值,1毫秒@12.000MHz
        TF0 = 0;                //清除TF0标志        
        ET0 = 1;        //使能定时器中断
       EA = 1;                    //打开总中断
        TR0 = 1;                //定时器0开始计时
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表