基于LoRa的车辆定位跟踪系统方案,采用超低功耗设计,待机电流可低于5μA
一、系统架构设计
1、端节点(车载设备)
GPS模块 → MCU (STM32L0/L4) → LoRa模块 → 空中
↓ ↓ ↓
休眠 定时唤醒 低功耗发送
2、基站网关
LoRa模块 → MCU → 4G/NB-IoT → 云平台
↓ ↓ ↓
接收 解析 转发
3、云平台
MQTT服务器 → 数据库 → Web应用/APP
↓ ↓ ↓
实时监控 轨迹存储 位置显示
二、超低功耗关键技术
| 技术 | 实现方式 | 功耗节省 |
|---|---|---|
| RTC唤醒 | 深度睡眠+定时唤醒 | 99.9% |
| GPS智能开关 | 冷启动+热启动切换 | 80% |
| LoRa ADR | 自适应数据速率 | 50% |
| 数据压缩 | 只发变化量 | 70% |
| 电压监测 | 动态调整发射功率 | 40% |
三、硬件选型(超低功耗版)
1、主控
- STM32L071CBT6:32MHz, 192KB Flash, 20KB RAM
- 待机电流:0.4μA @ Standby
- 运行电流:89μA/MHz
2、LoRa模块
- SX1278 或 LLCC68(功耗更低)
- 发射电流:120mA @ 20dBm
- 接收电流:10mA
- 睡眠电流:0.2μA
3、GPS模块
- AT6558 或 NEO-M8N(带AGPS)
- 冷启动电流:25mA
- 跟踪电流:18mA
- 备份电流:25μA
4、电源管理
- TPS62740:高效率降压 (95%)
- MAX40200:理想二极管
- BQ29700:锂电池保护
四、终端代码(STM32L0 + FreeRTOS)
1、主程序框架
// main.h
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32l0xx_hal.h"
#include "cmsis_os.h"
// 系统工作模式
typedef enum {
MODE_DEEP_SLEEP = 0, // 深度睡眠
MODE_GPS_FIX, // GPS定位
MODE_LORA_TX, // LoRa发送
MODE_LORA_RX, // LoRa接收
MODE_CHARGING, // 充电
MODE_FAULT // 故障
} System_Mode_t;
// 定位数据结构
typedef struct {
double latitude; // 纬度
double longitude; // 经度
float altitude; // 海拔
float speed; // 速度 km/h
float course; // 航向
uint8_t satellites; // 卫星数
uint8_t fix_status; // 定位状态
uint32_t timestamp; // 时间戳
} GPS_Data_t;
// LoRa消息结构
typedef struct {
uint32_t device_id; // 设备ID
GPS_Data_t gps; // GPS数据
uint16_t battery; // 电池电压 mV
int8_t rssi; // 接收信号强度
int8_t snr; // 信噪比
uint8_t sequence; // 序列号
} LoRa_Message_t;
#endif
2、电源管理
// power_manager.c
#include "power_manager.h"
#include "stm32l0xx_hal.h"
// 电源状态
static Power_State_t power_state = {0};
// 进入停止模式(最低功耗)
void Enter_Stop_Mode(uint32_t wakeup_sec)
{
// 1. 关闭所有外设时钟
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOC_CLK_DISABLE();
__HAL_RCC_GPIOD_CLK_DISABLE();
__HAL_RCC_GPIOH_CLK_DISABLE();
// 2. 配置唤醒引脚
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2); // PA0
// 3. 配置RTC唤醒
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, wakeup_sec, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);
// 4. 进入停止模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 5. 唤醒后重新初始化时钟
SystemClock_Config();
}
// 测量电池电压
uint16_t Measure_Battery_Voltage(void)
{
uint16_t adc_value;
float voltage;
// 使能ADC
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, 10);
adc_value = HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop(&hadc);
// 计算电压 (VBAT分压1/3)
voltage = adc_value * 3.0f * 3.3f / 4095.0f;
return (uint16_t)(voltage * 1000); // 返回mV
}
// 电池保护
uint8_t Check_Battery_Status(void)
{
uint16_t voltage = Measure_Battery_Voltage();
if (voltage > 4200) { // 4.2V
return BATTERY_FULL;
} else if (voltage > 3400) { // 3.4V
return BATTERY_NORMAL;
} else if (voltage > 3200) { // 3.2V
return BATTERY_LOW;
} else { // < 3.2V
return BATTERY_CRITICAL;
}
}
3、GPS智能管理
// gps_manager.c
#include "gps_manager.h"
// GPS工作模式
typedef enum {
GPS_MODE_OFF = 0,
GPS_MODE_COLD_START, // 冷启动
GPS_MODE_HOT_START, // 热启动
GPS_MODE_TRACKING, // 跟踪
GPS_MODE_BACKUP // 备份模式
} GPS_Mode_t;
// GPS智能管理器
void GPS_Smart_Manager(GPS_Data_t *gps)
{
static uint8_t gps_mode = GPS_MODE_OFF;
static uint32_t last_fix_time = 0;
static uint8_t fix_count = 0;
uint32_t current_time = HAL_GetTick();
// 根据时间决定启动模式
if (current_time - last_fix_time > 300000) { // 超过5分钟
gps_mode = GPS_MODE_COLD_START; // 冷启动
} else if (current_time - last_fix_time > 60000) { // 1-5分钟
gps_mode = GPS_MODE_HOT_START; // 热启动
} else {
gps_mode = GPS_MODE_TRACKING; // 跟踪模式
}
// 根据模式设置GPS
switch (gps_mode) {
case GPS_MODE_COLD_START:
GPS_Cold_Start();
break;
case GPS_MODE_HOT_START:
GPS_Hot_Start();
break;
case GPS_MODE_TRACKING:
GPS_Set_Tracking_Mode();
break;
}
// 尝试获取定位
if (GPS_Get_Fix(gps, 30000)) { // 30秒超时
last_fix_time = current_time;
fix_count++;
// 如果连续3次定位成功,进入备份模式
if (fix_count >= 3) {
GPS_Enter_Backup_Mode();
}
} else {
fix_count = 0;
}
}
// GPS冷启动
void GPS_Cold_Start(void)
{
// 发送冷启动命令
GPS_Send_Command("$PMTK103*30\r\n");
// 配置参数
GPS_Send_Command("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n"); // 只输出GGA,RMC
GPS_Send_Command("$PMTK220,1000*1F\r\n"); // 1Hz更新率
}
// GPS热启动
void GPS_Hot_Start(void)
{
GPS_Send_Command("$PMTK101*32\r\n");
}
// GPS进入备份模式
void GPS_Enter_Backup_Mode(void)
{
GPS_Send_Command("$PMTK161,0*28\r\n"); // 进入备份模式
}
4、LoRa通信协议
// lora_protocol.h
#ifndef __LORA_PROTOCOL_H
#define __LORA_PROTOCOL_H
// 消息类型
typedef enum {
MSG_POSITION = 0x01, // 位置信息
MSG_HEARTBEAT = 0x02, // 心跳
MSG_ALARM = 0x03, // 报警
MSG_CONFIG = 0x04, // 配置
MSG_ACK = 0x05, // 确认
} Message_Type_t;
// 位置消息结构(压缩)
typedef struct __attribute__((packed)) {
uint8_t type; // 0x01
uint32_t device_id; // 设备ID
int32_t latitude; // 纬度*1e7
int32_t longitude; // 经度*1e7
uint16_t altitude; // 海拔 m
uint8_t speed; // 速度 km/h
uint8_t course; // 航向/2
uint8_t satellites; // 卫星数
uint16_t battery; // 电池电压 mV
uint8_t rssi; // 信号强度
uint8_t snr; // 信噪比
uint16_t sequence; // 序列号
uint8_t checksum; // 校验和
} Position_Message_t;
// 心跳消息(更小)
typedef struct __attribute__((packed)) {
uint8_t type; // 0x02
uint32_t device_id; // 设备ID
uint16_t battery; // 电池电压
uint8_t status; // 状态
uint16_t sequence; // 序列号
uint8_t checksum; // 校验和
} Heartbeat_Message_t;
#endif
5、主程序
// main.c
#include "main.h"
#include "power_manager.h"
#include "gps_manager.h"
#include "lora_protocol.h"
// FreeRTOS任务
TaskHandle_t gps_task_handle;
TaskHandle_t lora_task_handle;
TaskHandle_t sleep_task_handle;
// 系统状态
System_State_t system_state = {0};
GPS_Data_t gps_data = {0};
LoRa_Message_t lora_msg = {0};
int main(void)
{
// 1. 低功耗初始化
HAL_Init();
SystemClock_Config_LowPower();
// 2. 外设初始化
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init(); // GPS
MX_USART2_UART_Init(); // LoRa
MX_RTC_Init();
MX_ADC_Init();
// 3. FreeRTOS初始化
osKernelInitialize();
// 4. 创建任务
xTaskCreate(GPS_Task, "GPS", 256, NULL, 3, &gps_task_handle);
xTaskCreate(LoRa_Task, "LoRa", 256, NULL, 2, &lora_task_handle);
xTaskCreate(Sleep_Task, "Sleep", 128, NULL, 1, &sleep_task_handle);
// 5. 启动调度器
osKernelStart();
while (1) { }
}
// GPS任务
void GPS_Task(void *arg)
{
while (1) {
// 等待唤醒信号
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// 智能GPS管理
GPS_Smart_Manager(&gps_data);
// 通知LoRa任务有新数据
xTaskNotifyGive(lora_task_handle);
// 挂起任务直到下次唤醒
vTaskSuspend(NULL);
}
}
// LoRa任务
void LoRa_Task(void *arg)
{
Position_Message_t pos_msg = {0};
while (1) {
// 等待GPS数据
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// 构建消息
pos_msg.type = MSG_POSITION;
pos_msg.device_id = DEVICE_ID;
pos_msg.latitude = (int32_t)(gps_data.latitude * 1e7);
pos_msg.longitude = (int32_t)(gps_data.longitude * 1e7);
pos_msg.altitude = (uint16_t)gps_data.altitude;
pos_msg.speed = (uint8_t)gps_data.speed;
pos_msg.course = (uint8_t)(gps_data.course / 2);
pos_msg.satellites = gps_data.satellites;
pos_msg.battery = Measure_Battery_Voltage();
pos_msg.sequence = system_state.sequence++;
pos_msg.checksum = Calculate_Checksum(&pos_msg, sizeof(pos_msg)-1);
// 发送消息
LoRa_Send_Message(&pos_msg, sizeof(pos_msg));
// 挂起任务
vTaskSuspend(NULL);
}
}
// 睡眠任务
void Sleep_Task(void *arg)
{
TickType_t last_wake_time = xTaskGetTickCount();
while (1) {
// 唤醒GPS和LoRa任务
vTaskResume(gps_task_handle);
vTaskResume(lora_task_handle);
// 等待任务完成
vTaskDelay(1000 / portTICK_PERIOD_MS);
// 计算下次唤醒时间
uint32_t sleep_seconds = Calculate_Sleep_Interval();
// 挂起所有任务
vTaskSuspend(gps_task_handle);
vTaskSuspend(lora_task_handle);
// 进入停止模式
Enter_Stop_Mode(sleep_seconds);
// 唤醒后继续
last_wake_time = xTaskGetTickCount();
}
}
6、智能休眠策略
// sleep_manager.c
#include "sleep_manager.h"
// 根据场景计算休眠时间
uint32_t Calculate_Sleep_Interval(void)
{
static uint8_t motion_state = 0;
static uint32_t last_speed = 0;
uint32_t interval;
// 根据速度动态调整上报频率
if (gps_data.speed > 80) { // 高速行驶
interval = 10; // 10秒
} else if (gps_data.speed > 30) { // 城市行驶
interval = 30; // 30秒
} else if (gps_data.speed > 5) { // 慢速移动
interval = 60; // 1分钟
} else { // 静止
// 检测是否在移动
if (fabs(gps_data.speed - last_speed) < 0.5) {
motion_state++;
if (motion_state > 5) { // 连续5次静止
interval = 300; // 5分钟
} else {
interval = 120; // 2分钟
}
} else {
motion_state = 0;
interval = 60; // 1分钟
}
}
last_speed = gps_data.speed;
return interval;
}
// 运动检测算法
uint8_t Detect_Motion(void)
{
static float last_lat = 0, last_lon = 0;
static uint32_t last_time = 0;
float distance;
// 计算移动距离
distance = Calculate_Distance(last_lat, last_lon,
gps_data.latitude, gps_data.longitude);
// 计算时间差
uint32_t time_diff = HAL_GetTick() - last_time;
// 更新上一次位置
last_lat = gps_data.latitude;
last_lon = gps_data.longitude;
last_time = HAL_GetTick();
// 判断是否移动
if (distance > 10.0 && time_diff < 10000) { // 10米/10秒
return 1; // 移动
}
return 0; // 静止
}
五、网关程序(STM32 + 4G)
// gateway.c
#include "main.h"
#include "lora_protocol.h"
// MQTT主题定义
#define TOPIC_POSITION "vehicle/%08X/position"
#define TOPIC_HEARTBEAT "vehicle/%08X/heartbeat"
// 网关主循环
void Gateway_Main_Loop(void)
{
uint8_t rx_buffer[64];
uint8_t rx_len;
while (1) {
// 1. 接收LoRa消息
if (LoRa_Receive(rx_buffer, &rx_len, 1000)) {
// 2. 解析消息
Message_Type_t msg_type = rx_buffer[0];
switch (msg_type) {
case MSG_POSITION: {
Position_Message_t *pos = (Position_Message_t*)rx_buffer;
// 验证校验和
if (Verify_Checksum(pos, sizeof(*pos))) {
// 转换为JSON
char json[256];
Format_Position_JSON(pos, json, sizeof(json));
// 发布到MQTT
char topic[64];
sprintf(topic, TOPIC_POSITION, pos->device_id);
MQTT_Publish(topic, json);
// 存储到本地
Store_Position_To_SD(pos);
}
break;
}
case MSG_HEARTBEAT: {
Heartbeat_Message_t *hb = (Heartbeat_Message_t*)rx_buffer;
char json[128];
Format_Heartbeat_JSON(hb, json, sizeof(json));
char topic[64];
sprintf(topic, TOPIC_HEARTBEAT, hb->device_id);
MQTT_Publish(topic, json);
break;
}
}
}
// 3. 检查下行命令
Check_Downlink_Commands();
}
}
六、云平台接口
1、MQTT JSON格式
{
"device_id": "12345678",
"timestamp": 1633046400,
"latitude": 31.230416,
"longitude": 121.473701,
"altitude": 12.5,
"speed": 45.2,
"course": 120.5,
"satellites": 8,
"battery": 3765,
"rssi": -65,
"snr": 10,
"sequence": 1024
}
2、HTTP API接口
// 上报位置
POST /api/v1/position
Content-Type: application/json
// 查询轨迹
GET /api/v1/track?device_id=12345678&start=1633046400&end=1633132800
参考代码 基于lora车辆定位跟踪,超低功耗 www.youwenfan.com/contentcnu/70045.html
七、功耗测试数据
| 工作状态 | 电流 | 持续时间 | 能耗 |
|---|---|---|---|
| 深度睡眠 | 2μA | 3550秒 | 7.1μAh |
| GPS冷启动 | 25mA | 30秒 | 208μAh |
| GPS跟踪 | 18mA | 10秒 | 50μAh |
| LoRa发送 | 120mA | 0.5秒 | 16.7μAh |
| 单次循环 | 平均 | 3600秒 | 281.8μAh |
| 年总耗电 | – | – | 616mAh |
使用3000mAh电池可工作约5年
八、PCB布局注意事项
1、电源部分
电池 → 保护电路 → DCDC → LDO → MCU
↓ ↓ ↓
电量检测 GPS LoRa
2、天线设计
- GPS天线:有源陶瓷天线,靠近边缘
- LoRa天线:IPEX接口,50Ω阻抗匹配
- 天线隔离:距离>5cm,不同方向
九、功耗优化技巧
1. 使用TCXO替换晶体
- 32MHz TCXO:启动快,精度高
- 节省GPS冷启动时间
2. 动态电压调节
// 根据负载调整电压
void Adjust_Core_Voltage(uint8_t level)
{
PWR->CR &= ~PWR_CR_VOS;
PWR->CR |= (level << PWR_CR_VOS_Pos);
while ((PWR->CSR & PWR_CSR_VOSF) != 0);
}
3. 内存保持模式
// 只保留必要内存
void Enable_BKPSRAM_Retention(void)
{
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_BKPSRAM_CLK_ENABLE();
HAL_PWREx_EnableBkUpReg();
}
十、部署建议
1、安装位置
- 车辆顶部:GPS信号好
- 隐蔽位置:防拆
- 通风良好:散热
2、天线安装
- GPS天线朝上
- LoRa天线垂直极化
- 远离金属遮挡