STC8H系列单片机入门教程之轻触按键基础知识(三)

一、轻触按键工作原理

当我们按下轻触开关的按钮时,其弹片受到弹力作用发生形变向下接触到焊片,使得开关的两组引脚相导通,从而使得电路呈现导通状态;而当我们撤离外力时,弹片形变恢复原始状态,脱离焊片,开关的两组引脚也不再导通,从而使得电路呈现截止状态。

二、按键抖动

对于机械按键,当机械触点断开或者闭合的时候,由于机械触点的弹性作用,一个按键在闭合时不会马上稳定的接通,在断开时也不会一下子断开,所以在按键闭合及断开瞬间会伴随一连串的抖动,如下图所示:

三、软件消抖

先判断一个按键是否按下,如按键按下波形可知,按键抖动在按下瞬间和按键松开瞬间发生的,抖动时长大概5-10ms。那么,延时对应的时长既可解决此问题。一般可以通过软件延时,但是实际产品一般采用硬件定时器延时判断,增加程序执行的实时性;如图是一段简单的软件延时判断按键按下代码:

四、硬件消抖 

按键硬件消抖利用电容的放电延时,采用并联电容法,也可以实现硬件消抖。如图所示,由于电容两端电压不能突变,使得按键两端的电压平缓变化,直至电容充放电到达一定电压阈值时,单片机才读取到电平变化。一般最佳的设计是硬件消抖配合程序软件去抖。

五、独立按键检测示例代码 

#include "STC8H.h" //头文件

#define	LED1	P41
#define	LED2	P73
#define	LED3	P72
#define	LED4	P71

#define KEY1	P05
#define KEY2	P06
#define KEY3	P07

void soft_delay(unsigned int num)
{
	unsigned int i,j;
	for(i = 0;i < num;i++)
		for(j = 0;j < 200;j++);
}

void main(void)
{
	P0M1 = 0X00; P0M0 = 0X00; //设置P05/P06/P07为准双向口
	P4M1 = 0X00; P4M0 = 0X02; //设置P41为推挽输出口
	P7M1 = 0X00; P7M0 = 0X0E; //设置P73/P72/P71为推挽输出口
	
	LED1 = 0;LED2 = 0;LED3 = 0;LED4 = 0; //关闭LED
	KEY1 = 1;KEY2 = 1;KEY3 = 1; //读取端口前先使能内部弱上拉电阻
	
	while(1)
	{
		if(KEY1 == 0) //按键按下
		{
			soft_delay(100); //延时消抖
			if(KEY1 == 0) //再次判断按键是否按下
			{
				LED1 = ~LED1; //发光二极管点亮--熄灭,循环控制
			}
			while(!KEY1); //等待按键松开
		}
		
		if(KEY2 == 0)
		{
			soft_delay(100);
			if(KEY2 == 0)
			{
				LED2 = ~LED2;
			}
			while(!KEY2);
		}
		
		if(KEY3 == 0)
		{
			soft_delay(100);
			if(KEY3 == 0)
			{
				LED3 = ~LED3;
			}
			while(!KEY3);
		}
	}
}

 六、矩阵按键检测示例代码

#include "STC8H.h" //头文件

/*宏定义矩阵按键控制IO*/
#define	ROW1	P36
#define	ROW2	P35
#define	ROW3	P51
#define	ROW4	P50

#define	COL1	P65
#define	COL2	P66
#define	COL3	P67
#define	COL4	P34

/*宏定义数码管显示控制IO*/
#define	LED_A		P77
#define	LED_B		P26
#define	LED_C		P46
#define	LED_D		P01
#define	LED_E		P02
#define	LED_F		P27
#define	LED_G		P45
#define	LED_DP		P00

#define LED_DIG1	P53
#define LED_DIG2	P52
#define LED_DIG3	P04
#define LED_DIG4	P03
#define LED_DIG5	P20
#define LED_DIG6	P21
#define LED_DIG7	P22
#define LED_DIG8	P23

unsigned char scan_step = 0; //扫描步骤
unsigned char key_value = 0; //键值

/*共阳数码管段码表*/
unsigned char const display_ca_table[16] = 
{
	0xc0,0xf9,0xa4,0xb0,
	0x99,0x92,0x82,0xf8,
	0x80,0x90,0x88,0x83,
	0xc6,0xa1,0x86,0x8e
}; //0-F

/*延时子函数*/
void soft_delay(unsigned int num)
{
	unsigned int i,j;
	for(i = 0;i < num;i++)
		for(j = 0;j < 200;j++);
}

/*主函数*/
void main(void)
{
	P0M1 = 0X00; P0M0 = 0X1F; //设置P00/P01/P02/P03/P04为推挽输出口
	P2M1 = 0X00; P2M0 = 0XCF; //设置P20/P21/P22/P23/P26/P27为推挽输出口
	P3M1 = 0X00; P3M0 = 0X00; //设置P33/P34/P35/P36为准双向口
	P4M1 = 0X00; P4M0 = 0X60; //设置P45/P46为推挽输出口
	P5M1 = 0X00; P5M0 = 0X0C; //设置P52/P53为推挽输出口、设置P50/P51为准双向口
	P6M1 = 0X00; P6M0 = 0X00; //设置P65/P66/P67为准双向口
	P7M1 = 0X00; P7M0 = 0X80; //设置P77为推挽输出口

	ROW1 = 1;ROW2 = 1;ROW3 = 1;ROW4 = 1; //读取端口前先使能内部弱上拉电阻
	
	while(1) //死循环
	{
		switch(scan_step)
		{
			case 0:
				COL1 = 0;COL2 = 1;COL3 = 1;COL4 = 1; //扫描第一列
				scan_step = 1;
			break;
			case 1:
				COL1 = 1;COL2 = 0;COL3 = 1;COL4 = 1; //扫描第二列
				scan_step = 2;
			break;
			case 2:
				COL1 = 1;COL2 = 1;COL3 = 0;COL4 = 1; //扫描第三列
				scan_step = 3;
			break;
			case 3:
				COL1 = 1;COL2 = 1;COL3 = 1;COL4 = 0; //扫描第四列
				scan_step = 4;
			break;
			default:
				COL1 = 1;COL2 = 1;COL3 = 1;COL4 = 1;
				scan_step = 0;
			break;		
		}
		/*假如有按键按下*/
		if( (ROW1 == 0) || (ROW2 == 0) || (ROW3 == 0) || (ROW4 == 0) )
		{
			soft_delay(10);
			if( (ROW1 == 0) || (ROW2 == 0) || (ROW3 == 0) || (ROW4 == 0) )
			{
				if(ROW1 == 0) //第一行有按键按下
				{
					key_value = 0 + (scan_step-1)*4; //获取键值
				}
				else if(ROW2 == 0) //第二行有按键按下
				{
					key_value = 1 + (scan_step-1)*4; //获取键值
				}
				else if(ROW3 == 0) //第三行有按键按下
				{
					key_value = 2 + (scan_step-1)*4; //获取键值
				}
				else if(ROW4 == 0) //第四行有按键按下
				{
					key_value = 3 + (scan_step-1)*4; //获取键值
				}
			}
		}
		soft_delay(10);
		/*数码管显示*/
		LED_A = (display_ca_table[key_value]>>0) & 0x01;
		LED_B = (display_ca_table[key_value]>>1) & 0x01;
		LED_C = (display_ca_table[key_value]>>2) & 0x01;
		LED_D = (display_ca_table[key_value]>>3) & 0x01;
		LED_E = (display_ca_table[key_value]>>4) & 0x01;
		LED_F = (display_ca_table[key_value]>>5) & 0x01;
		LED_G = (display_ca_table[key_value]>>6) & 0x01;
		LED_DP = (display_ca_table[key_value]>>7) & 0x01;
		LED_DIG1 = 1;
		LED_DIG2 = 1;
		LED_DIG3 = 1;
		LED_DIG4 = 1;
		LED_DIG5 = 1;
		LED_DIG6 = 1;
		LED_DIG7 = 1;
		LED_DIG8 = 0;
	}
}

 七、基于状态机的按键检测方法

采用状态机方式处理点触按键,根据不同按键状态执行不同操作,实现更灵活高效的控制方式。状态机设计可精确处理每个按键动作,确保操作准确可靠。

状态机的四要素

现态:状态机当前状态。

触发条件:改变当前状态的发生条件。

动作:状态改变产生相应的动作。

次态:状态机激活触发条件后跳转到的下一状态。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芯航路IOT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值