STM32实战:基于STM32F103的车内防窒息系统(红外检测+GSM报警)

文章目录

    • [1. 项目概述](#1. 项目概述)
    • [2. 系统设计与工作流程](#2. 系统设计与工作流程)
      • [2.1 系统功能](#2.1 系统功能)
      • [2.2 系统框图](#2.2 系统框图)
    • [3. 硬件准备与连接](#3. 硬件准备与连接)
      • [3.1 物料清单](#3.1 物料清单)
      • [3.2 电路连接图](#3.2 电路连接图)
    • [4. 软件开发环境搭建](#4. 软件开发环境搭建)
      • [4.1 软件安装](#4.1 软件安装)
      • [4.2 创建工程](#4.2 创建工程)
    • [5. 代码实现 (基于标准外设库)](#5. 代码实现 (基于标准外设库))
      • [5.1 HC-SR501人体红外传感器驱动](#5.1 HC-SR501人体红外传感器驱动)
      • [5.2 DS18B20温度传感器驱动](#5.2 DS18B20温度传感器驱动)
      • [5.3 SIM800A GSM模块驱动](#5.3 SIM800A GSM模块驱动)
      • [5.4 主程序逻辑与报警控制](#5.4 主程序逻辑与报警控制)
      • [5.5 延时函数实现](#5.5 延时函数实现)
    • [6. 系统测试与调试](#6. 系统测试与调试)
      • [6.1 硬件测试步骤](#6.1 硬件测试步骤)
      • [6.2 软件调试技巧](#6.2 软件调试技巧)
      • [6.3 常见问题排查](#6.3 常见问题排查)
    • [7. 项目优化与扩展建议](#7. 项目优化与扩展建议)
      • [7.1 功能扩展](#7.1 功能扩展)
      • [7.2 可靠性提升](#7.2 可靠性提升)
      • [7.3 产品化考虑](#7.3 产品化考虑)
    • [8. 总结](#8. 总结)

1. 项目概述

随着汽车保有量的激增,儿童或宠物被误锁车内导致窒息的安全事故时有发生。本设计基于STM32F103单片机,开发一套低成本、高可靠性的车内防窒息报警系统。系统通过HC-SR501人体红外传感器 检测车内是否有人,当检测到人员滞留且车内温度超过安全阈值时,立即通过SIM800A GSM模块向预设手机号发送报警短信,提醒车主及时处理,从而避免悲剧发生。

本教程面向零基础的STM32初学者,将从硬件选型、电路连接、软件编程到系统测试,提供完整、可直接落地的详细步骤。所有代码均提供完整文件,可直接复制使用。

2. 系统设计与工作流程

2.1 系统功能

  1. 人体检测:使用HC-SR501红外传感器实时监测车内是否有人。
  2. 温度监测:使用DS18B20数字温度传感器监测车内温度。
  3. 智能判断:当同时满足"车内有人"且"温度超过设定阈值(如35℃)"时,判定为危险状态。
  4. 远程报警:危险状态下,通过SIM800A GSM模块自动发送中文报警短信至车主手机。
  5. 状态指示:通过LED和蜂鸣器进行本地声光报警。

2.2 系统框图

下图展示了系统的核心组成与数据流:
通信与执行模块
传感器模块
数字信号
单总线数据
UART串口
GPIO控制
GPIO控制
条件满足
电源供电
STM32F103C8T6

主控制器
HC-SR501

人体红外传感器
DS18B20

温度传感器
SIM800A GSM模块
LED指示灯
有源蜂鸣器
逻辑判断
触发报警
发送报警短信
启动声光报警
车主手机

3. 硬件准备与连接

3.1 物料清单

组件 型号/规格 数量 备注
主控芯片 STM32F103C8T6 (最小系统板) 1 核心控制器,俗称"蓝 pill"
人体红外传感器 HC-SR501 1 检测人体移动
温度传感器 DS18B20 1 测量车内温度,防水型更佳
GSM模块 SIM800A 1 支持2G网络,用于发送短信
蜂鸣器 有源蜂鸣器 (低电平触发) 1 报警提示音
LED 5mm 红色LED 1 报警指示灯
电阻 220Ω、1kΩ、4.7kΩ 若干 限流、上拉用
SIM卡 移动/联通2G卡 1 需开通短信业务,关闭PIN码锁
电源 5V/2A 独立电源 1 为GSM模块单独供电
杜邦线 公对公、母对母 若干 连接电路
面包板 830孔 1 方便搭建原型

3.2 电路连接图

核心接线表 (请对照STM32F103C8T6最小系统板引脚)

STM32引脚 连接对象 说明
3.3V HC-SR501 VCC、DS18B20 VDD 传感器供电
GND 所有模块的GND 共地
PA0 HC-SR501 OUT 人体检测信号输入 (高电平有效)
PB12 DS18B20 DQ 温度数据线 (需接4.7kΩ上拉到3.3V)
PA9 (USART1_TX) SIM800A RX 发送AT指令
PA10 (USART1_RX) SIM800A TX 接收模块响应
PA1 LED阳极 (串联220Ω电阻) 报警指示灯
PA2 蜂鸣器信号端 (低电平触发) 报警发声器
5V (外部电源) SIM800A VCC 重要:GSM模块必须单独供电
GND (外部电源) SIM800A GND 与STM32共地

接线注意事项

  1. 电平匹配:HC-SR501输出高电平为5V,而STM32 GPIO耐受5V,可直接连接。若担心长期使用,可在OUT脚串联1kΩ电阻到PA0。
  2. DS18B20上拉:必须在DQ线上接一个4.7kΩ的上拉电阻到3.3V,否则无法通信。
  3. GSM模块供电 :SIM800A工作电流峰值可达2A,切勿直接从STM32开发板的5V引脚取电,必须使用独立的5V/2A电源适配器,否则会导致STM32复位或GSM模块无法正常工作。
  4. 串口交叉:STM32的TX接GSM的RX,STM32的RX接GSM的TX。

4. 软件开发环境搭建

4.1 软件安装

  1. Keil MDK-ARM:用于编写、编译和调试代码。从官网下载并安装,同时安装STM32F1的Device Family Pack。
  2. STM32CubeMX:用于图形化配置引脚和生成初始化代码。从ST官网下载安装。
  3. 串口调试助手:如XCOM、SSCOM,用于调试GSM模块的AT指令。

4.2 创建工程

  1. 打开STM32CubeMX,新建工程,选择MCU型号 STM32F103C8Tx
  2. 配置时钟 :在RCC中,将HSE设置为Crystal/Ceramic Resonator
  3. 配置引脚
    • PA0 设置为 GPIO_Input,模式为 Pull-down (因为HC-SR501高电平有效,下拉避免悬空干扰)。
    • PB12 设置为 GPIO_Output,初始输出高电平 (用于DS18B20通信)。
    • PA1PA2 设置为 GPIO_Output,推挽输出,初始输出高电平 (LED和蜂鸣器低电平触发)。
    • PA9PA10 设置为 USART1,模式为 Asynchronous
  4. 配置USART1 :波特率 9600,字长 8 Bits,停止位 1,无校验,无流控。
  5. 配置时钟树 :将HCLK设置为最大 72MHz
  6. 生成代码 :在Project Manager中设置工程名称、路径,选择MDK-ARM作为Toolchain,然后生成代码。

5. 代码实现 (基于标准外设库)

将生成的代码用Keil打开,我们将在Core/SrcCore/Inc目录下添加以下文件。

5.1 HC-SR501人体红外传感器驱动

创建文件:hcsr501.chcsr501.h

hcsr501.h 头文件:

c 复制代码
#ifndef __HCSR501_H
#define __HCSR501_H

#include "stm32f1xx_hal.h"

// 人体检测引脚定义
#define PIR_GPIO_PORT          GPIOA
#define PIR_GPIO_PIN           GPIO_PIN_0
#define PIR_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOA_CLK_ENABLE()

// 函数声明
void HCSR501_Init(void);
uint8_t HCSR501_Read(void);

#endif

hcsr501.c 源文件:

c 复制代码
#include "hcsr501.h"

/**
  * @brief  初始化HC-SR501人体红外传感器引脚
  * @param  None
  * @retval None
  */
void HCSR501_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 使能GPIOA时钟
    PIR_GPIO_CLK_ENABLE();
    
    // 配置PA0为上拉输入
    GPIO_InitStruct.Pin = PIR_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN; // 下拉,默认低电平
    HAL_GPIO_Init(PIR_GPIO_PORT, &GPIO_InitStruct);
}

/**
  * @brief  读取人体检测状态
  * @param  None
  * @retval 1: 检测到人体;0: 未检测到人体
  */
uint8_t HCSR501_Read(void)
{
    // HC-SR501输出高电平表示检测到人体
    return HAL_GPIO_ReadPin(PIR_GPIO_PORT, PIR_GPIO_PIN);
}

5.2 DS18B20温度传感器驱动

创建文件:ds18b20.cds18b20.h

ds18b20.h 头文件:

c 复制代码
#ifndef __DS18B20_H
#define __DS18B20_H

#include "stm32f1xx_hal.h"

// DS18B20引脚定义
#define DS18B20_GPIO_PORT        GPIOB
#define DS18B20_GPIO_PIN         GPIO_PIN_12
#define DS18B20_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()

// 函数声明
void DS18B20_Init(void);
void DS18B20_Start(void);
float DS18B20_GetTemp(void);
static void DS18B20_WriteByte(uint8_t data);
static uint8_t DS18B20_ReadByte(void);
static void DS18B20_SetPinOutput(void);
static void DS18B20_SetPinInput(void);
static uint8_t DS18B20_Reset(void);

#endif

ds18b20.c 源文件 (包含详细的单总线时序实现):

c 复制代码
#include "ds18b20.h"
#include "delay.h" // 需要微秒级延时函数,下文提供

// 微秒级延时函数声明 (需根据系统时钟实现)
void Delay_us(uint32_t us);

/**
  * @brief  初始化DS18B20的GPIO
  */
void DS18B20_Init(void)
{
    DS18B20_GPIO_CLK_ENABLE();
    // 初始状态设置为输出高电平
    DS18B20_SetPinOutput();
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET);
}

/**
  * @brief  DS18B20复位脉冲
  * @retval 1: 复位成功,检测到DS18B20存在脉冲;0: 复位失败
  */
static uint8_t DS18B20_Reset(void)
{
    uint8_t presence = 0;
    
    DS18B20_SetPinOutput();
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);
    Delay_us(480); // 保持低电平至少480us
    
    DS18B20_SetPinInput();
    Delay_us(60); // 等待15-60us后读取
    
    if (!HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN))
    {
        presence = 1; // 检测到存在脉冲
    }
    
    Delay_us(420); // 等待存在脉冲结束
    return presence;
}

/**
  * @brief  向DS18B20写入一个字节
  */
static void DS18B20_WriteByte(uint8_t data)
{
    for (uint8_t i = 0; i < 8; i++)
    {
        DS18B20_SetPinOutput();
        HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);
        Delay_us(1); // 拉低后等待1us
        
        if (data & 0x01) // 写1
        {
            HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET);
        }
        // 写0则保持低电平
        Delay_us(60); // 保持60us
        HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET);
        data >>= 1;
        Delay_us(1); // 恢复时间
    }
}

/**
  * @brief  从DS18B20读取一个字节
  */
static uint8_t DS18B20_ReadByte(void)
{
    uint8_t data = 0;
    
    for (uint8_t i = 0; i < 8; i++)
    {
        data >>= 1;
        DS18B20_SetPinOutput();
        HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);
        Delay_us(1); // 拉低至少1us
        
        DS18B20_SetPinInput();
        Delay_us(5); // 等待5us后读取
        
        if (HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN))
        {
            data |= 0x80; // 读到1
        }
        Delay_us(55); // 等待读时隙结束
    }
    return data;
}

/**
  * @brief  启动温度转换
  */
void DS18B20_Start(void)
{
    if (DS18B20_Reset())
    {
        DS18B20_WriteByte(0xCC); // 跳过ROM命令
        DS18B20_WriteByte(0x44); // 启动温度转换命令
    }
}

/**
  * @brief  读取温度值
  * @retval 温度值,单位:摄氏度
  */
float DS18B20_GetTemp(void)
{
    uint8_t temp_l, temp_h;
    int16_t temp;
    float temperature;
    
    if (DS18B20_Reset())
    {
        DS18B20_WriteByte(0xCC); // 跳过ROM
        DS18B20_WriteByte(0xBE); // 读暂存器
        
        temp_l = DS18B20_ReadByte();
        temp_h = DS18B20_ReadByte();
        
        temp = (temp_h << 8) | temp_l;
        temperature = temp / 16.0; // DS18B20精度为0.0625,除以16得到实际温度
        return temperature;
    }
    return -99.9; // 读取失败
}

// GPIO模式切换辅助函数
static void DS18B20_SetPinOutput(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
}

static void DS18B20_SetPinInput(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
}

5.3 SIM800A GSM模块驱动

创建文件:sim800a.csim800a.h

sim800a.h 头文件:

c 复制代码
#ifndef __SIM800A_H
#define __SIM800A_H

#include "stm32f1xx_hal.h"

// 使用USART1与SIM800A通信
extern UART_HandleTypeDef huart1;

// 函数声明
void SIM800A_Init(void);
void SIM800A_SendCmd(char *cmd);
uint8_t SIM800A_WaitForResponse(char *expected_resp, uint32_t timeout);
void SIM800A_SendSMS(char *phone_num, char *message);

#endif

sim800a.c 源文件:

c 复制代码
#include "sim800a.h"
#include <string.h>
#include <stdio.h>

// 接收缓冲区
char gsm_rx_buffer[256];
uint16_t gsm_rx_index = 0;

/**
  * @brief  初始化GSM模块 (发送AT指令测试)
  */
void SIM800A_Init(void)
{
    HAL_Delay(3000); // 等待模块上电稳定
    
    // 测试AT指令
    SIM800A_SendCmd("AT\r\n");
    if (SIM800A_WaitForResponse("OK", 2000))
    {
        // 设置短信文本模式
        SIM800A_SendCmd("AT+CMGF=1\r\n");
        SIM800A_WaitForResponse("OK", 1000);
        
        // 设置短信提示方式 (直接存储到SIM卡)
        SIM800A_SendCmd("AT+CNMI=2,1,0,0,0\r\n");
        SIM800A_WaitForResponse("OK", 1000);
    }
}

/**
  * @brief  向GSM模块发送AT指令
  * @param  cmd: AT指令字符串
  */
void SIM800A_SendCmd(char *cmd)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 1000);
}

/**
  * @brief  等待GSM模块返回特定响应
  * @param  expected_resp: 期望的响应字符串 (如 "OK", "ERROR")
  * @param  timeout: 超时时间 (毫秒)
  * @retval 1: 收到期望响应;0: 超时或收到错误
  */
uint8_t SIM800A_WaitForResponse(char *expected_resp, uint32_t timeout)
{
    uint32_t start_tick = HAL_GetTick();
    gsm_rx_index = 0;
    memset(gsm_rx_buffer, 0, sizeof(gsm_rx_buffer));
    
    while ((HAL_GetTick() - start_tick) < timeout)
    {
        // 检查是否有数据接收 (实际项目中应使用中断或DMA)
        uint8_t ch;
        if (HAL_UART_Receive(&huart1, &ch, 1, 10) == HAL_OK)
        {
            if (gsm_rx_index < sizeof(gsm_rx_buffer) - 1)
            {
                gsm_rx_buffer[gsm_rx_index++] = ch;
                gsm_rx_buffer[gsm_rx_index] = '\0';
                
                // 检查是否包含期望的响应
                if (strstr(gsm_rx_buffer, expected_resp) != NULL)
                {
                    return 1;
                }
                // 检查是否包含ERROR
                if (strstr(gsm_rx_buffer, "ERROR") != NULL)
                {
                    return 0;
                }
            }
        }
    }
    return 0; // 超时
}

/**
  * @brief  发送短信
  * @param  phone_num: 目标手机号码 (字符串,如 "13800138000")
  * @param  message: 短信内容 (支持中文,需注意编码)
  */
void SIM800A_SendSMS(char *phone_num, char *message)
{
    char cmd[50];
    
    // 1. 设置目标号码
    sprintf(cmd, "AT+CMGS=\"%s\"\r\n", phone_num);
    SIM800A_SendCmd(cmd);
    HAL_Delay(500);
    
    // 2. 发送短信内容 (中文短信)
    HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), 1000);
    HAL_Delay(100);
    
    // 3. 发送结束符 Ctrl+Z (0x1A)
    uint8_t ctrl_z = 0x1A;
    HAL_UART_Transmit(&huart1, &ctrl_z, 1, 1000);
    
    // 4. 等待发送完成
    SIM800A_WaitForResponse("+CMGS:", 10000);
}

5.4 主程序逻辑与报警控制

修改文件:main.c

main.c中添加以下代码:

c 复制代码
/* 用户头文件 */
#include "hcsr501.h"
#include "ds18b20.h"
#include "sim800a.h"
#include <stdio.h>
#include <string.h>

/* 报警引脚定义 */
#define ALARM_LED_PIN        GPIO_PIN_1
#define ALARM_LED_PORT       GPIOA
#define ALARM_BUZZER_PIN     GPIO_PIN_2
#define ALARM_BUZZER_PORT    GPIOA

/* 温度阈值 (单位:摄氏度) */
#define TEMP_THRESHOLD       35.0

/* 状态标志 */
typedef enum
{
    STATE_NORMAL = 0,
    STATE_WARNING,
    STATE_ALARM
} SystemState;

SystemState g_system_state = STATE_NORMAL;
uint8_t g_alarm_sent = 0; // 短信是否已发送标志

/* 函数声明 */
static void System_Init(void);
static void Alarm_Control(uint8_t on_off);
static void Check_Danger(void);

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    
    // 用户外设初始化
    System_Init();
    
    // 主循环
    while (1)
    {
        // 1. 检测危险状态
        Check_Danger();
        
        // 2. 根据状态控制报警
        if (g_system_state == STATE_ALARM)
        {
            Alarm_Control(1); // 打开声光报警
            
            // 首次进入报警状态,发送短信
            if (g_alarm_sent == 0)
            {
                char sms_msg[100];
                float current_temp = DS18B20_GetTemp();
                
                sprintf(sms_msg, "【车内防窒息报警】检测到车内有人且温度过高(%.1f℃),请立即查看!", current_temp);
                SIM800A_SendSMS("13800138000", sms_msg); // 替换为你的手机号
                
                g_alarm_sent = 1; // 标记已发送
            }
        }
        else
        {
            Alarm_Control(0); // 关闭报警
            g_alarm_sent = 0; // 重置发送标志
        }
        
        HAL_Delay(1000); // 每秒检测一次
    }
}

/**
  * @brief  系统初始化
  */
static void System_Init(void)
{
    // 初始化传感器
    HCSR501_Init();
    DS18B20_Init();
    
    // 初始化GSM模块
    SIM800A_Init();
    
    // 初始化报警输出引脚
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // LED引脚
    GPIO_InitStruct.Pin = ALARM_LED_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(ALARM_LED_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(ALARM_LED_PORT, ALARM_LED_PIN, GPIO_PIN_SET); // 初始关闭
    
    // 蜂鸣器引脚
    GPIO_InitStruct.Pin = ALARM_BUZZER_PIN;
    HAL_GPIO_Init(ALARM_BUZZER_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(ALARM_BUZZER_PORT, ALARM_BUZZER_PIN, GPIO_PIN_SET); // 初始关闭
}

/**
  * @brief  报警控制
  * @param  on_off: 1-打开报警,0-关闭报警
  */
static void Alarm_Control(uint8_t on_off)
{
    if (on_off)
    {
        // 声光报警 (LED闪烁,蜂鸣器间歇鸣响)
        HAL_GPIO_TogglePin(ALARM_LED_PORT, ALARM_LED_PIN);
        HAL_GPIO_WritePin(ALARM_BUZZER_PORT, ALARM_BUZZER_PIN, GPIO_PIN_RESET);
        HAL_Delay(200);
        HAL_GPIO_WritePin(ALARM_BUZZER_PORT, ALARM_BUZZER_PIN, GPIO_PIN_SET);
        HAL_Delay(200);
    }
    else
    {
        // 关闭报警
        HAL_GPIO_WritePin(ALARM_LED_PORT, ALARM_LED_PIN, GPIO_PIN_SET);
        HAL_GPIO_WritePin(ALARM_BUZZER_PORT, ALARM_BUZZER_PIN, GPIO_PIN_SET);
    }
}

/**
  * @brief  检测危险状态
  */
static void Check_Danger(void)
{
    static uint8_t human_detected = 0;
    static float temperature = 0;
    
    // 读取传感器数据
    human_detected = HCSR501_Read();
    DS18B20_Start(); // 启动温度转换
    HAL_Delay(750);  // 等待转换完成 (DS18B20最大转换时间750ms)
    temperature = DS18B20_GetTemp();
    
    // 判断逻辑
    if (human_detected && (temperature > TEMP_THRESHOLD))
    {
        g_system_state = STATE_ALARM;
    }
    else if (human_detected)
    {
        g_system_state = STATE_WARNING; // 有人但温度正常
    }
    else
    {
        g_system_state = STATE_NORMAL;
    }
}

5.5 延时函数实现

创建文件:delay.cdelay.h

delay.h 头文件:

c 复制代码
#ifndef __DELAY_H
#define __DELAY_H

#include "stm32f1xx_hal.h"

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);

#endif

delay.c 源文件:

c 复制代码
#include "delay.h"

/**
  * @brief  微秒级延时 (基于SysTick)
  * @note   系统时钟72MHz时,SysTick每1us计数72次
  */
void Delay_us(uint32_t us)
{
    uint32_t ticks;
    uint32_t told, tnow, tcnt = 0;
    uint32_t reload = SysTick->LOAD;
    
    ticks = us * 72; // 72MHz下,1us需要72个时钟周期
    told = SysTick->VAL;
    
    while (1)
    {
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            if (tnow < told)
            {
                tcnt += told - tnow;
            }
            else
            {
                tcnt += reload - tnow + told;
            }
            told = tnow;
            if (tcnt >= ticks)
            {
                break;
            }
        }
    }
}

/**
  * @brief  毫秒级延时 (基于HAL_Delay)
  */
void Delay_ms(uint32_t ms)
{
    HAL_Delay(ms);
}

6. 系统测试与调试

6.1 硬件测试步骤

  1. 单独测试GSM模块 :使用USB转TTL模块连接电脑,通过串口助手发送AT指令,确认模块返回OK
  2. 测试HC-SR501:用手在传感器前移动,用万用表测量OUT引脚电压,应有0V到3.3V/5V的跳变。
  3. 测试DS18B20:单独连接DS18B20到STM32,编写简单读取程序,确认能读取到环境温度。
  4. 整体连接:按接线表连接所有模块,特别注意GSM模块的独立供电。

6.2 软件调试技巧

  1. 串口调试 :在main.c中添加串口打印,实时输出传感器状态和温度值。

    c 复制代码
    char debug_msg[50];
    sprintf(debug_msg, "人体检测:%d, 温度:%.1f℃\r\n", human_detected, temperature);
    HAL_UART_Transmit(&huart1, (uint8_t*)debug_msg, strlen(debug_msg), 1000);
  2. 模拟测试:暂时调低温度阈值(如设为25℃),用打火机或吹风机轻微加热DS18B20,观察是否触发报警。

  3. GSM模块调试:先单独测试短信发送功能,确认能收到短信后再集成到主逻辑中。

6.3 常见问题排查

问题现象 可能原因 解决方案
GSM模块无反应 供电不足 使用独立的5V/2A电源,检查电源线是否接触良好
无法发送短信 SIM卡问题 确认SIM卡已开通短信业务,且关闭了PIN码锁
HC-SR501一直输出高电平 传感器误触发 调整传感器上的两个电位器: 1. 灵敏度调节:逆时针减小 2. 延时调节:逆时针缩短
DS18B20读取值为-99.9 通信失败 检查DQ线是否接了4.7kΩ上拉电阻,检查接线是否松动
报警不触发 阈值设置不当 根据实际环境调整TEMP_THRESHOLD宏定义的值

7. 项目优化与扩展建议

7.1 功能扩展

  1. 增加湿度监测:添加DHT11传感器,同时监测车内湿度。
  2. 多级报警:根据温度超过阈值的程度,实现分级报警(如短信、电话、APP推送)。
  3. 数据记录:添加SD卡模块,记录历史温湿度数据。
  4. 低功耗模式:车辆熄火后,系统进入休眠模式,定时唤醒检测,节省电瓶电量。
  5. GPS定位:添加GPS模块,在报警短信中附带车辆位置信息。

7.2 可靠性提升

  1. 防误报机制:要求人体信号持续检测超过30秒才触发报警,避免临时经过车辆触发。
  2. 看门狗:启用STM32的独立看门狗(IWDG),防止程序跑飞。
  3. 电源管理:增加电压检测电路,在电瓶电压过低时自动关机,防止车辆无法启动。

7.3 产品化考虑

  1. PCB设计:将电路集成到一块PCB上,提高稳定性和美观度。
  2. 外壳设计:3D打印或定制外壳,便于安装在车内隐蔽位置。
  3. 通信备份:在GSM信号弱的区域,可增加蓝牙模块,连接手机APP作为备用报警通道。

8. 总结

本教程详细介绍了基于STM32F103的车内防窒息系统的完整实现过程。从硬件选型、电路连接到软件编程,每一步都提供了可直接使用的代码和详细的解释。系统核心在于红外检测GSM报警的联动,能够在检测到人员滞留且温度过高时及时通知车主。

安全提示:本系统为辅助安全装置,不能完全替代驾驶员的注意力和责任心。任何时候都不应将儿童或宠物单独留在车内,即使安装了此类报警系统。

相关推荐
XTIOT66610 小时前
俄罗斯诚信标签Chestny ZNAK技术约束分析与智能化应对思路
大数据·人工智能·嵌入式硬件·物联网
崇山峻岭之间10 小时前
单片机串口实验
单片机·嵌入式硬件
爱的si念10 小时前
Zephyr 在 Nucleo G474RE 的完整编译与模块提取指南
stm32·单片机·嵌入式硬件
深圳市九鼎创展科技10 小时前
九鼎创展 X7110 开发板(JH7110):国产 RISC-V 多媒体平台全解析
大数据·linux·人工智能·嵌入式硬件·ubuntu·risc-v
Jason_zhao_MR11 小时前
RK3506工业网关:如何打通现场采集、无线传输与行业规约接入?
linux·嵌入式硬件·物联网·系统架构·嵌入式
m0_3771081411 小时前
stm32--I2C
stm32·单片机·嵌入式硬件
发光小北11 小时前
单通道串口服务器如何应用?
运维·服务器·单片机
车载测试牛马笔记11 小时前
CAN一致性-物理层--高压通信范围测试
单片机·嵌入式硬件
国产电子元器件11 小时前
ACS770还能打吗?最近测试了一款国产霍尔电流传感器
嵌入式硬件