最近真的是巨忙,蓝桥杯估计是要凉了,只能随缘发挥了……
今天看到了处理按键的一种新的算法,很牛批,详细见金沙滩的视频。宋老师的水平真的是强,完全打破了我过去的编程习惯,让我重新对单片机有了一个理解,单片机就是一块CPU,在写程序的时候尽量别用软件延时,这样会浪费资源,一定要好好利用中断(把微机里学得概念搬过来),感觉要真正地学好单片机还要去学一点操作系统的知识。
可惜看到的太晚了,原来的代码风格来不及改了,先把思想学会,以后在STM32的学习里再深入吧。
大致流程:

在这里插入图片描述

在之前的按键消抖中,我们都使用了一个延时函数,在这里,我们利用定时器中断,每1ms读取一次按键对应的IO口的值,如果连续4次都是高电平,那么按键就没有按下;连续4次都是低电平,则按键按下;这里再设置一个全局变量作为按键的状态(按下or弹起)
然后就是键盘扫描了,在这个函数中,定义一个静态的数组专门用来存放各个按键的上一状态。在该函数中,对各个按键此时的状态进行遍历,并分别与上一状态比较,如果不等,就说明按键处于按下(下降沿)或弹起(上升沿)的状态,我们在下降沿的时候将该按键对应的键码值(用到一个键码值映射的数组)发送给一个专门的按键处理函数进行响应处理(switch)。

#include<reg52.h>
#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,都不好意思开源……