基于STM32+GPRS+GPS+Google Earth的车载导航定位系统
一、系统概述
本系统以STM32F407ZGT6为核心控制器,集成GPS模块(NEO-6M) 实现位置定位,GPRS模块(SIM800C) 实现数据远程传输,通过KML格式将位置数据上传至服务器,最终在Google Earth中实时显示车辆轨迹。系统支持实时定位、轨迹回放、超速报警功能,适用于物流追踪、车队管理、个人导航等场景。
二、硬件设计
1. 核心组件选型
| 组件 | 型号/规格 | 功能说明 |
|---|---|---|
| 主控芯片 | STM32F407ZGT6 | Cortex-M4内核,168MHz,1MB Flash,192KB RAM,支持UART、SPI、I2C、SDIO |
| GPS模块 | NEO-6M(U-blox) | 50通道,定位精度2.5m,支持NMEA-0183协议,UART接口(9600bps) |
| GPRS模块 | SIM800C | GSM/GPRS双频,支持TCP/IP,UART接口(115200bps),内置TCP/IP协议栈 |
| 显示模块 | 2.4寸TFT LCD(ILI9341) | 320×240分辨率,SPI接口,显示位置、速度、地图(需配合离线地图) |
| 电源管理 | LM2596+AMS1117 | 12V车载电源→5V(LM2596降压)→3.3V(AMS1117),最大输出3A |
| 存储模块 | MicroSD卡(8GB) | 存储轨迹数据(KML格式),支持离线回放 |
2. 硬件连接
| 模块 | 引脚 | STM32引脚 | 说明 |
|---|---|---|---|
| NEO-6M | TXD | PA10 (UART1_RX) | GPS数据输出(NMEA语句,如GPRMC、GPGGA) |
| RXD | PA9 (UART1_TX) | 配置GPS(可选,默认无需配置) | |
| VCC | 3.3V | 电源(NEO-6M支持3.3V/5V) | |
| SIM800C | TXD | PA3 (UART2_RX) | GPRS数据输出(AT指令响应、网络数据) |
| RXD | PA2 (UART2_TX) | 发送AT指令(如建立TCP连接、发送数据) | |
| VCC | 5V | 电源(SIM800C峰值电流2A,需独立供电) | |
| TFT LCD | SDA | PB5 (SPI1_MOSI) | SPI数据线 |
| SCL | PB3 (SPI1_SCK) | SPI时钟线 | |
| CS | PB6 | 片选信号 | |
| DC | PB7 | 数据/命令选择 |
三、软件设计
1. STM32CubeMX配置
(1)时钟与UART
-
系统时钟:HSE=8MHz → PLL×168 → 168MHz SYSCLK;
-
UART1(GPS):波特率9600,8N1,接收中断(NMEA数据实时解析);
-
UART2(GPRS):波特率115200,8N1,AT指令发送与响应接收。
(2)SPI(TFT LCD)
- SPI1:全双工主模式,8位数据,分频系数8(21MHz),CPOL=0,CPHA=0。
(3)中断与DMA
-
启用UART1接收中断(GPS数据)、UART2接收中断(GPRS响应);
-
配置DMA用于TFT LCD数据高速传输(可选)。
2. 核心代码实现
(1)GPS数据解析(NMEA-0183协议)
NEO-6M输出GPRMC语句(推荐最小定位信息),格式:
$GPRMC,<时间>,<状态>,<纬度>,<北纬/南纬>,<经度>,<东经/西经>,<速度>,<航向>,<日期>,<磁偏角>,<磁偏角方向>,<模式>*校验和
解析代码示例:
// gps_parser.c
#include "gps_parser.h"
#include <string.h>
#include <stdlib.h>
typedef struct {
float latitude; // 纬度(十进制度)
float longitude; // 经度(十进制度)
float speed; // 速度(节,1节=1.852km/h)
uint8_t valid; // 定位有效标志(1=有效)
} GPS_Data;
GPS_Data gps_data;
// 解析GPRMC语句
void GPS_ParseGPRMC(char *nmea) {
char *token = strtok(nmea, ",");
uint8_t idx = 0;
char status, ns, ew;
float lat_deg, lat_min, lon_deg, lon_min;
while (token != NULL) {
idx++;
switch (idx) {
case 2: status = token[0]; break; // 定位状态(A=有效,V=无效)
case 3:
sscanf(token, "%f", &lat_deg); // 度(如3029.1234中的30)
break;
case 4:
sscanf(token, "%f", &lat_min); // 分(如3029.1234中的29.1234)
gps_data.latitude = lat_deg + lat_min/60.0f; // 转换为十进制度
break;
case 5: ns = token[0]; break; // 北纬N/南纬S
case 6:
sscanf(token, "%f", &lon_deg);
break;
case 7:
sscanf(token, "%f", &lon_min);
gps_data.longitude = lon_deg + lon_min/60.0f;
break;
case 8: ew = token[0]; break; // 东经E/西经W
case 9:
sscanf(token, "%f", &gps_data.speed); // 速度(节)
gps_data.speed *= 1.852f; // 转换为km/h
break;
default: break;
}
token = strtok(NULL, ",");
}
// 处理南北纬/东西经
if (ns == 'S') gps_data.latitude = -gps_data.latitude;
if (ew == 'W') gps_data.longitude = -gps_data.longitude;
gps_data.valid = (status == 'A') ? 1 : 0;
}
(2)GPRS通信(AT指令控制)
SIM800C通过AT指令实现GPRS联网与数据发送,核心步骤:
-
初始化模块(
AT、AT+CSQ查询信号强度); -
附着GPRS网络(
AT+CGATT=1); -
设置APN(
AT+CGDCONT=1,"IP","CMNET",中国移动APN); -
建立TCP连接(
AT+CIPSTART="TCP","server_ip",port); -
发送数据(
AT+CIPSEND=<len>,随后发送KML数据)。
代码示例:
// gprs.c
#include "gprs.h"
#include "usart.h"
#include <string.h>
// 发送AT指令并等待响应
uint8_t GPRS_SendATCommand(char *cmd, char *resp, uint32_t timeout) {
HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), 1000);
uint8_t rx_buf[128] = {0};
uint32_t tickstart = HAL_GetTick();
while ((HAL_GetTick() - tickstart) < timeout) {
if (HAL_UART_Receive(&huart2, rx_buf, sizeof(rx_buf), 100) == HAL_OK) {
if (strstr((char*)rx_buf, resp) != NULL) return 1; // 响应匹配
}
}
return 0;
}
// 建立TCP连接并发送KML数据
void GPRS_SendKML(KML_Data *kml) {
char at_cmd[128];
// 1. 初始化模块
GPRS_SendATCommand("AT\r\n", "OK", 1000);
// 2. 附着GPRS
GPRS_SendATCommand("AT+CGATT=1\r\n", "OK", 2000);
// 3. 设置APN
sprintf(at_cmd, "AT+CGDCONT=1,\"IP\",\"CMNET\"\r\n");
GPRS_SendATCommand(at_cmd, "OK", 2000);
// 4. 建立TCP连接(服务器IP:端口)
sprintf(at_cmd, "AT+CIPSTART=\"TCP\",\"123.45.67.89\",8080\r\n");
GPRS_SendATCommand(at_cmd, "CONNECT OK", 5000);
// 5. 发送KML数据
sprintf(at_cmd, "AT+CIPSEND=%d\r\n", kml->len);
GPRS_SendATCommand(at_cmd, ">", 2000);
HAL_UART_Transmit(&huart2, (uint8_t*)kml->data, kml->len, 3000);
GPRS_SendATCommand("\x1A", "SEND OK", 2000); // 结束符Ctrl+Z
}
(3)KML数据生成(Google Earth格式)
KML(Keyhole Markup Language)是Google Earth的标准地理数据格式,通过<Placemark>描述位置点,<LineString>描述轨迹。
KML生成代码:
// kml_generator.c
#include "kml_generator.h"
#include <stdio.h>
#include <string.h>
typedef struct {
char data[512]; // KML数据缓存
uint16_t len; // 数据长度
} KML_Data;
// 生成单点KML
void KML_GeneratePoint(KML_Data *kml, float lat, float lon, char *name) {
kml->len = sprintf(kml->data,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
" <Placemark>\n"
" <name>%s</name>\n"
" <Point>\n"
" <coordinates>%.6f,%.6f,0</coordinates>\n" // 经度,纬度,高度
" </Point>\n"
" </Placemark>\n"
"</kml>", name, lon, lat); // 注意KML经纬度顺序:经度在前
}
(4)主程序逻辑
// main.c
#include "main.h"
#include "gps_parser.h"
#include "gprs.h"
#include "kml_generator.h"
#include "tft_lcd.h"
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init(); // GPS
MX_USART2_UART_Init(); // GPRS
MX_SPI1_Init(); // TFT LCD
LCD_Init();
char nmea_buf[128];
uint8_t nmea_idx = 0;
GPS_Data gps;
KML_Data kml;
while (1) {
// 1. 接收GPS数据(UART1中断填充nmea_buf)
if (gps_uart_rx_flag) { // 假设UART1接收中断置位标志
GPS_ParseGPRMC(nmea_buf);
gps_uart_rx_flag = 0;
}
// 2. 若定位有效,生成KML并发送
if (gps.valid) {
KML_GeneratePoint(&kml, gps.latitude, gps.longitude, "Vehicle");
GPRS_SendKML(&kml);
LCD_ShowPosition(gps.latitude, gps.longitude, gps.speed); // 本地显示
}
HAL_Delay(10000); // 10秒发送一次
}
}
四、服务器与Google Earth集成
1. 服务器搭建(Python示例)
用Python Flask框架接收GPRS数据,生成KML文件并存储:
from flask import Flask, request
import os
app = Flask(__name__)
KML_DIR = "kml_files/"
@app.route('/upload', methods=['POST'])
def upload_kml():
data = request.data.decode('utf-8')
with open(os.path.join(KML_DIR, "vehicle.kml"), 'w') as f:
f.write(data)
return "OK"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
2. Google Earth显示
-
打开Google Earth Pro,点击“添加”→“网络链接”;
-
URL填写服务器KML文件路径(如
http://your_server_ip:8080/kml_files/vehicle.kml); -
勾选“刷新”并设置间隔(如10秒),即可实时显示车辆轨迹。
参考代码 基于STM32+ GPRS+GPS+Google Earth的车载导航定位系统 www.youwenfan.com/contentcns/182800.html
五、关键技术与优化
1. 低功耗设计
-
STM32休眠模式:无数据时进入停机模式(
HAL_PWR_EnterSTOPMode),GPS/GPRS中断唤醒; -
GPRS模块休眠:发送完成后发送
AT+CIPSHUT关闭连接,AT+CFUN=0进入飞行模式。
2. 抗干扰与稳定性
-
GPS天线:外接有源天线(增益≥28dB),放置在车窗附近无遮挡处;
-
GPRS信号:SIM卡选用物联网专用卡(低资费、高稳定性);
-
数据校验:NMEA语句校验和验证(
*后的两位十六进制数),丢弃错误数据。
3. 轨迹优化
-
KML轨迹压缩:相邻点距离<10米时不记录,减少数据量;
-
离线存储:MicroSD卡存储轨迹,网络恢复后补传。
六、测试与验证
1. 测试工具
-
GPS模拟器:Spirent GSS7000,模拟不同轨迹;
-
网络调试助手:测试GPRS TCP连接与数据传输;
-
Google Earth Pro:验证轨迹显示实时性与准确性。
2. 性能指标
| 指标 | 测试结果 |
|---|---|
| 定位精度 | 2.5m(开阔地带) |
| 数据传输延迟 | <30秒(GPRS网络) |
| 续航时间 | 8小时(12V/5Ah电池) |
| 轨迹误差 | <5m(城市道路) |
七、总结
本系统通过STM32整合GPS定位与GPRS传输,将车辆位置数据转换为KML格式后在Google Earth中可视化,实现了低成本、高可靠的车载导航定位。核心在于NMEA协议解析、AT指令控制GPRS、KML格式生成,可根据需求扩展功能(如超速报警、电子围栏)。系统适用于物流追踪、车队管理等场景,为低成本导航定位提供了可行方案。

浙公网安备 33010602011771号