Github
整个RTT学习过程中对工程的完善和开发都记录在Github上的一个项目中,项目还会随着学习的深入进行更新
项目URL:https://github.com/HITLIVING/-RT-Thread-.git
读者可以通过Pull下来整个项目进一步了解
对PWM驱动的实现需要格外关注steering_app.c
steering_app.h
两个文件
外设配置
STM32F1RCT6芯片
野火MINI开发板自带显示屏(240*320)(仅用来显示信息,与PWM自身无关)
显示屏控制芯片ILI9341(仅用来显示信息,与PWM自身无关)
Cube
配置Tim定时器引脚,绑定通道
- 在选定引脚上开启定时器(PA15,TIM2,通用定时器,Channel1)
- 选择时钟源内部时钟
- 配置通道1PWM通用输出功能
Kconfig
添加Env配置选项
在 menu "On-chip Peripheral Drivers"
下添加代码段
menuconfig BSP_USING_PWM
bool "Enable pwm"
default n
select RT_USING_PWM
if BSP_USING_PWM
menuconfig BSP_USING_PWM1
bool "Enable timer2 output pwm"
default n
if BSP_USING_PWM1
config BSP_USING_PWN2_CH1
bool "Enable PWM1 channel1"
default n
endif
endif
使得可以通过Env开启PWM驱动的配置
Env
开启PWM外设
使用 scons
指令生成MDK5工程,完成配置
MDK
在驱动文件夹下看到 drv_pwm
即配置成功
此时点击编译会报错
需要手动在pwm_config.h
文件下添加对PWM1的定义pwm_config.h可通过drv_pwm.c->drv_config.h->pwm_config.h找到
#ifdef BSP_USING_PWM1
#ifndef PWM1_CONFIG
#define PWM1_CONFIG \
{ \
.tim_handle.Instance = TIM2, \
.name = "pwm1", \
.channel = 1 \
}
#endif /* PWM1_CONFIG */
#endif /* BSP_USING_PWM1 */
再次编译,无错误时,PWM的驱动配置已经完成
接口函数
查找 PWM 设备
应用程序根据 PWM 设备名称获取设备句柄,进而可以操作 PWM 设备,查找设备函数如下所示:
rt_device_t rt_device_find(const char* name);
参数 | 描述 |
---|---|
name | 设备名称 |
返回 | —— |
设备句柄 | 查找到对应设备将返回相应的设备句柄 |
RT_NULL | 没有找到设备 |
设备名称即为在pwm_config.h中定义的设备名称
设备句柄需要用RT-Thread定义的PWM设备描述结构体接收
struct rt_device_pwm *pwm_dev; /* PWM 设备句柄 */
设置 PWM 周期和脉冲宽度
通过如下函数设置 PWM 周期和占空比:
rt_err_t rt_pwm_set(struct rt_device_pwm *device,
int channel,
rt_uint32_t period,
rt_uint32_t pulse);
参数 | 描述 |
---|---|
device | PWM 设备句柄 |
channel | PWM 通道 |
period | PWM 周期时间 (单位纳秒 ns) |
pulse | PWM 脉冲宽度时间 (单位纳秒 ns) |
返回 | —— |
RT_EOK | 成功 |
-RT_EIO | device 为空 |
-RT_ENOSYS | 设备操作方法为空 |
其他错误码 | 执行失败 |
使能 PWM 设备
设置好 PWM 周期和脉冲宽度后就可以通过如下函数使能 PWM 设备:
rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel);
参数 | 描述 |
---|---|
device | PWM 设备句柄 |
channel | PWM 通道 |
返回 | —— |
RT_EOK | 设备使能成功 |
-RT_ENOSYS | 设备操作方法为空 |
其他错误码 | 设备使能失败 |
关闭 PWM 设备通道
通过如下函数关闭 PWM 设备对应通道。
rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel);
参数 | 描述 |
---|---|
device | PWM 设备句柄 |
channel | PWM 通道 |
返回 | —— |
RT_EOK | 设备关闭成功 |
-RT_EIO | 设备句柄为空 |
其他错误码 | 设备关闭失败 |
上机实验
#include <rtthread.h>
#include <rtdevice.h>
#include <stdio.h>
#include "steering_app.h"
#include "drv_ili9341_lcd.h"
rt_uint32_t PWM1_freq = 2000;
rt_uint32_t PWM1_duty = 20;
rt_err_t Steering_PWM_init(void)
{
rt_uint32_t PWM1_period = 1000000000/PWM1_freq;
rt_uint32_t PWM1_pulse = PWM1_period/100*PWM1_duty;
/* PWM device handle */
struct rt_device_pwm *pwm_dev;
/* find device */
pwm_dev = (struct rt_device_pwm *)rt_device_find("pwm1");
if (pwm_dev == RT_NULL)
{
rt_kprintf("pwm sample run failed! can't find pwm1 device!\n");
return RT_ERROR;
}
/* set PWM period and pulse*/
rt_pwm_set(pwm_dev, 1, PWM1_period, PWM1_pulse);
/* enable PWM device */
rt_pwm_enable(pwm_dev, 1);u
ILI9341_DispStringLine_EN (LINE(4), "PWM Signal Frequence:");
ILI9341_DispStringLine_EN (LINE(6), "PWM Signal Duty:");
return RT_EOK;
}
void Steering_PWM_Condition(void)
{
char str_freq[] = {0};
char str_duty[] = {0};
sprintf(str_freq, "%d", PWM1_freq);
sprintf(str_duty, "%d", PWM1_duty);
ILI9341_DispStringLine_EN (LINE(5), str_freq);
ILI9341_DispStringLine_EN (LINE(7), str_duty);
}
void Steering_PWM_Disable(void)
{
/* PWM device handle */
struct rt_device_pwm *pwm_dev;
/* find device */
pwm_dev = (struct rt_device_pwm *)rt_device_find("pwm1");
/* disable PWM device */
rt_pwm_disable(pwm_dev, 1);
}
因为PWM在使用时更常用频率和占空比,这里设置了频率为2kHz,占空比为20%的PWM信号,转换成周期和脉宽后写入pwm1设备
结合前面控制界面的配置,将PWM设备定义成steering舵机的一个功能块并添加在了菜单中,可以通过选择调用,并将配置信息显示在显示屏上
万用表上有测量电信号的频率和占空比的功能,将表上显示的数据与屏幕显示对比即可得知PWM信号正常与否
实验效果
- 开机界面
- 菜单界面,选择第三个选项,舵机控制
- 测量输出信号频率
- 测量输出信号占空比