1. 项目概述与设计思路
红绿灯控制系统是城市交通管理的基础设施,传统方案多采用PLC或专用控制器实现。而基于STM32单片机的设计方案,在成本、灵活性和可扩展性方面具有显著优势。我这次设计的系统采用STM32F103C8T6作为主控芯片,这是一款性价比极高的Cortex-M3内核微控制器,72MHz主频完全能满足交通灯控制的实时性要求。
整个系统设计遵循"模块化、低功耗、易维护"三大原则。硬件上采用最小系统+功能模块的架构,软件上使用状态机模型实现灯态切换逻辑。这种设计方式使得系统既保证了稳定性,又便于后续功能扩展(比如增加车流量检测、远程控制等)。
提示:选择STM32F103系列主要考虑其丰富的外设资源(多达37个GPIO)和广泛的市场应用,相关资料和开发工具链都很成熟,非常适合教学和中小型项目开发。
2. 硬件系统设计与实现
2.1 核心电路设计
2.1.1 STM32最小系统
最小系统是单片机工作的基础,包含三个关键部分:
-
电源电路:采用AMS1117-3.3V稳压芯片,将输入的5V转换为3.3V。实际布线时要注意在输入输出端各加一个10μF电容滤波,我曾在早期版本中省略输出电容,导致单片机频繁复位。
-
时钟电路:
- 主时钟:8MHz晶振+两个22pF负载电容,为系统提供基础时钟
- RTC时钟:32.768kHz晶振,用于精确计时(本项目中未启用)
-
复位电路:采用经典的RC复位方案(10kΩ电阻+0.1μF电容),实测发现电容值不宜过大,否则会导致复位时间过长影响启动速度。
2.1.2 红绿灯驱动电路
LED驱动采用ULN2003达林顿阵列芯片,设计时需注意:
- 每个LED串联220Ω限流电阻
- 东西方向各3个LED(红黄绿),南北方向同样配置
- 驱动电流计算:假设LED正向压降2V,3.3V供电时电流=(3.3-2)/220≈5.9mA
2.2 扩展模块设计
2.2.1 数码管显示模块
使用共阳4位数码管显示倒计时,通过74HC595串行驱动。实际调试中发现:
- 动态扫描频率建议在100Hz以上,否则会出现闪烁
- 每个段码电流约3mA,需要合理设置限流电阻
2.2.2 超声波测距模块(预留)
虽然当前版本未使用,但为后续智能控制预留了HC-SR04接口:
- 触发信号连接PA8
- 回波信号连接PA9
- 测量周期建议≥60ms
3. 软件系统设计与实现
3.1 程序架构设计
采用分层架构:
code复制Application Layer(交通灯逻辑)
↓
Middleware Layer(定时器、数码管驱动)
↓
Hardware Layer(GPIO、TIM等外设)
3.1.1 主程序流程图
c复制void main() {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init(); // 用于1ms定时
while(1) {
TrafficLight_Update(); // 每100ms执行一次
Display_Update(); // 数码管刷新
}
}
3.2 核心算法实现
3.2.1 状态机设计
定义交通灯的5种状态:
c复制typedef enum {
STATE_EW_GREEN, // 东西绿灯
STATE_EW_YELLOW, // 东西黄灯
STATE_NS_GREEN, // 南北绿灯
STATE_NS_YELLOW, // 南北黄灯
STATE_ALL_RED // 全红(安全间隔)
} TrafficState;
状态转换表:
| 当前状态 | 条件 | 下一状态 | 持续时间 |
|---|---|---|---|
| EW_GREEN | 倒计时≤3s | EW_YELLOW | 30s |
| EW_YELLOW | 倒计时=0 | NS_GREEN | 3s |
| ... | ... | ... | ... |
3.2.2 倒计时处理
使用TIM2定时器产生1ms中断,在中断服务程序中:
c复制void TIM2_IRQHandler() {
static uint16_t count = 0;
if(++count >= 100) { // 100ms
count = 0;
if(g_timer > 0) g_timer--;
}
}
数码管显示采用查表法:
c复制const uint8_t SEG_CODE[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
void Display_Number(uint8_t num) {
HC595_Send(SEG_CODE[num % 10]); // 个位
HC595_Send(SEG_CODE[num / 10]); // 十位
}
4. 系统调试与优化
4.1 常见问题排查
-
LED亮度不均:
- 检查各支路限流电阻是否一致
- 测量实际工作电流(万用表串联测量)
-
数码管显示乱码:
- 确认74HC595的锁存信号时序
- 检查段码表定义是否正确
-
状态切换不同步:
- 确保定时器中断优先级最高
- 在状态切换点添加调试输出
4.2 性能优化记录
-
功耗优化:
- 将未使用的GPIO设为模拟输入模式
- 在绿灯常亮阶段启用PWM调光(50%占空比)
-
响应速度优化:
- 将数码管扫描频率从60Hz提升到120Hz
- 使用DMA传输段码数据
-
代码优化:
- 将频繁调用的函数添加
__inline修饰 - 使用位带操作替代GPIO读写
- 将频繁调用的函数添加
5. 扩展功能设计
5.1 车流量自适应控制(方案)
- 通过超声波模块检测排队长度
- 动态调整绿灯时长:
c复制void Adjust_GreenTime() { uint16_t queue_len = Get_QueueLength(); g_green_time = MIN_TIME + queue_len * ADJUST_RATE; g_green_time = MIN(MAX_TIME, g_green_time); }
5.2 远程控制接口
- 添加ESP8266 WiFi模块
- 实现简单的AT指令协议:
code复制SET TIME EW 30 // 设置东西方向绿灯30秒 GET STATUS // 获取当前状态
6. 项目总结与心得
经过三周的开发调试,这个红绿灯控制系统最终达到了设计目标。在开发过程中,有几个关键经验值得分享:
-
硬件设计:
- 电源滤波电容要尽可能靠近芯片引脚
- 预留测试点(我每隔5个引脚留一个GND测试点)
-
软件开发:
- 状态机模型非常适合这类时序控制系统
- 使用
volatile关键字保护多任务共享变量
-
调试技巧:
- 用LED指示灯辅助调试(比如每个状态对应一个LED)
- 在关键代码段添加时间戳打印
这个项目最让我满意的是其可扩展性设计。最近我正在为其添加蓝牙控制功能,只需要在原有框架上增加一个新任务即可,核心逻辑完全不用修改。对于想学习嵌入式开发的朋友,交通灯控制是个非常好的入门项目,它涵盖了GPIO控制、定时器、中断等核心知识点。