1. 系统概述:银行排队叫号系统的DIY实现
银行排队叫号系统是日常生活中常见的设备,但商用版本往往价格昂贵。基于51单片机的DIY方案,不仅成本低廉(整套硬件成本可控制在100元以内),而且完全开源可定制。我在实际项目中使用的STC89C52RC芯片,市场价仅5-8元,却能完美胜任基础叫号功能。
这个系统的核心价值在于:
- 对小型营业厅、社区银行等场景,商用系统性价比太低
- 电子爱好者可以借此深入理解嵌入式系统的完整开发流程
- 模块化设计便于功能扩展,比如我后来就加入了无线取号功能
提示:选择STC89C52而非更高级芯片的考虑是——它完全满足需求且价格低廉,GPIO数量足够驱动常规外设,同时有丰富的学习资料。
2. 硬件设计与选型要点
2.1 核心控制器选型
经过对比测试,我最终选择STC89C52RC作为主控芯片,主要基于以下实测数据:
- 工作电压:5V±10%(可直接USB供电)
- Flash ROM:8KB(足够存储基础逻辑代码)
- RAM:512字节(需注意变量优化)
- GPIO:32个(实际使用中分配如下:
- P0:LCD数据总线
- P1:按键输入
- P2:LED数码管段选
- P3:串口通信+位选
2.2 显示模块的两种方案对比
我在项目中实测了两种显示方案:
| 类型 | 成本 | 接线复杂度 | 显示效果 | 适用场景 |
|---|---|---|---|---|
| LED数码管 | ¥15 | 较简单(12线) | 仅数字 | 基础版本 |
| LCD1602 | ¥25 | 较复杂(16线) | 可显示文字 | 扩展版本 |
实际部署发现:银行场景更适合LCD,因为需要显示"请XX号到X窗口"这样的完整语句。
2.3 语音模块的实战选择
测试过三种语音芯片后的结论:
- WT588D:性价比最高(¥18),但需要配套上位机软件烧录语音
- SYN6288:TTS合成(¥35),可动态组合语音但音质机械
- JQ8900:MP3解码(¥30),音质好但需要预存完整语音文件
最终选择WT588D的方案,因为:
- 银行叫号语音固定,无需实时合成
- 通过分段录制"请"、"号"、"到1号窗口"等语音片段,再用代码组合播放
3. 软件架构与核心逻辑实现
3.1 取号队列的存储设计
考虑到51单片机有限的RAM,采用循环队列存储方式:
c复制#define MAX_QUEUE 50
unsigned char queue[MAX_QUEUE];
unsigned char front = 0, rear = 0;
void enqueue(unsigned char num) {
if((rear+1)%MAX_QUEUE != front) {
queue[rear] = num;
rear = (rear+1)%MAX_QUEUE;
}
}
unsigned char dequeue() {
if(front != rear) {
unsigned char num = queue[front];
front = (front+1)%MAX_QUEUE;
return num;
}
return 0; // 队列空
}
这种设计:
- 节省内存(仅用50字节存储50个号码)
- 避免内存碎片
- 取号叫号时间复杂度都是O(1)
3.2 中断驱动的按键处理
实际测试发现,直接扫描按键会有抖动问题。我的解决方案:
c复制sbit KEY_TAKE = P1^0;
sbit KEY_CALL = P1^1;
void timer0_isr() interrupt 1 {
static unsigned char count[2] = {0,0};
// 取号键消抖
if(!KEY_TAKE) {
if(++count[0] >= 10) { // 10ms*10=100ms防抖
current_num++;
enqueue(current_num);
update_display();
count[0] = 0;
}
} else {
count[0] = 0;
}
// 叫号键同理
...
}
注意:定时器中断建议配置为10ms一次,消抖时间100ms效果最佳(实测数据)
4. 语音播放的工程实现细节
4.1 语音片段的分段录制
使用WT588D配套软件时,语音地址分配很关键:
| 地址 | 语音内容 | 时长 |
|---|---|---|
| 0x00 | "请" | 0.5s |
| 0x01 | "1号" | 0.8s |
| ... | ... | ... |
| 0x0A | "到" | 0.3s |
| 0x0B | "1号窗口" | 1.2s |
播放逻辑示例:
c复制void play_number(unsigned char num) {
send_cmd(0x00); // 播放"请"
delay_ms(500);
send_cmd(num); // 播放"X号"
delay_ms(800);
send_cmd(0x0A); // 播放"到"
delay_ms(300);
send_cmd(0x0B + window_id); // 播放"X号窗口"
}
4.2 串口通信的稳定性优化
实测发现115200波特率下容易丢包,通过以下措施解决:
- 降波特率到9600
- 每个命令发送3次
- 增加50ms重发间隔
修改后的发送函数:
c复制void safe_send(unsigned char cmd) {
unsigned char i;
for(i=0; i<3; i++) {
SBUF = cmd;
while(!TI);
TI = 0;
delay_ms(50);
}
}
5. 系统部署的实用经验
5.1 电源管理的教训
初期使用手机充电器供电时,遇到以下问题:
- 数码管显示闪烁
- 语音播放断续
- 随机复位
解决方案:
- 改用5V/2A稳压电源
- 在单片机VCC对地并联1000μF电容
- 每个数码管段选线串联100Ω电阻
5.2 抗干扰布线技巧
通过惨痛教训总结的布线原则:
- 数字地与模拟地单点连接
- 晶振尽量靠近单片机(<1cm)
- 语音模块的RX/TX线加10K上拉电阻
- 按键线并联104瓷片电容
6. 功能扩展的进阶方案
6.1 多窗口支持实现
硬件改动:
- 增加窗口选择按键
- 每个窗口独立显示单元
软件修改:
c复制#define WINDOW_NUM 3
unsigned char window_queue[WINDOW_NUM][MAX_QUEUE];
unsigned char window_front[WINDOW_NUM], window_rear[WINDOW_NUM];
void call_number(unsigned char win_id) {
if(window_front[win_id] != window_rear[win_id]) {
unsigned char num = dequeue(win_id);
play_call(win_id, num);
}
}
6.2 无线取号模块添加
测试可用的两种方案:
-
HC-05蓝牙模块(¥25)
- 手机APP发送取号指令
- 需开发简易Android应用
-
ESP8266 WiFi模块(¥18)
- 可接入局域网
- 通过网页取号
实测吞吐量:
- 蓝牙:同时连接3台设备无压力
- WiFi:支持20+客户端同时访问
7. 常见问题排查指南
根据30+次部署经验整理的故障速查表:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 显示乱码 | 1. 对比度调节不当 2. 数据线接触不良 |
1. 调节LCD电位器 2. 重新压接排线 |
| 语音不播放 | 1. 波特率不匹配 2. 供电不足 |
1. 核对模块手册 2. 单独给模块供电 |
| 按键不响应 | 1. 消抖时间过长 2. 上拉电阻失效 |
1. 调整定时器中断 2. 更换10K电阻 |
| 系统死机 | 1. 看门狗未启用 2. 堆栈溢出 |
1. 配置WDT 2. 减少局部变量 |
8. 工程优化建议
- EEPROM存储每日统计:
c复制void save_stats() {
unsigned char date = get_date();
unsigned char count = read_eeprom(date);
write_eeprom(date, count+1);
}
- 低功耗模式设计:
- 无操作10分钟后关闭显示背光
- 通过外部中断唤醒
- 语音音量调节:
- 增加电位器控制音频输出
- 或通过PWM模拟DAC调节
这个项目最让我意外的是——用如此廉价的51单片机,经过合理设计后,完全可以满足小型营业厅的实际需求。后期我还尝试用STC15系列芯片(内置PLL时钟和EEPROM),系统稳定性得到进一步提升。对于想要深入嵌入式开发的朋友,这个项目涵盖了GPIO控制、定时器中断、串口通信、队列算法等多个核心知识点,是非常好的练手项目。
