ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

【STM32】软件模拟PWM波

2026/8/3 10:35:25 拓冰建站 浏览量
【STM32】软件模拟PWM波

一、代码分析

1.1 纯软件延时实现 PWM(不用 TIM)

实现原理

纯软件模拟 PWM 的核心是完全依靠 CPU 执行指令来手动控制 GPIO 引脚的电平翻转,不借助芯片内置的定时器硬件外设。PWM 波形的两个核心参数为周期与占空比,软件实现通过固定的循环延时来维持周期稳定,在单个周期内分别控制高电平与低电平的持续时长,通过改变两段时长的比例即可实现占空比的调节。整个波形生成过程完全依赖 CPU 逐条执行代码,每一次电平翻转都需要 CPU 主动调用 GPIO 操作函数完成。

设计思路

代码以固定的延时单位作为 PWM 的周期基准,通过循环变量控制单个周期内高低电平的分配比例。程序设置两个连续的循环结构,第一个循环逐步增加低电平的延时时长、对应缩短高电平时长,实现占空比的线性递减;第二个循环逐步增加高电平的延时时长、对应缩短低电平时长,实现占空比的线性递增。两个循环首尾衔接,即可实现占空比在 0%~100% 区间内的连续往复变化。

#include "stm32f10x.h" void MY_GPIOInit() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA外设时钟 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 配置引脚为推挽输出模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } void MY_Delay(int t) { while(t--); // 空循环消耗CPU时钟,实现粗略软件延时 } int main() { MY_GPIOInit(); while(1) { for(int i = 0; i <= 10000; i += 3) // i控制低电平时长,总周期固定为10000个延时单位 { GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); MY_Delay(i); GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); MY_Delay(10000 - i); } for(int i = 0; i <= 10000; i += 3) // i控制高电平时长,占空比随i递增逐步升高 { GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); MY_Delay(10000 - i); GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); MY_Delay(i); } } }

1.2 硬件定时器实现 PWM(用 TIM)

实现原理

硬件定时器 PWM 依托 STM32 内置的通用定时器外设,通过输出比较功能由硬件电路自动生成 PWM 波形。定时器内部的计数器 CNT 会按照预设的时钟频率自动累加计数,硬件实时将 CNT 的计数值与捕获比较寄存器 CCR 的数值进行比对,根据比对结果自动翻转输出引脚的电平状态。当 CNT 计数值达到自动重装载寄存器 ARR 的设定值时,计数器自动清零并开启下一个计数周期。其中 ARR 的数值决定 PWM 的周期长度,CCR 的数值决定单个周期内有效电平的持续时长,即占空比。

设计思路

代码采用模块化设计,将 PWM 的硬件初始化与占空比调节封装为独立函数。初始化流程遵循标准的外设配置逻辑,依次完成外设时钟使能、GPIO 引脚复用配置、定时器时基参数配置、输出比较通道模式配置四个步骤,最终启动定时器即可让硬件自动输出稳定的 PWM 波形。主循环中通过循环变量逐步修改 CCR 的数值,先递增后递减,实现占空比在设定范围内的连续往复调节,延时函数用于控制占空比变化的速率。

main.c
#include "stm32f10x.h" #include "Delay.h" #include "PWM.h" int main() { PWM_Init(); uint8_t i; while(1) { for(i = 0; i <= 100; i++) { PWM_SetCompare1(i); // 修改CCR值,线性提升占空比 Delay_ms(10); } for(i = 0; i <= 100; i++) { PWM_SetCompare1(100 - i); // 修改CCR值,线性降低占空比 Delay_ms(10); } } }
PWM.c
#include "stm32f10x.h" void PWM_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能TIM2定时器时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA端口时钟 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出,引脚控制权交给定时器硬件 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); TIM_InternalClockConfig(TIM2); // 选择内部72MHz时钟作为定时器计数时钟源 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置为向上计数模式 TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // ARR自动重装载值,决定PWM周期与分辨率 TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; // PSC预分频值,分频得到计数频率 TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 配置通道为PWM1输出模式 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 设置有效电平极性为高电平 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; // 初始CCR值,上电默认占空比为0 TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_Cmd(TIM2, ENABLE); // 启动定时器,硬件开始自动输出PWM波形 } void PWM_SetCompare1(uint16_t Compare) { TIM_SetCompare1(TIM2, Compare); // 修改捕获比较寄存器数值,调整占空比 }

二、波形显示

完成 PWM 代码编写后,可直接利用 Keil5 内置的软件仿真功能,通过逻辑分析仪工具在线观测引脚输出的波形,无需连接实物硬件即可验证 PWM 的周期、占空比变化是否符合设计预期。具体操作流程如下:

1. 仿真环境参数配置

点击工程工具栏的 “魔术棒” 图标,打开Options for Target...配置窗口,切换到Debug选项卡:

  • 勾选上方的Use Simulator,启用纯软件仿真模式;
  • Dialog DLL栏的内容修改为DARMSTM.DLL,加载 STM32 系列对应的仿真驱动库;
  • Parameter栏的内容修改为-pSTM32F103ZE,指定仿真的芯片型号,确保外设寄存器模型与代码中的 STM32F10x 系列完全匹配。

2. 添加引脚观测通道

配置完成后,点击工具栏的Start/Stop Debug Session按钮进入调试会话,在调试界面的菜单栏中调出Logic Analyzer(逻辑分析仪)窗口:

  • 点击逻辑分析仪窗口内的Setup...按钮,在弹出的配置面板中点击New
  • 在输入框中输入PORTA.0并按下回车,即将 PA0 引脚添加为波形观测对象,与代码中 PWM 的输出引脚对应。

3. 启动仿真查看波形

关闭配置面板后,在逻辑分析仪的波形显示区域右键,在弹出的菜单中将显示模式设置为Bit,以标准数字电平的形式展示引脚高低电平状态。 设置完成后点击调试工具栏的Run按钮启动仿真,即可在逻辑分析仪窗口中看到 PA0 引脚输出的连续 PWM 波形。随着程序循环运行,能够直观观察到占空比线性递增、再线性递减的完整变化过程,以此验证两种 PWM 实现方式的输出逻辑是否正确。