标题: 关于单片机独立按键程序分析 纯属新手分析的理论不知道对不对欢迎指正批评 [打印本页]

作者: SHANWAZI    时间: 2021-1-24 20:21
标题: 关于单片机独立按键程序分析 纯属新手分析的理论不知道对不对欢迎指正批评
首先非常感谢前面通过请教论坛师傅关于独立按键按下后等待松开例程的原理,后自己又继续研究其程序原理并且举一反三
根据前面的原理自己又在鼓捣敲了个程序并且配合软件调试单步运行似乎也可行。下面上程序:
       static uchar   loo_go=1;//按键松开检测变量
       static uchar  KEY_NUM=0;//键值变量
        void key_scan()
        {
                if(k1!= loo_go)
                {
                        if loo_go==0)
                        {
                                KYE_NUM1=1;        
                        }
                         loo_go=k1;        
                }
        }

下面为本人分析此程序过程:
1:当按按键没有按下时第一个if(k1!= loo_go)不成立所以不执行后面语句直接跳出并且把看k1原本的值赋值给按键松开检测变量《这个值没有发生改变
则认为按键没有按下》 loo_go=k1;
2:当按键第一次被按下时第一个if(k1!= loo_go)条件成立k1此时不等于1《因为按键被按下为0姑且k1不是1而是0而成立》后执行它后面语句
继续判断第二个条件if (loo_go==0)此时按键松开检测变量loo_go值不等于0《上面定义时默认为1》而不执行它后面语句直接跳出到loo_go=k1;此时
把k1的值赋值给按键松开检测变量loo_go《这里的时因为是按键被按下k1为0所以按键松开检测变量loo_go也为0》后退出按键扫描函数
3:在这里《假设按键第一次被按下后没有松开的话当主循环再次进入到按键扫描函数后》
4:再开始判断第一个if(k1!= loo_go)条件此时判断条件已经改变而是要判断按键不等于0时条件成立《此时因为上一次的按键按下后将 loo_go赋值为0所以判断条件被改变》如果按键还不松开又直接跳出到loo_go=k1;此时
把k1的值赋值给按键松开检测变量loo_go《这里的时因为是按键被按下k1为0所以按键松开检测变量loo_go也为0》后退出按键扫描函数
5:《假设按键松开当主循环再次进入到按键扫描函数》
6:再进入扫描函数开始判第一个if(k1!= loo_go)条件此时判断条件已经改变而是要判断按键不等于0时条件成立
此时因为按键被松条件成立《因为一松开就等于1所以不等于0》后继续执行后面语句进入到第二个条件if loo_go==0)此时条件时成立的《因为第一次按下时此 loo_go赋值为0并且保存所以条件成立》继续执行下面语句将KYE_NUM1=1;键值变量赋值为1,《再出来把k1赋值给按键松开检测变量loo_go因为按键已经松开k1为1此时loo_go也等于1》完成按键按下后和抬起的整个过程。
7:根据上述分析过程可认为按键按下并没有给KYE_NUM1=1;键值变量赋值为1;而是按键抬起后才给赋完成了按键按下检测和抬起检测而且。
如有不对的地方欢迎各位论坛老师指证批评!!!!!!!!!!!!!!!!!!!

作者: 人人学会单片机    时间: 2021-1-24 21:50
51单片机独立键盘的短按+长按 http://www.51hei.com/bbs/dpj-201806-1.html
作者: wulin    时间: 2021-1-25 09:04
楼主的探索精神可嘉。这个程序从逻辑上看没有问题,但用于实际电路就会发现响应慢和容易出错。
1.因为键按下loo_go只记忆了操作行为,必须等按键松手后才能响应按键功能。
2.常用的按键等机械开关,在翻转瞬间触点是抖动不稳定的,会产生噪波,持续时间几ms。为此需要外部硬件滤波或软件消抖。所以此函数还要进一步完善。
但软件消抖并不是在任何使用环境都必须的。如果按键扫描函数放在循环周期大于10ms的主函数或中断函数中运行就不必消抖。给你一个独立按键示例,非常简单。看懂以后可以很方便的扩展成多按键,组合键,长短按键。
  1. #include<reg51.h>

  2. sbit key=P3^0;
  3. sbit LED=P1^0;

  4. unsigned char Temp;
  5. unsigned char Record;

  6. void key_scan()
  7. {
  8.         unsigned char ReadData = key ^ 0x01;
  9.         Temp = ReadData & (ReadData ^ Record);
  10.         if(Temp)LED=~LED;
  11.         Record = ReadData;
  12. }

  13. void main()
  14. {
  15.         while(1)
  16.         {
  17.                 key_scan();
  18.                 //延时10ms
  19.         }
  20. }
复制代码


作者: 黄youhui    时间: 2021-1-25 09:19
       static uchar   loo_go=1;//按键松开检测变量
       static uchar  KEY_NUM=0;//键值变量
        void key_scan()
        {
                if(k1!= loo_go)
                {
                        if (loo_go==0)(这里缺个括号,给你补上)
                        {
                                KYE_NUM1=1;        
                        }
                         loo_go=k1;        
                }
        }if (loo_go==0)表示loo_go代表按下按键。
loo_go的定义是static uchar   loo_go=1;
也就是说开机后loo_go = 1;

k1 !=  1,表示按下按键那进入if(k1!= loo_go)判断后
if (loo_go==0)这个判断你仍然无法进入,而是直接执行下一条代码loo_go=k1 ;

如此时不松开按键的话if(k1!= loo_go)这条判断你也无法被再次触发
因为此时loo_go=k1 = 0;
松开按键后if(k1!= loo_go)再次被触发if (loo_go==0)也被触发,完成KYE_NUM1=1 赋值。


这个如果非要说什么缺点就是必须要等按键松开才能触发相应的功能,以及必须进入两次以上按键扫描代码才能完成赋值
还有就是有些按键按下后它的电平变化不是稳定的gnd或者vcc而是波浪形的,最好几个延时防止误触发


作者: 77599585    时间: 2021-1-25 12:48
我个人不建议把读取按键状态的函数宏定义成k1这种像变量名一样的形式,
会让人误解k1是个变量, 好像由赋值语句获取的,
这样就会误认为每次使用k1需要先k1=read(pin)赋一个新值,
而实际上却是#define k1 read(pin), 很容易误会,


我一般写成#define read_k1() read(pin),
用的时候也是if(read_k1() == 0){}
让读者明白这句话是个函数过程, 而不是变量
作者: SHANWAZI    时间: 2021-1-26 14:57
77599585 发表于 2021-1-25 12:48
我个人不建议把读取按键状态的函数宏定义成k1这种像变量名一样的形式,
会让人误解k1是个变量, 好像由赋值 ...

感谢纠正
作者: SHANWAZI    时间: 2021-1-26 15:02
黄youhui 发表于 2021-1-25 09:19
static uchar   loo_go=1;//按键松开检测变量
       static uchar  KEY_NUM=0;//键值变量
       ...

感谢回复纠正后续会多加学习
作者: SHANWAZI    时间: 2021-1-26 15:06
wulin 发表于 2021-1-25 09:04
楼主的探索精神可嘉。这个程序从逻辑上看没有问题,但用于实际电路就会发现响应慢和容易出错。
1.因为键按 ...

非常感谢指正和耐心回复 和纠正!回复慢了一点因为前面帖子突然找不到的被不知道移哪去了
作者: zsw3721    时间: 2021-1-26 17:22
wulin 发表于 2021-1-25 09:04
楼主的探索精神可嘉。这个程序从逻辑上看没有问题,但用于实际电路就会发现响应慢和容易出错。
1.因为键按 ...

感谢分享。这种方法真的简洁又好用。Record相当于记录按键的状态,按下后直到松开的整个区间都是1。Temp相当于一个trigger,只在按下后的第一次扫描时是1,确保一次按键周期内只执行一次动作。
作者: DKC_LIN_123    时间: 2021-1-27 12:18

作者: xianfajushi    时间: 2021-1-28 12:44
那么喜欢分析真好学,丢一个给你玩玩: void main()         //主函数 {   unsigned char aa=0,xd=0;         unsigned int i=0;         bit k=0; //        zdsz();         while(1)         {                 if(!k&&++xd==0&&k1==0)k=1;                 if(k&&++xd==0&&k2==0)k=0;                 if(k&&++i==0)                         QuDong595(aa++);         } }
作者: xianfajushi    时间: 2021-1-28 12:48


作者: SHANWAZI    时间: 2021-1-28 14:06
DKC_LIN_123 发表于 2021-1-27 12:18
  • static uchar  loo_go =1;    //按键状态保存  
  • static uchar  key_value =0;  [/bac ...

  • 感谢回复和建议
    作者: SHANWAZI    时间: 2021-1-28 14:08
    xianfajushi 发表于 2021-1-28 12:44
    那么喜欢分析真好学,丢一个给你玩玩: void main()         //主函数 {   unsigned char aa=0,xd=0;         unsign ...

    感谢回复  和建议!
    作者: xianfajushi    时间: 2021-1-28 15:32
    因为今天刚好回复有关2个按键问题,本案例不待按键释放.
    作者: SHANWAZI    时间: 2021-1-28 18:15
    xianfajushi 发表于 2021-1-28 15:32
    因为今天刚好回复有关2个按键问题,本案例不待按键释放.

    不知您的意思是?




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