返回列表 发新帖我要提问本帖赏金: 20.00元(功能说明)

[开发工具] 关于使用GPIO_ReadPin库函数读取按键状态无效问题的解决方法

[复制链接]
 楼主| 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灯初始化及验证代码如下:
  1. /***********************************************************************************************************************
  2.   * @brief
  3.   * @param
  4.   * @retval
  5.   * @attention
  6.   *********************************************************************************************************************/
  7. void LED_Init(void)
  8. {
  9. #if   defined (NBK_RD8x3x)
  10.     /* D2->P01 */
  11.     GPIO_Init(GPIO0, GPIO_PIN_1, GPIO_MODE_OUT_PP);
  12.     GPIO_WriteLow(GPIO0, GPIO_PIN_1);
  13. #elif defined (NBK_EBS001)
  14. #elif defined (NBK_EBS002)
  15.     /* L1->P46 */
  16.     GPIO_Init(GPIO4, GPIO_PIN_6, GPIO_MODE_OUT_PP);
  17.     GPIO_WriteLow(GPIO4, GPIO_PIN_6);<p>
  18.     /* L2->P47 */
  19.     GPIO_Init(GPIO4, GPIO_PIN_7, GPIO_MODE_OUT_PP);
  20.     GPIO_WriteLow(GPIO4, GPIO_PIN_7);
  21. #elif defined (NBK_EBS003)
  22. #endif
  23. }

将如下验证代码程序烧录到开发板后,LED可以正常的亮灭翻转显示,说明LED灯初始化配置和控制是OK的;
  1. /***********************************************************************************************************************
  2.   * @brief
  3.   * @param
  4.   * @retval
  5.   * @attention
  6.   *********************************************************************************************************************/
  7. void main(void)
  8. {
  9.     uint32_t i = 0;
  10.     BSP_Init();
  11.     while (1)
  12.     {
  13.         GPIO_TogglePin(GPIO4, GPIO_PIN_6);
  14.         GPIO_TogglePin(GPIO4, GPIO_PIN_7);
  15.         for (i = 0; i < 120000; i++)
  16.         {
  17.         }
  18.     }
  19. }

2.KEY初始化配置是否有问题?
KEY初始化代码如下所示:
  1. /***********************************************************************************************************************
  2.   * @brief
  3.   * @param
  4.   * @retval
  5.   * @attention
  6.   *********************************************************************************************************************/
  7. void KEY_Init(void)
  8. {
  9. #if   defined (NBK_RD8x3x)
  10. #elif defined (NBK_EBS001)
  11. #elif defined (NBK_EBS002)
  12.     /* K1->P36 */
  13.     GPIO_Init(GPIO3, GPIO_PIN_6, GPIO_MODE_IN_PU);
  14.     /* K2->P54 */
  15.     GPIO_Init(GPIO5, GPIO_PIN_4, GPIO_MODE_IN_PU);
  16. #elif defined (NBK_EBS003)
  17. #endif
  18. }

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

  1. /***********************************************************************************************************************
  2.   * @brief
  3.   * @param
  4.   * @retval
  5.   * @attention
  6.   *********************************************************************************************************************/
  7. void main(void)
  8. {
  9.     uint32_t i = 0;
  10.     BSP_Init();
  11.     while (1)
  12.     {
  13.         /* K1:P36 */
  14.         if (SET == GPIO_ReadPin(GPIO3, GPIO_PIN_6))
  15.         {
  16.             GPIO_WriteLow(GPIO4, GPIO_PIN_6);
  17.         }
  18.         else
  19.         {
  20.             GPIO_WriteHigh(GPIO4, GPIO_PIN_6);
  21.         }
  22.         /* K2:P54 */
  23.         if (SET == GPIO_ReadPin(GPIO5, GPIO_PIN_4))
  24.         {
  25.             GPIO_WriteLow(GPIO4, GPIO_PIN_7);
  26.         }
  27.         else
  28.         {
  29.             GPIO_WriteHigh(GPIO4, GPIO_PIN_7);
  30.         }
  31.     }
  32. }

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

  1. /***********************************************************************************************************************
  2.   * @brief
  3.   * @param
  4.   * @retval
  5.   * @attention
  6.   *********************************************************************************************************************/
  7. void main(void)
  8. {
  9.     uint32_t i = 0;<p>
  10.     BSP_Init();</p>
  11.     while (1)
  12.     {
  13.         /* K1:P36 */
  14.         if (0 != P36)   //(SET == GPIO_ReadPin(GPIO3, GPIO_PIN_6))
  15.         {
  16.             GPIO_WriteLow(GPIO4, GPIO_PIN_6);
  17.         }
  18.         else
  19.         {
  20.             GPIO_WriteHigh(GPIO4, GPIO_PIN_6);
  21.         }
  22.         /* K2:P54 */
  23.         if (0 != P54)   //(SET == GPIO_ReadPin(GPIO5, GPIO_PIN_4))
  24.         {
  25.             GPIO_WriteLow(GPIO4, GPIO_PIN_7);
  26.         }
  27.         else
  28.         {
  29.             GPIO_WriteHigh(GPIO4, GPIO_PIN_7);
  30.         }
  31.     }
  32. }

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


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

  1. /**************************************************
  2. *函数名称:BitStatus GPIO_ReadPin(GPIO_TypeDef GPIOx, uint8_t PortPins)
  3. *函数功能:读GPIO口管脚Pxy的值
  4. *入口参数:
  5. GPIO_TypeDef:GPIOx:待操作的GPIO口
  6. GPIO_Pin_TypeDef:PortPins:选择GPIO口管脚Pxy(uint8_t作为入参,方便进行位或操作)
  7. *出口参数:
  8. BitStatus:返回Pxy的值
  9. **************************************************/
  10. BitStatus GPIO_ReadPin(GPIO_TypeDef GPIOx, uint8_t PortPins)
  11. {
  12.   BitStatus TempBitstatus;
  13.   /* 选择需要操作的GPIO */
  14.   switch(GPIOx)
  15.   {
  16.     case GPIO0:
  17.       TempBitstatus = (P0 & PortPins);
  18.     case GPIO1:
  19.       TempBitstatus = (P1 & PortPins);
  20.     case GPIO2:
  21.       TempBitstatus = (P2 & PortPins);
  22. #if defined(RD8G36x) || defined(RD8G37x) || defined(RD8T36x) || defined(RD8T37x)
  23.     case GPIO3:
  24.       TempBitstatus = (P3 & PortPins);
  25.     case GPIO4:
  26.       TempBitstatus = (P4 & PortPins);
  27. #endif
  28. #if defined(RD8G36x) || defined(RD8G37x) || defined(RD8T36x) || defined(RD8T37x) || defined(RD8G05x) || defined(RD8T05x)
  29.     case GPIO5:
  30.       TempBitstatus = (P5 & PortPins);
  31. #endif
  32.     default:
  33.       TempBitstatus = RESET;
  34.   }
  35. if(TempBitstatus != RESET)
  36.     return SET;
  37.   else
  38.     return RESET;
  39. }

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


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

  1. /**************************************************
  2. *函数名称:BitStatus GPIO_ReadPin(GPIO_TypeDef GPIOx, uint8_t PortPins)
  3. *函数功能:读GPIO口管脚Pxy的值
  4. *入口参数:
  5. GPIO_TypeDef:GPIOx:待操作的GPIO口
  6. GPIO_Pin_TypeDef:PortPins:选择GPIO口管脚Pxy(uint8_t作为入参,方便进行位或操作)
  7. *出口参数:
  8. BitStatus:返回Pxy的值
  9. **************************************************/
  10. BitStatus GPIO_ReadPin(GPIO_TypeDef GPIOx, uint8_t PortPins)
  11. {
  12.   BitStatus TempBitstatus;
  13.   /* 选择需要操作的GPIO */
  14.   switch(GPIOx)
  15.   {
  16.     case GPIO0:
  17.       TempBitstatus = (P0 & PortPins); break;
  18.     case GPIO1:
  19.       TempBitstatus = (P1 & PortPins); break;
  20.     case GPIO2:
  21.       TempBitstatus = (P2 & PortPins); break;
  22. #if defined(RD8G36x) || defined(RD8G37x) || defined(RD8T36x) || defined(RD8T37x)
  23.     case GPIO3:
  24.       TempBitstatus = (P3 & PortPins); break;
  25.     case GPIO4:
  26.       TempBitstatus = (P4 & PortPins); break;
  27. #endif
  28. #if defined(RD8G36x) || defined(RD8G37x) || defined(RD8T36x) || defined(RD8T37x) || defined(RD8G05x) || defined(RD8T05x)
  29.     case GPIO5:
  30.       TempBitstatus = (P5 & PortPins); break;
  31. #endif
  32.     default:
  33.       TempBitstatus = RESET;           break;
  34.   }
  35.   if(TempBitstatus != RESET)
  36.     return SET;
  37.   else
  38.     return RESET;
  39. }

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

  1. /***********************************************************************************************************************
  2.   * @brief
  3.   * @param
  4.   * @retval
  5.   * @attention
  6.   *********************************************************************************************************************/
  7. void main(void)
  8. {
  9.     uint32_t i = 0;<p>
  10.     BSP_Init();</p>
  11.     while (1)
  12.     {
  13.         /* K1:P36 */
  14.         if (SET == GPIO_ReadPin(GPIO3, GPIO_PIN_6))
  15.         {
  16.             GPIO_WriteLow(GPIO4, GPIO_PIN_6);
  17.         }
  18.         else
  19.         {
  20.             GPIO_WriteHigh(GPIO4, GPIO_PIN_6);
  21.         }
  22.         /* K2:P54 */
  23.         if (SET == GPIO_ReadPin(GPIO5, GPIO_PIN_4))
  24.         {
  25.             GPIO_WriteLow(GPIO4, GPIO_PIN_7);
  26.         }
  27.         else
  28.         {
  29.             GPIO_WriteHigh(GPIO4, GPIO_PIN_7);
  30.         }
  31.     }
  32. }

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

     

打赏榜单

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

评论

细心,耐心,排除干扰,寻问题根源,底层驱动问题确实比较麻烦,一般容易忽视,默认底层没问题  发表于 2023-2-14 16:35
lulugl 发表于 2023-2-14 16:38 | 显示全部楼层
楼主历害了!感谢分享经验呀!
hudi008 发表于 2023-3-7 20:13 | 显示全部楼层
是IO没有配置的原因吗?              
macpherson 发表于 2023-3-7 21:01 | 显示全部楼层
GPIO_ReadPin不是固件函数吗?
alvpeg 发表于 2023-3-7 21:49 | 显示全部楼层
感觉还是之前的at89s52使用最简单。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

粉丝
快速回复 在线客服 返回列表 返回顶部
个人签名:King.Xu

77

主题

3023

帖子

38

粉丝
快速回复 在线客服 返回列表 返回顶部