简介:面向嵌入式开发者和单片机爱好者,这份基于STM32的项目围绕车内环境检测与儿童滞留报警展开,主要解决温度、湿度、有害气体超标及儿童被单独留在车内时的快速感知和报警通知问题,适用于课程设计、毕业设计、电子竞赛或产品预研。压缩包共6个文件,包含mp4实物运行演示视频和APP端操作演示视频、docx开题报告与方案文档、pdf电路原理图以及sql数据库脚本,整体约41.68MB,目录结构清晰,可分别用于查看硬件调试流程、移动端交互、电路连接关系和后台数据管理。已有71人学习下载。从实物录屏可了解传感器数据采集、STM32处理、阈值判断与报警联动的完整过程;APP视频展示了用户操作界面和各功能入口;电路原理图帮助理解系统电路设计,开题报告和方案文档提供研究背景、技术路线与实现方案,sql文件则负责数据支持。整包内容形成了从开题、电路设计、软件开发到实物演示的完整闭环,不仅适合复现系统原型,也能为撰写项目文档和后续二次开发提供扎实参考。
1. 基于STM32的车内环境检测与儿童滞留报警,先想清楚“怎么判定儿童还在车上”
夏天室外35℃的车,暴晒20分钟,座舱温度就能超过50℃,如果把儿童留在车里,热射病可能10分钟内出现。基于STM32的车内环境检测和儿童滞留报警系统,核心任务是在这个时间窗口里先判断“后排还有人”,再判断“环境已经危险”,最后用声光加短信把消息送出去。很多第一次做这个题目的人,会把重心放在温度传感器上,结果做出来的是“高温报警器”,车一热就叫,大人下车去后备箱拿东西也叫,真正该报的儿童滞留反而被误报淹没。这个系统的难点不是测环境,而是用状态机判断“人是不是还在车上”,传感器和报警链路都是为这个判断服务的。它适合作为嵌入式毕业设计,也适合新手用它把STM32的GPIO、ADC、定时器、串口和状态机设计串起来。
2. 传感器选型与电气架构:车内环境检测先过“选型关”
环境检测不是传感器越多越好。温度、湿度、CO、烟雾这几个量,每加一个都会多一个失效点、多一路电源负担和多一段要写的滤波逻辑。做车内儿童滞留报警,先确定两个问题:你要检测的“环境恶化的标志物”是什么,以及你要检测的“儿童存在的标志物”是什么。前者常见是温度、湿度和CO浓度,后者则是车门状态加后排占用信号。
传感器选型直接决定PCB尺寸和代码结构。比如温湿度用SHT30还是DHT22,会分别走向I2C和单总线两种驱动写法;气体传感器用MQ-7还是MQ-2,对ADC采样通道和预热逻辑的要求又完全不同。我一般先把传感器清单列成一张表,再决定STM32最小系统板的引脚分配。
2.1 温湿度传感器怎么选:SHT30和DHT22的真实差别
SHT30和DHT22是两类典型选择,前者是I2C接口的数字传感器,后者是单总线数字传感器。从参数上看,SHT30精度能做到±0.3℃,湿度精度±2%RH,DHT22的精度大约±0.5℃和±2%~5%RH。车内在夏天50℃以上的环境中,SHT30的温度上限到125℃,DHT22上限到80℃,两者都能用,但SHT30在长时间高温下的漂移更小。
接口差异对工程影响更大。SHT30用I2C,地址固定在0x44或0x45,用两根线上拉电阻就能挂到I2C总线,后面想扩展OLED显示屏也不用再加引脚。DHT22是单总线协议,读一次时序要求主机拉低总线至少18ms,然后切换输入模式读取40位数据,整个读取过程必须关闭中断或至少屏蔽某些中断,否则时序就会被定时器打断。这个问题在STM32上尤其容易踩坑,因为SysTick的滴答中断默认一直开着,DHT22读取出错时最典型的现象就是“数据全是0xFF”或“永远卡在while等待总线拉高”。
| 项目 | SHT30 | DHT22 |
|---|---|---|
| 接口 | I2C | 单总线 |
| 温度精度 | ±0.3℃ | ±0.5℃ |
| 湿度精度 | ±2%RH | ±2%~5%RH |
| 测温上限 | 125℃ | 80℃ |
| 采样速度 | 最快0.5ms | 读取一次耗时20ms以上 |
| 接线 | 4线含电源 | 3线,总线寄生供电也能跑 |
布点位置比传感器型号更影响读数。很多人把传感器贴在仪表台上,太阳一晒,仪表台表面温度先到70℃,空气温度其实还在45℃左右,报出来的“座舱温度”全是假的。我会把温湿度传感器放在后排座椅头枕附近的顶棚,或者B柱内衬里,避开空调直吹,也避开阳光直射。另外SHT30工作时自身会发热约0.1℃~0.2℃,如果塞进封闭的小壳里,读数还会再偏高一点,设计外壳时留个透气孔最省事。
2.2 CO、烟雾和空气质量:把MQ-7/MQ-2用在车内要注意什么
儿童滞留报警里最有价值的空气质量参数其实是CO。发动机怠速时如果排气管附近有缝隙,或暖风系统把尾气抽进座舱,CO浓度会快速上升,儿童在睡眠状态下更难察觉。常见的电化学或半导体式CO传感器的检测范围从几个ppm到几百ppm,车内封闭空间的CO中毒风险远高于烟雾,所以MQ-7是这类系统的常见选择。
MQ-7是半导体式气体传感器,内部有加热丝,正常工作需要加热电压和回路电压两个电源,模块板上通常已经做了放大电路,输出端是一个模拟电压,直接进STM32的ADC通道。要注意它上电后需要1~2分钟预热,刚上电那会儿输出很不稳定,我一般会在初始化时加一个“传感器预热完成”的布尔量,预热期不参与报警判断,否则车子一通电系统就可能误报。
MQ-2对液化气、丁烷和烟雾都敏感,适合做厨房燃气报警,放车里对香水、食物和内饰挥发物都可能响应,误触发率会高很多。我给这个系统的建议是:温度+CO作为主判据,湿度只做数据记录,不加报警条件。这样报警逻辑简单,也少一个传感器出“玄学故障”的入口。气体传感器放后排座椅侧面通风处,别贴地板,地毯挥发物会让传感器一直处于偏高状态。
2.3 整车取电与车门状态输入:“车辆信号比实验室信号脏得多”
电源方案要分成两路考虑:一路是常电,给报警系统的GSM模块和RTC维持供电;一路是ACC信号,用来判断车辆是否熄火。取电点常见做法是从保险丝盒取电,ACC线和常电线分别接两个保险位,用mini保险丝的取电插座引线,不要直接破线缠胶布,车内震动多,胶布松动后搭铁短路的风险很大。
12V车电不能直接给STM32用。我通常会先用DC-DC模块降到5V,再接AMS1117-3.3给MCU,或者直接用一个宽压输入的DC-DC出3.3V。车上的电压波动比实验室电源可怕得多,冷启动时电压可以掉到9V以下,发电机正常工作时又会到14.4V左右,铅酸电池老化的车甚至有几十伏的浪涌,输入耐压至少要45V以上才安全。
车门状态信号一般从门灯开关取。四个门灯开关在门框处,关门时触碰开关断开接地,开门时触点闭合接地,这个信号是12V电平,不能直接进STM32的GPIO。用光耦隔离最稳妥,输入串一个2.2kΩ电阻限流,输出端上拉到3.3V,这样即使门灯线路被干扰也能保证MCU侧不被反灌。后排占用检测可以放一个压力垫在座椅坐垫下,或放红外反射开关在B柱内侧,压力垫对儿童体重过轻不敏感,红外开关对深色衣物不敏感,两者各有各的毛病,后面避坑章会专门展开。
3. 用STM32标准库建工程:ADC采样、滤波和儿童滞留状态机
选定传感器后,主控程序从建工程开始。很多刚接触STM32的人会纠结用标准库还是HAL库:标准库函数直接、结构清晰,适合像这样一个功能明确的检测系统;HAL库适合有CubeMX自动生成代码、快速切换芯片型号的场景。这个项目用标准库完全够,而且网上的参考代码和教程最多,出问题好排查。
工程模板建议直接找一份自己熟悉的Keil5标准工程模板,确认里面已经配置好STM32F103C8T6的芯片支持包和ST-LINK下载器选项。项目里要用的外设比较固定:GPIO用来读车门状态、驱动蜂鸣器,ADC用来采气体传感器,I2C用来读SHT30,UART用来调试和接GSM模块,定时器用来做毫秒级的系统时钟。启动文件用的是startup_stm32f10x_md.s,对应中等容量的F103芯片。
3.1 最小外设集合:从Keil5标准工程模板开始
先把系统框架拆成几个独立模块。传感器采集模块负责温湿度和CO原始值读取,数据处理模块负责滤波和阈值判断,状态机模块负责儿童滞留逻辑,报警模块负责本地声光和远程短信,这样后加传感器或改报警方式都不用推倒重来。
// system_init.c 中的外设初始化骨架,省略错误处理 void System_Init(void) { // 设置系统时钟为72MHz,来源于外部8MHz晶振 SystemInit(); // 配置GPIO:PA0为ADC输入,PC13为车门信号输入,PB0为后排占用输入 // PC14接蜂鸣器控制引脚,PA2接红色LED MX_GPIO_Init(); // 配置ADC1通道0,采样时间为480周期,软件触发 MX_ADC1_Init(); // 配置I2C1,速率400kHz,用于SHT30 MX_I2C1_Init(); // 配置USART1,波特率115200,用于调试日志 MX_USART1_Init(); // 配置USART2,波特率9600,用于SIM800C MX_USART2_Init(); // 配置TIM2产生1ms的软件时基 MX_TIM2_Init(); // 传感器预热延时不在这里做,交给上层状态机 }初始化顺序有讲究。GPIO要先于ADC和I2C,因为外设初始化函数会用到对应的引脚配置;串口要在系统时钟之后配置,否则波特率计算全部错误,调试信息会变成乱码。TIM2的1ms时基用来作为整个系统的时钟节拍,比在main函数里写delay死等要靠谱得多,尤其后面状态机需要记录“已经监测了多少分钟”的时候,没有时基什么都做不了。
如果用标准库,注意外设时钟要手动打开。常见的问题是初始化了ADC但忘记RCC_APB2PeriphClockCmd开ADC1时钟,现象是ADC_GetConversionValue返回0或全满,调试时先查这一步。另外I2C引脚是开漏模式,必须外部上拉电阻,否则SHT30通信会直接失败,这是标准库工程里最容易翻车的地方之一。
3.2 ADC采样与软件滤波:把原始码值换算成温度和CO浓度
MQ-7输出的模拟电压从0V到3.3V,对应ADC的原始码值是0到4095,但单片机的参考电压VREF如果由AMS1117-3.3提供,实际可能只有3.28V左右。换算时不要偷懒写死4096当满量程,最好用一个电位器校准一下,或者用STM32内部的VREFINT通道做基准校正。气体浓度的ppm换算依赖传感器模块的放大倍数和负载电阻,不同商家模块差异很大,所以工程里用“原始码值”作为报警判断依据更可靠,真要想显示ppm,需要自己做两点标定。
// adc_sensor.c 中的ADC读取与中值滤波 #define ADC_BUF_SIZE 5 static uint16_t adc_buf[ADC_BUF_SIZE]; static uint8_t adc_idx = 0; uint16_t Read_CO_Raw(void) { uint16_t raw; uint16_t sorted[ADC_BUF_SIZE]; // 软件触发一次转换,等待EOC标志置位 ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); raw = ADC_GetConversionValue(ADC1); // 环形缓冲区存最近5次采样,用于后面取中值 adc_buf[adc_idx++] = raw; if (adc_idx >= ADC_BUF_SIZE) { adc_idx = 0; } // 拷贝并排序,样本只有5个,冒泡排序足够用 for (int i = 0; i < ADC_BUF_SIZE; i++) { sorted[i] = adc_buf[i]; } for (int i = 0; i < ADC_BUF_SIZE - 1; i++) { for (int j = 0; j < ADC_BUF_SIZE - 1 - i; j++) { if (sorted[j] > sorted[j + 1]) { uint16_t tmp = sorted[j]; sorted[j] = sorted[j + 1]; sorted[j + 1] = tmp; } } } return sorted[ADC_BUF_SIZE / 2]; }采样时间对CO传感器特别重要。MQ-7的内部等效阻抗不低,如果ADC采样时间太短,采到的值会偏小。用ADC_SampleTime_480Cycles,在72MHz时钟下大约是6.7μs,对小封装贴片模块上的高阻抗输出已经足够。软件触发模式最省事,不需要配置外部触发引脚。
中值滤波比均值滤波更适合这里。气体传感器偶尔会出现一个瞬时毛刺,可能来自车内电器干扰,均值滤波会把毛刺摊平到所有样本里,中值滤波则能直接把它丢弃。采样周期我一般设为1秒一次,连续采5次,每一秒更新一次滤波结果,既不会让报警响应太迟钝,也不会让数据变平滑到看不清趋势。
3.3 儿童滞留判定状态机:用“门开→有人→关门→温升”压缩误报
真正的儿童滞留报警逻辑用状态机来实现。四个状态分别是:待机、检测到开门、确认有人、关门后监测。用状态机的好处是每一次状态切换都对应一个明确的车辆事件,报警不是只看当前温度,而是要求“开门时后排有占用信号”且“关门后温度持续上升”,两个条件同时满足才触发,误报率大大降低。
// child_presence.c 中的状态机主体 typedef enum { STATE_IDLE, // 待机状态,车门一直关着 STATE_DOOR_OPENED, // 检测到车门打开 STATE_OCCUPIED, // 开门状态下后排占用信号有效 STATE_MONITORING // 车门关闭,持续监测环境 } PresenceState; static PresenceState state = STATE_IDLE; static uint32_t state_enter_tick = 0; void Presence_Update(void) { uint8_t door_open = READ_DOOR_STATUS(); uint8_t occupied = READ_OCCUPANT(); uint16_t temp_x10 = Read_Temp_X10(); // 温度×10,单位0.1℃ uint16_t co_raw = Read_CO_Raw(); switch (state) { case STATE_IDLE: if (door_open) { state = STATE_DOOR_OPENED; } break; case STATE_DOOR_OPENED: if (!door_open) { // 关门后确认后排有占用,进入监测 if (occupied) { state = STATE_OCCUPIED; state_enter_tick = Get_Tick_Ms(); } else { state = STATE_IDLE; } } break; case STATE_OCCUPIED: if (door_open) { // 大人回来开门,立刻复位 state = STATE_IDLE; } else { state = STATE_MONITORING; state_enter_tick = Get_Tick_Ms(); } break; case STATE_MONITORING: if (door_open) { state = STATE_IDLE; // 车门再次打开,默认大人返回 } else if (temp_x10 > TEMP_ALERT_LEVEL_X10 && co_raw > CO_ALERT_LEVEL_RAW && Get_Tick_Ms() - state_enter_tick > MONITOR_DELAY_MS) { // 连续监测超过设定时间且环境恶化,触发报警 Alert_Trigger(ALERT_LEVEL_2); } break; default: state = STATE_IDLE; break; } }这段状态机最关键的是“关门后才启动监测”。如果开门状态一直存在,说明大人还在车旁边,或者正在上下车,这时候报警没有任何意义。车门关闭后,再结合后排占用信号,才推断出“大人离开、儿童还在”这一结论。
占用信号要用锁存思路处理。压力垫或红外开关的信号在关门后可能被车身震动影响,我一般会在STATE_DOOR_OPENED状态里连续读三次,至少两次为有效才确认occupied,然后把这个值保持到进入MONITORING状态,而不是实时刷新。因为儿童在安全座椅上可能不乱动,实时检测反而可能因为“一段时间没动”判成没人。
4. 报警链路怎么做才管用:本地声光加GSM短信双路通知
报警链路是这个系统的最后一环,也是最容易被人糊弄过去的一环。很多毕设做到蜂鸣器响就算完了,但实际场景里,家长在超市里可能根本听不见车里的蜂鸣器。完整的报警链路应该是:本地声光持续提醒周围路人,同时通过GSM模块给家长手机发短信,两条路一起走。
本地报警和远程通知要分两个层级。第一级预警只做声光提醒,不触发短信;第二级紧急报警才会调GSM短信。这样既避免误报短信轰炸家长,又保证真正危险时能通知到人。
4.1 本地报警:蜂鸣器、LED和继电器驱动电路
蜂鸣器不能直接用STM32的GPIO驱动。有源蜂鸣器正常工作电流在20mA以上,GPIO的灌电流能力有限,直接接会拉低引脚电平,甚至把MCU的3.3V电源拖垮。常见做法是GPIO接一个NPN三极管,比如S8050,基极串1kΩ电阻,蜂鸣器串在集电极和电源之间,发射极接地,这样MCU只需要输出几毫安就能控制整个蜂鸣器。
LED指示用低电平驱动更符合F103的内部结构。点亮LED时GPIO输出低电平,LED串一个330Ω或470Ω电阻接到3.3V,电流控制在5mA到10mA左右。报警时可以做成闪烁模式,而不是常亮,闪烁更容易被路人注意到。如果还想增加威慑力,可以加一路继电器控制车辆双闪灯,但接继电器必须加续流二极管,否则继电器断开瞬间的反向电动势可能打坏GPIO。
void Alert_Trigger(alert_level_t level) { if (level == ALERT_LEVEL_1) { // 一级报警:LED以1Hz频率闪烁,蜂鸣器短鸣 GPIO_SetBits(GPIOA, GPIO_Pin_2); // 关闭LED for (int i = 0; i < 3; i++) { GPIO_ResetBits(GPIOC, GPIO_Pin_14); // 开蜂鸣器 Delay_Ms(200); GPIO_SetBits(GPIOC, GPIO_Pin_14); // 关蜂鸣器 Delay_Ms(200); } } else { // 二级报警:LED常亮,蜂鸣器持续响 GPIO_ResetBits(GPIOA, GPIO_Pin_2); // 点亮LED GPIO_ResetBits(GPIOC, GPIO_Pin_14); // 蜂鸣器常开 } }报警函数不能被状态机阻塞。蜂鸣器响200ms后继续执行其他任务,如果写成while死循环,短信发送和温度监测都会被卡住,整个系统就变成了“只会叫的哑巴”。我一般会把报警函数设计成非阻塞,只设置报警标志位,由主循环统一处理闪烁和响铃。
4.2 远程短信通知:SIM800C的AT指令和发送函数
远程通知常见做法是用GSM模块,SIM800C是应用最广泛的型号之一,四频段覆盖国内主流运营商网络。模块通过串口和STM32通信,波特率默认9600,上电后需要等它搜索网络,大约10到20秒。发送短信用的是标准AT指令,流程是:先设置文本模式,再指定收件人号码,最后发送内容。
// gsm_sms.c 中的短信发送函数 static void UART2_Send(const char* str) { while (*str) { while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); USART_SendData(USART2, (uint8_t)(*str++)); } } uint8_t GSM_Send_SMS(const char* phone, const char* content) { char cmd[48]; uint8_t retry = 0; while (retry < 3) { UART2_Send("AT+CMGF=1\r\n"); Delay_Ms(300); // 收到OK应答后才继续,不能盲目往下发 sprintf(cmd, "AT+CMGS=\"%s\"\r\n", phone); UART2_Send(cmd); // 等待模块返回“>”提示,表示可以输入短信内容 if (GSM_Wait_Prompt(5000)) { UART2_Send(content); UART2_Send("\x1A"); // 十六进制0x1A,表示发送 if (GSM_Wait_OK(10000)) { return 1; } } retry++; Delay_Ms(2000); } return 0; }GSM模块发送短信有三个关键坑。第一,每条AT指令都必须等待模块返回OK,不能只靠延时猜时间,信号差的时候模块应答可能晚到两三秒。第二,发送内容必须以十六进制0x1A结尾,这是标准的Ctrl+Z字符,串口发出的普通“\r\n”会被当作短信内容的一部分或者直接导致发送失败。第三,首次发送失败要重试,GSM模块在信号不稳定或SIM卡欠费时会返回ERROR,直接放弃会导致整个报警链失效。
如果只想做零星几条短信,接收端可以明确写成家长的手机号。更实用的做法是把号码存在STM32内部Flash的一个固定地址,工程里留一个串口指令支持改号码,这样换车换号都不用重新烧录程序。这个功能对毕设答辩尤其加分,能把“系统可配置”这个概念讲清楚。
4.3 分级报警与防误报参数:延迟时间怎么定才不“狼来了”
分级报警的延迟时间是整个系统参数里最需要抠的细节。延迟太短,停车拿个东西就触发短信;延迟太长,真出事了家长收到通知时已经来不及。我一般参考下面的参数表,具体数值留成宏定义,方便实车测试时调整。
| 报警级别 | 触发条件 | 延迟时间 | 动作 |
|---|---|---|---|
| 一级预警 | 温度≥38℃,CO偏高 | 30秒 | 本地声光,不发短信 |
| 二级报警 | 温度≥42℃,CO持续偏高 | 60秒 | 本地声光+发送短信 |
| 紧急报警 | 温度≥45℃,CO超过上限 | 90秒 | 持续声光+每5分钟重发短信 |
一级预警的30秒,是为了过滤掉家长只是临时开门拿东西的场景。二级报警的60秒要配合温度上升速率一起判断,上升速率大于每分钟0.3℃才触发,防止夏天暴晒后直接停在原地高温触发。短信重发间隔不要低于5分钟,否则GSM模块会一直被短信请求占用,主控的串口缓冲区也容易被AT指令返回的消息塞满。
报警复位条件也要想清楚。车门打开、或者检测到后排占用信号消失,都算复位条件。复位时短信要同步停止,不能系统已经判定人回来了还继续给家长发短信。这里用“车门打开即复位”最可靠,因为不管孩子是被抱走还是自己打开车门,车门动作是唯一不会撒谎的信号。
5. 车载环境里最容易翻车的五个坑:从传感器到烧录器
实车环境和实验室差得很远。这个系统在台架上测一周都可能一切正常,一上车就出现各种奇怪现象。下面五个坑都是我实际碰到过或者看别人反复栽进去的,按现象、原因、解决的顺序写,照着排查能省好几天的调试时间。
5.1 太阳暴晒下传感器读数虚高,座舱空气温度被“测歪了”
现象:车子在太阳下停一小时,系统显示温度已经60℃甚至70℃,但人坐进车里明显没这么热,手摸仪表台才烫手。报警阈值设45℃,结果系统一进车就报警,误报率极高。
原因:温度传感器被装进了封闭外壳,或者贴在了黑色塑料件附近。阳光直接加热外壳和安装面,传感器测到的是“外壳温度”而不是“空气温度”。SHT30的封装本身很小,热容低,外壳吸热后读数立刻跟着涨。
解决:传感器要悬空安装,外壳开透气孔,安装面用导热差的塑料柱支撑,避免大面积接触金属或深色内饰。如果还压不住,可以用一个小风扇在传感器附近强制对流,读数会明显回落。标定时把“传感器读数”和“车内实际空气温度”的差值记录成补偿偏置,在软件里统一减去。
5.2 ADC参考电压被拉低,CO浓度一路飘
现象:系统运行一段时间后,CO读数逐渐升高,误判为空气质量变差。拔掉蜂鸣器或LED后读数立刻恢复正常,接上就又飘。
原因:蜂鸣器和LED的电源与STM32共用同一个3.3V稳压器。报警时蜂鸣器瞬间拉到20mA以上电流,LED再叠加5mA,3.3V被拉低几十毫伏。ADC的参考电压VREF就是这路电源,参考电压下降后,同样的传感器输出电压会被ADC判成更大的码值,表现为CO浓度假性升高。
解决:给ADC的VREF引脚单独加一个10μF钽电容再加0.1μF陶瓷电容,气体传感器供电和MCU数字供电分开布线,或者直接用STM32内部的VREFINT通道计算真实参考电压,换算时用实时参考电压而不是写死的3.3V。调试时用万用表盯着3.3V,报警前后如果电压波动超过20mV,就说明电源退耦不够。
5.3 熄火断电导致系统复位,GSM模块掉线重连
现象:车辆熄火瞬间,报警系统重启,GSM模块从开机重新搜网,刚好错过最需要发短信的时刻。等重新搜网成功,已经过了好几分钟。
原因:ACC电源在熄火瞬间被切断,如果系统只从ACC取电,MCU会直接断电。GSM模块开机后搜索网络需要10秒以上,如果是冷启动,这个时间可能拖到30秒。很多国产GSM模块还有个特点:供电瞬间跌落再恢复时,模块内部的电源管理芯片可能进入异常状态,必须再次拉低PWRKEY才能正常开机。
解决:电源方案改成ACC+常电双路。常电负责给GSM模块的RTC唤醒电路和单片机备份域供电,ACC负责唤醒系统进入工作状态。GSM模块的VBAT接常电,PWRKEY由MCU控制,系统检测到ACC从低变高时,才给模块上电开机。如果不想接常电,至少要在ACC后端并一个超级电容,容量按1F左右起步,能维持系统几秒钟的完整关机流程,把短信发完再断电。
5.4 禁用JTAG后ST-LINK连不上,程序烧不进去
现象:程序下载一次后再也连不上ST-LINK,Keil报“No target connected”或“RDDI-DAP Error”。网上搜了一圈,有人说是固件坏了,有人说是线的问题,最后只能用串口ISP擦除。
原因:代码里为了省引脚,调用了禁用JTAG的库函数,把PA13/PA14/PA15和PB3/PB4释放成普通GPIO。调试接口被程序自己关掉后,ST-LINK自然无法连接。这是STM32开发里最常见的“手滑”问题,而且一旦禁用,下次就没法用调试器刷程序了。
解决:BOOT0引脚拉高,复位后进入系统存储器自举模式,用串口ISP工具或STM32 ST-LINK Utility做整片擦除,然后再把BOOT0拉回低电平重新下载。更稳妥的办法是代码里不要彻底禁用SWJ,只禁用JTAG、保留SWD,也就是调用GPIO_Remap_SWJ_JTAGDisable,这样ST-LINK的SWDIO和SWCLK还能工作,不会把自己锁死。
5.5 单一阈值报警必误报:只设高温会连叫三次问候
现象:系统只设了一个“温度高于40℃就报警”的阈值。夏天暴晒后车停在太阳下,温度就在38℃到42℃之间反复横跳,系统一下报警一下复位,手机短信连着收好几条,但车里的孩子其实已经被接走了。
原因:没有设置迟滞区间。升温到40℃触发报警,温度降到39.9℃就立刻复位,而停车场的阴影、旁边车开走带来的气流都会让温度小幅波动。报警在阈值附近反复动作,家长收到一堆短信,反而把真正需要关注的报警淹没了。
解决:报警逻辑加迟滞。触发报警用42℃作为高阈值,复位要等温度回落到34℃以下才允许。也就是“热到42℃才叫,凉到34℃才闭嘴”,中间不会频繁切换。短信发送也要加防重发锁,同一个滞留事件只发一条短信,除非系统复位又重新监测到危险,否则不重复发送。迟滞区间和防重发锁两个功能加起来,误报率能降一个数量级。
6. 交付前用泡沫箱和灯泡做标定:把报警阈值调到“不躺枪”
标定是整个系统从“能跑”到“敢装车”的分界线。没有条件天天把车停在太阳底下做实验时,可以用一个泡沫箱、一盏白炽灯或浴霸加热灯、再加一个水温计,低成本复现座舱暴晒的升温过程。泡沫箱模拟封闭座舱,加热灯模拟太阳辐照,把传感器放进去,记录从25℃升到50℃需要多长时间,顺便观察CO传感器在高温下的漂移方向。
标定流程分三步。第一步,把报警系统的调试串口接出来,程序里预留一个标定模式,长按按键进入,每秒打印一次温度、湿度和CO原始码值到串口助手。第二步,记录不同加热时长下的数据,自然冷却时再看读数能回落到多少,把“升得快落得慢”作为传感器热惯性的参考。第三步,把实测数据对应到报警参数上,你会发现加热灯直接照着传感器,读数比环境温度高8℃到10℃,这个差值就是要补偿的安装误差。
滞回比较的参数在标定模式里直接改。触发阈值设在实测高温曲线的中段,比如模拟结果表明车内会在15分钟内到45℃,那就把一级预警设成38℃、二级报警42℃、紧急报警45℃;复位阈值固定低于触发阈值4℃到6℃,保证一个完整的报警周期不会被温度抖动打断。最终交付前,我的习惯是连着三天每天跑两轮两小时的模拟实验,一轮加热一轮自然冷却,报警次数、短信发送时间、复位行为全记录在表格里,确认没有任何一次误报和漏报后才会考虑装车。
“能报”和“报得准”之间隔着的全是这类细节。状态机、迟滞比较、传感器补偿、电源退耦,每一项单独看都不复杂,但合在一起才是真正能用的儿童滞留报警系统。希望这篇能帮到你做出一套让自己心里有底的车内环境检测和儿童滞留报警方案。
本文还有配套的精品资源,点击获取