1. 项目概述:当单片机遇上自动售货机
十年前我第一次在东京街头见到自动售货机时,就被这种24小时不间断服务的商业形态震撼了。如今,借助单片机技术,我们完全可以在实验室里搭建自己的微型售货系统。这个基于单片机的自动售货机系统设计,本质上是一个典型的嵌入式控制应用案例,它完美展现了如何用几十元的硬件成本实现商业设备的智能化改造。
这个系统的核心价值在于:通过AT89C51这类经典51单片机,配合简单的传感器和执行机构,就能模拟真实售货机的完整工作流程。从投币识别、商品选择到出货控制,整个系统涉及硬件电路设计、信号采集处理、状态机编程等嵌入式开发的核心技术点。特别适合电子信息类专业学生作为课程设计项目,或是创客爱好者用来练手。
提示:选择51单片机作为主控,不仅因为其价格低廉(零售价约5-8元),更重要的是其丰富的中断资源和稳定的性能,特别适合处理售货机这类需要实时响应的场景。
2. 系统架构设计解析
2.1 硬件组成框架
一个完整的自动售货机系统通常包含以下核心模块:
- 主控单元:AT89C51单片机最小系统(含11.0592MHz晶振)
- 输入模块:矩阵键盘(商品选择)+ 投币传感器(红外对管)
- 输出模块:LCD1602显示屏 + 继电器控制的电磁铁出货机构
- 辅助电路:74HC245总线驱动器 + ULN2003达林顿管阵列

2.2 软件状态机设计
系统采用有限状态机(FSM)模型,主要包含以下几个状态:
- 待机状态:显示欢迎界面,等待投币
- 投币状态:累计金额并更新显示
- 选择状态:检测按键输入,判断余额是否充足
- 出货状态:驱动对应电磁铁,减少库存
- 找零状态:计算应退金额(需配合退币电机)
c复制enum VENDING_STATE {
STANDBY,
COIN_INPUT,
ITEM_SELECT,
DELIVERY,
CHANGE_RETURN
};
3. 核心电路实现细节
3.1 投币检测电路设计
采用槽型光电开关(如EE-SX670)作为硬币检测传感器,其输出信号经过LM393比较器整形后送入单片机外部中断引脚。关键参数计算:
- 硬币直径检测窗口:25mm(适合1元硬币)
- 比较器阈值电压:Vref = 2.5V(通过电位器调节)
- 消抖时间:硬件RC滤波(10kΩ+0.1μF)配合软件延时20ms
注意:实际商用设备会使用多组传感器区分不同面额,本设计为简化采用累计脉冲计数方式,每个脉冲代表固定金额(如1元)。
3.2 出货控制电路
使用5V继电器控制12V电磁铁,典型电路包含:
- 三极管驱动:2N3904基极串联1kΩ电阻
- 继电器选型:HRS1H-S-DC5V(触点容量10A)
- 保护二极管:1N4148反向并联在线圈两端
c复制void deliver_goods(uint8_t channel) {
P2 = 0x01 << channel; // 选中对应通道
delay_ms(500); // 电磁铁吸合时间
P2 = 0x00; // 释放继电器
}
4. 软件设计关键点
4.1 库存管理算法
采用位域结构体存储商品信息,节省RAM空间:
c复制typedef struct {
uint8_t price;
uint8_t stock:4; // 最大库存15
uint8_t reserved:4;
} GoodsItem;
GoodsItem goods[6] = {
{3, 10}, // 商品1:价格3元,库存10
{5, 8}, // 商品2:价格5元,库存8
// ...其他商品
};
4.2 人机交互实现
LCD1602显示采用四线接法,关键显示函数示例:
c复制void display_balance(uint16_t balance) {
lcd_set_cursor(0, 1);
lcd_print("Balance:");
lcd_print_uint(balance);
lcd_print(" Yuan");
}
键盘扫描采用行列反转法,配合状态机实现长按检测:
c复制uint8_t key_scan() {
static uint8_t last_key = 0xFF;
static uint16_t press_time = 0;
// ...扫描代码
if(key == last_key) {
if(++press_time > 1000) { // 长按1秒
return key | 0x80; // 最高位标记长按
}
}
// ...状态更新
}
5. 常见问题与调试技巧
5.1 电磁干扰导致复位
现象:出货时单片机异常复位
解决方案:
- 在继电器线圈两端并联0.1μF陶瓷电容
- 单片机复位引脚加10kΩ上拉电阻
- 电源输入端增加100μF电解电容
5.2 出货卡滞问题
可能原因及对策:
- 电磁铁行程不足:改用长行程型号(如MF-1220)
- 弹簧力度不够:更换刚度系数更大的弹簧
- 商品通道摩擦:用砂纸打磨塑料滑道内壁
5.3 投币误检测
优化方案:
- 增加红外对管的调制信号(38kHz载波)
- 软件上采用滑动窗口计数算法
- 设置最小硬币间隔时间(>300ms)
6. 系统优化方向
6.1 引入RFID支付模块
通过RC522模块增加IC卡支付功能:
- 卡片类型:Mifare S50(13.56MHz)
- 通信协议:SPI接口
- 典型接线:
- SCK → P1.5
- MOSI → P1.6
- MISO → P1.7
- NSS → P1.4
6.2 远程监控功能扩展
添加ESP8266 WiFi模块实现:
- 库存预警短信通知
- 销售数据上传云端
- 远程价格调整
c复制void wifi_send_data() {
uart_send("AT+CIPSTART=\"TCP\",\"api.xxx.com\",80\r\n");
uart_send("GET /update?stock=5&sales=120\r\n");
}
7. 工程文件组织建议
规范的代码目录结构:
code复制/vending_machine
├── /hardware # 硬件设计文件
│ ├── schematic.pdf
│ └── PCB/
├── /software
│ ├── main.c # 主程序
│ ├── lcd1602.c # 显示驱动
│ ├── keypad.c # 键盘处理
│ └── Makefile
└── /docs # 设计文档
├── BOM.xlsx # 物料清单
└── FSM.md # 状态机说明
在Keil工程中,建议启用LX51链接器优化选项,可以节省约15%的代码空间。对于包含较多字符串的显示程序,使用code关键字将常量存入ROM:
c复制code const char *welcome_msg = "Welcome!";
这个项目最让我惊喜的是,用如此简单的硬件就能实现完整的商业逻辑。在实际调试过程中,机械结构的稳定性往往比电路设计更具挑战性——建议先用3D打印制作商品滑道原型,反复测试出货机构的角度和力度参数。记住,一个好的嵌入式工程师不仅要懂电路和编程,还需要对机械结构有基本的感知能力。
