引言
本文为RT-Thread Studio 使用STM32CubeMX联合开发中——PWM的使用。PWM包含:
- 通用PWM;
- PWM互补输出;
一、CubeMX配置
先创建一个RTT工程
打开CubeMX Settings
使用外置时钟需要自己配置一下,你们根据自己的配好。
开串口、开定时器1,打开通道1PWM模式
重点来了,这里按默认的勾选下面两个就行了,不要生成单独的.c和.h文件。IDE选MDK吧,不重要,选哪个都可以。选完点生成代码。
最后,一定一定要记住,把CubeMX关了!不关了有些配置文件没给你写入,可能以后的版本会优化这个问题。
看到提示,说明文件生成好了。并且多了一个cubemx文件夹,而且是帮你自动生成好这个SConscript脚本文件。如果没有自己新建一个。
没有自动帮你生成SConscript文件的,新建一个然后粘贴一下代码就可以了,一样的:
import os
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
# add cubemx drivers
src = Split('''
Src/stm32f4xx_hal_msp.c
Src/main.c
''')
path = [cwd]
path += [cwd + '/Inc']
group = DefineGroup('cubemx', src, depend = [''], CPPPATH = path)
Return('group')
弄好之后,右键项目名称,点击同步scons配置,更新一下项目结构。然后编译,0错误0警告。
二、配置RT-Thread Studio
打开RT-Thread settings。打开PWM设备。然后Ctrl + s保存。
这时候编译会发现报几个错误。不要慌,因为还要配置一下代码。
打开board.h文件,找到配置PWM的地方。修改好宏定义。这里的PWM1就是定时器1,PWM2就是定时器2,具体通道+CHx。我这里配置了定时器1通道1。
这时候编译还有报错,这是因为RT-Thread的库没给你写好定时器1的配置代码,自己加一下就好了,很快。如果你是定时器2或者其他,它以及给你自己加好了。
我们现在继续来解决定时器1的问题。
来到pwm_config.h文件就发现,确实没加定时器1的代码。复制一下定时器2的上来改成1就行了。
此时所有的配置完成。还有一个警告不用管,那个是 long unsigned int* 和 unsigned int* 类型不符合报的,不重要。
三、加入测试代码
这个是main.c文件。主要是加入用PWM做呼吸灯的效果,加入后编译运行。
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-04-26 RT-Thread first version
*/
#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "drivers/rt_drv_pwm.h"
rt_thread_t Pwm_thread1;
#define PWM2_DEV "pwm1"
#define PWM_DEV_CHANNEL 1/* PWM通 道 */
struct rt_device_pwm *pwm_dev; /* PWM设 备 句 柄 */
void PWM_Thread(void *parameter)
{
rt_uint32_t period, pulse, dir;
period = 5000;
dir = 1; /* PWM脉冲宽度值的增减方向 */
pulse = 0; /* PWM脉冲宽度值 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM2_DEV);
if (pwm_dev == RT_NULL)
{
LOG_E("pwm sample run failed! can't find %s device!\n", PWM2_DEV);
goto EXIT_TASK;
}
/* 配置PWM */
if (rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse) != RT_EOK)
{
LOG_E("rt_pwm_set ERROR");
goto EXIT_TASK;
}
/* 使能PWM */
if (rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL) != RT_EOK)
{
LOG_E("rt_pwm_enable Error");
goto EXIT_TASK;
}
LOG_D("PWM device ready! find %s device!\n", PWM2_DEV);
for(;;)
{
rt_thread_mdelay(50);
if (dir)
{
pulse += 500;
}
else
{
pulse -= 500;
}
if (pulse >= period)
{
dir = 0;
}
if (0 == pulse)
{
LOG_D("rt_pwm_set Dir");
dir = 1;
}
/* 配置PWM */
if (rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse) != RT_EOK)
{
LOG_E("rt_pwm_set ERROR");
break;
}
}
EXIT_TASK:
rt_thread_mdelay(50);
}
int main(void)
{
int count = 1;
/* 创建 PWM_Thread 线程 */
Pwm_thread1 = rt_thread_create("PWM_Thread", PWM_Thread, RT_NULL, 1024, 10, 10);
/* 创建成功则启动线程 */
if (Pwm_thread1 != RT_NULL)
{
LOG_D("Create PWM_Thread success.");
rt_thread_startup(Pwm_thread1);
}
while (count++)
{
LOG_D("Hello RT-Thread!");
rt_thread_mdelay(1000);
}
return RT_EOK;
}
效果。
RTT系统PWM使用测试效果
四、配置PWM互补
(1)CubeMX配置
点开CubeMX settings,让它自动打开CubeMX。选择PWM互补,记住下互补输出引脚。然后生成代码关闭CubeMX。
(2)代码配置
之前的代码不要动!加几行代码即可。主要是:PWM互补通道、使能PWM互补通道。
效果,PA7互补通道的输出。
PWM呼吸灯测试
五、PWM没有输出问题或者没有互补输出
原因:在部分版本的RT-Thread代码中有些代码是没给你加的。例如:PWM的初始化、PWM的启动,这些都需要我们手动加一下。
开始解决:请注意,你的RT-Thread代码版本至少保持在V4.1.0以上,然后按照上面的配置做好,然后接下来我们开始加代码。
(1)解决没有PWM输出的问题
打开CubeMX生成的main.c文件,不是RT-Thread studio里面的那个!然后找到定时器的初始化函数,我们需要调用这个函数去初始化,否则你的PWM没有输出。
在main.c文件里面另外写一个给外部调用这个自动生成的初始化函数的函数。
void RTT_STM32_HAL_PWM_Init(void)
{
MX_TIM1_Init();
}
然后去到board.c文件里面声明并调用这个函数。
加入测试代码。
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-04-27 RT-Thread first version
*/
#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
/* --------------------------------------> PWM Test <-------------------------------------- */
#include "drivers/rt_drv_pwm.h"
rt_thread_t Pwm_thread1;
#define PWM1_DEV "pwm1"
#define PWM1_DEV_CHANNEL 1 /* PWM通 道 */
#define PWM1_DEV_CHANNEL_N -1 /* PW互补M通道 */
struct rt_device_pwm *pwm_dev; /* PWM设 备 句 柄 */
void PWM_Thread(void *parameter)
{
rt_uint32_t period, pulse;
period = 1000 * 1000; /* Unit: ns. */
pulse = 500 * 1000; /* Unit: ns. */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM1_DEV);
if (pwm_dev == RT_NULL)
{
LOG_E("pwm sample run failed! can't find %s device!\n", PWM1_DEV);
goto EXIT_TASK;
}
/* 配置PWM */
if (rt_pwm_set(pwm_dev, PWM1_DEV_CHANNEL, period, pulse) != RT_EOK)
{
LOG_E("rt_pwm_set ERROR");
goto EXIT_TASK;
}
/* 使能PWM */
if (rt_pwm_enable(pwm_dev, PWM1_DEV_CHANNEL) != RT_EOK)
{
LOG_E("rt_pwm_enable Error");
goto EXIT_TASK;
}
/* 使能PWM互补 */
if (rt_pwm_enable(pwm_dev, PWM1_DEV_CHANNEL_N) != RT_EOK)
{
LOG_E("rt_pwm_enable complementary Error");
goto EXIT_TASK;
}
LOG_D("PWM device ready! find %s device!\n", PWM1_DEV);
for (;;)
{
rt_thread_mdelay(50);
}
EXIT_TASK:
rt_thread_mdelay(50);
}
/* --------------------------------------> PWM Test End <-------------------------------------- */
int main(void)
{
int count = 1;
/* 创建 PWM_Thread 线程 */
Pwm_thread1 = rt_thread_create("PWM_Thread", PWM_Thread, RT_NULL, 2048, 10, 10);
/* 创建成功则启动线程 */
if (Pwm_thread1 != RT_NULL)
{
LOG_D("Create PWM_Thread success.");
rt_thread_startup(Pwm_thread1);
}
while (count++)
{
LOG_D("Hello RT-Thread!");
rt_thread_mdelay(1000);
}
return RT_EOK;
}
至此,可以解决PWM没有输出的问题,但是没有互补输出。
(2)解决没有PWM互补输出的问题
上面的代码中,明显我们加了互补输出的代码,但是看通道2,并没有输出。原因是RT-Thread给你启动PWM的时候并没有写控制互补输出的代码。我们加一下。
加入代码。注意!低版本的RT-Thread没有这个参数:configuration->complementary。这个参数是用来判断是否需要启动互补输出。
static rt_err_t drv_pwm_enable(TIM_HandleTypeDef *htim, struct rt_pwm_configuration *configuration, rt_bool_t enable)
{
/* Converts the channel number to the channel number of Hal library */
rt_uint32_t channel = 0x04 * (configuration->channel - 1);
if (!enable)
{
if (configuration->complementary != RT_TRUE)
{
HAL_TIM_PWM_Stop(htim, channel);
}
else
{
HAL_TIMEx_PWMN_Stop(htim, channel);
}
}
else
{
if (configuration->complementary != RT_TRUE)
{
HAL_TIM_PWM_Start(htim, channel);
}
else
{
HAL_TIMEx_PWMN_Start(htim, channel);
}
}
return RT_EOK;
}
编译,运行。可以发现有互补输出了!