这些天在学习研究基于STM32 HAL库的FreeRTOS系统,打算自行设计一个小项目,其中要实现这样一个功能:
STM32F103C8T6中的 PB11引脚开机默认初始化为TIM2CH4定时器输入捕获功能,在中间任务切换后,将该引脚再定义成TIM2CH4的PWM输出功能,下一次切换再换回来。
由于STM32CubeMX只能生成初始化的代码,只能默认一种模式初始化。所以切换后的引脚初始化要自己重新写。查询HAL库源代码发现,官方给出了两个针对输入逆初始化函数,于是写上:
HAL_TIM_IC_DeInit(&htim2);
HAL_TIM_Base_MspDeInit(&htim2);
然后,进行通道PWM的设置以及引脚的初始化,启用PWM输出。结果执行切换之后,PWM就是输出不出来,没信号。调试也没发现有哪句代码出现初始化错误。如果一开始就将其初始化为PWM模式的话,功能是正常的,所以排除硬件问题。万般无奈只能去研究底层的寄存器。
通过查询《STM32 参考手册》发现输入捕获切换PWM过程中主要影响的是两个寄存器,捕获/比较模式寄存器(TIMx_CCMR1/2)和捕获/比较使能寄存器(TIMx_CCER),其中TIM2CH4对应的捕获/比较模式寄存器是TIM2_CCMR2。于是在代码中加入了以下两句,方便调式:
printf("%x",htim2.Instance->CCMR2);
printf("%x",htim2.Instance->CCER);
结果发现了端倪,CCER寄存器是没有变化的,而TIM2_CCMR2有问题,在TIM2CH4是输入捕获模式时,TIM2_CCMR2值为0xF568,而切换为PWM波模式时是0xE868(此时PWM输出有问题),如果一开始就初始化为PWM模式,TIM2_CCMR2值为0x6868(此时正常工作)。
有问题时的TIM2_CCMR2:0xE868,二进制:1110100001101000
没问题时的TIM2_CCMR2:0x6868,二进制:0110100001101000
问题很明显,最左边一位出了问题!这时候其实可以解决了,但是还是想知道因为什么。所以再次查一下《STM32 参考手册》,TIMx_CCMR2的寄存器有下面一张图:
可以看出,TIM2_CCMR2两种模式下,16位数字的代表意义不同,上面一行是通道作为输出时的初始化设置,下面一行为作为输入时的初始化设置。可以看出,从IC模式向OC模式转换时,第15位的OC4CE没有转变成初始状态,本来应该是置0的,结果为1。
·进一步查查手册这一位是干什么的:
可以看出当OCxCE(本项目为OC4CE)为的时候输出的PWM会收到外部触发信号影响,一旦ETRF信号为高电平,会把输出的PWM信号(OCxREF)全部拉低。这就是为啥我的PWM信号一直为0了。至于为啥我的ETRF信号一直在触发,那可能是硬件问题了。
知道这个原因后,解决办法有很多种。之所以那两个DeInit函数没能将这个OC4CE复位,可能是我没有找到对应的函数,或者是官方库存在BUG。解决办法是切换模式之前可以手动将整个TIM2_CCMR2值复位(查询得知默认复位值就是0),在加入下面一句代码即可。
htim2.Instance->CCMR2 &=0x0000;
完整的切换代码段如下:
//逆初始化通道
HAL_TIM_IC_DeInit(&htim2);
HAL_TIM_Base_MspDeInit(&htim2);
__HAL_RCC_TIM2_CLK_ENABLE();
TIM_OC_InitTypeDef sConfigOC = {0};
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
//复位TIM2_CCMR2的值
htim2.Instance->CCMR2 &=0x0000;
//初始化PWM模式
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
//初始化引脚
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
__HAL_AFIO_REMAP_TIM2_PARTIAL_2();
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);
版权声明:本文为CSDN博主「洛小白2233」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/baidu_38952193/article/details/122697039
这些天在学习研究基于STM32 HAL库的FreeRTOS系统,打算自行设计一个小项目,其中要实现这样一个功能:
STM32F103C8T6中的 PB11引脚开机默认初始化为TIM2CH4定时器输入捕获功能,在中间任务切换后,将该引脚再定义成TIM2CH4的PWM输出功能,下一次切换再换回来。
由于STM32CubeMX只能生成初始化的代码,只能默认一种模式初始化。所以切换后的引脚初始化要自己重新写。查询HAL库源代码发现,官方给出了两个针对输入逆初始化函数,于是写上:
HAL_TIM_IC_DeInit(&htim2);
HAL_TIM_Base_MspDeInit(&htim2);
然后,进行通道PWM的设置以及引脚的初始化,启用PWM输出。结果执行切换之后,PWM就是输出不出来,没信号。调试也没发现有哪句代码出现初始化错误。如果一开始就将其初始化为PWM模式的话,功能是正常的,所以排除硬件问题。万般无奈只能去研究底层的寄存器。
通过查询《STM32 参考手册》发现输入捕获切换PWM过程中主要影响的是两个寄存器,捕获/比较模式寄存器(TIMx_CCMR1/2)和捕获/比较使能寄存器(TIMx_CCER),其中TIM2CH4对应的捕获/比较模式寄存器是TIM2_CCMR2。于是在代码中加入了以下两句,方便调式:
printf("%x",htim2.Instance->CCMR2);
printf("%x",htim2.Instance->CCER);
结果发现了端倪,CCER寄存器是没有变化的,而TIM2_CCMR2有问题,在TIM2CH4是输入捕获模式时,TIM2_CCMR2值为0xF568,而切换为PWM波模式时是0xE868(此时PWM输出有问题),如果一开始就初始化为PWM模式,TIM2_CCMR2值为0x6868(此时正常工作)。
有问题时的TIM2_CCMR2:0xE868,二进制:1110100001101000
没问题时的TIM2_CCMR2:0x6868,二进制:0110100001101000
问题很明显,最左边一位出了问题!这时候其实可以解决了,但是还是想知道因为什么。所以再次查一下《STM32 参考手册》,TIMx_CCMR2的寄存器有下面一张图:
可以看出,TIM2_CCMR2两种模式下,16位数字的代表意义不同,上面一行是通道作为输出时的初始化设置,下面一行为作为输入时的初始化设置。可以看出,从IC模式向OC模式转换时,第15位的OC4CE没有转变成初始状态,本来应该是置0的,结果为1。
·进一步查查手册这一位是干什么的:
可以看出当OCxCE(本项目为OC4CE)为的时候输出的PWM会收到外部触发信号影响,一旦ETRF信号为高电平,会把输出的PWM信号(OCxREF)全部拉低。这就是为啥我的PWM信号一直为0了。至于为啥我的ETRF信号一直在触发,那可能是硬件问题了。
知道这个原因后,解决办法有很多种。之所以那两个DeInit函数没能将这个OC4CE复位,可能是我没有找到对应的函数,或者是官方库存在BUG。解决办法是切换模式之前可以手动将整个TIM2_CCMR2值复位(查询得知默认复位值就是0),在加入下面一句代码即可。
htim2.Instance->CCMR2 &=0x0000;
完整的切换代码段如下:
//逆初始化通道
HAL_TIM_IC_DeInit(&htim2);
HAL_TIM_Base_MspDeInit(&htim2);
__HAL_RCC_TIM2_CLK_ENABLE();
TIM_OC_InitTypeDef sConfigOC = {0};
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
//复位TIM2_CCMR2的值
htim2.Instance->CCMR2 &=0x0000;
//初始化PWM模式
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
//初始化引脚
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
__HAL_AFIO_REMAP_TIM2_PARTIAL_2();
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);
版权声明:本文为CSDN博主「洛小白2233」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/baidu_38952193/article/details/122697039
暂无评论