关于51单片机的按键操作总结(状态机)

在大学里面,学习到了单片机。我们在学习按键的时候,都是利用电平的变化进行判断按键是否执行操作。如图所示:

 

而实际中,由于按键的弹片接触的时候,并不是一接触就紧紧的闭合,它还存在一定的
抖动,尽管这个时间非常的短暂,但是对于我们执行时间以 us 为计算单位的微控制器来说,

它太漫长了。因而,实际的波形图应该如下面这幅示意图一样;

这无疑我们要软件程序上进行消抖,从而判断稳定的电平来进行是否为有效操作。如果不做消抖操作,就会出现误判的现象,导致达不到有效的效果。

那么我们在大学里面的教科书上,是这样表述的:

unsinged char KeyScan(void)
{
	unsigned char KeyValue=0;
	if(KEY_IO != 0xFF) //检测到有按键按下
	{
		DelayNms(20); //延时 20 毫秒
		if(KEY_IO != 0xFF)//确认按键按下
		{
			switch(KEY_IO)
			{
				case 0xFE: KeyValue=1;break;
				case 0xFD: KeyValue=2;break;
				default : KeyValue=0;break;
			}
		}
	}
	return KeyValue;
}

在实际的系统中,一般是不允许这么样做的。为什么呢?首先,这里的 Delayms(20) , 让微控制器在这里白白等待了 20 ms 的时间,啥也没干,这是不可取的。所以我们要学会释放内存。不让单片机做无用功。

在这里我可以提供两种方法:

法1:(参考杨源鑫博主的)

//读取按键
uchar read_key()
{
   static int Key_on_off = 0 ;//按键自锁变量
   uchar  num , temp ;
   num = P2 ;            ///将P2的值存在变量num中
   num &= 0xf0 ; 	//将低四位清0
   if(num != 0xf0)
   {
   	  if(Key_on_off == 0)
	  {
	  	 Key_on_off = 1 ;
		 switch(num)
		 {
		 	//返回按键的编码
		 	case 0xe0 : temp = 1 ; break ; 
			case 0xd0 : temp = 2 ; break ; 
			case 0xb0 : temp = 3 ; break ; 
			case 0x70 : temp = 4 ; break ; 
		 }
	  }   
   }
   else
   	 Key_on_off = 0 ;


	return temp  ;
}

 

法2:按键在松手后有效,灵敏度高,消耗资源少,运行效率高

#include<reg52.h>
#include<intrins.h>
//独立键盘.无按键动作时其返回值 num_key=0,否则返回按键号 num_key
extern unsigned char keyboard_self()
{
    unsigned char num_key=0;//按键号
    unsigned char temp=0;//用于读取 P2 线上按键值
    static unsigned char temp_code=0;//保存按键值
    static unsigned char num_check=0;//低电平有效次数
    static unsigned char key_flag=0;//按键有效标识
    temp=P2&0xF0;//读取 P2 线数据
    if(temp!=0xF0)//低电平判断
    {
        num_check++;
        if(num_check==10)//连续 10 次(10ms)低电平有效,则认为按键有效
        {
            key_flag=1;//使能按键有效标识
            temp_code=temp;//保存按键值

        }
    else//松手时判断
    {
        num_check=0;
        if(key_flag==1)//按键有效
        {
            key_flag=0;
            switch(temp_code)//读取按键号
            {
                case 0xE0: num_key=1;
                break;
                case 0xD0: num_key=2;
                break;
                case 0xB0: num_key=3;
                break;
                case 0x70: num_key=4;
                break;
            }
        }
    }
    return(num_key);
}

 

多多学习,高手请绕道。大笑

  • 19
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的51单片机按键控制舵机的代码: ```c #include <reg52.h> sbit KEY = P1^0; // 定义按键输入口 sbit SERVO = P2^0; // 定义舵机控制口 void delay(unsigned int t) { // 延时函数 unsigned int i; while (t--) { for (i = 0; i < 500; i++); } } void main() { unsigned char cnt = 0; // 定义计数器,用于计算按键按下次数 unsigned char flag = 0; // 定义标志位,用于标记舵机当前状态 while (1) { if (KEY == 0) { // 检测按键是否按下 delay(5); // 消抖延时 if (KEY == 0) { cnt++; // 计数器加1 if (cnt == 10) cnt = 0; // 计数器满10清零 } while (!KEY); // 等待按键释放 } switch (cnt) { // 根据计数器的控制舵机 case 0: if (flag == 0) break; // 如果舵机已经在该位置,直接跳过 SERVO = 0; // 控制舵机旋转到0度位置 delay(20); // 延时等待舵机旋转到位 SERVO = 1; // 停止控制舵机 flag = 0; // 标志位更新为0 break; case 5: if (flag == 1) break; // 如果舵机已经在该位置,直接跳过 SERVO = 0; // 控制舵机旋转到90度位置 delay(20); // 延时等待舵机旋转到位 SERVO = 1; // 停止控制舵机 flag = 1; // 标志位更新为1 break; case 9: if (flag == 2) break; // 如果舵机已经在该位置,直接跳过 SERVO = 0; // 控制舵机旋转到180度位置 delay(20); // 延时等待舵机旋转到位 SERVO = 1; // 停止控制舵机 flag = 2; // 标志位更新为2 break; default: break; } } } ``` 此代码中使用一个计数器来记录按键按下的次数,根据计数器的来控制舵机旋转到不同的位置。同时使用一个标志位来标记当前舵机的位置,避免重复控制舵机。需要注意的是,舵机的控制方式可能因舵机型号而异,需根据具体型号的控制方式进行修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值