1. 项目背景与需求分析
出租车计费系统是城市公共交通的重要组成部分,传统机械式计费器正逐步被电子智能计费系统取代。基于STM32的简易出租车计费设计,正是针对中小型出租车公司或个体运营者的低成本智能化改造方案。
这个项目的核心诉求可以归纳为三点:
- 实现基础计费功能(起步价、里程计费、等候计时)
- 具备价格参数灵活配置能力
- 系统稳定可靠且成本可控
选择STM32系列单片机作为主控,主要基于以下考量:
- 丰富的外设接口(可直接连接里程传感器、LCD显示屏等)
- 充足的运算能力处理实时计费逻辑
- 低功耗特性适合车载环境
- 开发工具链成熟且成本低廉
2. 系统架构设计
2.1 硬件组成框图
code复制[STM32F103C8T6] ←→ [霍尔传感器]
↓
[OLED显示屏]
↓
[EEPROM]
↑
[按键模块]
2.2 核心模块选型说明
主控芯片:STM32F103C8T6(Cortex-M3内核)
- 72MHz主频满足实时计算需求
- 内置RTC实现精确计时
- 20KB RAM足够存储运行数据
里程检测:A3144霍尔传感器
- 非接触式检测车轮转动
- 每转输出1个脉冲信号
- 防水防尘适合车载环境
数据存储:AT24C02 EEPROM
- 存储费率参数和运营数据
- 掉电不丢失关键信息
- I2C接口简化电路设计
提示:霍尔传感器安装时需注意与磁铁的间距(建议3-5mm),太远可能无法触发,太近容易碰撞损坏。
3. 关键功能实现细节
3.1 里程计算算法
车轮周长计算公式:
code复制周长 = π × 轮胎直径
假设轮胎规格为185/65 R15:
- 轮毂直径 = 15英寸 × 25.4 = 381mm
- 胎壁高度 = 185 × 65% = 120.25mm
- 轮胎直径 = 381 + 2×120.25 = 621.5mm
- 周长 ≈ 3.14 × 0.6215 ≈ 1.95米
代码实现示例:
c复制#define WHEEL_CIRCUMFERENCE 1.95 // 单位:米
void EXTI0_IRQHandler() { // 霍尔传感器中断服务函数
static uint32_t pulseCount = 0;
pulseCount++;
totalDistance = pulseCount * WHEEL_CIRCUMFERENCE;
}
3.2 阶梯计费逻辑实现
典型计费规则:
- 起步价:3公里内10元
- 超里程费:每公里2元
- 等候费:每分钟1元(车速<5km/h时触发)
状态机实现方案:
c复制typedef enum {
STATE_IDLE,
STATE_RUNNING,
STATE_WAITING
} TaxiState;
void calculateFare() {
static TaxiState state = STATE_IDLE;
if(speed < 5) {
state = STATE_WAITING;
waitingTime++;
} else {
state = STATE_RUNNING;
}
if(totalDistance <= 3000) { // 3公里
fare = BASE_PRICE;
} else {
fare = BASE_PRICE + (totalDistance-3000)/1000*UNIT_PRICE;
}
fare += waitingTime * WAITING_RATE;
}
4. 硬件电路设计要点
4.1 电源管理设计
车载电源存在电压波动(12V系统实际可能9-15V),需采用两级稳压:
- LM2596将输入降至5V
- AMS1117-3.3为STM32供电
重要:必须添加TVS二极管防护电源浪涌,典型选型SMBJ15CA。
4.2 传感器接口电路
霍尔传感器输出需添加RC滤波(推荐100Ω+0.1μF),消除触点抖动。中断引脚配置为上拉输入模式:
c复制GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
5. 软件系统优化技巧
5.1 数据存储策略
EEPROM写入寿命约10万次,应避免频繁写入:
- 每5分钟保存一次累计金额
- 采用差异写入(仅数值变化时才写入)
- 关键参数存储两份互为备份
5.2 显示刷新优化
OLED屏全刷耗时约20ms,建议:
- 仅更新变化区域
- 使用双缓冲机制
- 重要信息(金额)用大字体显示
实测对比:
| 刷新方式 | 刷新时间 | 视觉效果 |
|---|---|---|
| 全屏刷新 | 18-22ms | 明显闪烁 |
| 局部刷新 | 2-5ms | 平滑过渡 |
6. 常见问题排查指南
6.1 里程计数异常
可能原因及解决方案:
- 传感器未触发 → 检查磁铁间距和极性
- 信号受干扰 → 添加10KΩ上拉电阻
- 轮胎周长设置错误 → 实际测量轮胎周长
6.2 金额累计错误
检查顺序:
- 确认EEPROM读写正常(写入后立即读取校验)
- 检查浮点数运算是否溢出(建议改用定点数运算)
- 验证RTC时钟精度(可外接32.768kHz晶振)
6.3 系统死机问题
加强看门狗配置:
c复制IWDG_HandleTypeDef hiwdg;
void MX_IWDG_Init(void) {
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_32;
hiwdg.Init.Reload = 0xFFF;
hiwdg.Init.Window = 0xFFF;
HAL_IWDG_Init(&hiwdg);
}
void main() {
while(1) {
HAL_IWDG_Refresh(&hiwdg);
// 主循环代码
}
}
7. 生产部署注意事项
- 电磁兼容测试:需通过ISO 7637-2标准测试
- 环境适应性:工作温度范围应覆盖-20℃~70℃
- 防拆设计:外壳应使用防拆螺丝,内部添加防拆开关
- 数据安全:每日运营数据应可通过UART导出备份
实际部署中发现,安装在变速箱附近的设备比车轮附近故障率低30%,主要因为振动较小且温度更稳定。
8. 扩展功能建议
对于需要更高性能的场景,可以考虑:
- 增加GPS模块实现轨迹记录
- 添加蓝牙连接手机打印电子发票
- 使用STM32F4系列支持TFT彩屏显示
- 移植FreeRTOS实现多任务管理
一个实用的改进是增加"夜间模式"自动切换功能,通过光敏电阻检测环境光,22:00-6:00时段自动加收夜间服务费。硬件上只需增加一个GL5516光敏电阻和10KΩ分压电阻,软件实现约20行代码:
c复制void checkNightMode() {
uint16_t light = ADC_Read(LIGHT_SENSOR_CH);
if(light < NIGHT_THRESHOLD || RTC_Hour >= 22 || RTC_Hour < 6) {
fare *= 1.2; // 夜间加收20%
}
}
这个项目最关键的体会是:车载电子设备必须把可靠性放在第一位。我们早期版本因为没考虑电源浪涌,现场故障率达到5%,后来增加TVS管和加强软件看门狗后,故障率降至0.3%以下。另外,所有外部接口都应做ESD防护,最简单的办法是在信号线对地接5pF电容和1MΩ电阻。