1. 从零搭建智能公交刷卡终端的技术路线
第一次接触嵌入式开发的朋友可能会觉得公交刷卡终端这种设备很高大上,但其实用GEC6818开发板配合RFID读卡器就能实现核心功能。这个项目最吸引人的地方在于,它完美融合了硬件驱动开发、多线程编程和状态机设计三大嵌入式核心技术。
我去年给本地公交公司做原型开发时,发现市面上大多数开发板要么外设太少,要么驱动兼容性差。GEC6818的开发板自带7寸触摸屏,还有现成的蜂鸣器和串口接口,特别适合做这种交互式终端。当时我们团队用两周时间就完成了从硬件组装到基础功能开发的全过程。
硬件配置上需要重点关注三个模块:
- RFID读卡模块:通过串口与开发板通信,建议选用FM11RF08芯片的读卡器,实测识别距离能稳定在3-5cm
- 触摸屏驱动:GEC6818的电容屏需要校准坐标映射,黑色边框板子和蓝色边框的坐标转换公式不一样
- 语音提示模块:用mplayer实现后台播放,记得编译时加入libmad库支持MP3解码
2. RFID读卡功能的深度优化
很多新手在实现刷卡功能时最常遇到两个坑:一是卡片反复误识别,二是多线程冲突。我在初期测试时,就遇到过连续刷卡导致余额被多次扣除的严重bug。
防抖处理是读卡稳定的关键。我们的解决方案是:
unsigned int rfid_get_id(int fd) { if(PiccRequest(fd)) return -1; usleep(10000); // 关键延时 unsigned int cardid = PiccAnticoll(fd); if(cardid == -1) return -1; usleep(10000); // 二次延时 return cardid; }对于不同类型的IC卡,建议用结构体管理属性:
typedef struct { unsigned int card_id; char card_type[20]; // "普通卡"/"学生卡"/"敬老卡" int balance; int discount_rate; // 折扣率 } CardInfo;实测发现,在多线程环境下读取卡号时,必须加互斥锁保护共享数据。我们创建了专门的读卡线程:
void *read_rfid_thread(void *arg) { while(!thread_exit_flag) { pthread_mutex_lock(&rfid_mutex); current_card = rfid_get_id(rfid_fd); pthread_mutex_unlock(&rfid_mutex); usleep(50000); } }3. 用户交互界面的状态机设计
公交终端的界面流转其实是个典型的状态机模型。我们定义了6个核心状态:
- 欢迎界面
- 功能选择界面
- 管理员登录
- 充值/调价界面
- 用户刷卡界面
- 交易结果提示
每个状态的切换都通过触摸事件触发:
typedef enum { STATE_WELCOME, STATE_FUNCTION_SELECT, STATE_ADMIN_LOGIN, STATE_RECHARGE, STATE_PAYMENT, STATE_RESULT } SystemState;触摸坐标处理有个实用技巧 - 把按钮区域定义为结构体数组:
typedef struct { int x_start; int y_start; int x_end; int y_end; void (*callback)(void); } TouchArea; TouchArea buttons[] = { {103,222,305,402,enter_admin_mode}, // 管理员按钮 {505,222,706,402,enter_user_mode} // 用户按钮 };4. 跨平台开发的环境配置
在Ubuntu上交叉编译时,最容易出问题的是第三方库的移植。这里分享几个避坑经验:
libjpeg库移植的完整步骤:
tar zxvf libjpeg2ubuntu.tar.gz -C ~ sudo cp ~/include/jpeglib.h /usr/local/include/ sudo cp ~/lib/libjpeg.* /usr/local/lib/字体显示方面,如果出现中文乱码,需要:
- 从Windows系统拷贝SimSun.ttf等中文字体
- 修改font.h中的路径定义
- 重新编译font库
音频播放的优化方案:
- 使用mplayer的slave模式实现后台控制
- 通过命名管道发送控制命令
system("mkfifo /tmp/mplayer_ctrl"); system("mplayer -slave -input file=/tmp/mplayer_ctrl 1.mp3 &");5. 系统集成与性能调优
当所有功能模块开发完成后,需要重点关注系统整体稳定性。我们通过以下手段提升性能:
内存管理方面:
- 使用mmap直接映射帧缓存,避免频繁IO操作
- 为每个界面预加载图片资源
- 采用双缓冲机制防止屏幕闪烁
线程调度策略:
- 读卡线程设为实时优先级
- 界面渲染线程绑定到特定CPU核心
- 使用条件变量协调各线程运行
一个典型的资源释放函数应该这样实现:
void system_cleanup() { munmap(lcd_ptr, 800*480*4); close(lcd_fd); close(ts_fd); rfid_uninit(rfid_fd); pthread_cancel(rfid_thread); }6. 生产环境部署建议
在实际公交场景部署时,我们总结了这些经验:
- 开发板需要加装金属外壳防电磁干扰
- 定期清理触摸屏表面油污(建议每周一次)
- 为RFID天线制作专用支架保持识别角度
- 系统日志要实时上传到云端监控
对于交易数据安全,建议:
- 使用HMAC-SHA256签名交易记录
- 本地存储采用SQLite加密数据库
- 定期通过4G模块同步到服务器
温度控制也很重要 - 我们在外壳加装了温控风扇,当CPU温度超过60度时自动启动。可以通过这个命令监控温度:
cat /sys/class/thermal/thermal_zone0/temp7. 功能扩展方向
现有系统还可以进一步扩展:
- 增加NFC手机支付支持
- 集成人脸识别模块
- 开发微信小程序查询余额
- 添加GPS模块实现线路跟踪
最近我们正在试验离线语音识别方案,使用LD3320芯片实现"叮咚,敬老卡"这样的语音反馈。测试发现识别率能达到85%以上,这对老年用户特别友好。
另一个有意思的扩展是客流统计,通过红外对射传感器计算上下车人数,这个数据对公交调度很有价值。我们在前后门各安装了两个传感器,用74HC165扩展IO口采集数据。