最近真的是巨忙,蓝桥杯估计是要凉了,只能随缘发挥了……
今天看到了处理按键的一种新的算法,很牛批,详细见金沙滩的视频。宋老师的水平真的是强,完全打破了我过去的编程习惯,让我重新对单片机有了一个理解,单片机就是一块CPU,在写程序的时候尽量别用软件延时,这样会浪费资源,一定要好好利用中断(把微机里学得概念搬过来),感觉要真正地学好单片机还要去学一点操作系统的知识。
可惜看到的太晚了,原来的代码风格来不及改了,先把思想学会,以后在STM32的学习里再深入吧。
大致流程:
在之前的按键消抖中,我们都使用了一个延时函数,在这里,我们利用定时器中断,每1ms读取一次按键对应的IO口的值,如果连续4次都是高电平,那么按键就没有按下;连续4次都是低电平,则按键按下;这里再设置一个全局变量作为按键的状态(按下or弹起)
然后就是键盘扫描了,在这个函数中,定义一个静态的数组专门用来存放各个按键的上一状态。在该函数中,对各个按键此时的状态进行遍历,并分别与上一状态比较,如果不等,就说明按键处于按下(下降沿)或弹起(上升沿)的状态,我们在下降沿的时候将该按键对应的键码值(用到一个键码值映射的数组)发送给一个专门的按键处理函数进行响应处理(switch)。
#include
#define uchar unsigned char
#define uint unsigned int
sbit S7=P3^0;
sbit S6=P3^1;
sbit S5=P3^2;
sbit S4=P3^3;
uchar Key_State[4]={1,1,1,1}; //默认1为弹起状态
uint Key_Downtime[4]={1,1,1,1}; //按下的时间
uchar Key_Map[4]={'1','2','3','4'}; //键码
void Timer0_Init()
{
TMOD=0x00;
TH0=0xFC;
TL0=0x66;
ET0=1;
EA=1;
TR0=1;
}
void Timer0_Service() interrupt 1
{
static uchar KeyBuf[4]={0xff,0xff,0xff,0xff};
uchar i;
static j=0;
KeyBuf[0]=(KeyBuf[0]<<1)|S7;
KeyBuf[1]=(KeyBuf[1]<<1)|S6;
KeyBuf[2]=(KeyBuf[2]<<1)|S5;
KeyBuf[3]=(KeyBuf[3]<<1)|S4;
//实现消抖
for(i=0;i<4;i++)
{
if((KeyBuf[i]&0x0f)==0x0f)
Key_State[i]=1;
else if((KeyBuf[i]&0x0f)==0x00)
Key_State[i]=0;
}
}
void Scan_KeyAlone()
{
static uchar Key_backup[4]={1,1,1,1}; //用来保存上一次的状态
uchar i;
for(i=0;i<4;i++)
{
if(Key_State[i]!=Key_backup[i])
{
if(Key_backup[i]!=0) //下降沿
Key_Action(Key_Map[i]);
Key_backup[i]=Key_State[i];
}
}
}
void Key_Action(uchar x)
{
switch(x)
{
case '1': Display_SMG(107);
break;
case '2': Display_SMG(106);
break;
case '3': Display_SMG(105);
break;
case '4': Display_SMG(104);
break;
}
}
继续附上矩阵键盘的操作
void Timer1_Service() interrupt 3
{
static uchar Key_Gnd_posi=0;
static uchar Key_Buf[4][4]={{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff}};
uchar i;
switch(Key_Gnd_posi)
{
case 0: R1=0;R2=1;R3=1;R4=1;
break;
case 1: R2=0;R1=1;R3=1;R4=1;
break;
case 2: R3=0;R1=1;R2=1;R4=1;
break;
case 3: R4=1;R1=1;R2=1;R3=1;
break;
}
Key_Buf[Key_Gnd_posi][0]=(Key_Buf[Key_Gnd_posi][0]<<1)|C1;
Key_Buf[Key_Gnd_posi][1]=(Key_Buf[Key_Gnd_posi][1]<<1)|C2;
Key_Buf[Key_Gnd_posi][2]=(Key_Buf[Key_Gnd_posi][2]<<1)|C3;
Key_Buf[Key_Gnd_posi][3]=(Key_Buf[Key_Gnd_posi][3]<<1)|C4;
for(i=0;i<4;i++)
{
if((Key_Buf[Key_Gnd_posi][i]&0x0f)==0x0f)
{
Key_state[Key_Gnd_posi][i]=1;
}
else if((Key_Buf[Key_Gnd_posi][i]&0x0f)==0x00)
{
Key_state[Key_Gnd_posi][i]=0;
}
}
Key_Gnd_posi++;
//Key_Gnd_posi&=0x03;
if(Key_Gnd_posi>4)
{
Key_Gnd_posi=0;
}
Scan_KeyMuli();
Display_SMG();
}
void Scan_KeyMuli()
{
uchar i,j;
static uchar Key_Backup[4][4]={{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(Key_Backup[i][j]!=Key_state[i][j])
{
if(Key_state[i][j]!=1)
{
Key_Action(Key_Map[i][j]);
}
Key_Backup[i][j]=Key_state[i][j];
}
}
}
}
void Key_Action(uchar x)
{
switch(x)
{
case '0': Deal_With_0();
break;
case '1': Deal_With_1();
break;
case '2': Deal_With_2();
break;
case '3': Deal_With_3();
break;
case '4': Deal_With_4();
break;
case '5': Deal_With_5();
break;
case '6': Deal_With_6();
break;
case '7': Deal_With_7();
break;
case '8': Deal_With_8();
break;
case '9': Deal_With_9();
break;
}
}
还有这个缓冲区真的是个好东西,但就是现在不怎么会用……
大致给数码管搞了半个缓冲区,有点不伦不类……
void Load_data_Buf(uint num)
{
char i;
//现将数的各个位放到缓冲区里
for(i=7;i>=0;i--)
{
SMG_Buf[i]=num%10;
num=num/10;
}
}
越学越觉得自己菜,已经不好意思说自己会用单片机了……自己写的代码就是坨shi,都不好意思开源……