定时扫描独立按键与自己的理解
在ReCclay的代码上稍加了修改和注释。
在中断服务函数里扫描按键活的按键值,根据按键按下的值然后存入缓冲区,等主函数有需要再来处理按键消息。(关于消息机制其实是一个很有意思的东西,这里这样称不知道准不准确。。。)
优点:避免消抖浪费时间,不会丢失捕捉按键按下,*容易实现按键按下,长按,以及弹起等动作的识别。
缺点:需要使用定时器中断。
--------------------- 作者:ReCclay 来源:CSDN 原文:https://blog.csdn.net/ReCclay/article/details/79293182
版权声明:本文为博主原创文章,转载请附上博文链接! /
******************************************************************************
* 文件名:定时扫描独立按键
* 描 述:
* 作 者:思索与猫
* 日 期: 19/3/7
* 备 注:S4每次加1,S5每次减2,S6每次加3,S7每次减4
*
******************************************************************************
#include<stc15f2k60s2.h>
#define uchar unsigned char
#define uint unsigned int
uchar code duan[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};
uchar dispbuff[8];
uchar dispcom = 0;
uint num = 123;
uchar KeySat[4] = {1,1,1,1}; //按键状态 1松手 0按下
uchar KeyMap[4] = {'1','2','3','4'}; //可用于扩展,字符型,+,-
sbit key_in1 = P3^3;
sbit key_in2 = P3^2;
sbit key_in3 = P3^1;
sbit key_in4 = P3^0;
void CloseFucker();
void Timer0Init();
void Display();
void ShowNumber(uint num);
void KeyScan(); //按键扫描
void KeyAction(uchar keycode); //按键指令
void KeyDriver(); //按键驱动
void main()
{
CloseFucker();
Timer0Init();
ShowNumber(num);
while(1)
{
KeyDriver();
}
}
void KeyDriver()
{
char i;
static uchar keyback[4] = {1,1,1,1};
for(i=0 ;i<4 ;i++)
{
if(KeySat[i] != keyback[i]) //按键按下,按键值为0,0!=1
{
if(KeySat[i] != 0) //按键松开,按键值为1,1!=0
{
KeyAction(KeyMap[i]);
}
keyback[i] = KeySat[i]; //按键按住,按键值为0,赋值
}
}
}
void KeyAction(uchar keycode) //keycode对应KeySat,可用于扩展
{
if(keycode == '1')
{
num += 1;
}
else if(keycode == '2')
{
num -= 2;
}
else if(keycode == '3')
{
num += 3;
}
else if(keycode == '4')
{
num -= 4;
}
ShowNumber(num);
}
void KeyScan()
{
char i;
static uchar keybuff[4] = {0xff,0xff,0xff,0xff};
keybuff[0] = (keybuff[0]<<1)|key_in1; //通过移位进行扫描,获取连续八个当前值
keybuff[1] = (keybuff[1]<<1)|key_in2;
keybuff[2] = (keybuff[2]<<1)|key_in3;
keybuff[3] = (keybuff[3]<<1)|key_in4;
for(i=0 ;i<8 ;i++)
{
if(keybuff[i] == 0xff) //1111 1111松开
{
KeySat[i] = 1;
}
else if(keybuff[i] == 0x00) //0000 0000按下
{
KeySat[i] = 0;
}
}
}
void ShowNumber(uint num)
{
char i;
uchar buf[8];
for(i=0 ;i<8 ;i++)
{
buf[i] = num%10;
num /= 10;
}
for(i=7; i>0 ;i--)
{
if(buf[i] == 0) //区分显示0和空
{
dispbuff[i]=10; //遇到有效数字之前都是空
}
else
{
break;
}
}
for(;i>=0 ;i--)
{
dispbuff[i] = buf[i]; //赋值有效数字,最后的0也可以取到
}
}
void Display()
{
P2 = (P2&0x1f)|0xe0;
P0 = 0xff;
P2 = P2&0x1f;
P2 = (P2&0x1f)|0xc0;
P0 = 0x80>>dispcom; //从左到右
P2 = P2&0x1f;
P2 = (P2&0x1f)|0xe0;
P0 = ~duan[dispbuff[dispcom]];
P2 = P2&0x1f;
if(++dispcom == 8) dispcom=0;
}
void Timer0Init(void)
{
AUXR |= 0x80;
TMOD &= 0xF0;
TL0 = 0x40;
TH0 = 0xA2;
TF0 = 0;
TR0 = 1;
ET0 = 1;
EA = 1;
}
void T0_time() interrupt 1
{
TL0 = 0x40;
TH0 = 0xA2;
Display();
KeyScan();
}
void CloseFucker()
{
P2 = (P2&0X1F)|0xa0;
P0 = 0xaf;
P2 = P2&0x1f;
}
理解独立按键,必须理解应用层KeyDriver()和底层KeyScan(),KeyAction()三者的联系
- KeyScan()在中断里扫描键值 运用移位操作,静态变量,循环,判断按下的键值
- KeyDriver()在主函数循环里刷新 使用静态变量keyback,进行按键松开,按下,按住的判断
- KeyAction()根据扫描的键值操作 使用多个if语句,或者case语句进行直接操作或flag操作
流程:判断按下的哪个键,进行松开,按下,按住的判断,最后执行按键的指令
充分利用模块化编程的便利,应用层和底层分离,维护修改记忆都方便,一石好几鸟。
真的十分感谢ReCclay的博客
《关于按键的故事》 作者 ReCclay (https://blog.csdn.net/ReCclay/article/details/79293182)