====>>> 文章汇总(有代码汇总) <<<====
目标:使用PWM实现呼吸灯。
第一步:在 RT-Thread Settings 中 -> 组件 -> 设备驱动程序 -> 使用 PWM 设备驱动程序,勾选上。
第二步:在board.h
中打开#define BSP_USING_PWM3
宏定义,并添加使用的通道宏定义#define BSP_USING_PWM3_CH2
。
这里测试使用的引脚为PB5(TIM3的通道2)。根据自己使用的定时器和通道进行修改上述宏定义。
注意:通道宏定义board.h默认里面没写,要自己添加上。
第三步:从左侧窗口打开cubemx,勾选上TIM3的CH2,选择PWM输出模式,确认一下引脚是不是对的,参数配置可以不用管,然后关闭cubemx界面,生成代码后刷新左侧目录界面。即可在cubemx文件夹中的stm32f1xx_hal_msp.c
文件中看到TIM的引脚初始化代码,一共有两个函数。
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
第四步:修改drv_pwm.c
在drv_pwm.c
文件中的static rt_err_t stm32_hw_pwm_init(struct stm32_pwm *device)
函数中,添加定时器的初始化。
添加之后如下:
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
// 以下是自己添加的
// 注意这里是定时器的初始化 别看混了!!!
if (HAL_TIM_Base_Init(tim) != HAL_OK)
{
LOG_E("%s tim init failed", device->name);
result = -RT_ERROR;
goto __exit;
}
// 以上是自己添加的
if (HAL_TIM_PWM_Init(tim) != HAL_OK)
{
LOG_E("%s pwm init failed", device->name);
result = -RT_ERROR;
goto __exit;
}
...
}
第五步:添加测试例程
/*
* 程序清单:这是一个 PWM 设备使用例程
* 例程导出了 pwm_thread_test 命令到控制终端
* 命令调用格式:pwm_thread_test
* 程序功能:通过 PWM 设备控制 LED 灯的亮度,可以看到LED不停的由暗变到亮,然后又从亮变到暗。
*/
#include
#include
#define PWM_DEV_NAME "pwm3" /* PWM设备名称 */
#define PWM_DEV_CHANNEL 2 /* PWM通道 */
struct rt_device_pwm *pwm_dev; /* PWM设备句柄 */
static rt_thread_t pwm_thread = NULL;
// 线程相关参数
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
static void pwm_led_thread_entry(void *parameter)
{
rt_uint32_t period, pulse, dir;
period = 500000; /* 周期为0.5ms,单位为纳秒ns */
dir = 1; /* PWM脉冲宽度值的增减方向 */
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);
}
/* 设置PWM周期和脉冲宽度默认值 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
/* 使能设备 */
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
while (1)
{
rt_thread_mdelay(50);
if (dir)
{
pulse += 5000; /* 从0值开始每次增加5000ns */
}
else
{
pulse -= 5000; /* 从最大值开始每次减少5000ns */
}
if (pulse >= period)
{
dir = 0;
}
if (0 == pulse)
{
dir = 1;
}
/* 设置PWM周期和脉冲宽度 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
}
}
static int pwm_thread_test(void)
{
pwm_thread = rt_thread_create("pwm_th", // name
pwm_led_thread_entry, // 函数体入口
RT_NULL, // 函数体 参数
THREAD_STACK_SIZE, // 分配内存大小
THREAD_PRIORITY, // 优先级
THREAD_TIMESLICE); // 时间片大小
/* 如果获得线程控制块,启动这个线程 */
if (pwm_thread != RT_NULL)
rt_thread_startup(pwm_thread); // 启动线程
else
{
// 输出错误码
rt_kprintf("pwm led thread is failed...the error code is %ld \r\n", pwm_thread->error);
}
return RT_EOK;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(pwm_thread_test, pwm thread test);
这里简单分析一下,定义这两个东西之后都改变了什么东西。
#define BSP_USING_PWM3
#define BSP_USING_PWM3_CH2
第一个:声明了BSP_USING_PWM3之后,在drivers
文件夹中,会打开如下内容的声明。即声明了PWM3_CONFIG、PWM3_INDEX。
而PWM3_CONFIG的内容如下,即定义了定时器3。
而我们定义的 BSP_USING_PWM3_CH2 通道,在pwm_get_channel
函数中。