文章目录
- 一、ATGM336H
- 1、简介
- 2、引脚说明
- 3、数据帧
- 二、实例代码
一、ATGM336H
1、简介
ATGM336H 是一款由中科微电子设计生产的中高精度、高性能 GNSS 定位模块。
支持的卫星系统:
支持 BDS、GPS、GALILEO、QZSS、IRNSS 等卫星导航系统,可接收 B1I、B1C、B2a、L1、L5、E1、E5a 等多频点信号,还支持 SBAS 星基增强系统。
性能指标:
水平定位精度(CEP50)可达 1.0m;冷启动时间为 20s,热启动时间为 1s,重捕获时间为 1s;跟踪灵敏度可达 - 162dBm,冷启动捕获灵敏度为 - 148dBm。
功耗与供电:
功耗为 31mA@3.3V,主电源供电电压为 2.7V 至 3.6V。
数据输出:
输出频率最高为 10Hz,默认波特率为 115200,数据格式为 NMEA0183。
尺寸与封装:
封装尺寸为 10.1mm×9.7mm×2.1mm。
特点:
模块提供标准的 UART 串行接口,也可选择支持 I2C 接口,内置 1PPS 秒脉冲输出,可提供高精度的时间同步信号。此外,模块还支持 AGNSS 功能,可利用网络辅助数据加速定位。
应用领域:
适用于共享单车、电单车、宠物跟踪器等多种场景,还可用于车载导航、便携式手持设备、无人机、物联网设备等。
2、引脚说明
如果单纯做定位,只需要前4个引脚即可,也即PPS引脚用不到,所以我们PPS这个引脚可以不接,空着就行。
3、数据帧
GPS模块通过串口将数据发给主控芯片,ATGM336H会一次性返回多条信息,其中信息头的第一个是消息ID,标示着通过什么定位系统的采集的数据。
本次学习只关注“GNRMC”信息。
$GNRMC,121520.000,A,3438.1766,N,11224.5016,E,0.08,292.36,140816,A*77
二、实例代码
在LCD1602上显示经纬度。
#include<REGX52.H>#include<string.h>#include<stdio.h>#include<stdlib.h>#include<math.h>#include"LCD1602.h"// 定义串口缓冲区大小(根据实际GPS波特率/数据长度调整)#defineGPRMC_BUF_SIZE80// 经纬度放大倍数(用整数代替浮点:如48.1173° → 481173,避免浮点运算)#defineLAT_LON_SCALE10000// 串口接收缓冲区相关#defineUART_BUF_SIZE100// 串口接收缓冲区大小(可容纳完整GPRMC语句)// 全局变量:串口接收缓冲区(中断中使用,需全局)unsignedcharuart_buf[UART_BUF_SIZE];// 存储接收到的串口数据unsignedintuart_buf_idx=0;// 缓冲区索引bit gprmc_ready=0;// GPRMC语句接收完成标志// GPRMC解析结果结构体typedefstruct{unsignedcharvalid;// 定位有效性:1=有效(A),0=无效(V)unsignedcharutc_time[7];// UTC时间 hhmmss(6位+结束符)unsignedcharutc_date[7];// UTC日期 ddmmyy(6位+结束符)longlatitude;// 纬度(十进制*10000,如48.1173°→481173)longlongitude;// 经度(十进制*10000,如11.5167°→115167)unsignedcharlat_dir;// 纬度方向:'N'/'S'unsignedcharlon_dir;// 经度方向:'E'/'W'unsignedintspeed_knots;// 速度(节,放大10倍:22.4→224)unsignedintcourse;// 航向(度,放大10倍:84.4→844)}GPRMC_Data;// 全局/局部解析结果存储(根据实际需求调整存储位置)GPRMC_Data gprmc_data;// ------------------- 经纬度转字符串函数 -------------------/** * @brief 将纬度转换为字符串(如 481173 → "48.1173°N") * @param lat: 解析后的纬度整数(放大10000倍) * @param lat_dir: 纬度方向('N'/'S') * @param str_buf: 输出字符串缓冲区(至少12字节:如"-12.3456°S") * @retval 0:失败,1:成功 */unsignedcharLat2Str(longlat,unsignedcharlat_dir,unsignedchar*str_buf){longabs_lat=0;unsignedintint_part=0;unsignedintdec_part=0;if(str_buf==NULL)return0;memset(str_buf,0,12);// 初始化缓冲区abs_lat=lat>0?lat:-lat;// 取绝对值(处理负数)int_part=abs_lat/LAT_LON_SCALE;// 整数部分(481173→48)dec_part=abs_lat%LAT_LON_SCALE;// 小数部分(481173→1173)// 拼接字符串:符号(可选)+ 整数.小数 + ° + 方向if(lat<0){sprintf((char*)str_buf,"-%d.%04d %c",int_part,dec_part,lat_dir);}else{sprintf((char*)str_buf,"%d.%04d %c",int_part,dec_part,lat_dir);}return1;}/** * @brief 将经度转换为字符串(如 115167 → "11.5167°E") * @param lon: 解析后的经度整数(放大10000倍) * @param lon_dir: 经度方向('E'/'W') * @param str_buf: 输出字符串缓冲区(至少12字节) * @retval 0:失败,1:成功 */unsignedcharLon2Str(longlon,unsignedcharlon_dir,unsignedchar*str_buf){longabs_lon=0;unsignedintint_part=0;unsignedintdec_part=0;if(str_buf==NULL)return0;memset(str_buf,0,12);abs_lon=lon>0?lon:-lon;int_part=abs_lon/LAT_LON_SCALE;dec_part=abs_lon%LAT_LON_SCALE;if(lon<0){sprintf((char*)str_buf,"-%d.%04d %c",int_part,dec_part,lon_dir);}else{sprintf((char*)str_buf,"%d.%04d %c",int_part,dec_part,lon_dir);}return1;}unsignedcharParseGPRMC(unsignedchar*gprmc_buf,GPRMC_Data*p_data){unsignedchar*ptr=NULL;unsignedcharfield_idx=0;// 字段索引(对应GPRMC各字段)unsignedcharfield_buf[20];// 单个字段缓冲区unsignedcharbuf_idx=0;// 1. 基础校验:非空、以$GPRMC开头if(gprmc_buf==NULL||p_data==NULL)return0;if(strstr((char*)gprmc_buf,"$GPRMC")==NULL)return0;// 2. 初始化解析结果结构体memset(p_data,0,sizeof(GPRMC_Data));// 3. 按逗号分割字段(核心解析逻辑)ptr=gprmc_buf;while(*ptr!='\0'&&field_idx<=12)// GPRMC共13个核心字段(0-12){if(*ptr==','||*ptr=='*')// 字段分隔符或校验和起始符{field_buf[buf_idx]='\0';// 字段结束符buf_idx=0;// 重置字段缓冲区索引// 4. 按字段索引解析对应数据switch(field_idx){case1:// UTC时间(hhmmss)if(strlen((char*)field_buf)==6){strcpy((char*)p_data->utc_time,(char*)field_buf);}break;case2:// 状态(A=有效,V=无效)if(field_buf[0]=='A'){p_data->valid=1;}elseif(field_buf[0]=='V'){p_data->valid=0;}else{return0;// 状态非法,解析失败}break;case3:// 纬度(ddmm.mmmm)if(strlen((char*)field_buf)>=5){// 提取度(前2位)和分(后几位),转换为十进制整数unsignedintdeg=atoi((char*)field_buf);unsignedintmin=atoi((char*)field_buf+2);floatlat_float=(deg/100)+(min%100+(atof((char*)field_buf+4))/10000)/60.0;p_data->latitude=(long)(lat_float*LAT_LON_SCALE);}break;case4:// 纬度方向(N/S)p_data->lat_dir=field_buf[0];if(p_data->lat_dir=='S'){p_data->latitude=-p_data->latitude;// 南半球取负}break;case5:// 经度(dddmm.mmmm)if(strlen((char*)field_buf)>=6){unsignedintdeg=atoi((char*)field_buf);unsignedintmin=atoi((char*)field_buf+3);floatlon_float=(deg/100)+(min%100+(atof((char*)field_buf+5))/10000)/60.0;p_data->longitude=(long)(lon_float*LAT_LON_SCALE);}break;case6:// 经度方向(E/W)p_data->lon_dir=field_buf[0];if(p_data->lon_dir=='W'){p_data->longitude=-p_data->longitude;// 西半球取负}break;case7:// 速度(节),放大10倍存储(22.4→224)p_data->speed_knots=(unsignedint)(atof((char*)field_buf)*10);break;case8:// 航向(度),放大10倍存储(84.4→844)p_data->course=(unsignedint)(atof((char*)field_buf)*10);break;case9:// UTC日期(ddmmyy)if(strlen((char*)field_buf)==6){strcpy((char*)p_data->utc_date,(char*)field_buf);}break;default:break;}field_idx++;// 下一个字段if(*ptr=='*')break;// 校验和之后无有效字段,退出循环}else{// 存储当前字符到字段缓冲区(避免缓冲区溢出)if(buf_idx<sizeof(field_buf)-1){field_buf[buf_idx++]=*ptr;}}ptr++;// 下一个字符}// 5. 最终校验:必须包含有效状态和经纬度if(p_data->valid==0||p_data->latitude==0||p_data->longitude==0){return0;}return1;// 解析成功}// ------------------- 串口初始化函数(必须先初始化) -------------------voidUART_Init(void){TMOD|=0x20;// 定时器1工作在模式2(8位自动重装)TH1=0xFD;// 波特率9600(晶振11.0592MHz)TL1=0xFD;TR1=1;// 启动定时器1SCON=0x50;// 串口工作在模式1,允许接收(REN=1)EA=1;// 开启总中断ES=1;// 开启串口中断}// ------------------- 串口接收中断服务函数(核心) -------------------voidRECEIVE_DATA(void)interrupt4using3{unsignedcharrecv_char;// 接收的单个字符// 1. 清除中断标志(必须!否则会重复进入中断)if(RI)// RI=1表示串口接收到一个字符{RI=0;// 清除接收中断标志recv_char=SBUF;// 读取接收寄存器中的字符// 2. 数据缓存:存储字符到缓冲区,避免溢出if(uart_buf_idx<UART_BUF_SIZE-1){// 关键:GPRMC语句以换行符(\n或\r)结束,以此判断接收完成if(recv_char=='\n'||recv_char=='\r'){uart_buf[uart_buf_idx]='\0';// 字符串结束符// 判断是否是GPRMC语句(以$GPRMC开头)if(strstr((char*)uart_buf,"$GPRMC")!=NULL){gprmc_ready=1;// 标记GPRMC语句接收完成}uart_buf_idx=0;// 重置缓冲区,准备接收下一条语句}else{uart_buf[uart_buf_idx++]=recv_char;// 存储字符}}else{// 缓冲区溢出,重置(避免数据错乱)uart_buf_idx=0;memset(uart_buf,0,UART_BUF_SIZE);}}}voidmain(){// 模拟GPS串口接收的GPRMC数据// unsigned char gprmc_test[] = "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A";unsignedcharlat_str[12];// 纬度字符串缓冲区unsignedcharlon_str[12];// 经度字符串缓冲区LCD_Init();UART_Init();// 初始化串口(必须先执行)while(1){// 检测GPRMC语句是否接收完成if(gprmc_ready){gprmc_ready=0;// 清除标志// 解析GPRMC数据if(ParseGPRMC(uart_buf,&gprmc_data)){// 经纬度转字符串Lat2Str(gprmc_data.latitude,gprmc_data.lat_dir,lat_str);Lon2Str(gprmc_data.longitude,gprmc_data.lon_dir,lon_str);LCD_ShowString(1,0,lat_str);LCD_ShowString(2,0,lon_str);}}}}