研究学习实验箱示例代码15-IO行列扫描键盘代码疑问
今天研究学习实验箱示例代码“15-IO行列扫描键盘数码管显示键值和调整时间”其中键盘扫描,如下两行红色代码,感觉代码写得有点冗余,修改成括号内代码应该可行,经过测试还真可行。但这个代码是出自大咖,不知大咖多写一点是出于哪些考虑,期望赐教。谢谢!
void IO_KeyScan(void) //50ms call
{
u8j;
j = IO_KeyState1; //保存上一次状态
P0 = 0xf0;//X低,读Y
IO_KeyDelay();
IO_KeyState1 = P0 & 0xf0;(改成IO_KeyState1 = P0;)
P0 = 0x0f;//Y低,读X
IO_KeyDelay();
IO_KeyState1 |= (P0 & 0x0f);(改成IO_KeyState1 |= P0;)
IO_KeyState1 ^= 0xff; //取反
if(j == IO_KeyState1) //连续两次读相等
{
j = IO_KeyState;
IO_KeyState = IO_KeyState1;
if(IO_KeyState != 0) //有键按下
{
F0 = 0;
if(j == 0)F0 = 1; //第一次按下
else if(j == IO_KeyState)
{
if(++IO_KeyHoldCnt >= 20) //1秒后重键
{
IO_KeyHoldCnt = 18;
F0 = 1;
}
}
if(F0)
{
j = T_KeyTable;
if((j != 0) && (T_KeyTable != 0))
KeyCode = (j - 1) * 4 + T_KeyTable + 16; //计算键码,17~32
}
}
else IO_KeyHoldCnt = 0;
}
P0 = 0xff;
}
个人猜测,大咖可能是为了提高代码的可阅读性。
根据试验箱的原理图,两行四列按键是由P0的低四位和P0的高两位来控制的,大咖这里用的扫描办法就是先P0=0xF0,再读取P0的高两位(是否因为按键按下而置为0)来定位行,然后再P0=0x0F,在读取P0的低四位(是否因为按键按下而置为0)来定位列。所以在读取P0高两位定位行时,只需分辨P0的高两位是否被置为0即可(所以IO_KeyState1 = P0 & 0xF0),在读取P0低四位定位列时,只需分辨P0的低四位是否被置为0即可(所以IO_KeyState1 |= (P0 & 0xF0)).
所以IO_KeyState1 = P0 & 0xF0是为了更明确告诉我们(或大咖自己),这里是为了定位行,而行信息保存在IO_KeyState1的高四位(查验哪一位是0);所以IO_KeyState1 |= (P0 & 0xF0)是为了更明确告诉我们(或大咖自己),这里是为了定位列,而列信息保存在IO_KeyState1的低四位(查验哪一位是0)
如果独立按键,长按重建代码怎么写? 请参考冲哥视频第十三集:简易多任务处理上
//========================================================================
// 函数名称: KEY_Deal
// 函数功能: 按键状态读取
// 入口参数: 无
// 函数返回: 无
// 当前版本: VER1.0
// 修改日期: 2023 - 1-1
// 当前作者:
// 其他备注:循环读取八个端口的状态,并将按下的时间赋值给 Count 数组,按下的状态赋值给LastState
//========================================================================
void KEY_Deal(void) //检查所有的按键状态 10ms执行一次
{
u8 i = 0;
for(i=0;i<8;i++) //循环8次 i的取值范围是0-7代表了P30-P37的状态查询
{
if( ~KEY & ( 1<<i ) ) //持续按下,变量+1
{
if( Count<60000 )
Count ++; //按键按下,这个计数变量+1
}
else //按键松开了,变量清0
{
if( Count>0 ) //如果这个变量是按下过的
{
LastState |= (1<<i); //这个变量相应的标志位置位
}
else
{
LastState &= ~(1<<i); //这个变量相应的标志位清0
}
Count = 0; //按键按下,这个计数变量清0
}
}
}
//========================================================================
// 函数名称: KEY_ReadState
// 函数功能: 读取指定的按钮的状态
// 入口参数: @keynum : 按钮的端口号 例如P32端口,端口号就是2
// 函数返回: 看其他备注
// 当前版本: VER1.0
// 修改日期: 2023 - 1- 1
// 当前作者:
// 其他备注: 函数返回值如下
// #define KEY_NOPRESS 0 //按键未按下
// #define KEY_FILCKER 1 //消抖
// #define KEY_PRESS 2 //单击
// #define KEY_PRESSOVER 3 //单击结束
// #define KEY_LONGPRESS 4 //长按3秒
// #define KEY_LONGOVER 5 //长按结束
// #define KEY_RELAX 6 //按键松开
//========================================================================
u8 KEY_ReadState(u8 keynum) //读取指定的按键的状态 10ms执行一次
{
if( Count>0 ) //按键是按下的各种状态返回
{
if( Count<3 ) //按下<30ms 返回消抖状态
{
return KEY_FILCKER;
}
else if( Count==3 ) //按下正好30ms 返回单击
{
return KEY_PRESS;
}
else if( Count<300 ) //按下不到3000ms 返回单击结束
{
return KEY_PRESSOVER;
}
else if( Count==300 ) //按下正好3000ms 返回长按状态
{
return KEY_LONGPRESS;
}
else //长按结束
{
return KEY_LONGOVER;
}
}
else //按键已经松开了,返回各种状态
{
if( LastState &( 1<<keynum ) ) //按键之前按下过
{
return KEY_RELAX;
}
else //按键之前没有按下
{
return KEY_NOPRESS;
}
}
}
https://www.stcaimcu.com/home.php?mod=space&uid=6700 发表于 昨天 11:48 |
如果独立按键,长按重建代码怎么写?
或者参考试验箱源代码:15-IO行列扫描键盘数码管显示键值和调整时间
void IO_KeyScan(void) //50ms call
{
u8j;
j = IO_KeyState1; //保存上一次状态
P0 = 0xf0;//X低,读Y
IO_KeyDelay();
IO_KeyState1 = P0 & 0xf0;
P0 = 0x0f;//Y低,读X
IO_KeyDelay();
IO_KeyState1 |= (P0 & 0x0f);
IO_KeyState1 ^= 0xff; //取反
if(j == IO_KeyState1) //连续两次读相等
{
j = IO_KeyState;
IO_KeyState = IO_KeyState1;
if(IO_KeyState != 0) //有键按下
{
F0 = 0;
if(j == 0)F0 = 1; //第一次按下
else if(j == IO_KeyState)
{
if(++IO_KeyHoldCnt >= 20) //1秒后重键
{
IO_KeyHoldCnt = 18;
F0 = 1;
}
}
if(F0)
{
j = T_KeyTable;
if((j != 0) && (T_KeyTable != 0))
KeyCode = (j - 1) * 4 + T_KeyTable + 16; //计算键码,17~32
}
}
else IO_KeyHoldCnt = 0;
}
P0 = 0xff;
} IO_KeyState1 = P0 & 0xf0;(改成IO_KeyState1 = P0;)
我觉得是直接读P0,低4位的状态会一起读进去,虽然结果不影响高4位,还是严谨一点 可能人家是为了移植方便
页:
[1]