基于STM32F03RCT的多路频率占空比可调PWM输出

基于STM32F03RCT的多路频率占空比可调PWM输出

  • 1. 准备
    • 1.1. 硬件
    • 1.2. 软件
  • 2. 基础知识
  • 3. CubeMX配置
    • 3.1. 通用配置
    • 3.2. 定时器配置及初始化代码生成
  • 4. PWM相关代码编写
  • 5. 代码验证
  • 6.后记

1. 准备

1.1. 硬件

STM32RCT6核心板、STLink V2.1调试器、线材若干、Mini示波器

1.2. 软件

STM32CubeMX、STMCubeIDE

2. 基础知识

利用CubeMX配置PWM时,大多数参数保持软件给出的默认值即可。为了使PWM频率及占空比可调,我们只需要额外控制预分频器寄存器 (TIMx_PSC)自动装载寄存器 (TIMx_ARR)捕获/比较寄存器(TIMx_CCRx) 三个寄存器的值即可。HAL库对某些操作进行了封装,调用特定的函数即可对寄存器进行操作,当然也可以采用直接操作寄存器的方式。

PWM频率及占空比与上述三个寄存器内数值的关系如下:

PWM頻率:
f r e q = S y s C l o c k ( P S C + 1 ) ( A R R + 1 ) freq = \frac{ {SysClock}}{ {(PSC + 1)(ARR + 1)}} freq=(PSC+1)(ARR+1)SysClock
PWM占空比:
d u t y = C C R x A R R + 1 duty = \frac{ {CCRx}}{ {ARR + 1}} duty=ARR+1CCRx
SysClock为系统时钟频率,本例中为72MHz,PSC、ARR、CCRx分别为对应寄存器内数值。

3. CubeMX配置

3.1. 通用配置

配置HCLK时钟频率为最大频率,即72MHz,APB1定时器时钟为72MHz,调试方式选择“Serial Wire"。

基于STM32F03RCT的多路频率占空比可调PWM输出_第1张图片

3.2. 定时器配置及初始化代码生成

首先应该明确的是PWM频率

使用定时器2和定时器3作为PWM输出定时器,二者配置相同,下面以定时器2为例说明。

Clock Source(时钟源)选择Internal Clock(内部时钟),四个通道均配置为PWM输出,如下图所示。
基于STM32F03RCT的多路频率占空比可调PWM输出_第2张图片

定时器预分频器(PSC)设置为720-1,自动装载寄存器ARR设置为100-1,自动重装设置为Enable,CCRx设置为50. 由上面的公式计算可知,按照此参数初始化后,PWM的频率为1000Hz,占空比为50%.

基于STM32F03RCT的多路频率占空比可调PWM输出_第3张图片
配置完成后,设置目标IDE及其他配置选项,生成初始化代码.

4. PWM相关代码编写

新建"pwm.h"和"pwm.c"文件,添加头文件地址到项目,并将"pwm.c"添加至项目中;

在"pwm.h"中做如下定义:

#define hpwm0   htim2
#define hpwm1   htim3

#define PWM_CH1 0x00
#define PWM_CH2 0x01
#define PWM_CH3 0x02
#define PWM_CH4 0x03

#define PWM0_CLOCK 72 * 1000 * 1000

声明如下函数:

void PWM_SetFreq(TIM_HandleTypeDef *hpwmx, float freq);
void PWM_SetDuty(TIM_HandleTypeDef *hpwmx, uint32_t ch, float duty);
void PWM_Stop(TIM_HandleTypeDef *hpwmx, uint32_t ch);
void PWM_Start(TIM_HandleTypeDef *hpwmx, uint32_t ch);

在"pwm.c"中实现上述函数:

/**
 * @description: 设置PWM的频率(不能分通道设置)
 * @param {TIM_HandleTypeDef} htimx PWM句柄 hpwmx
 * @param {float} freq 频率值
 * @return {*}
 */
void PWM_SetFreq(TIM_HandleTypeDef *hpwmx, float freq)
{
     
    /* 有时需要在设置PSC寄存器前重新选择合适的ARR寄存器值(例如:1000-1)
    // 1.读出占空比
    uint32_t duty=hpwmx->Instance->CCR1/hpwmx->Instance->ARR;
    // 2.设置ARR寄存器的值
    hpwmx->Instance->ARR=1000-1;
    // 3.为保持占空比不变设置CCRx寄存器的值
    hpwmx->Instance->CCR1=(uint32_t)((hpwmx->Instance->ARR+1)*duty);
    */
    // 根据ARR寄存器的值设置计算预分频PSC的值
    hpwmx->Instance->PSC = PWM0_CLOCK / (hpwmx->Instance->ARR + 1) / freq - 1;
}

/**
 * @description: 设置PWM某一通道的占空比
 * @param {TIM_HandleTypeDef} htimx PWM句柄 hpwmx
 * @param {float} duty 占空比(百分制,占空=50%,则duty=50)
 * @param {uint8_t} ch 通道
 * @return {*}
 */
void PWM_SetDuty(TIM_HandleTypeDef *hpwmx, uint32_t channel, float duty)
{
     
    // 设置CCRx寄存器的值
    // 也可以用HAL库的函数:
    // __HAL_TIM_SET_COMPARE(&hpwm0,TIM_CHANNEL_1,duty/100.0*(hpwmx->Instance->ARR);
    *(uint32_t *)(&hpwmx->Instance->CCR1 + channel) = duty/100.0*(hpwmx->Instance->ARR+1);
}

/**
     * @description: 开启PWM某一通道
     * @param {TIM_HandleTypeDef} htimx hpwmx
     * @return {*}
     */
void PWM_Start(TIM_HandleTypeDef *hpwmx, uint32_t channel)
{
     
    HAL_TIM_PWM_Start(hpwmx, (uint32_t)channel * 4);
}

/**
     * @description: 关闭PWM某一通道
     * @param {TIM_HandleTypeDef} htimx hpwmx
     * @return {*}
     */
void PWM_Stop(TIM_HandleTypeDef *hpwmx, uint32_t channel)
{
     
    HAL_TIM_PWM_Stop(hpwmx, (uint32_t)channel * 4);
}

代码中已有详尽的注释,此处不再赘述。

在"main.c"中的用户代码区域添加如下代码对PWM功能进行测试:

/* USER CODE BEGIN 2 */
  PWM_SetFreq(&hpwm0, 1000.0);	// 设置第1组PWM的频率
  PWM_SetDuty(&hpwm0, PWM_CH1, 10.0);	// 设置通道1的占空比
  PWM_SetDuty(&hpwm0, PWM_CH2, 30.0);	// 设置通道2的占空比
  PWM_SetDuty(&hpwm0, PWM_CH3, 50.0);	// 设置通道3的占空比
  PWM_SetDuty(&hpwm0, PWM_CH4, 70.0);	// 设置通道4的占空比
  PWM_Start(&hpwm0, PWM_CH1);	// 开启第1组PWM的通道1输出
  PWM_Start(&hpwm0, PWM_CH2);	// 开启第1组PWM的通道2输出
  PWM_Start(&hpwm0, PWM_CH3);	// 开启第1组PWM的通道3输出
  PWM_Start(&hpwm0, PWM_CH4);	// 开启第1组PWM的通道4输出

  PWM_SetFreq(&hpwm1, 2000.0);	// 设置第2组PWM的频率
  PWM_SetDuty(&hpwm1, PWM_CH1, 20.0);
  PWM_SetDuty(&hpwm1, PWM_CH2, 40.0);
  PWM_SetDuty(&hpwm1, PWM_CH3, 60.0);
  PWM_SetDuty(&hpwm1, PWM_CH4, 80.0);
  PWM_Start(&hpwm1, PWM_CH1);
  PWM_Start(&hpwm1, PWM_CH2);
  PWM_Start(&hpwm1, PWM_CH3);
  PWM_Start(&hpwm1, PWM_CH4);
  /* USER CODE END 2 */

5. 代码验证

编译代码,下载到单片机中,用示波器观察对应引脚输出如下:
第1组PWM(Timer2):
基于STM32F03RCT的多路频率占空比可调PWM输出_第4张图片

第2组PWM(Timer3)基于STM32F03RCT的多路频率占空比可调PWM输出_第5张图片

6.后记

由上述PWM频率和占空比计算式可知,PWM的频率与PSC*ARR成反比,当PWM频率一定时,PSC和ARR寄存器的数值必然会此消彼长。本例中为了使PWM频率在较大值时仍具有较高的精度,ARR值选为100,如果您对占空比精度要求较高,可以将ARR寄存器的数值设置为1000或更大的数值,但时这必然会使得PWM频率精度降低,尤其是频率较高时,这个现象应该会很明显。

喜欢的话可以关注公众号“早点儿毕业”,祝愿学生朋友们都能早点儿毕业!!!

你可能感兴趣的:(单片机,STM32,stm32,单片机)