基于北斗的户外遇险预警定位装置
项目开发背景
随着户外探险、徒步旅行和野外作业等活动的日益普及,越来越多的人投身于自然环境中寻求挑战与乐趣。然而,这些活动往往伴随着较高的风险,如迷路、跌落、突发疾病或遭遇自然灾害等。在偏远地区,传统通信网络覆盖不足,导致遇险时难以及时求助,严重威胁用户生命安全。因此,开发一种高效可靠的户外遇险预警定位装置成为迫切需求,以提升户外活动的安全性和应急救援效率。
北斗卫星导航系统作为中国自主建设的全球卫星导航系统,具有高精度、高可靠性和广域覆盖的特点,尤其适用于复杂地形和恶劣环境下的定位服务。结合北斗技术,可以确保用户在户外活动中实时获取准确的地理位置信息,为快速救援提供关键数据支撑。这一系统的发展为户外安全设备提供了坚实的技术基础,推动相关创新应用的涌现。
本装置通过集成北斗定位、4G通信和姿态传感等功能,实现了对用户位置和身体状态的智能监控。用户可通过一键报警按钮主动发送精确的求救信息,而姿态解算功能则能在检测到剧烈跌落或长时间静止等异常情况时自动触发报警,弥补了人工操作的局限性。这种设计不仅提高了遇险响应的及时性,还增强了设备在紧急情况下的自主应对能力。
为了适应户外长时间使用的场景,装置采用低功耗硬件设计,包括高性能主控芯片和大容量锂电池,确保在恶劣环境下仍能保持稳定运行和较长待机时间。这使得设备在徒步、登山、科考或应急救援等活动中具有广泛的适用性,为用户提供持续的安全保障。
设计实现的功能
(1) 集成北斗定位模块,实时获取并记录用户的地理位置坐标。
(2) 配备一键报警按钮,遇险时按下可将包含精确位置的求救信息通过4G网络发送给预设联系人。
(3) 具备姿态解算功能,当检测到使用者发生剧烈跌落或长时间静止不动时,触发自动报警。
(4) 装置待机时间长,适合户外长时间使用。
项目硬件模块组成
(1) 主控芯片:STM32F103C8T6单片机。
(2) 定位与通信:ATGM336H北斗/GPS双模定位模块、SIM7600CE 4G Cat1通信模块。
(3) 姿态传感:MPU6050六轴传感器。
(4) 输入与供电:物理报警按钮、大容量18650锂电池。
设计意义
该装置通过集成北斗定位模块和4G通信功能,能够在用户遇险时实时获取并发送精确地理位置,显著提高户外活动中的安全性和救援效率。这确保了在紧急情况下,用户能够迅速向预设联系人发出求救信号,缩短救援响应时间,为户外探险者提供关键的生命保障。
姿态解算功能通过MPU6050六轴传感器检测使用者的运动状态,当发生剧烈跌落或长时间静止不动时自动触发报警,提供额外的安全保障,防止因意外事故而无法手动报警的情况,增强了设备的主动防护能力。
装置采用大容量锂电池和低功耗设计,确保长时间待机,适合户外探险、徒步等长时间活动使用,增强了设备的实用性和可靠性,满足用户在偏远或无人区域对持久电力的需求。
整体设计结合了先进的定位、通信和传感技术,为户外爱好者提供了一个可靠的安全伴侣,有助于减少户外活动中的风险,提升用户体验,同时推动户外安全设备的智能化发展。
设计思路
本装置的设计以STM32F103C8T6单片机作为核心控制器,负责协调和管理各个硬件模块的运行。该主控芯片具备高效的处理能力和低功耗特性,能够实时处理定位数据、姿态传感器信息以及通信任务,确保系统稳定可靠。通过集成ATGM336H北斗/GPS双模定位模块,装置能够持续获取用户的地理位置坐标,并将数据记录在系统中,为后续报警功能提供精确的位置信息。
在通信方面,装置采用SIM7600CE 4G Cat1模块实现无线传输功能。当用户遇到险情时,可通过物理报警按钮手动触发求救,主控芯片会立即将包含当前位置的报警信息通过4G网络发送给预设的联系人。同时,该模块支持高效的数据传输,确保求救信息及时送达,增强了户外使用的安全性。
姿态检测功能通过MPU6050六轴传感器实现,该传感器能够实时监测用户的加速度和角速度变化。主控芯片对传感器数据进行解算和分析,当检测到剧烈跌落或长时间静止不动等异常状态时,系统会自动触发报警机制,无需用户手动干预,从而提高了应对突发情况的响应能力。
电源管理部分采用大容量18650锂电池供电,结合主控芯片的低功耗设计,优化了整体能耗。通过合理的电源调度和休眠机制,装置在待机状态下能够长时间运行,适合户外探险等场景的持续使用,确保用户在需要时随时可用。
用户交互设计简单直观,物理报警按钮直接连接到主控芯片,便于在紧急情况下快速操作。整个系统注重实用性和可靠性,各模块协同工作,实现了定位、报警和姿态监测的核心功能,满足户外遇险预警的需求。
框架图
+-------------------+ +-------------------+ +-------------------+
| | | | | |
| 北斗/GPS定位模块 |------>| 主控芯片 |<------| MPU6050姿态传感器 |
| (ATGM336H) | | (STM32F103C8T6) | | |
| | | | | |
+-------------------+ +-------------------+ +-------------------+
|
|
v
+-------------------+ +-------------------+
| | | |
| 4G通信模块 |------>| 预设联系人 |
| (SIM7600CE) | | (通过4G网络) |
| | | |
+-------------------+ +-------------------+
^
|
+-------------------+
| |
| 物理报警按钮 |
| |
+-------------------+
|
+-------------------+
| |
| 18650锂电池供电 |
| |
+-------------------+
系统总体设计
系统总体设计围绕北斗户外遇险预警定位装置的功能需求和硬件模块展开,以STM32F103C8T6单片机作为核心控制器,协调各模块的运作。该系统旨在为户外活动提供可靠的遇险预警和定位服务,通过集成北斗定位、4G通信和姿态传感功能,实现实时监控和快速响应。
系统通过ATGM336H北斗/GPS双模定位模块实时获取用户的地理位置坐标,并将数据记录在主控芯片中。同时,SIM7600CE 4G Cat1通信模块负责数据传输,确保在遇险时能够通过4G网络将包含精确位置的求救信息发送给预设联系人。这种设计保证了定位和通信的稳定性和实时性。
报警机制包括手动和自动两种方式:用户可通过物理报警按钮一键触发报警,而MPU6050六轴传感器则用于姿态解算,当检测到剧烈跌落或长时间静止不动时,系统会自动判断为遇险状态并启动报警流程。这增强了装置的主动预警能力,适应户外复杂环境。
电源部分采用大容量18650锂电池供电,结合低功耗设计,确保装置具有较长的待机时间,适合户外长时间使用。整个系统通过硬件模块的协同工作,实现了高效、可靠的遇险预警和定位功能。
系统功能总结
| 功能 | 描述 |
|---|---|
| 实时定位 | 集成北斗定位模块,实时获取并记录用户的地理位置坐标。 |
| 一键报警 | 配备一键报警按钮,遇险时按下可将包含精确位置的求救信息通过4G网络发送给预设联系人。 |
| 自动报警 | 具备姿态解算功能,当检测到使用者发生剧烈跌落或长时间静止不动时,触发自动报警。 |
| 长待机 | 装置待机时间长,适合户外长时间使用。 |
设计的各个功能模块描述
主控芯片模块采用STM32F103C8T6单片机作为核心控制器,负责协调系统中各个模块的运行。它处理来自定位模块的地理位置数据、姿态传感器的运动信息,并控制通信模块在必要时发送报警信号。同时,该芯片管理电源分配,以优化能耗,确保装置在户外长时间稳定工作。
定位与通信模块集成ATGM336H北斗/GPS双模定位模块,用于实时获取并记录用户的精确地理位置坐标,提高定位的可靠性和覆盖范围。SIM7600CE 4G Cat1通信模块则负责在用户触发报警时,通过4G网络将包含位置信息的求救消息快速发送给预设的联系人,实现高效的远程通信。
姿态传感模块使用MPU6050六轴传感器监测使用者的运动状态,通过内置的姿态解算功能分析加速度和角速度数据。当检测到剧烈跌落或长时间静止不动等异常情况时,该模块会向主控芯片发送信号,自动触发报警流程,增强户外安全防护。
输入与供电模块包括物理报警按钮和大容量18650锂电池。报警按钮提供一键报警功能,用户在遇险时可手动启动求救。锂电池为整个装置供电,通过高效能源管理确保长待机时间,适应户外活动的持久使用需求。
上位机代码设计
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <chrono>
#include <mutex>
#include <map>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
// 设备数据结构
struct DeviceData {
std::string deviceId;
double latitude;
double longitude;
std::string alertType; // "manual", "fall", "static"
std::string timestamp;
bool isOnline;
std::chrono::system_clock::time_point lastUpdate;
};
class OutdoorAlertSystem {
private:
std::map<std::string, DeviceData> devices;
std::mutex dataMutex;
SOCKET serverSocket;
bool isRunning;
int serverPort;
public:
OutdoorAlertSystem(int port = 8080) : serverPort(port), isRunning(false) {}
~OutdoorAlertSystem() {
stopServer();
}
// 初始化服务器
bool initializeServer() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed" << std::endl;
return false;
}
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Socket creation failed" << std::endl;
WSACleanup();
return false;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(serverPort);
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Bind failed" << std::endl;
closesocket(serverSocket);
WSACleanup();
return false;
}
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
std::cerr << "Listen failed" << std::endl;
closesocket(serverSocket);
WSACleanup();
return false;
}
std::cout << "Server started on port " << serverPort << std::endl;
return true;
}
// 解析设备数据
DeviceData parseDeviceData(const std::string& data) {
DeviceData device;
std::istringstream iss(data);
std::string token;
std::getline(iss, device.deviceId, ',');
std::getline(iss, token, ',');
device.latitude = std::stod(token);
std::getline(iss, token, ',');
device.longitude = std::stod(token);
std::getline(iss, device.alertType, ',');
std::getline(iss, device.timestamp);
device.isOnline = true;
device.lastUpdate = std::chrono::system_clock::now();
return device;
}
// 处理客户端连接
void handleClient(SOCKET clientSocket) {
char buffer[1024];
int bytesReceived;
while ((bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0)) > 0) {
buffer[bytesReceived] = '\0';
std::string data(buffer);
std::lock_guard<std::mutex> lock(dataMutex);
DeviceData device = parseDeviceData(data);
devices[device.deviceId] = device;
// 报警处理
if (device.alertType != "normal") {
handleAlert(device);
}
// 发送确认响应
std::string response = "ACK";
send(clientSocket, response.c_str(), response.length(), 0);
}
closesocket(clientSocket);
}
// 处理报警
void handleAlert(const DeviceData& device) {
std::cout << "\n=== ALERT RECEIVED ===" << std::endl;
std::cout << "Device ID: " << device.deviceId << std::endl;
std::cout << "Alert Type: " << device.alertType << std::endl;
std::cout << "Location: " << std::fixed << std::setprecision(6)
<< device.latitude << ", " << device.longitude << std::endl;
std::cout << "Time: " << device.timestamp << std::endl;
std::cout << "========================\n" << std::endl;
// 记录报警日志
logAlert(device);
// 这里可以添加发送邮件、短信等通知功能
// sendEmergencyNotification(device);
}
// 记录报警日志
void logAlert(const DeviceData& device) {
std::ofstream logFile("alerts.log", std::ios::app);
if (logFile.is_open()) {
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
logFile << "[" << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S") << "] "
<< "Device: " << device.deviceId << " | "
<< "Type: " << device.alertType << " | "
<< "Location: " << device.latitude << ", " << device.longitude
<< std::endl;
logFile.close();
}
}
// 设备状态监控线程
void deviceMonitorThread() {
while (isRunning) {
std::this_thread::sleep_for(std::chrono::seconds(30));
std::lock_guard<std::mutex> lock(dataMutex);
auto now = std::chrono::system_clock::now();
for (auto& pair : devices) {
auto& device = pair.second;
auto duration = std::chrono::duration_cast<std::chrono::seconds>(
now - device.lastUpdate);
if (duration.count() > 60) { // 超过60秒无更新视为离线
device.isOnline = false;
}
}
}
}
// 显示设备状态
void displayDeviceStatus() {
std::lock_guard<std::mutex> lock(dataMutex);
std::cout << "\n=== Device Status ===" << std::endl;
std::cout << std::left << std::setw(15) << "Device ID"
<< std::setw(10) << "Status"
<< std::setw(20) << "Location"
<< std::setw(15) << "Last Alert"
<< std::setw(20) << "Last Update" << std::endl;
std::cout << std::string(80, '-') << std::endl;
for (const auto& pair : devices) {
const auto& device = pair.second;
std::string status = device.isOnline ? "Online" : "Offline";
std::string location = std::to_string(device.latitude).substr(0, 8) + ", " +
std::to_string(device.longitude).substr(0, 8);
auto time_t = std::chrono::system_clock::to_time_t(device.lastUpdate);
std::string lastUpdate = std::put_time(std::localtime(&time_t), "%H:%M:%S");
std::cout << std::left << std::setw(15) << device.deviceId
<< std::setw(10) << status
<< std::setw(20) << location
<< std::setw(15) << device.alertType
<< std::setw(20) << lastUpdate << std::endl;
}
std::cout << std::endl;
}
// 启动服务器
void startServer() {
if (!initializeServer()) {
return;
}
isRunning = true;
// 启动设备监控线程
std::thread monitorThread(&OutdoorAlertSystem::deviceMonitorThread, this);
monitorThread.detach();
// 启动状态显示线程
std::thread displayThread([this]() {
while (isRunning) {
std::this_thread::sleep_for(std::chrono::seconds(10));
displayDeviceStatus();
}
});
displayThread.detach();
// 主接收循环
while (isRunning) {
sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrSize);
if (clientSocket == INVALID_SOCKET) {
if (isRunning) {
std::cerr << "Accept failed" << std::endl;
}
continue;
}
char clientIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN);
std::cout << "Client connected: " << clientIP << std::endl;
// 为每个客户端创建新线程
std::thread clientThread(&OutdoorAlertSystem::handleClient, this, clientSocket);
clientThread.detach();
}
}
// 停止服务器
void stopServer() {
isRunning = false;
if (serverSocket != INVALID_SOCKET) {
closesocket(serverSocket);
serverSocket = INVALID_SOCKET;
}
WSACleanup();
}
// 导出设备数据到文件
void exportDeviceData(const std::string& filename) {
std::lock_guard<std::mutex> lock(dataMutex);
std::ofstream file(filename);
if (file.is_open()) {
file << "DeviceID,Latitude,Longitude,AlertType,LastUpdate,Status\n";
for (const auto& pair : devices) {
const auto& device = pair.second;
auto time_t = std::chrono::system_clock::to_time_t(device.lastUpdate);
file << device.deviceId << ","
<< device.latitude << ","
<< device.longitude << ","
<< device.alertType << ","
<< std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S") << ","
<< (device.isOnline ? "Online" : "Offline") << "\n";
}
file.close();
std::cout << "Device data exported to " << filename << std::endl;
}
}
};
int main() {
OutdoorAlertSystem server(8080);
std::cout << "北斗户外遇险预警定位系统 - 上位机软件" << std::endl;
std::cout << "=====================================" << std::endl;
// 启动服务器
std::thread serverThread([&server]() {
server.startServer();
});
// 主线程处理用户输入
std::string command;
while (true) {
std::cout << "\nCommands: [status] [export] [quit]" << std::endl;
std::cout << "Enter command: ";
std::getline(std::cin, command);
if (command == "quit" || command == "exit") {
break;
} else if (command == "status") {
server.displayDeviceStatus();
} else if (command == "export") {
server.exportDeviceData("device_data.csv");
}
}
server.stopServer();
if (serverThread.joinable()) {
serverThread.join();
}
std::cout << "Server stopped." << std::endl;
return 0;
}
模块代码设计
#include "stm32f10x.h"
// MPU6050寄存器定义
#define MPU6050_ADDR 0xD0
#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define PWR_MGMT_1 0x6B
#define WHO_AM_I 0x75
// 硬件定义
#define BUTTON_PIN GPIO_Pin_0
#define LED_PIN GPIO_Pin_13
// 全局变量
volatile uint8_t alarm_triggered = 0;
int16_t Accel_X, Accel_Y, Accel_Z;
int16_t Gyro_X, Gyro_Y, Gyro_Z;
// 延时函数
void Delay(uint32_t nCount) {
for(; nCount != 0; nCount--);
}
// I2C初始化
void I2C1_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_CNF7);
GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_1;
GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_MODE7;
I2C1->CR1 &= ~I2C_CR1_PE;
I2C1->CR2 = 36;
I2C1->CCR = 180;
I2C1->TRISE = 37;
I2C1->CR1 |= I2C_CR1_PE;
}
// I2C起始信号
void I2C1_Start(void) {
I2C1->CR1 |= I2C_CR1_START;
while(!(I2C1->SR1 & I2C_SR1_SB));
}
// I2C停止信号
void I2C1_Stop(void) {
I2C1->CR1 |= I2C_CR1_STOP;
while(I2C1->CR1 & I2C_CR1_STOP);
}
// I2C发送地址
void I2C1_Address(uint8_t address) {
I2C1->DR = address;
while(!(I2C1->SR1 & I2C_SR1_ADDR));
(void)I2C1->SR2;
}
// I2C发送数据
void I2C1_Write(uint8_t data) {
I2C1->DR = data;
while(!(I2C1->SR1 & I2C_SR1_TXE));
}
// I2C读取数据
uint8_t I2C1_Read(void) {
while(!(I2C1->SR1 & I2C_SR1_RXNE));
return I2C1->DR;
}
// MPU6050写寄存器
void MPU6050_WriteReg(uint8_t reg, uint8_t data) {
I2C1_Start();
I2C1_Address(MPU6050_ADDR);
I2C1_Write(reg);
I2C1_Write(data);
I2C1_Stop();
}
// MPU6050读寄存器
uint8_t MPU6050_ReadReg(uint8_t reg) {
uint8_t data;
I2C1_Start();
I2C1_Address(MPU6050_ADDR);
I2C1_Write(reg);
I2C1_Start();
I2C1_Address(MPU6050_ADDR | 0x01);
data = I2C1_Read();
I2C1_Stop();
return data;
}
// MPU6050初始化
void MPU6050_Init(void) {
MPU6050_WriteReg(PWR_MGMT_1, 0x80);
Delay(100000);
MPU6050_WriteReg(PWR_MGMT_1, 0x00);
MPU6050_WriteReg(SMPLRT_DIV, 0x07);
MPU6050_WriteReg(CONFIG, 0x06);
MPU6050_WriteReg(GYRO_CONFIG, 0x18);
MPU6050_WriteReg(ACCEL_CONFIG, 0x01);
}
// 读取MPU6050数据
void MPU6050_ReadData(void) {
I2C1_Start();
I2C1_Address(MPU6050_ADDR);
I2C1_Write(ACCEL_XOUT_H);
I2C1_Start();
I2C1_Address(MPU6050_ADDR | 0x01);
Accel_X = (I2C1_Read() << 8) | I2C1_Read();
Accel_Y = (I2C1_Read() << 8) | I2C1_Read();
Accel_Z = (I2C1_Read() << 8) | I2C1_Read();
Gyro_X = (I2C1_Read() << 8) | I2C1_Read();
Gyro_Y = (I2C1_Read() << 8) | I2C1_Read();
Gyro_Z = (I2C1_Read() << 8) | I2C1_Read();
I2C1_Stop();
}
// USART1初始化 (GPS模块)
void USART1_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;
GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_CNF10);
GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_CNF10_0;
GPIOA->CRH |= GPIO_CRH_MODE9 | GPIO_CRH_MODE10;
USART1->BRR = 0x1D4C;
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}
// USART2初始化 (4G模块)
void USART2_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_CNF3);
GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_CNF3_0;
GPIOA->CRL |= GPIO_CRL_MODE2 | GPIO_CRL_MODE3;
USART2->BRR = 0x1D4C;
USART2->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}
// USART发送字符串
void USART_SendString(USART_TypeDef* USARTx, char* str) {
while(*str) {
while(!(USARTx->SR & USART_SR_TXE));
USARTx->DR = *str++;
}
}
// GPIO初始化
void GPIO_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;
// 报警按钮输入
GPIOA->CRL &= ~GPIO_CRL_CNF0;
GPIOA->CRL |= GPIO_CRL_CNF0_1;
// LED输出
GPIOC->CRH &= ~GPIO_CRH_CNF13;
GPIOC->CRH |= GPIO_CRH_MODE13;
}
// 外部中断初始化
void EXTI_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PA;
EXTI->IMR |= EXTI_IMR_MR0;
EXTI->FTSR |= EXTI_FTSR_TR0;
NVIC->ISER[0] |= 1 << 6;
}
// 姿态检测函数
uint8_t DetectFall(void) {
static uint32_t stationary_time = 0;
float accel_magnitude = sqrt(Accel_X*Accel_X + Accel_Y*Accel_Y + Accel_Z*Accel_Z);
// 检测剧烈跌落
if(accel_magnitude > 16000 || accel_magnitude < 8000) {
return 1;
}
// 检测长时间静止
if(abs(Gyro_X) < 100 && abs(Gyro_Y) < 100 && abs(Gyro_Z) < 100) {
stationary_time++;
if(stationary_time > 300000) { // 约5分钟
stationary_time = 0;
return 1;
}
} else {
stationary_time = 0;
}
return 0;
}
// 发送报警信息
void SendAlarm(void) {
char alarm_msg[] = "SOS! Emergency! Location: ";
USART_SendString(USART2, "AT+CMGF=1\r\n");
Delay(100000);
USART_SendString(USART2, "AT+CMGS=\"+86138xxxxyyyy\"\r\n");
Delay(100000);
USART_SendString(USART2, alarm_msg);
// 这里添加GPS坐标信息
USART_SendString(USART2, "\x1A");
}
// 外部中断服务函数
void EXTI0_IRQHandler(void) {
if(EXTI->PR & EXTI_PR_PR0) {
alarm_triggered = 1;
EXTI->PR |= EXTI_PR_PR0;
}
}
int main(void) {
SystemInit();
GPIO_Init();
I2C1_Init();
USART1_Init();
USART2_Init();
EXTI_Init();
MPU6050_Init();
while(1) {
MPU6050_ReadData();
// 检测姿态异常
if(DetectFall()) {
alarm_triggered = 1;
}
// 触发报警
if(alarm_triggered) {
GPIOC->BSRR = LED_PIN;
SendAlarm();
alarm_triggered = 0;
Delay(1000000);
GPIOC->BRR = LED_PIN;
}
Delay(10000);
}
}
项目核心代码
#include "stm32f10x.h"
// 硬件模块定义
#define BUTTON_GPIO_PORT GPIOA
#define BUTTON_PIN GPIO_Pin_0
#define LED_GPIO_PORT GPIOC
#define LED_PIN GPIO_Pin_13
// 模块初始化状态
typedef enum {
MODULE_INIT_SUCCESS = 0,
MODULE_INIT_FAIL = 1
} Module_Status;
// 报警状态
typedef enum {
ALARM_OFF = 0,
ALARM_BUTTON = 1,
ALARM_FALL = 2,
ALARM_STATIC = 3
} Alarm_State;
// 全局变量
volatile uint8_t alarm_triggered = 0;
volatile Alarm_State alarm_type = ALARM_OFF;
volatile uint32_t system_tick = 0;
// 假设的外部模块函数声明
extern Module_Status GPS_Init(void);
extern Module_Status GPRS_Init(void);
extern Module_Status MPU6050_Init(void);
extern Module_Status Battery_Init(void);
extern void GPS_GetPosition(float *latitude, float *longitude);
extern uint8_t GPRS_SendAlert(float lat, float lon, Alarm_State type);
extern uint8_t MPU6050_DetectFall(void);
extern uint8_t MPU6050_DetectStatic(void);
extern float Battery_GetVoltage(void);
// 系统时钟初始化
void RCC_Configuration(void)
{
// 开启HSE
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
// 等待HSE就绪
while(!(RCC->CR & RCC_CR_HSERDY));
// FLASH预取指缓冲使能
FLASH->ACR |= FLASH_ACR_PRFTBE;
// 设置等待周期
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
// HCLK = SYSCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
// PCLK2 = HCLK
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
// PCLK1 = HCLK/2
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
// PLL配置: PLLCLK = HSE * 9 = 72 MHz
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
// 开启PLL
RCC->CR |= RCC_CR_PLLON;
// 等待PLL就绪
while(!(RCC->CR & RCC_CR_PLLRDY));
// 选择PLL作为系统时钟
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
// 等待时钟切换完成
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08);
}
// GPIO初始化
void GPIO_Configuration(void)
{
// 开启GPIO时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;
// 报警按钮配置(PA0输入)
BUTTON_GPIO_PORT->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
BUTTON_GPIO_PORT->CRL |= GPIO_CRL_CNF0_1; // 浮空输入
// LED指示灯配置(PC13推挽输出)
LED_GPIO_PORT->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
LED_GPIO_PORT->CRH |= GPIO_CRH_MODE13_1; // 输出模式,最大速度2MHz
}
// SysTick定时器初始化
void SysTick_Init(void)
{
// 重装载值,1ms中断一次
SysTick->LOAD = 72000 - 1;
// 设置当前值
SysTick->VAL = 0;
// 设置时钟源,使能中断,启动定时器
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
}
// 外部中断初始化(报警按钮)
void EXTI_Configuration(void)
{
// 开启AFIO时钟
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
// PA0连接到EXTI0
AFIO->EXTICR[0] &= ~AFIO_EXTICR1_EXTI0;
AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PA;
// 配置EXTI0为下降沿触发
EXTI->FTSR |= EXTI_FTSR_TR0;
// 使能EXTI0中断
EXTI->IMR |= EXTI_IMR_MR0;
// 配置NVIC
NVIC_EnableIRQ(EXTI0_IRQn);
NVIC_SetPriority(EXTI0_IRQn, 0x00);
}
// LED控制
void LED_Control(uint8_t state)
{
if(state) {
LED_GPIO_PORT->BSRR = LED_PIN; // 置位
} else {
LED_GPIO_PORT->BRR = LED_PIN; // 复位
}
}
// 系统延时函数
void Delay_ms(uint32_t ms)
{
uint32_t start_tick = system_tick;
while((system_tick - start_tick) < ms);
}
// 报警处理函数
void Handle_Alarm(Alarm_State alarm_type)
{
float latitude, longitude;
// 获取当前位置
GPS_GetPosition(&latitude, &longitude);
// 发送报警信息
if(GPRS_SendAlert(latitude, longitude, alarm_type)) {
// 发送成功,LED闪烁3次
for(int i = 0; i < 3; i++) {
LED_Control(1);
Delay_ms(200);
LED_Control(0);
Delay_ms(200);
}
} else {
// 发送失败,持续闪烁
while(1) {
LED_Control(1);
Delay_ms(100);
LED_Control(0);
Delay_ms(100);
}
}
}
// 系统初始化
uint8_t System_Init(void)
{
// 初始化系统时钟
RCC_Configuration();
// 初始化GPIO
GPIO_Configuration();
// 初始化SysTick
SysTick_Init();
// 初始化外部中断
EXTI_Configuration();
// 初始化各功能模块
if(GPS_Init() != MODULE_INIT_SUCCESS) return 0;
if(GPRS_Init() != MODULE_INIT_SUCCESS) return 0;
if(MPU6050_Init() != MODULE_INIT_SUCCESS) return 0;
if(Battery_Init() != MODULE_INIT_SUCCESS) return 0;
// 开机指示灯
LED_Control(1);
Delay_ms(1000);
LED_Control(0);
return 1;
}
// 主函数
int main(void)
{
// 系统初始化
if(!System_Init()) {
// 初始化失败,LED常亮
LED_Control(1);
while(1);
}
uint32_t last_position_update = 0;
uint32_t last_sensor_check = 0;
uint32_t last_battery_check = 0;
while(1) {
// 检查报警触发
if(alarm_triggered) {
Handle_Alarm(alarm_type);
alarm_triggered = 0;
alarm_type = ALARM_OFF;
}
// 每30秒更新一次位置信息
if((system_tick - last_position_update) > 30000) {
float lat, lon;
GPS_GetPosition(&lat, &lon);
last_position_update = system_tick;
// LED闪烁指示正常工作
LED_Control(1);
Delay_ms(50);
LED_Control(0);
}
// 每2秒检查一次姿态传感器
if((system_tick - last_sensor_check) > 2000) {
// 检测跌落
if(MPU6050_DetectFall()) {
alarm_triggered = 1;
alarm_type = ALARM_FALL;
}
// 检测长时间静止
else if(MPU6050_DetectStatic()) {
alarm_triggered = 1;
alarm_type = ALARM_STATIC;
}
last_sensor_check = system_tick;
}
// 每5分钟检查一次电池电量
if((system_tick - last_battery_check) > 300000) {
float voltage = Battery_GetVoltage();
// 低电量处理(可根据需要扩展)
if(voltage < 3.3f) {
// 低电量警告
for(int i = 0; i < 5; i++) {
LED_Control(1);
Delay_ms(100);
LED_Control(0);
Delay_ms(100);
}
}
last_battery_check = system_tick;
}
// 进入低功耗模式(根据实际需求实现)
// __WFI();
}
}
// SysTick中断服务函数
void SysTick_Handler(void)
{
system_tick++;
}
// 外部中断服务函数(报警按钮)
void EXTI0_IRQHandler(void)
{
if(EXTI->PR & EXTI_PR_PR0) {
// 清除中断标志
EXTI->PR = EXTI_PR_PR0;
// 触发按钮报警
alarm_triggered = 1;
alarm_type = ALARM_BUTTON;
}
}
总结
本装置是一款专为户外活动设计的遇险预警定位设备,依托北斗系统实现精准定位和紧急通信功能,旨在保障用户在偏远或危险环境中的安全。
在功能上,它能够实时获取并记录用户的地理位置坐标,配备一键报警按钮,可在遇险时快速发送包含精确位置的求救信息至预设联系人,同时通过姿态解算自动检测剧烈跌落或长时间静止状态,及时触发报警机制。
硬件方面,装置采用STM32F103C8T6单片机作为主控核心,集成ATGM336H北斗/GPS双模定位模块和SIM7600CE 4G通信模块,确保定位与数据传输的可靠性,并搭载MPU6050六轴传感器进行姿态监测,辅以物理报警按钮和大容量18650锂电池供电。
整体设计注重实用性和耐用性,待机时间长,适合户外长时间使用,为用户提供全天候的遇险预警和定位保障。
- 点赞
- 收藏
- 关注作者
评论(0)