定时扫描独立按键

定时扫描独立按键与自己的理解

在ReCclay的代码上稍加了修改和注释。

在中断服务函数里扫描按键活的按键值,根据按键按下的值然后存入缓冲区,等主函数有需要再来处理按键消息。(关于消息机制其实是一个很有意思的东西,这里这样称不知道准不准确。。。)
优点:避免消抖浪费时间,不会丢失捕捉按键按下,*容易实现按键按下,长按,以及弹起等动作的识别。
缺点:需要使用定时器中断。
--------------------- 作者:ReCclay 来源:CSDN 原文:https://blog.csdn.net/ReCclay/article/details/79293182
版权声明:本文为博主原创文章,转载请附上博文链接! /

******************************************************************************
* 文件名:定时扫描独立按键
* 描  述:
* 作  者:思索与猫
* 日  期:  19/3/7 
* 备  注:S4每次加1,S5每次减2,S6每次加3,S7每次减4
*         
******************************************************************************
#include
#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()三者的联系

  1. KeyScan()在中断里扫描键值 运用移位操作,静态变量,循环,判断按下的键值
  2. KeyDriver()在主函数循环里刷新 使用静态变量keyback,进行按键松开,按下,按住的判断
  3. KeyAction()根据扫描的键值操作 使用多个if语句,或者case语句进行直接操作或flag操作

流程:判断按下的哪个键,进行松开,按下,按住的判断,最后执行按键的指令

充分利用模块化编程的便利,应用层和底层分离,维护修改记忆都方便,一石好几鸟。

真的十分感谢ReCclay的博客

《关于按键的故事》 作者 ReCclay (https://blog.csdn.net/ReCclay/article/details/79293182)

你可能感兴趣的:(蓝桥杯单片机,蓝桥杯单片机)