强烈建议,在配置PWM输出前,先将PWM对应管脚配置成普通GPIO,并高低切换输出,用示波器或万用表检测输出,以验证电路板的没问题!
官方教程:
/** if you want to use pwm you can use the following instructions.
*
* STEP 1, open pwm driver framework support in the RT-Thread Settings file
*
* STEP 2, define macro related to the pwm
* such as #define BSP_USING_PWM1
*
* STEP 3, copy your pwm timer init function from stm32xxxx_hal_msp.c generated by stm32cubemx to the end if board.c file
* such as void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) and
* void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
*
* STEP 4, modify your stm32xxxx_hal_config.h file to support pwm peripherals. define macro related to the peripherals
* such as #define HAL_TIM_MODULE_ENABLED
*
*/
这个没啥好说的,用rt thread studio就配置,用mdk5就用env中的menuconfig配置
这个地方要加入,BSP_USING_PWM1_CH1,这类通道宏,这样才能通过drv_pwm.c文件中pwm_get_channel()函数打开通道。
当然工程中如果没有drv_pwm.h和drv_pwm.c,可以从rt thread源文件中拷贝出来。
#define BSP_USING_PWM1
#define BSP_USING_PWM1_CH1
#define BSP_USING_PWM1_CH2
#define BSP_USING_PWM1_CH3
#define BSP_USING_PWM3
#define BSP_USING_PWM3_CH1
#define BSP_USING_PWM3_CH2
#define BSP_USING_PWM3_CH3
#define BSP_USING_PWM4
#define BSP_USING_PWM4_CH1
#define BSP_USING_PWM4_CH2
#define BSP_USING_PWM4_CH3
pwm_get_channel()函数原型如下
static void pwm_get_channel(void)
{
#ifdef BSP_USING_PWM1_CH1
stm32_pwm_obj[PWM1_INDEX].channel |= 1 << 0;
#endif
#ifdef BSP_USING_PWM1_CH2
stm32_pwm_obj[PWM1_INDEX].channel |= 1 << 1;
#endif
#ifdef BSP_USING_PWM1_CH3
stm32_pwm_obj[PWM1_INDEX].channel |= 1 << 2;
#endif
....................
}
在stm32裸机配置外设中,无非三个步骤,1、配置管脚,2、使能时钟(管脚时钟和外设时钟),3、配置外设
rt thread通过使用rt device的方法,帮你封装了第三步,配置外设,而前两个步骤就需要自己配置
官方给出需要拷贝void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) 和
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)这两个函数到board.c中
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim);这个函数是配置对应管脚,相信大家在配置如IIC,ADC都遇到类似函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base);这个函数是配置时钟的函数。
在配置完成后,generate code,生成对应工程,但可能是由于cubemx版本问题,
在time.c文件中只找到配置管脚void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim); 函数,
而配置时钟的void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) ;没有找到
/****************************************************************************
* 名称:HAL_TIM_MspPostInit
* 功能:配置tim管脚
* 参数:
* 作者:cubeMx
* 日期:2021年12月15日
****************************************************************************/
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
rt_kprintf("tim_gpio_init\r\n");
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM1)
{
/* USER CODE BEGIN TIM1_MspPostInit 0 */
/* USER CODE END TIM1_MspPostInit 0 */
__HAL_RCC_GPIOE_CLK_ENABLE();
/**TIM1 GPIO Configuration
PE9 ------> TIM1_CH1
PE11 ------> TIM1_CH2
PE13 ------> TIM1_CH3
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_11|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* USER CODE BEGIN TIM1_MspPostInit 1 */
/* USER CODE END TIM1_MspPostInit 1 */
}
else if(timHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspPostInit 0 */
/* USER CODE END TIM3_MspPostInit 0 */
__HAL_RCC_GPIOC_CLK_ENABLE();
/**TIM3 GPIO Configuration
PC6 ------> TIM3_CH1
PC7 ------> TIM3_CH2
PC8 ------> TIM3_CH3
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* USER CODE BEGIN TIM3_MspPostInit 1 */
/* USER CODE END TIM3_MspPostInit 1 */
}
else if(timHandle->Instance==TIM4)
{
/* USER CODE BEGIN TIM4_MspPostInit 0 */
/* USER CODE END TIM4_MspPostInit 0 */
__HAL_RCC_GPIOD_CLK_ENABLE();
/**TIM4 GPIO Configuration
PD12 ------> TIM4_CH1
PD13 ------> TIM4_CH2
PD14 ------> TIM4_CH3
*/
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* USER CODE BEGIN TIM4_MspPostInit 1 */
/* USER CODE END TIM4_MspPostInit 1 */
}
}
虽然没有找到 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) ;,
但是找到了同样功能的 void HAL_TIM_OC_MspInit(TIM_HandleTypeDef* tim_ocHandle);
作用都是将TIM的时钟使能,将这个函数复制到board.c中,并在drv_pwm.c中调用,调用位置可以放在
static rt_err_t stm32_hw_pwm_init(struct stm32_pwm *device)中的靠前部分(测试过,靠后可能失效)
其实,知道原理的话,这个问题好解,比如可以自己将__HAL_RCC_TIM1_CLK_ENABLE();放到函数static int stm32_pwm_init(void)中
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef* tim_ocHandle)
{
if(tim_ocHandle->Instance==TIM1)
{
/* USER CODE BEGIN TIM1_MspInit 0 */
/* USER CODE END TIM1_MspInit 0 */
/* TIM1 clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* USER CODE BEGIN TIM1_MspInit 1 */
/* USER CODE END TIM1_MspInit 1 */
}
else if(tim_ocHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspInit 0 */
/* USER CODE END TIM3_MspInit 0 */
/* TIM3 clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
/* USER CODE BEGIN TIM3_MspInit 1 */
/* USER CODE END TIM3_MspInit 1 */
}
else if(tim_ocHandle->Instance==TIM4)
{
/* USER CODE BEGIN TIM4_MspInit 0 */
/* USER CODE END TIM4_MspInit 0 */
/* TIM4 clock enable */
__HAL_RCC_TIM4_CLK_ENABLE();
/* USER CODE BEGIN TIM4_MspInit 1 */
/* USER CODE END TIM4_MspInit 1 */
}
}
调用位置:
static rt_err_t stm32_hw_pwm_init(struct stm32_pwm *device)
{
rt_err_t result = RT_EOK;
TIM_HandleTypeDef *tim = RT_NULL;
TIM_OC_InitTypeDef oc_config = {0};
TIM_MasterConfigTypeDef master_config = {0};
TIM_ClockConfigTypeDef clock_config = {0};
RT_ASSERT(device != RT_NULL);
tim = (TIM_HandleTypeDef *)&device->tim_handle;
/* configure the timer to pwm mode */
tim->Init.Prescaler = 0;
tim->Init.CounterMode = TIM_COUNTERMODE_UP;
tim->Init.Period = 0;
tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32L4)
tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
#endif
//时钟配置,调用位置在此处,尽量放在前面,经过测试,放在后面就失效了
HAL_TIM_OC_MspInit(tim);
if (HAL_TIM_PWM_Init(tim) != HAL_OK)
{
LOG_E("%s pwm init failed", device->name);
result = -RT_ERROR;
goto __exit;
}
省略.....
}
#define HAL_TIM_MODULE_ENABLED
#include
#include
//PWM使能管脚
#define PWM_PITCH_EN 78 //PE14
#define PWM_ROLL_EN 38 //PC6
#define PWM_YAW_EN 60 //PD12
#define PWM_DEV_NAME "pwm1" /* PWM设备名称 */
#define PWM_DEV_CHANNEL 1 /* PWM通道 */
struct rt_device_pwm *pwm_dev; /* PWM设备句柄 */
static int pwm()
{
rt_uint32_t period, pulse;
period = 10000; /* 周期为0.5ms,单位为纳秒ns */ //500000 8s
pulse = 0; /* PWM脉冲宽度值,单位为纳秒ns */
/* 查找设备 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
if (pwm_dev == RT_NULL)
{
rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
return RT_ERROR;
}
/* 使能设备 */
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
pulse = period/2;
/* 设置PWM周期和脉冲宽度 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
return 0;
}
INIT_APP_EXPORT(pwm);