/* main.c - 主程序文件 */
#include "main.h"
#include <string.h>
#include <stdio.h>
#include <math.h>
/* 外设句柄 */
extern TIM_HandleTypeDef htim2;
extern I2C_HandleTypeDef hi2c1;
extern UART_HandleTypeDef huart1; // GPS
extern UART_HandleTypeDef huart2; // SIM800C
/* 全局变量 */
volatile uint32_t IC_Val1 = 0, IC_Val2 = 0;
volatile uint32_t pulse_width = 0;
volatile uint8_t is_first_captured = 0;
volatile float distance_cm = 0;
// 独立缓冲区
char gps_buffer[128];
uint8_t gps_index = 0;
char sim800c_buffer[64];
uint8_t sim800c_index = 0;
float latitude = 0.0, longitude = 0.0;
uint8_t gps_fix_valid = 0;
uint8_t emergency_flag = 0;
const char EMERGENCY_PHONE[] = "13800138000"; // 预设紧急电话号码
/* 函数原型 */
void SystemClock_Config(void);
//static void MX_GPIO_Init(void);
//static void MX_TIM2_Init(void);
//static void MX_USART1_UART_Init(void);
//static void MX_USART2_UART_Init(void);
//static void MX_I2C1_Init(void);
void Trigger_Ultrasonic(void);
void Ultrasonic_Process(void);
void GPS_Process(void);
void SIM800C_Init(void);
uint8_t SIM800C_SendCommand(const char *cmd, const char *expect, uint32_t timeout);
void SIM800C_Emergency_Call(void);
void MPU6050_Init(void);
uint8_t MPU6050_ReadAccel(int16_t *accel);
uint8_t Check_Fall_Detection(void);
void Parse_GPGGA(const char *ggastr);
void Feedback_Distance(float dist);
/* MPU6050 寄存器地址 */
#define MPU6050_ADDR 0xD0
#define MPU6050_WHO_AM_I 0x75
#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_ACCEL_CONFIG 0x1C
#define MPU6050_ACCEL_XOUT_H 0x3B
#ifndef M_PI
#define M_PI 3.14159265358979323846 // 定义M_PI常量
#endif
// 超声波超时计数器
volatile uint32_t ultrasonic_timeout = 0;
int main(void) {
/* HAL库初始化 */
HAL_Init();
/* 系统时钟配置 */
SystemClock_Config();
/* 外设初始化 */
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
/* 启动外设 */
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2); // 超声波输入捕获
HAL_UART_Receive_IT(&huart1, (uint8_t*)&gps_buffer[0], 1); // GPS接收
HAL_UART_Receive_IT(&huart2, (uint8_t*)&sim800c_buffer[0], 1); // SIM800C接收
/* 模块初始化 */
MPU6050_Init();
SIM800C_Init();
/* 启用超声波超时定时器 */
HAL_TIM_Base_Start_IT(&htim2);
/* 主循环 */
while (1) {
/* 1. 超声波测距 */
Trigger_Ultrasonic();
Ultrasonic_Process();
/* 2. 障碍物反馈 */
if (distance_cm > 0 && distance_cm < 40) {
Feedback_Distance(distance_cm);
}
/* 3. 摔倒检测 */
if (Check_Fall_Detection()) {
emergency_flag = 1;
}
/* 4. 紧急按钮检测 */
if (HAL_GPIO_ReadPin(EMERGENCY_BTN_GPIO_Port, EMERGENCY_BTN_Pin) == GPIO_PIN_SET) {
HAL_Delay(50); // 防抖
if (HAL_GPIO_ReadPin(EMERGENCY_BTN_GPIO_Port, EMERGENCY_BTN_Pin) == GPIO_PIN_SET) {
emergency_flag = 1;
}
}
/* 5. 处理紧急情况 */
if (emergency_flag) {
SIM800C_Emergency_Call();
emergency_flag = 0;
HAL_Delay(5000); // 防止重复触发
}
/* 6. 空闲时延时 */
HAL_Delay(100); // 100ms循环周期
}
}
/* 超声波触发函数 */
void Trigger_Ultrasonic(void) {
// 重置捕获状态
is_first_captured = 0;
ultrasonic_timeout = 0;
// 发送10μs触发脉冲
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
HAL_Delay(0.01); // 10μs
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
/* TIM2全局中断回调 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// 超声波超时处理
if (is_first_captured) {
ultrasonic_timeout++;
if (ultrasonic_timeout > 100) { // 100ms超时
is_first_captured = 0;
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
}
}
}
}
/* TIM2输入捕获中断回调 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
if (!is_first_captured) {
// 获取第一个捕获值(上升沿)
IC_Val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
is_first_captured = 1;
ultrasonic_timeout = 0;
// 切换为下降沿捕获
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);
} else {
// 获取第二个捕获值(下降沿)
IC_Val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
// 计算脉冲宽度
if (IC_Val2 > IC_Val1) {
pulse_width = IC_Val2 - IC_Val1;
} else {
pulse_width = (0xFFFF - IC_Val1) + IC_Val2;
}
// 计算距离(cm)
distance_cm = pulse_width * 0.034 / 2;
// 重置状态
is_first_captured = 0;
// 恢复为上升沿捕获
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
__HAL_TIM_SET_COUNTER(htim, 0);
}
}
}
/* 超声波数据处理 */
void Ultrasonic_Process(void) {
static float filtered_distance = 0;
const float alpha = 0.3; // 滤波器系数
// 应用一阶低通滤波器
if (distance_cm > 0) {
if (filtered_distance == 0) {
filtered_distance = distance_cm;
} else {
filtered_distance = alpha * distance_cm + (1 - alpha) * filtered_distance;
}
}
// 更新有效距离
distance_cm = filtered_distance;
}
/* USART接收中断回调 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
uint8_t rx_data;
if (huart->Instance == USART1) { // GPS
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
if (rx_data == '\n') {
gps_buffer[gps_index] = '\0';
// 检查是否为GPGGA语句
if (strstr(gps_buffer, "$GPGGA")) {
Parse_GPGGA(gps_buffer);
}
gps_index = 0;
} else if (gps_index < sizeof(gps_buffer) - 1) {
gps_buffer[gps_index++] = rx_data;
}
}
else if (huart->Instance == USART2) { // SIM800C
HAL_UART_Receive_IT(&huart2, &rx_data, 1);
if (rx_data == '\n') {
sim800c_buffer[sim800c_index] = '\0';
// 这里可以处理SIM800C响应
sim800c_index = 0;
} else if (sim800c_index < sizeof(sim800c_buffer) - 1) {
sim800c_buffer[sim800c_index++] = rx_data;
}
}
}
/* 解析GPGGA语句 (无破坏性解析) */
void Parse_GPGGA(const char *ggastr) {
char buffer[128];
strncpy(buffer, ggastr, sizeof(buffer));
buffer[sizeof(buffer)-1] = '\0';
char *token = strtok(buffer, ",");
uint8_t field = 0;
char lat_str[16] = {0}, lon_str[16] = {0};
char ns = 'N', ew = 'E';
uint8_t fix_quality = 0;
while (token != NULL && field < 15) {
switch (field) {
case 2: // 纬度
strncpy(lat_str, token, sizeof(lat_str)-1);
break;
case 3: // 北纬/南纬
ns = token[0];
break;
case 4: // 经度
strncpy(lon_str, token, sizeof(lon_str)-1);
break;
case 5: // 东经/西经
ew = token[0];
break;
case 6: // 定位质量
fix_quality = atoi(token);
break;
}
token = strtok(NULL, ",");
field++;
}
// 如果定位有效
if (fix_quality > 0 && lat_str[0] != '\0' && lon_str[0] != '\0') {
// 解析纬度 (格式: DDMM.MMMMM)
double lat_deg = atof(lat_str) / 100.0;
int lat_deg_int = (int)lat_deg;
double lat_min = lat_deg - lat_deg_int;
latitude = lat_deg_int + (lat_min * 100.0) / 60.0;
if (ns == 'S') latitude = -latitude;
// 解析经度 (格式: DDDMM.MMMMM)
double lon_deg = atof(lon_str) / 100.0;
int lon_deg_int = (int)lon_deg;
double lon_min = lon_deg - lon_deg_int;
longitude = lon_deg_int + (lon_min * 100.0) / 60.0;
if (ew == 'W') longitude = -longitude;
gps_fix_valid = 1;
} else {
gps_fix_valid = 0;
}
}
/* SIM800C初始化 */
void SIM800C_Init(void) {
// 等待模块启动
HAL_Delay(2000);
// 发送AT指令测试连接
SIM800C_SendCommand("AT\r\n", "OK", 1000);
// 禁用命令回显
SIM800C_SendCommand("ATE0\r\n", "OK", 1000);
// 设置短信文本模式
SIM800C_SendCommand("AT+CMGF=1\r\n", "OK", 1000);
}
/* 发送AT命令并等待响应 */
uint8_t SIM800C_SendCommand(const char *cmd, const char *expect, uint32_t timeout) {
HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), timeout);
uint32_t start = HAL_GetTick();
uint8_t response[128] = {0};
uint8_t index = 0;
while ((HAL_GetTick() - start) < timeout) {
if (HAL_UART_Receive(&huart2, &response[index], 1, 10) == HAL_OK) {
if (response[index] == '\n') {
if (strstr((char*)response, expect)) {
return 1; // 成功
}
index = 0;
memset(response, 0, sizeof(response));
} else if (index < sizeof(response)-1) {
index++;
}
}
}
return 0; // 超时或未找到
}
/* SIM800C紧急呼叫 */
void SIM800C_Emergency_Call(void) {
// 1. 拨打紧急电话
char call_cmd[32];
sprintf(call_cmd, "ATD%s;\r\n", EMERGENCY_PHONE);
SIM800C_SendCommand(call_cmd, "OK", 2000);
// 等待10秒通话
HAL_Delay(10000);
// 挂断电话
SIM800C_SendCommand("ATH\r\n", "OK", 1000);
// 2. 发送紧急短信
SIM800C_SendCommand("AT+CMGF=1\r\n", "OK", 1000);
char sms_cmd[64];
sprintf(sms_cmd, "AT+CMGS=\"%s\"\r", EMERGENCY_PHONE);
HAL_UART_Transmit(&huart2, (uint8_t*)sms_cmd, strlen(sms_cmd), 100);
// 等待提示符
HAL_Delay(500);
// 短信内容
char sms[128];
if (gps_fix_valid) {
sprintf(sms, "紧急求助!位置:https://maps.google.com/?q=%.6f,%.6f", latitude, longitude);
} else {
strcpy(sms, "紧急求助!GPS未定位");
}
HAL_UART_Transmit(&huart2, (uint8_t*)sms, strlen(sms), 1000);
// 发送Ctrl+Z结束短信
uint8_t ctrl_z = 0x1A;
HAL_UART_Transmit(&huart2, &ctrl_z, 1, 100);
// 等待发送完成
HAL_Delay(2000);
}
/* MPU6050初始化 */
void MPU6050_Init(void) {
uint8_t data[2];
// 唤醒MPU6050
data[0] = MPU6050_PWR_MGMT_1;
data[1] = 0x01; // 使用X轴陀螺仪作为参考
HAL_I2C_Master_Transmit(&hi2c1, MPU6050_ADDR, data, 2, 100);
HAL_Delay(100);
// 设置加速度量程±8g
data[0] = MPU6050_ACCEL_CONFIG;
data[1] = 0x10; // ±8g
HAL_I2C_Master_Transmit(&hi2c1, MPU6050_ADDR, data, 2, 100);
HAL_Delay(100);
// 验证设备ID
uint8_t reg = MPU6050_WHO_AM_I;
uint8_t id;
HAL_I2C_Master_Transmit(&hi2c1, MPU6050_ADDR, ®, 1, 100);
HAL_I2C_Master_Receive(&hi2c1, MPU6050_ADDR, &id, 1, 100);
if (id != 0x68) {
// 设备ID错误处理
while(1) {
HAL_GPIO_TogglePin(BUZZER_GPIO_Port, BUZZER_Pin);
HAL_Delay(200);
}
}
}
/* 读取加速度数据 */
uint8_t MPU6050_ReadAccel(int16_t *accel) {
uint8_t buffer[6];
uint8_t reg = MPU6050_ACCEL_XOUT_H;
// 发送寄存器地址
if (HAL_I2C_Master_Transmit(&hi2c1, MPU6050_ADDR, ®, 1, 10) != HAL_OK) {
return 0;
}
// 读取6字节数据
if (HAL_I2C_Master_Receive(&hi2c1, MPU6050_ADDR, buffer, 6, 10) != HAL_OK) {
return 0;
}
// 转换数据
accel[0] = (buffer[0] << 8) | buffer[1]; // X轴
accel[1] = (buffer[2] << 8) | buffer[3]; // Y轴
accel[2] = (buffer[4] << 8) | buffer[5]; // Z轴
return 1;
}
/* 检测摔倒 */
uint8_t Check_Fall_Detection(void) {
static int16_t accel_history[3][5] = {0}; // 历史数据 (X,Y,Z × 5个样本)
static uint8_t index = 0;
static uint32_t last_check = 0;
int16_t current_accel[3];
// 每200ms检查一次
if (HAL_GetTick() - last_check < 200) {
return 0;
}
last_check = HAL_GetTick();
if (!MPU6050_ReadAccel(current_accel)) {
return 0;
}
// 保存历史数据
accel_history[0][index] = current_accel[0];
accel_history[1][index] = current_accel[1];
accel_history[2][index] = current_accel[2];
index = (index + 1) % 5;
// 计算移动平均值
int32_t avg_accel[3] = {0};
for (int i = 0; i < 5; i++) {
avg_accel[0] += accel_history[0][i];
avg_accel[1] += accel_history[1][i];
avg_accel[2] += accel_history[2][i];
}
avg_accel[0] /= 5;
avg_accel[1] /= 5;
avg_accel[2] /= 5;
// 计算加速度矢量
float ax = avg_accel[0] / 4096.0; // ±8g灵敏度4096 LSB/g
float ay = avg_accel[1] / 4096.0;
float az = avg_accel[2] / 4096.0;
float magnitude = sqrt(ax*ax + ay*ay + az*az);
// 计算姿态角度 (判断是否平躺)
float pitch = atan2(-ax, sqrt(ay*ay + az*az)) * 180.0 / M_PI;
float roll = atan2(ay, az) * 180.0 / M_PI;
// 摔倒判断条件
if ((magnitude < 0.5 || magnitude > 2.5) && // 加速度剧烈变化
(fabs(pitch) > 60 || fabs(roll) > 60)) { // 身体倾斜角度大
return 1;
}
return 0;
}
/* 距离反馈 */
void Feedback_Distance(float dist) {
// 距离越近,反馈越强烈
uint16_t duration = 50; // 基础持续时间
uint16_t interval = (uint16_t)(dist * 10); // 间隔时间
// 蜂鸣器和马达同时工作
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(VIBRATION_MOTOR_GPIO_Port, VIBRATION_MOTOR_Pin, GPIO_PIN_SET);
HAL_Delay(duration);
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(VIBRATION_MOTOR_GPIO_Port, VIBRATION_MOTOR_Pin, GPIO_PIN_RESET);
HAL_Delay(interval);
}
/* I2C错误中断回调 */
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) {
if (hi2c->Instance == I2C1) {
// I2C恢复 - 重新初始化
HAL_I2C_DeInit(&hi2c1);
MX_I2C1_Init();
MPU6050_Init();
}
}
/* 系统时钟配置函数 */
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 配置主电源调节器
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
// 初始化RCC振荡器
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
// 初始化CPU、AHB和APB总线时钟
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
Error_Handler();
}
}
/* 错误处理函数 */
void Error_Handler(void) {
// 错误时快速闪烁LED
while(1) {
HAL_GPIO_TogglePin(BUZZER_GPIO_Port, BUZZER_Pin);
HAL_Delay(100);
}
}
这是我mian.c里的代码,按图片中的引脚,基于STM32F407VET6和cubemx。装置集成hc-sr04超声波测距模块、neo6M的GPS定位模块及sim800c紧急通信模块和mpu6050。超声波模块扫描前方40厘米范围内的障碍物,通过蜂鸣器反馈距离信息;GPS模块实时获取地理位置,mpu6050检测到摔倒或者遇紧急情况时可一键触发SIM800c模块拨打预设电话并发送含经纬度的求救短信。这是我要实现功能,但是烧录后没反应,debug后发现他卡在 HAL_Init();这一步,然后我把所有外设都断开后发现他还是卡在debug这一步
最新发布