当前位置: 首页 > news >正文

【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 实现方式的输出逻辑是否正确。

http://www.jsqmd.com/news/1319372/

相关文章:

  • 湖北工控自动化PLC编程选哪家培训机构好?一文解读零基础怎么学?学完能拿多少钱? - 学途指南
  • 档案行业低代码平台选型与实施指南
  • 如何免费突破城通网盘限速?3种简单方法让你的下载速度飙升10倍
  • AI扁平风终极进化路径(从静态扁平→感知扁平→意图扁平),谷歌Material 4.0核心团队未公开方法论首次披露
  • 如何正确搭建组织
  • 线程池核心原理与Java实战优化指南
  • 2026年,哪些AI设计工具生产厂家能为你带来高性价比之选?
  • 泉州中央空调维修-周边全小区覆盖-欧米到家本地师傅当日上门|排查准不乱收费不返工|熟悉全城区机型管路|修后有质保|
  • NSudo:突破性Windows系统权限管理解决方案
  • 迭代器模式解析:统一遍历与高效数据访问
  • 2026年四类优选推荐的占地面积小的低排放燃烧器工程案例指南 - geo交流
  • 魔兽争霸3终极优化指南:如何5分钟解决画面变形和卡顿问题
  • CI/CD失败分析与预防:嵌入式与Web自动化实战
  • Linux文件系统进程间通信原理与实践
  • PCM 30/32系统:从时分复用原理到E1接口故障排查
  • GPT-5.6快速模式实战指南:成本优化与API集成详解
  • 2026阜南二手车交易市场实用指南:本地优质商家全解析 - 谁都没有我好看
  • 镇江中考复读需要准备什么材料?南京天元如何报名 - 米諾
  • 中英文提示词对比:中文提示词与英文提示词的选择策略
  • 烟台中央空调维修-周边全小区覆盖-欧米到家本地师傅当日上门|排查准不乱收费不返工|熟悉全城区机型管路|修后有质保|
  • VectorBT:Python量化回测的性能革命与向量化实践
  • CST时域求解器网格设置全解析:从基础原理到实战优化
  • AMD Ryzen处理器深度调试:SMU Debug Tool全方位指南
  • 2026十堰性价比高的二手车市场选购指南 - 谁都没有我好看
  • Spring Boot跨域问题解决方案全解析
  • Unity TextMeshPro中文乱码终极解决方案:定制专属字体资产
  • 魔兽争霸3终极兼容性修复:5分钟解决所有现代电脑问题
  • 5分钟极速配置:网盘直链解析工具完全指南
  • Python零基础入门:从环境搭建到实战项目,手把手教你系统学习
  • 突破!国产 Kimi-K3 降价增量,DMXAPI 稳定调用,直享 7.9