发新帖本帖赏金 20.00元(功能说明)我要提问
返回列表
打印
[开发工具]

关于使用GPIO_ReadPin库函数读取按键状态无效问题的解决方法

[复制链接]
1400|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xld0932|  楼主 | 2023-2-11 13:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 xld0932 于 2023-2-11 15:02 编辑

#申请原创#   @21小跑堂


开发环境:

1.电脑上安装的是从新定义官网下载的易码魔盒:EasyCodeCube_RDSV3.2.5_20230105.rar

2.硬件环境使用NBK-RD8x3x核心板 + NBK-EBS002基础功能扩展板

3.调试下载器使用RD LINK PRL


问题描述:

通过开发板上的丝印描述LED灯的L1和L2分别对应的MCU控制引脚是P46和P47,KEY按键的K1和K2分别对应的MCU控制引脚为P36和P54,通过调用库函数对其进行初始化配置后,实现按键按下时对应的LED点亮,按键释放时对应的LED灯熄灭的功能,但在实现操作过程中,按键按下和释放其LED灯都没有反应;

问题分析:
1.LED初始化配置是否有问题?
LED灯初始化及验证代码如下:
/***********************************************************************************************************************
  * @brief
  * @param
  * @retval
  * @attention
  *********************************************************************************************************************/
void LED_Init(void)
{
#if   defined (NBK_RD8x3x)
    /* D2->P01 */
    GPIO_Init(GPIO0, GPIO_PIN_1, GPIO_MODE_OUT_PP);
    GPIO_WriteLow(GPIO0, GPIO_PIN_1);
#elif defined (NBK_EBS001)
#elif defined (NBK_EBS002)
    /* L1->P46 */
    GPIO_Init(GPIO4, GPIO_PIN_6, GPIO_MODE_OUT_PP);
    GPIO_WriteLow(GPIO4, GPIO_PIN_6);<p>
    /* L2->P47 */
    GPIO_Init(GPIO4, GPIO_PIN_7, GPIO_MODE_OUT_PP);
    GPIO_WriteLow(GPIO4, GPIO_PIN_7);
#elif defined (NBK_EBS003)
#endif
}

将如下验证代码程序烧录到开发板后,LED可以正常的亮灭翻转显示,说明LED灯初始化配置和控制是OK的;
/***********************************************************************************************************************
  * @brief
  * @param
  * @retval
  * @attention
  *********************************************************************************************************************/
void main(void)
{
    uint32_t i = 0;
    BSP_Init();
    while (1)
    {
        GPIO_TogglePin(GPIO4, GPIO_PIN_6);
        GPIO_TogglePin(GPIO4, GPIO_PIN_7);
        for (i = 0; i < 120000; i++)
        {
        }
    }
}

2.KEY初始化配置是否有问题?
KEY初始化代码如下所示:
/***********************************************************************************************************************
  * @brief
  * @param
  * @retval
  * @attention
  *********************************************************************************************************************/
void KEY_Init(void)
{
#if   defined (NBK_RD8x3x)
#elif defined (NBK_EBS001)
#elif defined (NBK_EBS002)
    /* K1->P36 */
    GPIO_Init(GPIO3, GPIO_PIN_6, GPIO_MODE_IN_PU);
    /* K2->P54 */
    GPIO_Init(GPIO5, GPIO_PIN_4, GPIO_MODE_IN_PU);
#elif defined (NBK_EBS003)
#endif
}

实现上述功能的代码如下所示:

/***********************************************************************************************************************
  * @brief
  * @param
  * @retval
  * @attention
  *********************************************************************************************************************/
void main(void)
{
    uint32_t i = 0;
    BSP_Init();
    while (1)
    {
        /* K1:P36 */
        if (SET == GPIO_ReadPin(GPIO3, GPIO_PIN_6))
        {
            GPIO_WriteLow(GPIO4, GPIO_PIN_6);
        }
        else
        {
            GPIO_WriteHigh(GPIO4, GPIO_PIN_6);
        }
        /* K2:P54 */
        if (SET == GPIO_ReadPin(GPIO5, GPIO_PIN_4))
        {
            GPIO_WriteLow(GPIO4, GPIO_PIN_7);
        }
        else
        {
            GPIO_WriteHigh(GPIO4, GPIO_PIN_7);
        }
    }
}

现在还不确定问题是出在KEY初始化配置还是读取按键状态的驱动函数上,导致了我们想要的功能一下没有实现,所以我们进行了如下的实验:先不通过驱动函数来读取按键的状态,而是直接通过P36和P54这两个引脚直接读取,功能代码如下所示:

/***********************************************************************************************************************
  * @brief
  * @param
  * @retval
  * @attention
  *********************************************************************************************************************/
void main(void)
{
    uint32_t i = 0;<p>
    BSP_Init();</p>
    while (1)
    {
        /* K1:P36 */
        if (0 != P36)   //(SET == GPIO_ReadPin(GPIO3, GPIO_PIN_6))
        {
            GPIO_WriteLow(GPIO4, GPIO_PIN_6);
        }
        else
        {
            GPIO_WriteHigh(GPIO4, GPIO_PIN_6);
        }
        /* K2:P54 */
        if (0 != P54)   //(SET == GPIO_ReadPin(GPIO5, GPIO_PIN_4))
        {
            GPIO_WriteLow(GPIO4, GPIO_PIN_7);
        }
        else
        {
            GPIO_WriteHigh(GPIO4, GPIO_PIN_7);
        }
    }
}

此时KEY控制LED显示的功能竟让显示正常了,这下就说明,问题出在了GPIO_ReadPin这个底层驱动函数上了……


3.分析底层驱动函数
GPIO_ReadPin底层驱动函数实现如下所示:

/**************************************************
*函数名称:BitStatus GPIO_ReadPin(GPIO_TypeDef GPIOx, uint8_t PortPins)
*函数功能:读GPIO口管脚Pxy的值
*入口参数:
GPIO_TypeDef:GPIOx:待操作的GPIO口
GPIO_Pin_TypeDef:PortPins:选择GPIO口管脚Pxy(uint8_t作为入参,方便进行位或操作)
*出口参数:
BitStatus:返回Pxy的值
**************************************************/
BitStatus GPIO_ReadPin(GPIO_TypeDef GPIOx, uint8_t PortPins)
{
  BitStatus TempBitstatus;
  /* 选择需要操作的GPIO */
  switch(GPIOx)
  {
    case GPIO0:
      TempBitstatus = (P0 & PortPins);
    case GPIO1:
      TempBitstatus = (P1 & PortPins);
    case GPIO2:
      TempBitstatus = (P2 & PortPins);
#if defined(RD8G36x) || defined(RD8G37x) || defined(RD8T36x) || defined(RD8T37x)
    case GPIO3:
      TempBitstatus = (P3 & PortPins);
    case GPIO4:
      TempBitstatus = (P4 & PortPins);
#endif
#if defined(RD8G36x) || defined(RD8G37x) || defined(RD8T36x) || defined(RD8T37x) || defined(RD8G05x) || defined(RD8T05x)
    case GPIO5:
      TempBitstatus = (P5 & PortPins);
#endif
    default:
      TempBitstatus = RESET;
  }
if(TempBitstatus != RESET)
    return SET;
  else
    return RESET;
}

我们可以看到程序的实现部分是通过相应的GPIO端口与对应的PIN引脚宏定义进行与操作,最后判断与的结果来返回当前引脚的电平状态,但程序中使用了CASE语句,但没有对应的BREAK语句,这就导致了只要某一个CASE一但满足条件,那它后面的所有CASE语句都会执行一变,我要读取GPIO3,它却读取了GPIO3\GPIO4\GPIO5对应引脚的状态,最后执行到了default,也就是说,不管我要读取哪个端口引脚的电平状态,都会执行到default这边去处理,所以这就是导致这个函数出错的原因了……


4.修正底层驱动程序BUG
修改后的GPIO_ReadPin函数具体实现如下所示:

/**************************************************
*函数名称:BitStatus GPIO_ReadPin(GPIO_TypeDef GPIOx, uint8_t PortPins)
*函数功能:读GPIO口管脚Pxy的值
*入口参数:
GPIO_TypeDef:GPIOx:待操作的GPIO口
GPIO_Pin_TypeDef:PortPins:选择GPIO口管脚Pxy(uint8_t作为入参,方便进行位或操作)
*出口参数:
BitStatus:返回Pxy的值
**************************************************/
BitStatus GPIO_ReadPin(GPIO_TypeDef GPIOx, uint8_t PortPins)
{
  BitStatus TempBitstatus;
  /* 选择需要操作的GPIO */
  switch(GPIOx)
  {
    case GPIO0:
      TempBitstatus = (P0 & PortPins); break;
    case GPIO1:
      TempBitstatus = (P1 & PortPins); break;
    case GPIO2:
      TempBitstatus = (P2 & PortPins); break;
#if defined(RD8G36x) || defined(RD8G37x) || defined(RD8T36x) || defined(RD8T37x)
    case GPIO3:
      TempBitstatus = (P3 & PortPins); break;
    case GPIO4:
      TempBitstatus = (P4 & PortPins); break;
#endif
#if defined(RD8G36x) || defined(RD8G37x) || defined(RD8T36x) || defined(RD8T37x) || defined(RD8G05x) || defined(RD8T05x)
    case GPIO5:
      TempBitstatus = (P5 & PortPins); break;
#endif
    default:
      TempBitstatus = RESET;           break;
  }
  if(TempBitstatus != RESET)
    return SET;
  else
    return RESET;
}

5.再次验证问题功能是否正常
在修改了底层的GPIO_ReadPin函数BUG后,将main函数的实现修改为如下所示,使用库函数来进行功能实现,经运行后发再功能正常了!!!

/***********************************************************************************************************************
  * @brief
  * @param
  * @retval
  * @attention
  *********************************************************************************************************************/
void main(void)
{
    uint32_t i = 0;<p>
    BSP_Init();</p>
    while (1)
    {
        /* K1:P36 */
        if (SET == GPIO_ReadPin(GPIO3, GPIO_PIN_6))
        {
            GPIO_WriteLow(GPIO4, GPIO_PIN_6);
        }
        else
        {
            GPIO_WriteHigh(GPIO4, GPIO_PIN_6);
        }
        /* K2:P54 */
        if (SET == GPIO_ReadPin(GPIO5, GPIO_PIN_4))
        {
            GPIO_WriteLow(GPIO4, GPIO_PIN_7);
        }
        else
        {
            GPIO_WriteHigh(GPIO4, GPIO_PIN_7);
        }
    }
}

总结:
通过这个功能发现了GPIO驱动部分还需要进一步的去验证,易码魔盒方便开发人员的入门和操作,但都是基于底层硬件驱动程序没有问题的基础上,才可以有更好的发挥;所以基建决定了上层建筑,底层代码还需要确认没有问题,要不然真出了问题,要查的就太多太麻烦了……

     

使用特权

评论回复

打赏榜单

21小跑堂 打赏了 20.00 元 2023-02-14
理由:恭喜通过原创审核!期待您更多的原创作品~

评论
21小跑堂 2023-2-14 16:35 回复TA
细心,耐心,排除干扰,寻问题根源,底层驱动问题确实比较麻烦,一般容易忽视,默认底层没问题 
沙发
lulugl| | 2023-2-14 16:38 | 只看该作者
楼主历害了!感谢分享经验呀!

使用特权

评论回复
板凳
hudi008| | 2023-3-7 20:13 | 只看该作者
是IO没有配置的原因吗?              

使用特权

评论回复
地板
macpherson| | 2023-3-7 21:01 | 只看该作者
GPIO_ReadPin不是固件函数吗?

使用特权

评论回复
5
alvpeg| | 2023-3-7 21:49 | 只看该作者
感觉还是之前的at89s52使用最简单。

使用特权

评论回复
发新帖 本帖赏金 20.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:上海灵动微电子股份有限公司资深现场应用工程师
简介:诚信·承诺·创新·合作

67

主题

2995

帖子

29

粉丝