找回密码
 立即注册

QQ登录

只需一步,快速开始

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

求教,7个独立按键都不在同一单片机IO上,状态机按键检测咋实现?

[复制链接]
ID:190577 发表于 2020-3-17 18:07 | 显示全部楼层 |阅读模式
7个独立按键都不在同一IO上,状态机按键检测咋实现?
回复

使用道具 举报

ID:190577 发表于 2020-3-17 18:44 | 显示全部楼层
假如3个独立按键,分别对应3个I/O,这3个I/O口分属于P1、P2、P3的某个引脚,怎样用状态机的思路进行检测,一个按键的已经会了,但怎样用状态机方法同时检测3个按键的动作?另外如果是组合按键(2个或者3个同时按下才生效)又该怎样处理?能否提供思路!!!
回复

使用道具 举报

ID:687694 发表于 2020-3-17 22:23 | 显示全部楼层
if(a&&b)or if(b&&c)多按键状态判断,各个IO的状态判断跟1个IO一样的。
回复

使用道具 举报

ID:709787 发表于 2020-3-17 22:28 来自手机 | 显示全部楼层
首先,单片机运行速度是很快的。你按一次按钮的时间,单片机都检测了一二十次了!不同同时检测,挨个检测也行!!要同时按下,用if语句:if(按钮一按下){if(按钮二按下){执行动作}}
回复

使用道具 举报

ID:687694 发表于 2020-3-18 18:56 | 显示全部楼层
天地一微尘 发表于 2020-3-17 22:28
首先,单片机运行速度是很快的。你按一次按钮的时间,单片机都检测了一二十次了!不同同时检测,挨个检测也 ...

楼主说的是在状态机状态下由状态标志判断。
回复

使用道具 举报

ID:742384 发表于 2020-5-1 17:58 | 显示全部楼层
用位移将7个IO口状态赋值到一个变量中
回复

使用道具 举报

ID:420836 发表于 2020-5-2 02:56 | 显示全部楼层
如果状态机检查基于时间,则必须在实时系统中的不同单芯片计算机之间同步时间。
回复

使用道具 举报

ID:190577 发表于 2020-7-25 12:47 | 显示全部楼层
// 按键
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
#define key_state_3 3
#define key_no 0
#define key_click 1
#define key_double 2
#define key_long 3
sbit KEY = P0^4;
sbit key1=P5^0;// 红光
sbit key2=P3^0;//绿光开关
sbit key3=P0^2;        //蓝
sbit key4=P4^0;        //白
sbit key5=P0^3; //加湿度
sbit key6=P5^2;//自动

static unsigned char key_read(void)
{
        static unsigned char key_state_buffer1 = key_state_0;
        static unsigned char key_timer_cnt1 = 0;
                static         unsigned char temp=0;
        unsigned char key_return = key_no;
       // unsigned char key;

        //key = KEY;  //read the I/O states

        switch(key_state_buffer1)
        {
                case key_state_0:
                        if((KEY == 0)||(key1 == 0)||(key2==0)||(key3==0)||(key4==0)||(key5==0)||(key6==0))
                         {  key_state_buffer1 = key_state_1; temp=0;
                                                         return 0;
                                                 }
                                //按键被按下,状态转换到按键消抖和确认状态//
                        break;
                case key_state_1:
                        if(KEY== 0)
                        {
                                temp=1;
                                                            key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                //按键仍然处于按下状态
                                //消抖完成,key_timer开始准备计时
                                //状态切换到按下时间计时状态
                        }
                                                else if(key1==0)
                                                {
                                                           temp=2;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key2==0)
                                                {
                                                            temp=4;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key3==0)
                                                {
                                                            temp=5;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key4==0)
                                                {
                                                            temp=6;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key5==0)
                                                {
                                                            temp=7;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                                                else if(key6==0)
                                                {
                                                            temp=8;
                                                           // key_timer_cnt1 = 0;
                                key_state_buffer1 = key_state_2;
                                                }
                        else
                                                {
                                key_state_buffer1 = key_state_0; temp=0;
                                                }
                                //按键已经抬起,回到按键初始状态
                        break;  //完成软件消抖
                case key_state_2:
                                                 if((KEY == 0)||(key1 == 0)||(key2==0)||(key3==0)||(key4==0)||(key5==0)||(key6==0))
                                                {
                                                         key_state_buffer1 = key_state_2;
                                                         if(temp==1)
                                                         {
                                                                 if(++key_timer_cnt1 >= 100)  //按键继续按下,计时超过1000ms
                                                                 {
                                                                    
                                        key_return = key_long;  //送回长按事件
                                        key_state_buffer1 = key_state_3;  //转换到等待按键释放状态
                                                                 }
                                                          }
                                                }
                                                else
                                                {
                                                         key_return = temp;  //按键抬起,产生一次click操作
                             key_state_buffer1 = key_state_0;  //转换到按键初始状态
                                                }
                       /* if(KEY == 1)
                        {
                                key_return = key_click;  //按键抬起,产生一次click操作
                                key_state_buffer1 = key_state_0;  //转换到按键初始状态
                        }
                        else if(++key_timer_cnt1 >= 100)  //按键继续按下,计时超过1000ms
                        {
                                key_return = key_long;  //送回长按事件
                                key_state_buffer1 = key_state_3;  //转换到等待按键释放状态
                        } */
                        break;
                case key_state_3:  //等待按键释放
                        if((KEY == 0)||(key1 == 0)||(key2==0)||(key3==0)||(key4==0)||(key5==0)||(key6==0)) //按键释放
                                key_state_buffer1 = key_state_3;  //切回按键初始状态
                                                 else //按键释放
                                key_state_buffer1 = key_state_0;  //切回按键初始状态
                        break;
        }
        return key_return;
}

回复

使用道具 举报

ID:311846 发表于 2020-7-27 17:23 | 显示全部楼层
有个东西叫寄存器,读取IO口的寄存器,比如你7个IO同在P1,那么P1寄存器读出来,对应位为1则为高电平,32自行研究,
回复

使用道具 举报

ID:213173 发表于 2020-7-28 09:28 | 显示全部楼层
bbxyliyang 发表于 2020-3-17 18:44
假如3个独立按键,分别对应3个I/O,这3个I/O口分属于P1、P2、P3的某个引脚,怎样用状态机的思路进行检测, ...

给你写一个示例程序,你按实际需要修改。 无标题.jpg

  1. #include <reg51.H>

  2. #define PD 0x80|(P1<<3&0x60)|(P2>>1&0x18)|(P3&0x07)//P1.2~3/P2.4~5/P3.0~2组合7个按键为1个字节数据

  3. unsigned char code table[]={//共阳数码管段码"0~f-."
  4.                 0xc0,0xf9,0xa4,0xb0,
  5.                 0x99,0x92,0x82,0xf8,
  6.                 0x80,0x90,0x88,0x83,
  7.                 0xc6,0xa1,0x86,0x8e,0xbf,0x7f};

  8. unsigned char KeySec=0;//键值变量

  9. //延时程序
  10. void delayms(unsigned int k)
  11. {
  12.         unsigned int i,j;
  13.         for(i=k;i>0;i--)
  14.                 for(j=110;j>0;j--);
  15. }

  16. //按键扫描
  17. void keyscan()
  18. {
  19.         static unsigned int count=0;//计数变量
  20.         static bit key_sign=0;     //按键状态标志
  21.         unsigned char time;                        //临时变量

  22.         if((PD&0xff)!= 0xff)//有按键按下
  23.         {
  24.                 count++;                //计数变量自加1
  25.                 if(count>500)
  26.                         count=501;//防止溢出

  27.                 if(count>10 && key_sign==0)//10ms消抖与按键状态识别
  28.                 {//使用组合键要适当延长消抖时间
  29.                         key_sign=1;//确认按键按下
  30.                         time=PD&0xff;//保存键态值
  31.                 }
  32.                 if(count==500)//判断按下0.5s长按有效
  33.                 {
  34.                         switch(time)
  35.                         {
  36.                                 //单键
  37.                                 case 0xfe: KeySec=8;  break;
  38.                                 case 0xfd: KeySec=9;  break;
  39.                                 case 0xfb: KeySec=10; break;
  40.                                 case 0xf7: KeySec=11; break;
  41.                                 case 0xef: KeySec=12; break;
  42.                                 case 0xdf: KeySec=13; break;
  43.                                 case 0xbf: KeySec=14; break;
  44.                         // 组合键
  45.                         //        case 0xee: KeySec=?; break;
  46.                         }
  47.                 }
  48.         }
  49.         else //没有按或按下后松手
  50.         {
  51.                 if(key_sign==1)//判断是按键按下后松手
  52.                 {
  53.                         key_sign=0; //按键状态标志清0
  54.                         if(count>10 && count<500)//小于0.5s判断为短按
  55.                         {
  56.                                 switch(time)
  57.                                 {
  58.                                         //单键
  59.                                         case 0xfe: KeySec=1; break;
  60.                                         case 0xfd: KeySec=2; break;
  61.                                         case 0xfb: KeySec=3; break;
  62.                                         case 0xf7: KeySec=4; break;
  63.                                         case 0xef: KeySec=5; break;
  64.                                         case 0xdf: KeySec=6; break;
  65.                                         case 0xbf: KeySec=7; break;
  66.                                 // 组合键
  67.                                 //        case 0xee: KeySec=?; break;
  68.                                 }
  69.                         }
  70.                 }
  71.                 count=0;//计数变量清0
  72.         }
  73. }
  74. //主函数
  75. void main()
  76. {
  77.         P0=table[KeySec];//初始显示状态0
  78.         while(1)
  79.         {
  80.                 keyscan();        //按键扫描
  81.                 if(KeySec!=0)//刷新显示
  82.                 {
  83.                         P0=table[KeySec];//显示键值
  84.                         KeySec=0;//键值清0
  85.                 }
  86.                 delayms(1);//控制主循环周期1ms
  87.         }
  88. }
复制代码



回复

使用道具 举报

ID:808700 发表于 2020-7-28 11:37 | 显示全部楼层
7个独立按键状态,直接放进一个8位的数据里面,最高位或者最低位不要
回复

使用道具 举报

ID:190577 发表于 2020-7-30 22:18 | 显示全部楼层
感觉状态机应用比较广,这个程序我已经学会了状态的使用。
回复

使用道具 举报

ID:548551 发表于 2020-7-31 09:29 | 显示全部楼层
7个独立按键? 7个独立IO口? 然后你就不知道怎么控制了?
回复

使用道具 举报

ID:190577 发表于 2020-7-31 11:52 | 显示全部楼层
xqleft 发表于 2020-7-31 09:29
7个独立按键? 7个独立IO口? 然后你就不知道怎么控制了?

已经学会了
回复

使用道具 举报

ID:190577 发表于 2020-7-31 19:11 | 显示全部楼层
有限状态机由有限的状态和相互之间的转移构成,在任何时候只
能处于给定数目的状态中的一个。当接收到一个输入事件时,状态机产生一个输出,同时也可能伴随着状态的转移。
#define key_input    PIND.7      // 按键输入口
#define key_state_0  0
#define key_state_1  1
#define key_state_2  2
char read_key(void)
{
static char key_state = 0;
char key_press, key_return = 0;
key_press = key_input;        // 读按键 I/O (状态机的输入)
switch (key_state)
{
case key_state_0:        // 按键初始态
        if (!key_press) key_state = key_state_1;  // 键被按下,状态转换到键确认态 , 确定下一次按键的状态值
break;
case key_state_1:        // 按键确认态
if (!key_press)
{
            key_return = 1;      // 按键仍按下,按键确认输出为“1”
            key_state = key_state_2;  // 状态转换到键释放态
}
else
            key_state = key_state_0;  // 按键已抬起,转换到 按键初始态
       break;
case key_state_2:
            if (key_press) key_state = key_state_0;  //按键已释放,转换到按键初始态
       break;
}  
      return key_return;
}
该简单按键接口函数 read_key()在整个系统程序中应每隔10ms
调用执行一次,每次执行时将先读取与按键连接的 I/O 的电平到变量 key_press 中,然后进入用 switch 结构构成的状态机。switch 结构中的 case 语句分别实现了 3 个不同状态的处理判别过程,在每个状态中将根据状态的不同,以及 key_press 的值(状态机的输入)确定输出值(key_return),和确定下一次按键的状态值(key_state) 。 函数 read_key()的返回参数提供上层程序使用。返回值为 0 时,表示按键无动作;而返回 1 表示有一次按键闭合动作,需要进入按键处理程序做相应的键处理。在函数 read_key()中定义了 3 个局部变量,其中 key_press和key_return为一般普通的局部变量,每次函数执行时,key_press 中保存着刚检测的按键值。key_return 为函数的返回值,总是先初始化为 0,只有在状态 1 中重新置 1,作为表示按键确认的标志返回。变量 key_state 非常重要,它保存着按键的状态值,该变量的值在函数调用结束后不能消失,
必须保留原值,因此在程序中定义为“局部静态变量” ,用static 声明。如果使用的语言环境不支持 static 类型的局部变量,应将 key_state 定义为全局变量(关于局部静态变量的特点请参考相关介绍 C 语言程序设计的书籍) 。
回复

使用道具 举报

ID:190577 发表于 2021-1-21 15:29 | 显示全部楼层
bbxyliyang 发表于 2020-7-30 22:18
感觉状态机应用比较广,这个程序我已经学会了状态的使用。

对的,状态机比较常见的。
回复

使用道具 举报

ID:190577 发表于 2021-6-14 19:39 | 显示全部楼层
xqleft 发表于 2020-7-31 09:29
7个独立按键? 7个独立IO口? 然后你就不知道怎么控制了?

知道控制
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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