三行代码实现独立按键程序

三行代码来源:http://www.ebaina.com/bbs/forum.php?mod=viewthread&tid=2126&extra=page%3D1

uchar cont,trg;    //triger触发 continue连续
void KeyScan()
{
	    uchar ReadData = P3^0xff;
		trg = ReadData&(ReadData^cont);
		cont = ReadData;
}

具体原理

(1) 没有按键的时候
端口为0xff,ReadData读端口并且取反,很显然,就是 0x00 了。
Trg = ReadData & (ReadData ^ Cont); (初始状态下,Cont也是为0的)很简单的数学计算,因为ReadData为0,则它和任何数“相与”,结果也是为0的。
Cont = ReadData; 保存Cont 其实就是等于ReadData,为0;
结果就是:
ReadData = 0;
Trg = 0;
Cont = 0;
(2) 第一次PB0按下的情况
端口数据为0xfe,ReadData读端口并且取反,很显然,就是 0x01 了。
Trg = ReadData & (ReadData ^ Cont); 因为这是第一次按下,所以Cont是上次的值,应为为0。那么这个式子的值也不难算,也就是 Trg = 0x01 & (0x01^0x00) = 0x01
Cont = ReadData = 0x01;
结果就是:
ReadData = 0x01;
Trg = 0x01;Trg只会在这个时候对应位的值为1,其它时候都为0
Cont = 0x01;
(3) PB0按着不松(长按键)的情况
端口数据为0xfe,ReadData读端口并且取反是 0x01 了。
Trg = ReadData & (ReadData ^ Cont); 因为这是连续按下,所以Cont是上次的值,应为为0x01。那么这个式子就变成了 Trg = 0x01 & (0x01^0x01) = 0x00
Cont = ReadData = 0x01;
结果就是:
ReadData = 0x01;
Trg = 0x00;
Cont = 0x01;
因为现在按键是长按着,所以MCU会每个一定时间(20ms左右)不断的执行这个函数,那么下次执行的时候情况会是怎么样的呢?
ReadData = 0x01;这个不会变,因为按键没有松开
Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) = 0 ,只要按键没有松开,这个Trg值永远为 0 !!!
Cont = 0x01;只要按键没有松开,这个值永远是0x01!!
(4) 按键松开的情况
端口数据为0xff,ReadData读端口并且取反是 0x00 了。
Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) = 0x00
Cont = ReadData = 0x00;
结果就是:
ReadData = 0x00;
Trg = 0x00;
Cont = 0x00;
很显然,这个回到了初始状态,也就是没有按键按下的状态。

应用(触发和长按)

注意:连续快速的按下S7,数字会突然出现+10的情况,目前为止我没想出好办法避免,欢迎有高人指点

******************************************************************************
* 文件名:三行代码独立键盘  
* 描  述:
* 作  者:思索与猫
* 日  期:  19/3/10
* 备  注:按下S7数字+1,按下S6数字-1,长按S7数字+10
*         
******************************************************************************
#include
#define uchar unsigned char
#define uint unsigned int
	
uchar code duan[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40}; //10black,11-
uchar dispbuff[8];
uchar cont,trg;    //触发triger,连续continue
uint num=100;
//function
void CloseFucker();
void Timer0Init();
void Display();
void ShowNumber();
void KeyScan();
void KeyAction();

void main()
{
		CloseFucker();
		Timer0Init();
		while(1)
		{
				ShowNumber();
//				KeyScan();         //触发可以直接放在主函数里扫描,长按不行
//				KeyAction();
		}
}

void T0_time() interrupt 1
{
		static uchar key_count = 0;
		TL0 = 0x40;		
		TH0 = 0xA2;	
		Display();
		if(++key_count >= 10)       //20ms扫描一次键盘
		{
				key_count = 0;
				KeyScan();
				KeyAction();
		}
}

void KeyAction()
{
		static uchar cont_count = 0;
		if(trg & 0x01)                	//按下S7
		{
				num += 1;
		}
		else if(trg & 0x02)         //按下S6
		{
				num -= 1;
		}		
		else if(cont & 0x01)       //长按S7 1S
		{
				if(++cont_count == 50)
				{
						cont_count = 0;
						num += 10;
				}
		}
}

void KeyScan()             //三行代码独立按键
{
	    uchar ReadData = P3^0xff;
		trg = ReadData&(ReadData^cont);
		cont = ReadData;
}

void ShowNumber()
{
		dispbuff[0] = num/100;
		dispbuff[1] = num/10%10;
		dispbuff[2] = num%10;	
		dispbuff[3] = 10;
		dispbuff[4] = 10;
		dispbuff[5] = 10;
		dispbuff[6] = 10;
		dispbuff[7] = 10;
}

void Display()
{
		static uchar index = 0;
	
		P2 = P2&0x1f|0xe0;
		P0 = 0xff;
		P2 = P2&0x1f;
	
		P2 = P2&0x1f|0xc0;
		P0 = 1<

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