1. 项目概述
这个基于STM32单片机的PWM波形发生器项目,是我最近完成的一个嵌入式系统实验。核心功能是通过STM32的定时器产生可调频率的PWM信号,配合LCD1602显示屏和独立按键实现人机交互。整个系统在Proteus环境下完成了仿真验证,实测效果相当稳定。
作为嵌入式开发中常见的基础项目,PWM波形发生器在电机控制、LED调光、电源管理等领域都有广泛应用。这个项目的特别之处在于:
- 采用硬件定时器直接生成PWM,精度高且不占用CPU资源
- 通过按键实现频率的实时调节,操作直观
- LCD1602实时显示当前频率值,反馈及时
- 完整的Proteus仿真方案,无需硬件即可验证
2. 硬件设计解析
2.1 核心器件选型
STM32F103C8T6 作为主控芯片,选择理由:
- 内置多个高级定时器,特别适合PWM生成
- 72MHz主频,性能足够应对基础控制需求
- 价格亲民,开发资源丰富
- 最小系统电路简单,便于快速搭建
LCD1602 作为显示模块:
- 经典字符型LCD,驱动简单
- 2行16字符显示,足够展示频率信息
- 5V供电,与STM32的3.3V电平通过限流电阻匹配
独立按键 采用轻触开关:
- 硬件消抖电路简化软件设计
- 直接连接GPIO,配置为上拉输入模式
- 通过中断或轮询方式检测按键动作
2.2 电路连接方案
关键连接关系如下表所示:
| STM32引脚 | 外设连接 | 功能说明 |
|---|---|---|
| PB6-PB15 | LCD1602数据/控制 | 8位数据总线+3条控制线 |
| PA0 | 按键1 | 频率增加 |
| PA1 | 按键2 | 频率减少 |
| PA8 | PWM输出 | 连接示波器测量 |
提示:实际布线时,PWM输出线应远离数字信号线,避免高频干扰。建议使用屏蔽线连接示波器探头。
3. 软件实现详解
3.1 PWM生成原理
STM32的定时器(TIM2)工作在PWM模式1,关键参数关系:
code复制PWM频率 = 定时器时钟 / (ARR + 1)
占空比 = CCR / (ARR + 1)
本项目中:
- 定时器时钟配置为72MHz
- ARR(自动重装载值)可调范围500-10000
- CCR(捕获比较值)固定为ARR的一半,实现50%占空比
因此输出频率范围:
- 最小值:72,000,000 / (10000 + 1) ≈ 7.2kHz
- 最大值:72,000,000 / (500 + 1) ≈ 143.7kHz
3.2 关键代码解析
初始化定时器2的配置函数:
c复制void TIM2_Configuration(uint16_t arr)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 时基单元配置
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// PWM模式配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = arr/2; // 50%占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
TIM_CtrlPWMOutputs(TIM2, ENABLE);
}
频率调整逻辑(按键处理部分):
c复制if(Key_Value == 1) // 频率+
{
if(TIM2->ARR < 10000) {
TIM2->ARR += 500; // 步进500
TIM2->CCR2 = TIM2->ARR/2; // 保持50%占空比
}
}
else if(Key_Value == 2) // 频率-
{
if(TIM2->ARR > 500) {
TIM2->ARR -= 500;
TIM2->CCR2 = TIM2->ARR/2;
}
}
3.3 LCD显示实现
频率值显示采用分解数字方式:
c复制WrByte1602(0,5,AsciiCode[1000000/(TIM2->ARR)%10000/1000]); // 千位
WrByte1602(0,6,AsciiCode[1000000/(TIM2->ARR)%1000/100]); // 百位
WrByte1602(0,7,AsciiCode[1000000/(TIM2->ARR)%100/10]); // 十位
WrByte1602(0,8,AsciiCode[1000000/(TIM2->ARR)%10]); // 个位
注意:这里使用1000000/ARR的计算方式是为了直接得到Hz单位的值,避免了浮点运算。
4. Proteus仿真要点
4.1 仿真电路搭建
关键器件清单:
- STM32F103C6 (与C8T6引脚兼容)
- LCD1602
- BUTTON组件
- 虚拟示波器
信号连接注意事项:
- PWM输出接示波器A通道
- 按键另一端接地,STM32端配置上拉
- LCD的VO引脚接10K电位器调节对比度
4.2 仿真参数设置
- 单片机频率设为72MHz
- 示波器时基根据频率范围调整:
- 低频时:1ms/div
- 高频时:50μs/div
- 添加电压探针便于观察信号质量
5. 开发经验分享
5.1 常见问题排查
-
PWM无输出
- 检查定时器时钟是否使能
- 验证GPIO模式是否正确(应配置为复用推挽输出)
- 确认TIM_CtrlPWMOutputs()函数已调用
-
LCD显示乱码
- 检查初始化序列是否完整
- 测量VO引脚电压(应在0.5-1V之间)
- 确认总线时序延时足够(尤其在使用软件模拟时)
-
按键响应不灵敏
- 添加硬件消抖电路(104电容)
- 在软件中实现防抖逻辑(建议20ms延时)
- 检查GPIO上拉电阻是否启用
5.2 性能优化建议
- 将频率计算改为定时中断中执行,减轻主循环负担
- 使用DMA传输LCD数据,提高刷新率
- 增加频率预设功能,通过长按实现快速调节
- 添加EEPROM存储最后设置,实现断电记忆
6. 项目扩展思路
这个基础框架可以进一步扩展:
-
多波形输出
- 增加正弦波、三角波选项
- 使用DAC或PWM+滤波实现
-
无线控制
- 添加蓝牙模块(HC-05)
- 通过手机APP调节参数
-
参数存储
- 使用STM32内部Flash
- 外接24C02 EEPROM
-
上位机接口
- 通过USART连接PC
- 开发LabVIEW或QT控制界面
实际测试中发现,当频率超过100kHz时,由于示波器采样率限制,波形显示会出现失真。这时可以:
- 降低定时器预分频值
- 改用更高性能的探头
- 在硬件环境中使用逻辑分析仪验证