1. 项目概述
1.1 实验背景与目标
在嵌入式Linux开发中,串口通信是最基础也最重要的外设接口之一。本次实验基于IMX6ULL开发板,通过UART5接口连接GPS模块,实现NMEA-0183协议数据的接收与解析。这个实验看似简单,但涉及多个关键知识点:
- Linux串口设备操作(打开、配置、读写)
- 阻塞与非阻塞模式的选择与实现
- NMEA协议解析与数据格式转换
- 嵌入式系统调试技巧与问题排查
通过这个实验,开发者可以掌握Linux环境下串口设备的完整操作流程,理解GPS模块的工作原理,并学会处理嵌入式开发中常见的硬件接口问题。
1.2 硬件环境准备
实验所需硬件包括:
- 百问网IMX6ULL开发板(主控芯片为NXP i.MX6ULL)
- GPS模块(建议选用UBLOX NEO-6M或兼容模块)
- 杜邦线4根(建议使用不同颜色区分电源和信号线)
- USB转串口调试工具(用于连接开发板调试串口)
特别提醒:GPS模块的供电电压必须为3.3V,绝对不能接5V,否则会损坏模块。建议使用万用表确认电压后再连接。
1.3 软件环境说明
开发环境配置如下:
- 主机系统:Ubuntu 18.04/20.04 LTS(推荐使用虚拟机)
- 交叉编译工具链:arm-buildroot-linux-gnueabihf-gcc
- 开发板系统:百问网定制Buildroot系统
- 代码共享方式:NFS网络文件系统(共享目录为/home/book/nfs_rootfs)
2. 硬件连接与验证
2.1 引脚连接详解
GPS模块与IMX6ULL开发板的连接必须严格按照以下方式:
| GPS模块引脚 | IMX6ULL引脚 | 连接说明 |
|---|---|---|
| VCC | 3.3V | 电源正极 |
| GND | GND | 电源地 |
| TX | UART5_RXD | 数据接收 |
| RX | UART5_TXD | 数据发送 |
重要提示:
- 必须采用交叉连接方式(TX接RXD,RX接TXD)
- 连接前确保开发板断电
- 建议先连接电源线(VCC和GND),确认模块供电正常后再连接信号线
2.2 硬件验证步骤
在正式开发前,建议先进行硬件验证:
- 使用USB转TTL工具直接连接GPS模块,通过串口助手查看原始数据输出
- 使用万用表测量开发板3.3V电源输出是否正常
- 检查杜邦线连接是否牢固,避免接触不良
2.3 常见硬件问题排查
如果GPS模块无数据输出,可按以下步骤排查:
- 检查供电:模块LED是否亮起(部分模块有电源指示灯)
- 检查接线:确认TX/RX没有接反
- 尝试更换GPS模块:排除模块损坏的可能性
- 用示波器测量信号线:确认是否有数据波形
3. 软件实现详解
3.1 串口配置核心代码解析
串口配置是GPS数据接收的关键,主要涉及termios结构体的设置:
c复制struct termios {
tcflag_t c_cflag; // 控制模式标志
tcflag_t c_lflag; // 本地模式标志
tcflag_t c_iflag; // 输入模式标志
tcflag_t c_oflag; // 输出模式标志
cc_t c_cc[NCCS]; // 控制字符
};
关键配置项说明:
c_cflag:设置波特率、数据位、停止位等c_lflag:设置为原始模式(ICANON关闭规范模式)c_cc[VMIN]和c_cc[VTIME]:控制读取行为的超时机制
3.2 超时机制实现
为避免程序在无GPS信号时卡死,我们设置了非阻塞读取模式:
c复制newtio.c_cc[VMIN] = 0; // 不要求最小读取字符数
newtio.c_cc[VTIME] = 10; // 超时时间为1秒(10×0.1秒)
这种配置下:
- 有数据时立即返回
- 无数据时等待1秒后返回
- 既保证了实时性,又避免了无限等待
3.3 NMEA协议解析
GPS模块输出的NMEA-0183协议数据格式如下:
code复制$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
各字段含义:
- $GPGGA:帧头,表示GPS定位信息
- 123519:UTC时间(12:35:19)
- 4807.038,N:纬度(48度07.038分北纬)
- 01131.000,E:经度(11度31.000分东经)
- 1:定位质量指示(1=有效定位)
- 08:使用的卫星数量
- 0.9:水平精度因子
- 545.4,M:海拔高度(米)
- *47:校验和
3.4 经纬度格式转换
GPS输出的经纬度是"度分"格式,需要转换为十进制格式:
纬度转换示例:
原始数据:4807.038(48度07.038分)
计算过程:
- 度部分:48
- 分部分:07.038/60 = 0.1173
- 十进制结果:48 + 0.1173 = 48.1173
代码实现:
c复制// 纬度转换
sscanf(Lat+2, "%f", &fLat); // 提取分部分
fLat = fLat / 60; // 分转度
fLat += (Lat[0] - '0')*10 + (Lat[1] - '0'); // 加上度部分
4. 开发流程与调试
4.1 交叉编译步骤详解
- 编写代码并保存为gps_read.c
- 使用交叉编译工具链编译:
bash复制
arm-buildroot-linux-gnueabihf-gcc -o gps_read gps_read.c - 检查生成的可执行文件:
bash复制
应显示为ARM架构可执行文件file gps_read
4.2 程序部署与运行
- 将编译好的程序复制到NFS共享目录:
bash复制cp gps_read /home/book/nfs_rootfs/ - 在开发板上挂载NFS目录(如果未自动挂载):
bash复制
mount -t nfs 192.168.x.x:/home/book/nfs_rootfs /mnt - 运行程序:
bash复制
./gps_read /dev/ttymxc5
4.3 调试技巧与工具
-
查看串口设备:
bash复制ls /dev/ttymxc* -
检查串口权限:
bash复制ls -l /dev/ttymxc5确保当前用户有读写权限
-
使用strace跟踪系统调用:
bash复制
strace ./gps_read /dev/ttymxc5
5. 进阶优化与扩展
5.1 性能优化建议
- 使用select/poll实现多路复用,避免忙等待
- 增加数据校验(NMEA协议的校验和验证)
- 实现环形缓冲区存储GPS数据,提高处理效率
5.2 功能扩展思路
- 增加GPS数据持久化存储功能
- 实现基于GPS的简单导航应用
- 结合地图API显示当前位置
- 增加运动轨迹记录功能
5.3 其他串口设备适配
相同的代码框架可以适配其他串口设备,只需修改:
- 串口设备路径(/dev/ttyXXX)
- 通信参数(波特率、数据位等)
- 数据解析逻辑
6. 经验总结与注意事项
在实际开发中,有几个关键点需要特别注意:
- 串口权限问题:普通用户可能需要sudo或修改udev规则
- 波特率匹配:必须与设备设置完全一致
- 数据接收不完整:适当增加读取缓冲区大小
- 多线程安全:如果多线程访问串口,需要加锁保护
一个实用的调试技巧:可以先在PC上用USB转串口工具测试GPS模块,确认模块工作正常后再移植到嵌入式平台。这样可以快速定位是硬件问题还是软件问题。