Clyde011 发表于 2024-12-15 07:55

使用STM32G431实现PWM信号的精确控制

在嵌入式系统中,PWM(脉宽调制)信号常用于控制电机速度、调节LED亮度等场景。本文将以STM32G431微控制器为例,详细讲解如何配置TIM1定时器生成PWM信号,并通过调整占空比实现精确控制。
STM32G431简介STM32G431是ST公司推出的一款功能强大的32位微控制器,基于Cortex-M4内核,主频高达170 MHz。它内置多个高级定时器(如TIM1),支持高分辨率的PWM输出,非常适合电机控制、工业自动化和其他实时应用。
PWM信号生成原理PWM信号通过固定频率的方波控制信号强度,其占空比(即高电平持续时间与整个周期的比值)决定了输出的平均功率。例如,50%占空比表示输出信号的高低电平时间相等,而25%占空比表示高电平时间仅为整个周期的四分之一。
开发环境准备
[*]STM32CubeIDE(用于编写代码和调试)。
[*]STM32G431开发板。
[*]一个PWM信号测试设备(如LED或示波器)。
硬件连接将一个LED连接到开发板的PWM引脚(例如PA8),并在电路中串联一个限流电阻(如220欧姆)。
软件实现以下代码实现了使用TIM1定时器生成PWM信号,并通过调整占空比控制LED的亮度。
#include "stm32g4xx_hal.h"

// 定时器句柄
TIM_HandleTypeDef htim1;

// 初始化定时器
void TIM1_Init(void) {
    __HAL_RCC_TIM1_CLK_ENABLE();
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = 170 - 1; // 定时器预分频值
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim1.Init.Period = 1000 - 1; // PWM周期1000个计数
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    HAL_TIM_PWM_Init(&htim1);

    // 配置PWM输出通道
    TIM_OC_InitTypeDef sConfigOC;
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 500; // 初始占空比为50%
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

    // 启动PWM
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}

// 初始化GPIO
void GPIO_Init(void) {
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_8; // TIM1_CH1引脚
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// 修改占空比
void Set_PWM_DutyCycle(uint16_t dutyCycle) {
    if (dutyCycle <= 1000) { // 确保占空比值合法
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, dutyCycle);
    }
}

int main(void) {
    HAL_Init();
    SystemClock_Config();
    GPIO_Init();
    TIM1_Init();

    while (1) {
      for (uint16_t duty = 0; duty <= 1000; duty += 10) {
            Set_PWM_DutyCycle(duty); // 增加占空比
            HAL_Delay(50);
      }
      for (uint16_t duty = 1000; duty > 0; duty -= 10) {
            Set_PWM_DutyCycle(duty); // 减小占空比
            HAL_Delay(50);
      }
    }
}
代码解析
[*]TIM1_Init函数:初始化TIM1定时器并配置PWM模式。
[*]Set_PWM_DutyCycle函数:通过修改TIM1的比较寄存器(CCR1),动态调整PWM占空比。
[*]主循环:实现占空比在0%到100%之间的循环渐变,从而让LED的亮度逐渐变化。
测试与优化
[*]使用示波器测试PA8引脚的PWM输出信号,观察占空比是否随代码变化。
[*]如果需要更高的分辨率,可以调整Prescaler和Period参数,使PWM周期更精确。
小结通过STM32G431和其高级定时器TIM1,我们可以轻松生成高精度的PWM信号,并灵活调整占空比。这种方法广泛适用于工业控制、电机驱动和信号调制等场景。

公羊子丹 发表于 2024-12-15 07:56

看起来很详细,正好最近在学习STM32的定时器,受教了。

周半梅 发表于 2024-12-15 07:56

有没有遇到初始化失败的情况?想了解一下调试经验。

帛灿灿 发表于 2024-12-15 07:56

PWM输出能支持多高的频率?对实际应用有些好奇。

童雨竹 发表于 2024-12-15 07:57

LED亮度变化很流畅,这种代码结构很实用!

万图 发表于 2024-12-15 07:57

你觉得用STM32G4控制电机和用G0系列有什么主要区别?

Wordsworth 发表于 2024-12-15 07:58

如果换成其他定时器,比如TIM2,是不是改一下引脚和时钟就可以了?

Bblythe 发表于 2024-12-15 07:58

定时器初始化这块代码很经典,感觉可以直接用到很多项目中。

Pulitzer 发表于 2024-12-15 07:58

想了解更多关于STM32CubeMX生成代码的方式,能否再写一篇?

Uriah 发表于 2024-12-15 07:59

G4系列的PWM精度真不错,支持!

Amazingxixixi 发表于 2024-12-27 16:55

过来学习学习

Stahan 发表于 2024-12-29 21:40

G4是专门做电机控制的吗

是你的乱码 发表于 2024-12-31 00:32

通过调整占空比来控制 LED 亮度

通过调整占空比来控制 LED 亮度
页: [1]
查看完整版本: 使用STM32G431实现PWM信号的精确控制