RT-Thread 中配置 PWM 输出详细过程
强烈建议,在配置PWM输出前,先将PWM对应管脚配置成普通GPIO,并高低切换输出,用示波器或万用表检测输出,以验证电路板的没问题! 官方教程:
1、配置 RT-Thread Setting
这个没啥好说的,用rt thread studio就配置,用mdk5就用env中的menuconfig配置
2、board.h中给出定义
这个地方要加入,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
....................
}
3、加入cubemx生成的配置函数
在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) ;没有找到
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
rt_kprintf("tim_gpio_init\r\n");
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM1)
{
__HAL_RCC_GPIOE_CLK_ENABLE();
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);
}
else if(timHandle->Instance==TIM3)
{
__HAL_RCC_GPIOC_CLK_ENABLE();
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);
}
else if(timHandle->Instance==TIM4)
{
__HAL_RCC_GPIOD_CLK_ENABLE();
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);
}
}
虽然没有找到 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)
{
__HAL_RCC_TIM1_CLK_ENABLE();
}
else if(tim_ocHandle->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_ENABLE();
}
else if(tim_ocHandle->Instance==TIM4)
{
__HAL_RCC_TIM4_CLK_ENABLE();
}
}
调用位置:
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;
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;
}
省略.....
}
4、在stm32f4xx_hal_conf.h中打开宏:
#define HAL_TIM_MODULE_ENABLED
5、放个简单测试代码
#include <rtthread.h>
#include <rtdevice.h>
#define PWM_PITCH_EN 78
#define PWM_ROLL_EN 38
#define PWM_YAW_EN 60
#define PWM_DEV_NAME "pwm1"
#define PWM_DEV_CHANNEL 1
struct rt_device_pwm *pwm_dev;
static int pwm()
{
rt_uint32_t period, pulse;
period = 10000;
pulse = 0;
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;
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
return 0;
}
INIT_APP_EXPORT(pwm);
6、结果
|