公司动态
多星座GNSS NMEA-0183协议解析与FPGA硬件实现
1. 多星座GNSS与NMEA-0183协议基础全球导航卫星系统GNSS已经发展成包含GPS、北斗、GLONASS和伽利略在内的多星座体系。这些系统虽然来自不同国家但都遵循NMEA-0183这一通用通信协议标准。我第一次接触这个协议时发现它就像不同国家的人用同一种语言交流——虽然卫星系统各异但输出的数据格式却高度统一。NMEA-0183协议采用ASCII文本格式每条语句以$符号开头以回车换行符结束。以最常见的GGA语句为例$GPGGA代表GPS系统数据$GBGGA代表北斗系统数据但它们的字段结构完全一致。这种设计让多星座数据处理变得异常简单我们只需要关注报文头两个字符就能区分数据来源。在实际项目中我遇到过GPS信号被高楼遮挡的情况。这时如果能同时接收北斗信号定位连续性会大幅提升。多星座融合的优势就在于当某个系统信号弱时其他系统可以补上。NMEA-0183的GN前缀如$GNGGA就是为多星座数据融合设计的它会自动选择最优的定位结果输出。2. GGA报文深度解析实战GGAGlobal Positioning System Fix Data是定位信息的核心报文包含时间、经纬度、海拔等关键数据。让我们拆解一个真实案例$GPGGA,092725.00,4717.11399,N,00833.91590,E,1,08,1.01,499.6,M,48.0,M,,*5B这个报文看着像天书其实结构很有规律。每个逗号分隔一个字段字段1$GPGGA是报文头字段2092725.00表示UTC时间09时27分25.00秒字段3/44717.11399,N表示北纬47度17.11399分字段5/600833.91590,E表示东经8度33.91590分字段9499.6是海拔高度米经纬度的度分格式需要特别注意。4717.11399要转换成十进制先取前两位47度剩余17.11399分除以60得到0.28523度最终是47.28523°N。我在早期项目中就踩过这个坑直接读取原始数据导致定位偏移了几公里。报文末尾的5B是校验和用于验证数据完整性。校验算法很简单对$和之间的所有字符做异或运算。这个步骤看似简单但在工业环境中能有效过滤电磁干扰导致的错误数据。3. FPGA硬件解析架构设计在FPGA上实现NMEA解析器需要考虑资源占用和实时性的平衡。根据我的工程经验推荐采用三级流水线架构UART接收层配置波特率通常9600bps每个字节触发rx_done信号。这里要注意消除亚稳态我通常用双寄存器同步处理异步信号。协议解析层这是核心模块需要识别报文头、提取字段、转换数据格式。状态机是最佳选择我用过的最稳定设计包含以下状态IDLE等待$字符HEADER识别xxGGA前缀FIELD处理各个字段CHECK验证校验和数据输出层将解析后的结构化数据存入寄存器供主控读取。建议添加数据有效信号避免读取到中间状态。资源优化方面可以复用字符处理电路。比如经纬度的度分转换和海拔处理可以共用乘法器。在Xilinx Artix-7上实测整个解析器仅需300个LUT和5个Block RAM即使低端FPGA也能轻松胜任。4. 多协议兼容性实现技巧处理多星座数据时GPGGA、GBGGA等报文只有头两字符不同。我的做法是用一个4位状态寄存器标识系统来源always (posedge clk) begin if(rx_char $) begin sys_flag 4b0000; // 重置来源标志 end else if(cntChar 1) begin case(rx_char) G: sys_flag[0] 1b1; // GPS B: sys_flag[1] 1b1; // 北斗 L: sys_flag[2] 1b1; // GLONASS A: sys_flag[3] 1b1; // 伽利略 endcase end end这样后续处理无需修改只需在输出时附带sys_flag即可。我曾用这个方法在同一个解析器上同时处理四系统数据实测功耗仅增加3%。对于GNGGA这种融合数据建议优先使用。它的定位精度通常比单系统高30%以上特别是在城市峡谷环境中。我在上海陆家嘴的测试显示单GPS的定位误差在15米左右而GNGGA能控制在8米内。5. 时序优化与异常处理FPGA处理串口数据最容易出现的问题就是溢出。当主频为50MHz时处理9600bps的串口数据看似充裕但实际要考虑以下情况连续报文无间隔时缓冲区可能溢出校验失败需要丢弃整条报文字段长度异常如海拔出现非数字字符我的解决方案是设计一个16字节的FIFO缓冲配合超时机制// 超时计数器 always (posedge clk) begin if(rx_done) begin timeout 0; end else if(timeout 16d50000) begin timeout timeout 1; end end // 超时复位 assign packet_end (timeout 16d50000) || (rx_char \n);当两个字符间隔超过10ms50MHz时钟计数50000次或收到换行符时强制结束当前报文。这个方法在野外测试中成功过滤了99%的异常数据。对于关键字段建议添加合理性检查。比如纬度范围应在0-90度经度范围应在0-180度时间的小时部分应小于24这些检查只需简单的比较器就能实现但能有效防止错误数据导致系统异常。