项目 2-2 独立按键进阶——非阻塞延时实现独立按键的识别与数码管动态刷新的常用程序框架——基于定时器

利用定时计数器实现一个定时的变量累加。

2-1 中用while实现变量累加,随着程序中任务的增加,那么数码管动态刷新的时间就会增加 ,按键扫描累加的时间就会发生变化。
改进:将按键扫描和数码管动态刷新放到定时计数器里面,人机交互界面可以用该程序框架编写
以后主要针对功能代码,而不用关心数码管的显示情况和按键识别。

如本程序中设定2ms进入一次按键扫描,如果我们想要实现10ms的延时消抖,那么我们可以在按键扫描函数中设定累加值key1_cnt > KEY_DE LAY_TIME,将KEY_DE LAY_TIME宏定义为5,满足条件key1_cnt > KEY_DE LAY_TIME,也就是key1_cnt为11时满足条件,则 key1_lock_flag = 1; //自锁标志置1,代表按键按下,防止按键多次触发
KeyNum = 1; //赋键值编码
其他按键同理,最终实现定时器实现变量累加的非阻塞延时

main.c

#include<reg51.h>
#include "Key.h"
#include "display.h"
#include"time.h"
void Key_Service();
void Dis_Service();

unsigned int NumCnt;
void main()
{
    Timer0Init();//定时器初始化
	while(1){
		Key_Service();
		Dis_Service();
		//Display();  //由于Display在定时器中执行了
	}
}
void Dis_Service()
{
	LEDBuf[0] = NumCnt / 1000;    //取千位
	LEDBuf[1] = NumCnt / 100%10;  //取百位
	LEDBuf[2] = NumCnt / 10 % 10; //取十位
	LEDBuf[3] = NumCnt % 10;      //取个位
}
void Key_Service()
{
	//switch(Key_Scan()){
	switch(Key_Val){  //全局变量Key_Val
		case 0:break;
		case 1:NumCnt++;if(NumCnt > 9999)NumCnt = 0;break;
		case 2:NumCnt--;if(NumCnt > 9999)NumCnt = 9999; break;
		case 3:NumCnt=0; break;
		case 4:NumCnt=88;break;
		default:break;
	}
}

time.c

#include"display.h"
#include"Key.h"

在这里插入图片描述
接着以上代码,编写中断服务函数
注意消隐(GPIO_DIG = 0x00)的位置需要调整至分支开头

在这里插入图片描述
用定时计数器取代Delaxms延时函数,每隔2ms执行一个动态刷新的分支

按键扫描:带返回值

time.c需要定义一个全局变量来接收扫描值,然后将该值传递给主程序处理

unsigned char Key_Val = 0;  //全局变量
void timer0_ISR() interrupt 1  //每隔2ms进入定时中断
{
	TR0 = 0; 
	
	Display();//数码管定时刷新,这样主程序就可以注释掉动态刷新函数了
	Key_Val = Key_Scan();//Key_Val是全局变量 
	
 	TL0 = 0x30;  //设置定时初始值
 	TH0 = 0xF8; //设置定时初始值
 	TR0 = 1;
 	
}

time.h

#ifndef __TIME_H__
#define __TIME_H__
#include <reg51.h>

extern unsigned char Key_Val;//外部声明
void Timer0Init(void);

#endif

key.c

#include "Key.h"
#include "delay.h"

unsigned char key1_lock_flag;//自锁标志,为的是去掉松手等待
unsigned char key1_cnt;//非阻塞延时代替阻塞延时,需要用到变量累加
unsigned char key2_lock_flag;//自锁标志,为的是去掉松手等待
unsigned char key2_cnt;//非阻塞延时代替阻塞延时,需要用到变量累加
unsigned char key3_lock_flag;//自锁标志,为的是去掉松手等待
unsigned char key3_cnt;//非阻塞延时代替阻塞延时,需要用到变量累加
unsigned char key4_lock_flag;//自锁标志,为的是去掉松手等待
unsigned char key4_cnt;//非阻塞延时代替阻塞延时,需要用到变量累加
unsigned char Key_Scan(){
	unsigned char KeyNum = 0;
	//如果按键不稳定,产生抖动,当key1_cnt加到88,突然抖动,那么key1_cnt清零,重新计数,实现消抖的作用。
	if(KEY1)//如果没有按键按下,按键处于高电平
	{
		//如果没有按键按下,则给他清零
		key1_lock_flag = 0;//清零自锁标志
		key1_cnt = 0;  //清零计数标志
    }
    else if(!key1_lock_flag && KEY1 == 0){
		key1_cnt++;  //累计按键消抖延时次数,主循环while每执行一次,key1_cnt加一
		if(key1_cnt > KEY_DE LAY_TIME)//KEY_DELAY_TIME的大小可以调节按键的灵敏度,取决于任务多少个,每个任务的执行时间是多少
		{
		   key1_cnt = 0;  //清零计数变量
		   key1_lock_flag = 1;  //自锁标志置1,代表按键按下,防止按键多次触发
		   KeyNum = 1;  //赋键值编码
		}
	}
	if(KEY2)//如果没有按键按下,按键处于高电平
	{
		//如果没有按键按下,则给他清零
		key2_lock_flag = 0;//清零自锁标志
		key2_cnt = 0;  //清零计数标志
    }
    else if(!key2_lock_flag && KEY2 == 0){
		key2_cnt++;  //累计按键消抖延时次数
		if(key2_cnt > KEY_DE LAY_TIME)//KEY_DELAY_TIME的大小可以调节按键的灵敏度
		{
		   key2_cnt = 0;  //清零计数变量
		   key2_lock_flag = 1;  //自锁标志置1,代表按键按下,防止按键多次触发
		   KeyNum = 1;  //赋键值编码
		}
	}
	if(KEY3)//如果没有按键按下,按键处于高电平
	{
		//如果没有按键按下,则给他清零
		key3_lock_flag = 0;//清零自锁标志
		key3_cnt = 0;  //清零计数标志
    }
    else if(!key3_lock_flag && KEY3 == 0){
		key3_cnt++;  //累计按键消抖延时次数
		if(key3_cnt > KEY_DE LAY_TIME)//KEY_DELAY_TIME的大小可以调节按键的灵敏度
		{
		   key3_cnt = 0;  //清零计数变量
		   key3_lock_flag = 1;  //自锁标志置1,代表按键按下,防止按键多次触发
		   KeyNum = 1;  //赋键值编码
		}
	}
	if(KEY4)//如果没有按键按下,按键处于高电平
	{
		//如果没有按键按下,则给他清零
		key4_lock_flag = 0;//清零自锁标志
		key4_cnt = 0;  //清零计数标志
    }
    else if(!key4_lock_flag && KEY1 == 0){
		key4_cnt++;  //累计按键消抖延时次数
		if(key4_cnt > KEY_DE LAY_TIME)//KEY_DELAY_TIME的大小可以调节按键的灵敏度
		{
		   key4_cnt = 0;  //清零计数变量
		   key4_lock_flag = 1;  //自锁标志置1,代表按键按下,防止按键多次触发
		   KeyNum = 1;  //赋键值编码
		}
	}
}

Key.h

#ifndef __KEY_H__
#define __KEY_H__
#include <reg51.h>

//#define KEY_DELAY_TIME 100
#define KEY_DELAY_TIME 5   //由于定时器每2ms进入一次计数,此时需要将100改为5,普遍消抖时间是10ms-20ms
sbit KEY1 = P3^0;
sbit KEY2 = P3^1;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;

unsigned char Key_Scan();
#endif

问题:按键按下一次不是加1次,而是很多次(全局变量作为键值,进入case后需要清零)

按键识别没问题,可能功能代码有问题
由于Key_Val是全局变量
全局变量一旦赋值,他就会占用内存
需要进入case 后将Key_Val清零,否则它会卡在某个case一直进行运算操作,直到下一次按键按下。

void Key_Service()
{
	//switch(Key_Scan()){
	switch(Key_Val){  //全局变量Key_Val
		case 0:break;
		case 1:Key_Val = 0;NumCnt++;if(NumCnt > 9999)NumCnt = 0;break;
		case 2:Key_Val = 0;NumCnt--;if(NumCnt > 9999)NumCnt = 9999; break;
		case 3:Key_Val = 0;NumCnt=0; break;
		case 4:Key_Val = 0;NumCnt=88;break;
		default:break;
	}
}

另外一种写法(按键扫描不带返回值,但是键值需要作为全局变量)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值