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

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

[复制链接]
  • TA的每日心情
    难过
    7 小时前
  • 签到天数: 105 天

    [LV.6]常住居民II

    11

    主题

    69

    回帖

    247

    积分

    中级会员

    积分
    247
    发表于 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;
    }

    回复 送花

    使用道具 举报

  • TA的每日心情
    开心
    9 小时前
  • 签到天数: 137 天

    [LV.7]常住居民III

    4

    主题

    45

    回帖

    316

    积分

    中级会员

    积分
    316
    发表于 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)
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    10 小时前
  • 签到天数: 176 天

    [LV.7]常住居民III

    17

    主题

    283

    回帖

    474

    积分

    中级会员

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

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

    使用道具 举报

  • TA的每日心情
    难过
    7 小时前
  • 签到天数: 105 天

    [LV.6]常住居民II

    11

    主题

    69

    回帖

    247

    积分

    中级会员

    积分
    247
     楼主| 发表于 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;
                    }
            }
    }


    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    难过
    7 小时前
  • 签到天数: 105 天

    [LV.6]常住居民II

    11

    主题

    69

    回帖

    247

    积分

    中级会员

    积分
    247
     楼主| 发表于 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;
    }
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    9 小时前
  • 签到天数: 73 天

    [LV.6]常住居民II

    7

    主题

    144

    回帖

    390

    积分

    中级会员

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

    使用道具 举报

  • TA的每日心情
    慵懒
    8 小时前
  • 签到天数: 63 天

    [LV.6]常住居民II

    0

    主题

    157

    回帖

    425

    积分

    中级会员

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

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-5-20 17:32 , Processed in 0.068226 second(s), 52 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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