找回密码
 立即注册
查看: 624|回复: 6

研究学习实验箱示例代码15-IO行列扫描键盘代码疑问

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-06 11:13:12

24

主题

108

回帖

468

积分

中级会员

积分
468
发表于 2024-3-2 00:30:30 | 显示全部楼层 |阅读模式
今天研究学习实验箱示例代码“15-IO行列扫描键盘数码管显示键值和调整时间
其中键盘扫描,如下两行红色代码,感觉代码写得有点冗余,修改成括号内代码应该可行,经过测试还真可行。但这个代码是出自大咖,不知大咖多写一点是出于哪些考虑,期望赐教。谢谢!
void IO_KeyScan(void)    //50ms call
{
    u8  j;
    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[IO_KeyState >> 4];
                if((j != 0) && (T_KeyTable[IO_KeyState& 0x0f] != 0))
                    KeyCode = (j - 1) * 4 + T_KeyTable[IO_KeyState & 0x0f] + 16;    //计算键码,17~32
            }
        }
        else    IO_KeyHoldCnt = 0;
    }
    P0 = 0xff;
}

回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:398
  • 最近打卡:2025-05-06 08:25:03
已绑定手机

5

主题

49

回帖

1191

积分

金牌会员

积分
1191
发表于 2024-3-2 14:28:33 | 显示全部楼层
个人猜测,大咖可能是为了提高代码的可阅读性。
根据试验箱的原理图,两行四列按键是由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)
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:527
  • 最近打卡:2025-05-06 06:40:44
已绑定手机

34

主题

459

回帖

2285

积分

金牌会员

积分
2285
发表于 2024-3-19 11:48:18 | 显示全部楼层

如果独立按键,长按重建代码怎么写?
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-06 11:13:12

24

主题

108

回帖

468

积分

中级会员

积分
468
发表于 2024-3-20 08:31:15 | 显示全部楼层
请参考冲哥视频第十三集:简易多任务处理上
//========================================================================
// 函数名称: 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[i]<60000 )
                                Count[i] ++;                        //按键按下,这个计数变量+1
                }
                else                                                        //按键松开了,变量清0
                {
                        if( Count[i]>0 )                        //如果这个变量是按下过的
                        {
                                LastState |= (1<<i);        //这个变量相应的标志位置位
                        }
                        else
                        {
                                LastState &= ~(1<<i);        //这个变量相应的标志位清0
                        }
                        Count[i] = 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[keynum]>0 )                                        //按键是按下的各种状态返回
        {
                if( Count[keynum]<3 )                                //按下<30ms 返回消抖状态
                {
                        return KEY_FILCKER;
                }
                else if( Count[keynum]==3 )                        //按下正好30ms 返回单击
                {
                        return KEY_PRESS;
                }
                else if( Count[keynum]<300 )                //按下不到3000ms 返回单击结束
                {
                        return KEY_PRESSOVER;
                }               
                else if( Count[keynum]==300 )                //按下正好3000ms 返回长按状态
                {
                        return KEY_LONGPRESS;
                }
                else                                                                //长按结束
                {
                        return KEY_LONGOVER;
                }                       
               
        }
        else                                                                        //按键已经松开了,返回各种状态
        {
                if( LastState &( 1<<keynum ) )                //按键之前按下过
                {
                        return KEY_RELAX;               
                }
                else                                                                //按键之前没有按下
                {
                        return KEY_NOPRESS;
                }
        }
}


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-06 11:13:12

24

主题

108

回帖

468

积分

中级会员

积分
468
发表于 2024-3-20 11:06:37 | 显示全部楼层


https://www.stcaimcu.com/home.php?mod=space&uid=6700 发表于 昨天 11:48 |

如果独立按键,长按重建代码怎么写?


或者参考试验箱源代码:15-IO行列扫描键盘数码管显示键值和调整时间
void IO_KeyScan(void)    //50ms call
{
    u8  j;

    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[IO_KeyState >> 4];
                if((j != 0) && (T_KeyTable[IO_KeyState& 0x0f] != 0))
                    KeyCode = (j - 1) * 4 + T_KeyTable[IO_KeyState & 0x0f] + 16;    //计算键码,17~32
            }
        }
        else    IO_KeyHoldCnt = 0;
    }
    P0 = 0xff;
}
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:339
  • 最近打卡:2025-05-06 20:07:45

23

主题

296

回帖

1168

积分

金牌会员

积分
1168
发表于 2024-3-20 13:25:25 | 显示全部楼层
IO_KeyState1 = P0 & 0xf0;(改成  IO_KeyState1 = P0;)
我觉得是直接读P0,低4位的状态会一起读进去,虽然结果不影响高4位,还是严谨一点
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:407
  • 最近打卡:2025-05-06 09:09:03

0

主题

170

回帖

1025

积分

金牌会员

积分
1025
发表于 2024-3-20 21:39:00 | 显示全部楼层
可能人家是为了移植方便
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-7 03:23 , Processed in 0.131085 second(s), 92 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表