1. 项目概述
这个基于51单片机的出租车计价器项目,是我去年为本地一家小型出租车公司开发的低成本解决方案。传统计价器动辄上千元,而用STC89C51这套方案,硬件成本不到200元。核心思路是通过霍尔传感器检测车轮转动来计量里程,配合定时器计算等待时间,再按照预设费率进行费用计算。
整个系统最关键的三个部分:里程检测模块确保距离计量准确,这是计价的基础;实时时钟模块区分白天/夜间不同费率;掉电存储模块保证设置的参数不会丢失。实测下来,在30公里行程中误差能控制在±200米以内,完全满足出租车日常运营需求。
2. 硬件设计详解
2.1 核心控制器选型
选用STC89C51RC这颗国产51芯片主要考虑三点:
- 内置4KB FlashROM,足够存储计价程序
- 支持5V宽电压供电,适合车载环境
- 价格仅3-5元,性价比极高
注意:实际开发中发现STC芯片需要冷启动下载程序,建议购买专用下载器时选择支持自动断电复位的型号。
2.2 里程检测方案
采用A4133霍尔传感器配合磁钢的方案:
- 磁钢安装在车轮辐条上,每转一圈触发一次霍尔信号
- 通过公式计算里程:距离(km)=触发次数×车轮周长/1000
- 车轮周长需要实地测量,以195/55R16轮胎为例:
- 直径=(16×25.4)+2×(195×0.55)=634.9mm
- 周长=π×634.9≈1994mm
c复制// 里程计算代码片段
#define WHEEL_CIRCUMFERENCE 1.994 // 单位:米
volatile unsigned long pulseCount = 0;
void EXTI0_IRQHandler() interrupt 0 {
pulseCount++;
EX0 = 0; // 清除中断标志
EX0 = 1;
}
2.3 人机交互设计
LCD1602显示布局优化方案:
code复制-----------------
|KM:12.5 F:35.0 |
|DAY 02:30 15:40|
-----------------
第一行显示实时里程和费用,第二行左侧显示昼夜状态,中间是等待计时,右侧是实时时钟。
独立按键功能分配:
- K1:模式切换(设置/运行)
- K2:参数项选择
- K3:数值增加
- K4:数值减少
3. 软件实现关键点
3.1 费率计算逻辑
费用由三部分组成:
- 起步价(默认15元)
- 里程费:超出起步里程后按单价计费
- 等待费:停车超过3分钟开始计费
c复制float calculateFee(bool isNight) {
float baseFee = isNight ? nightBase : dayBase;
float distanceFee = (distance > startDistance) ?
(distance - startDistance) * (isNight ? nightPrice : dayPrice) : 0;
float waitFee = (waitTime > 3) ?
(waitTime - 3) * (isNight ? nightWaitPrice : dayWaitPrice) : 0;
return baseFee + distanceFee + waitFee;
}
3.2 掉电存储实现
AT24C02使用注意事项:
- 每次写入前需要检查ACK信号
- 单次写入不超过8字节
- 重要参数建议存储两份互为备份
c复制void saveParameters() {
unsigned char buf[8];
buf[0] = dayPrice * 10; // 放大10倍存储
buf[1] = nightPrice * 10;
AT24C02_Write(0x50, 0x00, buf, 2);
delay(10); // 必须的写入延时
}
3.3 状态机设计
系统采用五状态机模型:
- 运行状态:正常计价
- 时钟设置:调整实时时钟
- 费率设置:修改各费率参数
- 数据查询:查看历史记录
- 系统校准:传感器校准
状态转换示意图:
code复制[运行状态]
↑ ↓ K1长按
[费率设置] ←→ [时钟设置]
↑ ↓ K2长按
[数据查询]
4. 开发调试经验
4.1 Proteus仿真技巧
-
霍尔传感器仿真:用脉冲发生器模拟,频率=车速/(车轮周长)
- 60km/h ≈ 16.67m/s
- 脉冲频率=16.67/1.994≈8.36Hz
-
LCD显示异常排查:
- 检查对比度电压(通常接10K电位器)
- 确认初始化延时足够(>40ms)
- 注意总线时序,51单片机建议用4bit模式
4.2 现场校准方法
-
里程校准:
- 实测1公里路程,记录脉冲数N
- 修改代码中WHEEL_CIRCUMFERENCE定义:
c复制#define WHEEL_CIRCUMFERENCE (1000.0/N) // 单位:米
-
时钟校准:
- 用示波器测量32.768kHz晶振频率
- 调整定时器重装值:
c复制#define TIMER_RELOAD (65536 - FOSC/12/32768*1000)
5. 常见问题解决方案
5.1 里程计数异常
可能原因及处理:
- 磁钢距离过远 → 调整至3-5mm间隙
- 信号抖动 → 在INT0引脚加0.1uF电容
- 电源干扰 → 霍尔传感器单独供电
5.2 LCD显示乱码
排查步骤:
- 检查电位器是否调节到合适电压(约0.5VDD)
- 确认初始化序列完整发送
- 测量背光电压(通常4.2V-5V)
5.3 参数存储丢失
预防措施:
- 每次写入后做校验读取
- 关键参数双备份存储
- 增加超级电容作为备用电源
6. 性能优化建议
-
节电模式设计:
- 无操作5分钟后关闭LCD背光
- 使用STC15系列芯片的掉电模式
c复制PCON |= 0x02; // 进入掉电模式 -
打印小票功能扩展:
- 添加微型热敏打印机模块
- 选用串口通信的TP-58型号
-
GPS里程互补:
- 接入SIM808模块
- 当霍尔传感器异常时自动切换
这个项目最让我意外的是AT24C02的写入寿命问题。最初版本每天频繁存储参数,三个月后就出现了数据丢失。后来改为仅在参数变更时存储,并增加了写入次数统计功能,当接近10万次时主动提示更换芯片。