RT-Thread使用PWM实现灯亮度调节——STM32F407

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

RT-Thread使用PWM实现灯亮度调节——STM32F407ZG


前言

作为新入门的嵌入式选手,最近在学习RT-Thread操作系统,鉴于自己健忘的记性,打算记录下来后面好回顾学习。
今天要总结的是RT-Thread使用PWM实现灯亮度调节,参考了很多大神的博文,站在大神的高度进行内容重复和汇总,算是督促自己学习进步的手段之一吧,如有错误请大家及时指出,感谢!


提示:以下是本篇文章正文内容,如有错误请评论指出哈

一、PWM介绍

PWM(Pulse Width Modulation , 脉冲宽度调制) 是一种对模拟信号电平进行数字编码的方法,通过不同频率的脉冲使用方波的占空比用来对一个具体模拟信号的电平进行编码,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替所需要波形的设备。
PWM原理示意图

上图是一个简单的 PWM 原理示意图,假定定时器工作模式为向上计数,当计数值小于阈值时,则输出一种电平状态,比如高电平,当计数值大于阈值时则输出相反的电平状态,比如低电平。当计数值达到最大值是,计数器从0开始重新计数,又回到最初的电平状态。高电平持续时间(脉冲宽度)和周期时间的比值就是占空比,范围为0~100%。上图高电平的持续时间刚好是周期时间的一半,所以占空比为50%。

常用应用场景:用来调节灯或者屏幕的亮度,根据占空比的不同,就可以完成亮度的调节。PWM调节亮度并不是持续发光的,而是在不停地点亮、熄灭屏幕。当亮、灭交替够快时,肉眼就会认为一直在亮。在亮、灭的过程中,灭的状态持续时间越长,屏幕给肉眼的观感就是亮度越低。亮的时间越长,灭的时间就相应减少,屏幕就会变亮。


二、STM32F4相关硬件介绍

STM32F4 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出!
这里我们仅使用 TIM14 的通道 1 来产生 PWM 来控制 DS0 的亮度
如下图所示为STM32F4的LED灯的原理图,可以看出PF9可以复用为定时器14的通道1.
STM32F4的LED原理图


三、RT-Thread配置PWM

1.RT-Thread Setting设置

如下图所示,打开“使用PWM设备驱动程序”的开关
RT-Thread Setting设置

2.board.h的4步实现

board.h

第一步:已经在“RT-Thread Setting设置”中实现了。

第二步:定义与pwm相关的宏——board.h

在STM32F407ZG中,我们将使用 TIM14 的通道 1 来产生 PWM ,因此需要重新定义 #define BSP_USING_PWM14

#define BSP_USING_PWM14
#define BSP_USING_PWM14_CH1
/*#define BSP_USING_PWM1*/
/*#define BSP_USING_PWM2*/
/*#define BSP_USING_PWM3*/

此外,需要注意的是,除了需要自己新定义TIM14外,还需要定义#define BSP_USING_PWM14_CH1,这个是操作文档没提到的,这个是和通道设置相关的,只有定义了这个才能产生波形。同时,响应的需要在drv_pwm.c文件的pwm_get_channel()函数增加配置如下【仿照其他定义来写】:
BSP_USING_PWM14_CH1

第三步:stm32cubemx生成pwm定时器初始化函数:

cubeMx配置PWM
通过在cubeMx配置PWM的输出通道,自动生成代码:
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)

可以发现HAL_TIM_Base_MspInit这个函数并没有具体的实现,只有HAL_TIM_MspPostInit的具体实现。 依据STM32F4的开发手册,配置PWM需要配置2部分:一是IO的配置,二是PWM所对应定时器的配置。查看可以看出函数HAL_TIM_MspPostInit()配置IO,所以HAL_TIM_Base_MspInit()执行的是定时器的使能操作。

第四步:打开stm32xxxx_hal_config.h文件中支持pwm外围设备的宏#define HAL_TIM_MODULE_ENABLED。

#define HAL_TIM_MODULE_ENABLED

注意:按照以上步骤配置完以后如果还没有波形输出,我们查看pwm_get_channel()函数,此函数的作用是得到PWM各通道的索引值(这个我们已经在第二步补充定义了)。但索引的前提是PWM端口已经定义,查看pwm_config.h文件[dirver-include-config中],发现rt-thread工程源码里没有定义PWM14的端口,需要补充定义:

#ifdef BSP_USING_PWM14
#ifndef PWM14_CONFIG
#define PWM14_CONFIG                            \
    {                                           \
       .tim_handle.Instance     = TIM14,        \
       .name                    = "pwm14",      \
       .channel                 = 0             \
    }
#endif /* PWM14_CONFIG */
#endif /* BSP_USING_PWM14 */

pwm_config.h

3.PWM的函数

应用程序通过 RT-Thread 提供的 PWM 设备管理接口来访问 PWM 设备硬件,相关接口如下所示:

rt_device_find() 根据 PWM 设备名称查找设备获取设备句柄
rt_pwm_set() 设置 PWM 周期和脉冲宽度
rt_pwm_enable() 使能 PWM 设备
rt_pwm_disable() 关闭 PWM 设备

查找 PWM 设备

应用程序根据 PWM 设备名称获取设备句柄,进而可以操作 PWM 设备,查找设备函数如下所示:

rt_device_t rt_device_find(const char* name);

设置 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 的输出频率由周期时间 period 决定,例如周期时间为 0.5ms (毫秒),则 period 值为 500000ns(纳秒),输出频率为 2KHz,占空比为 pulse / period,pulse 值不能超过 period。

使能 PWM 设备

设置好 PWM 周期和脉冲宽度后就可以通过如下函数使能 PWM 设备:

rt_err_t rt_pwm_enable(struct rt_device_pwm *device,
					 int channel);

参数
device PWM 设备句柄
channel PWM 通道 -channel代表互补通道
返回
-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 设备句柄为空
-其他错误码 设备关闭失败

4.实现PWM控制灯明暗变化的函数

PWM 设备的具体使用方式可以参考如下示例代码,示例代码的主要步骤如下:

  1. 查找 PWM 设备获取设备句柄。
  2. 设置 PWM 周期和脉冲宽度。
  3. 使能 PWM 设备。
  4. while 循环里每 50 毫秒修改一次脉冲宽度。

因为PWM通道对应引脚和 LED0对应引脚相连,可以看到 LED0不停的由暗变到亮,然后又从亮变到暗。

#include <rtthread.h>
#include <rtdevice.h>
#define PWM_DEV_NAME        "pwm14"  /* PWM设备名称 */
#define PWM_DEV_CHANNEL     1      /* PWM通道 */

struct rt_device_pwm *pwm_dev;      /* PWM设备句柄 */

static int pwm_led_sample(int argc, char *argv[])
{
    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);
        return RT_ERROR;
    }

    /* 设置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);
    }
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(pwm_led_sample, pwm sample);

四、实验结果

编译无错后,烧录程序,连接串口list_device可以看到pwm14。
pwm14
输入指令:pwm_led_sample,就可以看到看到 LED0不停的由暗变到亮,然后又从亮变到暗。
pwm_led_sample

总结

其实是一个简单的配置,但还是遇到了很多问题,主要参考了rt-thread参考文档和STM32开发指南,算是对自己学习的一种总结吧,希望坚持下去,之前总是在网上索取资源,第一次做总结,发现表达完全是一件很难的事情,但很有意思,感谢各位大神们。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值