垂柳工作室 发表于 2024-3-2 00:30:30

研究学习实验箱示例代码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;
}

遥指杏花村 发表于 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)

jackfangxq 发表于 2024-3-19 11:48:18


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

垂柳工作室 发表于 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<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;
                }
        }
}


垂柳工作室 发表于 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
{
    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;
}

lezjin 发表于 2024-3-20 13:25:25

IO_KeyState1 = P0 & 0xf0;(改成IO_KeyState1 = P0;)
我觉得是直接读P0,低4位的状态会一起读进去,虽然结果不影响高4位,还是严谨一点

yjawei 发表于 2024-3-20 21:39:00

可能人家是为了移植方便
页: [1]
查看完整版本: 研究学习实验箱示例代码15-IO行列扫描键盘代码疑问