三行代码来源: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<stc15f2k60s2.h>
#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<<index;
P2 = P2&0x1f;
P2 = P2&0x1f|0xe0;
P0 = ~duan[dispbuff[index]];
P2 = P2&0x1f;
index++;
index &= 0x07;
}
void Timer0Init() //2ms@12.000MHz
{
AUXR |= 0x80;
TMOD &= 0xF0;
TL0 = 0x40;
TH0 = 0xA2;
TF0 = 0;
TR0 = 1;
ET0 = 1;
EA = 1;
}
void CloseFucker()
{
P2 = P2&0x1f|0xa0;
P0 = 0xaf;
P2 = P2&0x1f;
}