本帖最后由 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驱动部分还需要进一步的去验证,易码魔盒方便开发人员的入门和操作,但都是基于底层硬件驱动程序没有问题的基础上,才可以有更好的发挥;所以基建决定了上层建筑,底层代码还需要确认没有问题,要不然真出了问题,要查的就太多太麻烦了…… |
细心,耐心,排除干扰,寻问题根源,底层驱动问题确实比较麻烦,一般容易忽视,默认底层没问题