基于多传感器的厕所意外跌倒检测与警报系统
项目开发背景
随着社会老龄化的加剧和独居人口的增多,卫生间作为家庭中易发生意外的场所,其安全监控需求日益凸显。传统监控方式如摄像头存在隐私泄露问题,而手动报警设备在用户跌倒后可能无法及时触发,导致救援延迟,危及生命安全。因此,开发一种非接触、智能化且能综合判断环境风险的卫生间安全监测系统,具有重要的现实意义。
现有技术中,跌倒检测多依赖于穿戴设备或视频分析,但穿戴设备易被遗忘或拒绝使用,视频监控则侵犯个人隐私。毫米波雷达传感器作为一种新兴技术,能通过微波反射监测人体活动和生命体征,实现非接触、无隐私侵犯的持续监控。结合环境传感器,系统还能提前预警地滑、火灾等潜在风险,弥补单一监测的不足。
本项目旨在设计一套集成化的卫生间安全监测系统,通过毫米波雷达实时监测人体状态与呼吸频率,结合温湿度、烟雾传感器评估环境安全。当检测到疑似跌倒静止时,系统自动启动声光报警并倒计时,若无解除则通过4G模块远程报警,同时支持一键紧急呼叫与误报取消。硬件上采用STM32主控、LD2410C雷达、AHT20和MQ-2传感器以及Air724UG通信模块,确保可靠性与实时性,为用户提供全天候守护。
该系统的开发将提升卫生间的安全水平,尤其适用于老年人、残疾人士或康复患者,减少意外发生后的响应时间,并辅助家庭或护理人员及时干预。通过智能化手段,项目期望推动居家安全技术的普及,促进健康养老和智慧家居的发展。
设计实现的功能
(1)通过毫米波雷达传感器监测卫生间内人体的活动状态与生命体征(呼吸频率)。
(2)检测到疑似跌倒的静止状态后,启动声光报警,并启动倒计时。
(3)倒计时结束后若无解除信号,则通过4G模块自动拨打预设电话并发送包含位置的报警短信。
(4)集成温湿度、烟雾传感器,实现环境异常(地滑、火灾)的辅助判断与报警。
(5)设计一键紧急呼叫按钮,支持本地手动取消误报警。
项目硬件模块组成
(1)主控模块:采用STM32F103RCT6单片机作为数据处理中心。
(2)人体感知模块:采用LD2410C毫米波雷达传感器进行非接触式监测。
(3)环境传感模块:包括AHT20温湿度传感器和MQ-2烟雾传感器。
(4)通信模块:采用Air724UG 4G Cat.1模块进行远程通信。
(5)交互与电源模块:包括LED指示灯、有源蜂鸣器、紧急按钮及AMS1117稳压电路。
设计意义
本设计通过毫米波雷达传感器实现对卫生间内人体活动状态与生命体征的非接触式监测,有效保护用户隐私的同时,能够实时检测疑似跌倒等静止状态。这一功能在家庭或护理机构的卫生间环境中尤为重要,可显著降低因跌倒未及时救助导致的安全风险,尤其适用于老年人、病患等脆弱群体,提升独处时的安全保障。
集成呼吸频率监测功能,不仅关注跌倒事件,还扩展了对用户基本生命体征的观察。这为日常健康管理提供了辅助数据,有助于早期发现呼吸异常等潜在健康问题,增强预防性护理能力,体现了健康与安全相结合的智能关怀理念。
环境传感模块的加入,通过温湿度传感器识别地滑风险(如高湿度),以及烟雾传感器预警火灾隐患,实现了对卫生间环境安全的综合监控。这种多维度判断机制减少了单一传感器误报的可能,提高了报警准确性,进一步保障用户免受环境因素引发的意外伤害。
通信模块采用4G技术,确保在无Wi-Fi覆盖环境下也能可靠传输报警信号,自动拨打预设电话并发送位置信息,使远程监护人能迅速响应紧急情况。一键紧急呼叫按钮的设计赋予用户手动控制权,方便在误报警时及时取消,平衡了自动化与人工干预的需求,提升系统实用性和用户信任度。
整体设计以实际应用为导向,通过硬件模块的协同工作,构建了一个低成本、高效率的卫生间安全监控系统。它不仅响应了老龄化社会对智能安防的需求,还推动了家居安全技术的普及,有助于减轻家庭和社会的照护压力,促进安全、便捷的生活环境建设。
设计思路
设计思路围绕实现一个智能卫生间安全监测系统,以STM32F103RCT6单片机为核心控制器,集成毫米波雷达、环境传感器和4G通信模块,旨在实时监测人体状态与环境参数,并在检测到异常时及时报警。系统通过硬件模块的协同工作,确保功能稳定可靠,避免添加不必要的扩展。
系统首先通过LD2410C毫米波雷达传感器非接触式监测卫生间内人体的活动状态与呼吸频率,该传感器将数据实时传输给主控单片机进行处理,以识别正常活动与异常静止情况。同时,AHT20温湿度传感器和MQ-2烟雾传感器采集环境数据,用于辅助判断地滑或火灾等风险,当温湿度或烟雾浓度超出阈值时,系统将触发环境异常报警,增强综合监测能力。
当毫米波雷达检测到人体处于疑似跌倒的静止状态时,主控模块立即触发声光报警,包括LED指示灯和有源蜂鸣器,并启动一个倒计时器。在倒计时期间,用户可以通过一键紧急呼叫按钮手动取消报警,以防止误报,这为用户提供了本地干预的机会,确保报警的准确性。
倒计时结束后,若未收到解除信号,主控模块通过Air724UG 4G Cat.1模块自动拨打预设电话号码,并发送包含位置的报警短信,实现远程紧急通知。通信模块的集成使系统能够在无人响应时快速联系外部救援,提升应急响应效率。
交互与电源模块设计包括紧急按钮用于手动呼叫或取消报警,电源模块通过AMS1117稳压电路提供稳定电压,确保整个系统在各类环境下可靠运行。整个设计注重实用性和响应速度,以实际硬件为基础,实现从监测到报警的完整流程,保障卫生间使用者的安全。
框架图
系统框架图
+---------------------+ +---------------------+ +---------------------+
| 人体感知模块 | | 环境传感模块 | | 交互模块 |
| LD2410C毫米波雷达 |---->| AHT20温湿度传感器 |---->| LED指示灯 |
| 监测活动与呼吸频率 | | MQ-2烟雾传感器 | | 有源蜂鸣器 |
+---------------------+ +---------------------+ | 紧急按钮 |
| | +---------------------+
| | |
v v v
+-----------------------------------------------------------------------+
| 主控模块 |
| STM32F103RCT6 |
| 处理传感器数据、判断跌倒与环境异常、控制报警与通信逻辑 |
+-----------------------------------------------------------------------+
| | |
v v v
+---------------------+ +---------------------+ +---------------------+
| 通信模块 | | 电源模块 | | 报警与反馈控制 |
| Air724UG 4G模块 | | AMS1117稳压电路 | | (声光报警触发) |
| 拨打电话与发送短信 | | 供电整个系统 | | (倒计时管理) |
+---------------------+ +---------------------+ +---------------------+
连接说明:
- 箭头表示数据流或控制流方向。
- 人体感知模块和环境传感模块将监测数据发送至主控模块。
- 主控模块根据逻辑控制交互模块(声光报警、按钮响应)和通信模块(远程报警)。
- 电源模块为所有模块提供稳定电源。
系统总体设计
系统总体设计以STM32F103RCT6单片机为核心处理单元,协调各硬件模块实现卫生间内人体活动与环境状态的智能监控。LD2410C毫米波雷达传感器作为人体感知模块,非接触式监测人体移动状态和呼吸频率,数据实时传输至主控模块进行分析处理,用于识别正常活动与疑似跌倒的静止情况。
当检测到疑似跌倒时,主控模块立即控制LED指示灯和有源蜂鸣器启动声光报警,同时触发内部倒计时机制。倒计时期间,系统持续监测一键紧急呼叫按钮的状态,支持用户手动取消误报警;若倒计时结束前未收到解除信号,主控模块通过Air724UG 4G Cat.1通信模块自动拨打预设电话,并发送包含设备位置的报警短信,实现远程紧急求助。
环境传感模块集成AHT20温湿度传感器和MQ-2烟雾传感器,实时采集卫生间内的温度、湿度及烟雾浓度数据。主控模块对这些数据进行分析,辅助判断地滑风险或火灾异常,并在环境参数超出安全阈值时触发辅助报警,通过声光方式提醒用户,增强整体安全防护。
交互与电源模块包括LED指示灯、有源蜂鸣器、紧急按钮及AMS1117稳压电路,提供本地报警反馈和手动操作界面。紧急按钮允许用户主动触发紧急呼叫或取消误报警,而稳压电路确保各模块供电稳定,保障系统长期可靠运行。所有硬件模块通过主控模块统一调度,实现数据采集、处理、报警与通信的闭环控制,形成一个高效、实用的安全监控系统。
系统功能总结
| 功能类别 | 功能描述 | 核心实现模块 |
|---|---|---|
| 人体状态监测 | 非接触式监测卫生间内人员的活动状态与呼吸频率生命体征。 | LD2410C 毫米波雷达传感器 |
| 跌倒检测与报警 | 检测到疑似跌倒后的长时间静止状态,立即启动本地声光报警并开始倒计时。 | STM32主控、LED与蜂鸣器 |
| 远程紧急通知 | 倒计时结束后若未手动解除,系统自动通过4G网络拨打预设电话并发送含位置的报警短信。 | Air724UG 4G通信模块 |
| 环境安全监测 | 实时监测环境温湿度与烟雾浓度,对地滑(高湿度)、火灾等风险进行辅助判断与报警。 | AHT20温湿度、MQ-2烟雾传感器 |
| 本地交互与控制 | 提供一键紧急呼叫按钮,支持在报警倒计时期间手动取消误报警。 | 紧急按钮、STM32主控 |
| 系统核心与供电 | 负责所有传感器数据采集、逻辑判断、功能协调与系统稳定供电。 | STM32F103RCT6主控、AMS1117稳压电路 |
设计的各个功能模块描述
主控模块采用STM32F103RCT6单片机作为数据处理中心,负责接收并处理来自其他传感器的数据,监测人体活动状态与呼吸频率,判断疑似跌倒事件,并控制声光报警、倒计时以及通信模块的启动与停止。
人体感知模块使用LD2410C毫米波雷达传感器进行非接触式监测,实时检测卫生间内人体的活动状态和生命体征如呼吸频率,以识别疑似跌倒的静止状态,为系统提供关键的人体感知数据。
环境传感模块包括AHT20温湿度传感器和MQ-2烟雾传感器,AHT20传感器监测环境温湿度以辅助判断地滑风险,MQ-2传感器检测烟雾浓度以实现火灾预警,这些数据集成到系统中用于环境异常的辅助判断与报警。
通信模块采用Air724UG 4G Cat.1模块进行远程通信,当检测到跌倒事件且倒计时结束后若无解除信号,该模块自动拨打预设电话并发送包含位置的报警短信,实现紧急远程通知功能。
交互与电源模块包括LED指示灯、有源蜂鸣器、紧急按钮及AMS1117稳压电路,LED指示灯和有源蜂鸣器用于实现声光报警,紧急按钮支持一键紧急呼叫和本地手动取消误报警,AMS1117稳压电路则为整个系统提供稳定的电源供应。
上位机代码设计
// 主程序入口
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QTimer>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QDateTime>
#include <QSettings>
#include <QFile>
#include <QThread>
// 传感器数据结构体
struct SensorData {
QDateTime timestamp;
bool isMoving;
float respirationRate;
float temperature;
float humidity;
int smokeLevel;
bool fallDetected;
bool emergencyButton;
bool cancelAlarm;
};
// 串口通信类
class SerialManager : public QObject {
Q_OBJECT
private:
QSerialPort *serialPort;
QString portName;
int baudRate;
QByteArray buffer;
public:
explicit SerialManager(QObject *parent = nullptr) : QObject(parent) {
serialPort = new QSerialPort(this);
}
bool connectSerial(const QString &port, int baud) {
portName = port;
baudRate = baud;
serialPort->setPortName(portName);
serialPort->setBaudRate(baudRate);
serialPort->setDataBits(QSerialPort::Data8);
serialPort->setParity(QSerialPort::NoParity);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);
if (serialPort->open(QIODevice::ReadWrite)) {
connect(serialPort, &QSerialPort::readyRead, this, &SerialManager::readData);
return true;
}
return false;
}
void disconnectSerial() {
if (serialPort->isOpen()) {
serialPort->close();
}
}
void sendCommand(const QByteArray &command) {
if (serialPort->isOpen()) {
serialPort->write(command);
serialPort->flush();
}
}
signals:
void dataReceived(const SensorData &data);
void connectionStatusChanged(bool connected);
private slots:
void readData() {
buffer.append(serialPort->readAll());
// 解析数据包(假设以'\n'结束)
while (buffer.contains('\n')) {
int endIndex = buffer.indexOf('\n');
QByteArray packet = buffer.left(endIndex);
buffer.remove(0, endIndex + 1);
if (packet.size() > 0) {
processPacket(packet);
}
}
}
private:
void processPacket(const QByteArray &packet) {
// 解析传感器数据包格式
// 格式示例: "MOVE:1,RESP:16.5,TEMP:25.3,HUM:60,SMOKE:0,FALL:0,BTN:0"
SensorData data;
data.timestamp = QDateTime::currentDateTime();
QString strPacket = QString::fromLatin1(packet);
QStringList items = strPacket.split(',');
for (const QString &item : items) {
QStringList keyValue = item.split(':');
if (keyValue.size() == 2) {
QString key = keyValue[0].trimmed();
QString value = keyValue[1].trimmed();
if (key == "MOVE") {
data.isMoving = value.toInt();
} else if (key == "RESP") {
data.respirationRate = value.toFloat();
} else if (key == "TEMP") {
data.temperature = value.toFloat();
} else if (key == "HUM") {
data.humidity = value.toFloat();
} else if (key == "SMOKE") {
data.smokeLevel = value.toInt();
} else if (key == "FALL") {
data.fallDetected = value.toInt();
} else if (key == "BTN") {
data.emergencyButton = value.toInt();
} else if (key == "CANCEL") {
data.cancelAlarm = value.toInt();
}
}
}
emit dataReceived(data);
}
};
// 主窗口类
class MainWindow : public QMainWindow {
Q_OBJECT
private:
// UI组件
QWidget *centralWidget;
QVBoxLayout *mainLayout;
// 状态显示区域
QLabel *connectionStatusLabel;
QLabel *movementStatusLabel;
QLabel *respirationLabel;
QLabel *temperatureLabel;
QLabel *humidityLabel;
QLabel *smokeLabel;
QLabel *fallStatusLabel;
// 控制按钮
QPushButton *connectButton;
QPushButton *disconnectButton;
QPushButton *emergencyStopButton;
QPushButton *clearLogButton;
// 日志区域
QTextEdit *logTextEdit;
// 系统组件
SerialManager *serialManager;
QTimer *dataTimer;
QSettings *settings;
// 报警状态
bool isAlarmActive;
int alarmCountdown;
QTimer *alarmTimer;
public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
setupUI();
setupConnections();
loadSettings();
serialManager = new SerialManager(this);
isAlarmActive = false;
alarmCountdown = 30; // 30秒倒计时
}
~MainWindow() {
saveSettings();
}
private:
void setupUI() {
// 设置窗口属性
setWindowTitle("智能卫生间安全监测系统");
setGeometry(100, 100, 800, 600);
// 创建中心部件和布局
centralWidget = new QWidget(this);
mainLayout = new QVBoxLayout(centralWidget);
// 连接状态
connectionStatusLabel = new QLabel("串口状态: 未连接", this);
connectionStatusLabel->setStyleSheet("QLabel { font-weight: bold; }");
mainLayout->addWidget(connectionStatusLabel);
// 创建网格布局用于传感器数据显示
QGridLayout *sensorGrid = new QGridLayout();
movementStatusLabel = new QLabel("人体活动: --", this);
sensorGrid->addWidget(new QLabel("人体活动状态:"), 0, 0);
sensorGrid->addWidget(movementStatusLabel, 0, 1);
respirationLabel = new QLabel("呼吸频率: -- bpm", this);
sensorGrid->addWidget(new QLabel("呼吸频率:"), 1, 0);
sensorGrid->addWidget(respirationLabel, 1, 1);
temperatureLabel = new QLabel("温度: -- °C", this);
sensorGrid->addWidget(new QLabel("温度:"), 0, 2);
sensorGrid->addWidget(temperatureLabel, 0, 3);
humidityLabel = new QLabel("湿度: -- %", this);
sensorGrid->addWidget(new QLabel("湿度:"), 1, 2);
sensorGrid->addWidget(humidityLabel, 1, 3);
smokeLabel = new QLabel("烟雾浓度: -- ppm", this);
sensorGrid->addWidget(new QLabel("烟雾浓度:"), 2, 0);
sensorGrid->addWidget(smokeLabel, 2, 1);
fallStatusLabel = new QLabel("跌倒检测: 无", this);
fallStatusLabel->setStyleSheet("QLabel { color: green; font-weight: bold; }");
sensorGrid->addWidget(new QLabel("跌倒检测:"), 2, 2);
sensorGrid->addWidget(fallStatusLabel, 2, 3);
mainLayout->addLayout(sensorGrid);
// 按钮布局
QHBoxLayout *buttonLayout = new QHBoxLayout();
connectButton = new QPushButton("连接串口", this);
disconnectButton = new QPushButton("断开连接", this);
disconnectButton->setEnabled(false);
emergencyStopButton = new QPushButton("紧急停止报警", this);
emergencyStopButton->setEnabled(false);
emergencyStopButton->setStyleSheet("QPushButton { background-color: red; color: white; }");
clearLogButton = new QPushButton("清空日志", this);
buttonLayout->addWidget(connectButton);
buttonLayout->addWidget(disconnectButton);
buttonLayout->addWidget(emergencyStopButton);
buttonLayout->addWidget(clearLogButton);
buttonLayout->addStretch();
mainLayout->addLayout(buttonLayout);
// 日志区域
logTextEdit = new QTextEdit(this);
logTextEdit->setReadOnly(true);
logTextEdit->setMaximumHeight(200);
mainLayout->addWidget(new QLabel("系统日志:"));
mainLayout->addWidget(logTextEdit);
setCentralWidget(centralWidget);
}
void setupConnections() {
connect(connectButton, &QPushButton::clicked, this, &MainWindow::connectSerial);
connect(disconnectButton, &QPushButton::clicked, this, &MainWindow::disconnectSerial);
connect(emergencyStopButton, &QPushButton::clicked, this, &MainWindow::stopAlarm);
connect(clearLogButton, &QPushButton::clicked, this, &MainWindow::clearLog);
// 报警定时器
alarmTimer = new QTimer(this);
connect(alarmTimer, &QTimer::timeout, this, &MainWindow::updateAlarmCountdown);
}
void loadSettings() {
settings = new QSettings("SmartBathroom", "MonitorSystem", this);
}
void saveSettings() {
settings->setValue("WindowGeometry", saveGeometry());
}
private slots:
void connectSerial() {
// 这里可以添加串口选择对话框
QString portName = "COM3"; // 默认串口,实际中应该让用户选择
int baudRate = 115200;
if (serialManager->connectSerial(portName, baudRate)) {
connectionStatusLabel->setText("串口状态: 已连接 (COM3, 115200)");
connectionStatusLabel->setStyleSheet("QLabel { color: green; font-weight: bold; }");
connectButton->setEnabled(false);
disconnectButton->setEnabled(true);
logMessage("系统", "串口连接成功");
// 开始数据接收
connect(serialManager, &SerialManager::dataReceived, this, &MainWindow::updateSensorData);
} else {
QMessageBox::warning(this, "连接失败", "无法打开串口,请检查连接");
logMessage("系统", "串口连接失败");
}
}
void disconnectSerial() {
serialManager->disconnectSerial();
connectionStatusLabel->setText("串口状态: 未连接");
connectionStatusLabel->setStyleSheet("QLabel { color: black; font-weight: bold; }");
connectButton->setEnabled(true);
disconnectButton->setEnabled(false);
logMessage("系统", "串口连接已断开");
}
void updateSensorData(const SensorData &data) {
// 更新UI显示
movementStatusLabel->setText(data.isMoving ? "活动" : "静止");
respirationLabel->setText(QString("呼吸频率: %1 bpm").arg(data.respirationRate, 0, 'f', 1));
temperatureLabel->setText(QString("温度: %1 °C").arg(data.temperature, 0, 'f', 1));
humidityLabel->setText(QString("湿度: %1 %").arg(data.humidity, 0, 'f', 1));
smokeLabel->setText(QString("烟雾浓度: %1 ppm").arg(data.smokeLevel));
// 跌倒检测处理
if (data.fallDetected && !isAlarmActive) {
fallStatusLabel->setText("跌倒检测: 警报!");
fallStatusLabel->setStyleSheet("QLabel { color: red; font-weight: bold; font-size: 14pt; }");
isAlarmActive = true;
alarmCountdown = 30;
emergencyStopButton->setEnabled(true);
// 启动报警倒计时
alarmTimer->start(1000); // 每秒触发
logMessage("警报", "检测到疑似跌倒事件!");
logMessage("警报", QString("开始30秒倒计时..."));
}
// 紧急按钮状态
if (data.emergencyButton) {
logMessage("用户", "紧急呼叫按钮被按下");
}
// 取消报警信号
if (data.cancelAlarm && isAlarmActive) {
stopAlarm();
logMessage("系统", "本地报警已取消");
}
// 环境异常检测
if (data.humidity > 85) {
logMessage("警告", "湿度过高,可能存在地滑风险");
}
if (data.smokeLevel > 500) {
logMessage("警报", "烟雾浓度过高,可能存在火灾风险!");
}
}
void updateAlarmCountdown() {
alarmCountdown--;
if (alarmCountdown > 0) {
logMessage("警报", QString("倒计时: %1秒").arg(alarmCountdown));
} else {
alarmTimer->stop();
logMessage("警报", "倒计时结束,正在拨打预设电话...");
logMessage("警报", "正在发送报警短信...");
// 这里可以添加实际的4G通信代码
// 模拟发送报警
QMessageBox::critical(this, "紧急报警",
"跌倒警报!\n已自动拨打预设电话并发送报警短信。\n"
"位置信息: 智能卫生间001号");
}
}
void stopAlarm() {
if (isAlarmActive) {
alarmTimer->stop();
isAlarmActive = false;
emergencyStopButton->setEnabled(false);
fallStatusLabel->setText("跌倒检测: 无");
fallStatusLabel->setStyleSheet("QLabel { color: green; font-weight: bold; }");
// 发送停止报警命令到下位机
serialManager->sendCommand("STOP_ALARM\n");
logMessage("系统", "报警已手动停止");
}
}
void clearLog() {
logTextEdit->clear();
}
void logMessage(const QString &category, const QString &message) {
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
QString logEntry = QString("[%1] [%2] %3").arg(timestamp, category, message);
logTextEdit->append(logEntry);
// 保存到文件
QFile logFile("system_log.txt");
if (logFile.open(QIODevice::Append | QIODevice::Text)) {
QTextStream out(&logFile);
out << logEntry << "\n";
logFile.close();
}
}
};
// 程序入口
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 设置应用信息
QApplication::setApplicationName("智能卫生间安全监测系统");
QApplication::setOrganizationName("智能安全系统");
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
#include "main.moc"
这个上位机程序包含以下主要功能:
-
串口通信管理:
- 通过SerialManager类处理与STM32的串口通信
- 实时接收并解析传感器数据包
-
数据监控界面:
- 实时显示人体活动状态和呼吸频率
- 显示温湿度、烟雾浓度等环境数据
- 醒目显示跌倒检测状态
-
报警管理系统:
- 检测到跌倒后启动30秒倒计时
- 倒计时结束后模拟拨打预设电话和发送报警短信
- 支持手动紧急停止报警
-
环境异常检测:
- 湿度过高(>85%)时提示地滑风险
- 烟雾浓度过高(>500ppm)时提示火灾风险
-
日志记录系统:
- 记录所有系统事件和报警信息
- 支持日志保存到文件
- 提供日志清空功能
-
用户交互:
- 串口连接/断开控制
- 紧急停止报警按钮
- 实时数据显示界面
程序采用模块化设计,便于扩展和维护,可以实时监控卫生间安全状态并及时响应紧急情况。
模块代码设计
由于代码量非常大,我将提供一个精简但完整的STM32寄存器版本框架代码,包含主要模块的初始化配置和关键函数。
// main.h
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32f10x.h"
// 引脚定义
// LED指示灯 - PC13
#define LED_PIN 13
#define LED_PORT GPIOC
// 蜂鸣器 - PB12
#define BEEP_PIN 12
#define BEEP_PORT GPIOB
// 紧急按钮 - PA0
#define BTN_PIN 0
#define BTN_PORT GPIOA
// 烟雾传感器模拟输入 - PA1
#define SMOKE_ADC_CHANNEL 1
// 系统状态
typedef enum {
STATE_NORMAL,
STATE_FALL_DETECTED,
STATE_COUNTDOWN,
STATE_ALARMING
} SystemState;
extern SystemState system_state;
extern uint32_t fall_timer;
#endif
// stm32f10x_reg.h
#ifndef __STM32F10X_REG_H
#define __STM32F10X_REG_H
// RCC寄存器
#define RCC_BASE 0x40021000
#define RCC_CR (*((volatile uint32_t *)(RCC_BASE + 0x00)))
#define RCC_CFGR (*((volatile uint32_t *)(RCC_BASE + 0x04)))
#define RCC_APB2ENR (*((volatile uint32_t *)(RCC_BASE + 0x18)))
#define RCC_APB1ENR (*((volatile uint32_t *)(RCC_BASE + 0x1C)))
// GPIO寄存器
#define GPIOA_BASE 0x40010800
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define GPIO_CRL(port) (*((volatile uint32_t *)(port + 0x00)))
#define GPIO_CRH(port) (*((volatile uint32_t *)(port + 0x04)))
#define GPIO_IDR(port) (*((volatile uint32_t *)(port + 0x08)))
#define GPIO_ODR(port) (*((volatile uint32_t *)(port + 0x0C)))
#define GPIO_BSRR(port) (*((volatile uint32_t *)(port + 0x10)))
#define GPIO_BRR(port) (*((volatile uint32_t *)(port + 0x14)))
// USART寄存器
#define USART1_BASE 0x40013800
#define USART2_BASE 0x40004400
#define USART_SR(uart) (*((volatile uint32_t *)(uart + 0x00)))
#define USART_DR(uart) (*((volatile uint32_t *)(uart + 0x04)))
#define USART_BRR(uart) (*((volatile uint32_t *)(uart + 0x08)))
#define USART_CR1(uart) (*((volatile uint32_t *)(uart + 0x0C)))
#define USART_CR2(uart) (*((volatile uint32_t *)(uart + 0x10)))
#define USART_CR3(uart) (*((volatile uint32_t *)(uart + 0x14)))
// ADC寄存器
#define ADC1_BASE 0x40012400
#define ADC_SR (*((volatile uint32_t *)(ADC1_BASE + 0x00)))
#define ADC_CR1 (*((volatile uint32_t *)(ADC1_BASE + 0x04)))
#define ADC_CR2 (*((volatile uint32_t *)(ADC1_BASE + 0x08)))
#define ADC_SMPR1 (*((volatile uint32_t *)(ADC1_BASE + 0x0C)))
#define ADC_SMPR2 (*((volatile uint32_t *)(ADC1_BASE + 0x10)))
#define ADC_SQR1 (*((volatile uint32_t *)(ADC1_BASE + 0x2C)))
#define ADC_SQR2 (*((volatile uint32_t *)(ADC1_BASE + 0x30)))
#define ADC_SQR3 (*((volatile uint32_t *)(ADC1_BASE + 0x34)))
#define ADC_DR (*((volatile uint32_t *)(ADC1_BASE + 0x4C)))
// I2C寄存器
#define I2C1_BASE 0x40005400
#define I2C_CR1(i2c) (*((volatile uint32_t *)(i2c + 0x00)))
#define I2C_CR2(i2c) (*((volatile uint32_t *)(i2c + 0x04)))
#define I2C_OAR1(i2c) (*((volatile uint32_t *)(i2c + 0x08)))
#define I2C_OAR2(i2c) (*((volatile uint32_t *)(i2c + 0x0C)))
#define I2C_DR(i2c) (*((volatile uint32_t *)(i2c + 0x10)))
#define I2C_SR1(i2c) (*((volatile uint32_t *)(i2c + 0x14)))
#define I2C_SR2(i2c) (*((volatile uint32_t *)(i2c + 0x18)))
#define I2C_CCR(i2c) (*((volatile uint32_t *)(i2c + 0x1C)))
#define I2C_TRISE(i2c) (*((volatile uint32_t *)(i2c + 0x20)))
// NVIC寄存器
#define NVIC_ISER0 (*((volatile uint32_t *)0xE000E100))
#define NVIC_ISER1 (*((volatile uint32_t *)0xE000E104))
#define NVIC_IPR3 (*((volatile uint32_t *)0xE000E40C))
// EXTI寄存器
#define EXTI_BASE 0x40010400
#define EXTI_IMR (*((volatile uint32_t *)(EXTI_BASE + 0x00)))
#define EXTI_EMR (*((volatile uint32_t *)(EXTI_BASE + 0x04)))
#define EXTI_RTSR (*((volatile uint32_t *)(EXTI_BASE + 0x08)))
#define EXTI_FTSR (*((volatile uint32_t *)(EXTI_BASE + 0x0C)))
#define EXTI_PR (*((volatile uint32_t *)(EXTI_BASE + 0x14)))
// AFIO寄存器
#define AFIO_BASE 0x40010000
#define AFIO_EXTICR1 (*((volatile uint32_t *)(AFIO_BASE + 0x08)))
// SysTick寄存器
#define SysTick_BASE 0xE000E010
#define SysTick_CTRL (*((volatile uint32_t *)(SysTick_BASE + 0x00)))
#define SysTick_LOAD (*((volatile uint32_t *)(SysTick_BASE + 0x04)))
#define SysTick_VAL (*((volatile uint32_t *)(SysTick_BASE + 0x08)))
#endif
// system.c
#include "main.h"
#include "stm32f10x_reg.h"
SystemState system_state = STATE_NORMAL;
uint32_t fall_timer = 0;
uint32_t system_tick = 0;
// 系统时钟初始化
void SystemClock_Config(void) {
// 使能HSE
RCC_CR |= 0x00010000;
while(!(RCC_CR & 0x00020000));
// 配置PLL为9倍频
RCC_CFGR |= 0x001C0000;
RCC_CFGR |= 0x00010000;
// 选择PLL作为系统时钟
RCC_CFGR |= 0x00000002;
while(!(RCC_CFGR & 0x00000008));
}
// GPIO初始化
void GPIO_Init(void) {
// 使能GPIO时钟
RCC_APB2ENR |= 0x0000001C; // 使能GPIOA, GPIOB, GPIOC
// LED引脚配置为推挽输出
GPIO_CRH(GPIOC_BASE) &= ~(0xF << ((LED_PIN-8)*4));
GPIO_CRH(GPIOC_BASE) |= (0x1 << ((LED_PIN-8)*4));
// 蜂鸣器引脚配置为推挽输出
GPIO_CRH(GPIOB_BASE) &= ~(0xF << ((BEEP_PIN-8)*4));
GPIO_CRH(GPIOB_BASE) |= (0x1 << ((BEEP_PIN-8)*4));
// 紧急按钮配置为上拉输入
GPIO_CRL(GPIOA_BASE) &= ~(0xF << (BTN_PIN*4));
GPIO_CRL(GPIOA_BASE) |= (0x8 << (BTN_PIN*4));
GPIO_ODR(GPIOA_BASE) |= (1 << BTN_PIN);
// 烟雾传感器ADC引脚配置为模拟输入
GPIO_CRL(GPIOA_BASE) &= ~(0xF << (1*4));
GPIO_CRL(GPIOA_BASE) |= (0x0 << (1*4));
}
// USART1初始化 (用于4G模块)
void USART1_Init(uint32_t baudrate) {
// 使能USART1时钟
RCC_APB2ENR |= 0x00004000;
// 配置TX(PA9)为复用推挽输出
GPIO_CRH(GPIOA_BASE) &= ~(0xF << ((9-8)*4));
GPIO_CRH(GPIOA_BASE) |= (0xB << ((9-8)*4));
// 配置RX(PA10)为浮空输入
GPIO_CRH(GPIOA_BASE) &= ~(0xF << ((10-8)*4));
GPIO_CRH(GPIOA_BASE) |= (0x4 << ((10-8)*4));
// 配置波特率
USART_BRR(USART1_BASE) = 72000000 / baudrate;
// 使能USART
USART_CR1(USART1_BASE) = 0x0000200C; // 使能TX, RX, USART
}
// USART2初始化 (用于毫米波雷达)
void USART2_Init(uint32_t baudrate) {
// 使能USART2时钟
RCC_APB1ENR |= 0x00020000;
// 配置TX(PA2)为复用推挽输出
GPIO_CRL(GPIOA_BASE) &= ~(0xF << (2*4));
GPIO_CRL(GPIOA_BASE) |= (0xB << (2*4));
// 配置RX(PA3)为浮空输入
GPIO_CRL(GPIOA_BASE) &= ~(0xF << (3*4));
GPIO_CRL(GPIOA_BASE) |= (0x4 << (3*4));
// 配置波特率
USART_BRR(USART2_BASE) = 36000000 / baudrate;
// 使能USART
USART_CR1(USART2_BASE) = 0x0000200C;
}
// ADC初始化
void ADC_Init(void) {
// 使能ADC1时钟
RCC_APB2ENR |= 0x00000200;
// ADC校准
ADC_CR2 = 0x00000001; // 开启ADC
delay_ms(1);
ADC_CR2 |= 0x00000008; // 开始校准
while(ADC_CR2 & 0x00000008);
// 配置ADC
ADC_CR1 = 0x00000000; // 独立模式
ADC_CR2 = 0x00000001; // 单次转换模式
ADC_SMPR2 = 0x00000007 << (SMOKE_ADC_CHANNEL * 3); // 239.5周期采样
}
// I2C初始化 (用于AHT20温湿度传感器)
void I2C_Init(void) {
// 使能I2C1时钟
RCC_APB1ENR |= 0x00200000;
// 配置PB6(SCL), PB7(SDA)为复用开漏输出
GPIO_CRL(GPIOB_BASE) &= ~(0xFF << 24);
GPIO_CRL(GPIOB_BASE) |= (0xBB << 24);
// 配置I2C
I2C_CR1(I2C1_BASE) = 0x0000; // 禁用I2C
I2C_CR2(I2C1_BASE) = 0x0024; // 36MHz
I2C_CCR(I2C1_BASE) = 0x00B4; // 100kHz
I2C_TRISE(I2C1_BASE) = 0x0025;
I2C_CR1(I2C1_BASE) = 0x0001; // 使能I2C
}
// 外部中断初始化 (紧急按钮)
void EXTI_Init(void) {
// 使能AFIO时钟
RCC_APB2ENR |= 0x00000001;
// 配置PA0为EXTI0
AFIO_EXTICR1 &= ~(0x000F);
AFIO_EXTICR1 |= 0x0000;
// 配置下降沿触发
EXTI_FTSR |= 0x00000001;
// 使能EXTI0中断
EXTI_IMR |= 0x00000001;
// 配置NVIC
NVIC_ISER0 |= 0x00000040; // 使能EXTI0中断
}
// SysTick初始化
void SysTick_Init(void) {
SysTick_LOAD = 72000 - 1; // 1ms中断
SysTick_VAL = 0;
SysTick_CTRL = 0x00000007; // 使能SysTick
}
// 延迟函数
void delay_ms(uint32_t ms) {
uint32_t start = system_tick;
while((system_tick - start) < ms);
}
// 发送字符
void USART_SendChar(uint32_t usart, char ch) {
while(!(USART_SR(usart) & 0x00000080));
USART_DR(usart) = ch;
}
// 发送字符串
void USART_SendString(uint32_t usart, char *str) {
while(*str) {
USART_SendChar(usart, *str++);
}
}
// 读取ADC值
uint16_t ADC_Read(uint8_t channel) {
// 配置通道序列
ADC_SQR3 = channel;
// 开始转换
ADC_CR2 |= 0x00000004;
// 等待转换完成
while(!(ADC_SR & 0x00000002));
// 清除标志位
ADC_SR &= ~0x00000002;
return ADC_DR;
}
// AHT20读取温湿度
uint8_t AHT20_Read(float *temperature, float *humidity) {
uint8_t data[6];
uint32_t temp;
// 发送测量命令
I2C_Start(I2C1_BASE);
I2C_SendAddress(I2C1_BASE, 0x70, 0); // 写模式
I2C_SendData(I2C1_BASE, 0xAC);
I2C_SendData(I2C1_BASE, 0x33);
I2C_SendData(I2C1_BASE, 0x00);
I2C_Stop(I2C1_BASE);
delay_ms(80);
// 读取数据
I2C_Start(I2C1_BASE);
I2C_SendAddress(I2C1_BASE, 0x70, 1); // 读模式
for(uint8_t i = 0; i < 5; i++) {
data[i] = I2C_ReceiveData(I2C1_BASE, 1);
}
data[5] = I2C_ReceiveData(I2C1_BASE, 0);
I2C_Stop(I2C1_BASE);
if(!(data[0] & 0x80)) {
return 0; // 忙状态
}
// 计算湿度
temp = ((uint32_t)data[1] << 12) | ((uint32_t)data[2] << 4) | (data[3] >> 4);
*humidity = (temp * 100.0) / 0x100000;
// 计算温度
temp = ((uint32_t)(data[3] & 0x0F) << 16) | ((uint32_t)data[4] << 8) | data[5];
*temperature = (temp * 200.0) / 0x100000 - 50.0;
return 1;
}
// I2C起始条件
void I2C_Start(uint32_t i2c) {
I2C_CR1(i2c) |= 0x0100; // 产生起始条件
while(!(I2C_SR1(i2c) & 0x0001));
}
// I2C停止条件
void I2C_Stop(uint32_t i2c) {
I2C_CR1(i2c) |= 0x0200; // 产生停止条件
}
// I2C发送地址
void I2C_SendAddress(uint32_t i2c, uint8_t address, uint8_t read) {
I2C_DR(i2c) = (address << 1) | read;
while(!(I2C_SR1(i2c) & 0x0002));
(void)I2C_SR1(i2c);
(void)I2C_SR2(i2c);
}
// I2C发送数据
void I2C_SendData(uint32_t i2c, uint8_t data) {
I2C_DR(i2c) = data;
while(!(I2C_SR1(i2c) & 0x0084));
}
// I2C接收数据
uint8_t I2C_ReceiveData(uint32_t i2c, uint8_t ack) {
if(ack) {
I2C_CR1(i2c) |= 0x0400; // 使能ACK
} else {
I2C_CR1(i2c) &= ~0x0400; // 禁用ACK
}
while(!(I2C_SR1(i2c) & 0x0040));
return I2C_DR(i2c);
}
// LED控制
void LED_Control(uint8_t state) {
if(state) {
GPIO_BRR(LED_PORT) = (1 << LED_PIN);
} else {
GPIO_BSRR(LED_PORT) = (1 << LED_PIN);
}
}
// 蜂鸣器控制
void Beep_Control(uint8_t state) {
if(state) {
GPIO_BSRR(BEEP_PORT) = (1 << BEEP_PIN);
} else {
GPIO_BRR(BEEP_PORT) = (1 << BEEP_PIN);
}
}
// 毫米波雷达解析
void Radar_ParseData(uint8_t *data, uint8_t len) {
// 解析雷达数据,检测跌倒
// LD2410C数据格式: 0xAA 0xAA 命令 长度 数据... 校验和
uint8_t checksum = 0;
for(uint8_t i = 0; i < len - 1; i++) {
checksum += data[i];
}
if(checksum == data[len-1]) {
// 解析运动状态
uint16_t movement = (data[4] << 8) | data[5];
uint16_t respiration = (data[6] << 8) | data[7];
// 跌倒检测逻辑:运动能量突然降低并保持静止
if(movement < 50 && respiration > 0) {
// 疑似跌倒,启动倒计时
system_state = STATE_FALL_DETECTED;
fall_timer = system_tick;
LED_Control(1); // LED亮
}
}
}
// 4G模块发送报警
void Send_Alarm_SMS(char *phone, char *message) {
char cmd[100];
// 设置短信文本模式
USART_SendString(USART1_BASE, "AT+CMGF=1\r\n");
delay_ms(1000);
// 设置短信中心号码
USART_SendString(USART1_BASE, "AT+CSCA=\"+8613800270500\"\r\n");
delay_ms(1000);
// 发送短信
sprintf(cmd, "AT+CMGS=\"%s\"\r\n", phone);
USART_SendString(USART1_BASE, cmd);
delay_ms(1000);
USART_SendString(USART1_BASE, message);
delay_ms(100);
USART_SendChar(USART1_BASE, 0x1A); // Ctrl+Z
}
// 4G模块拨打电话
void Make_Phone_Call(char *phone) {
char cmd[50];
sprintf(cmd, "ATD%s;\r\n", phone);
USART_SendString(USART1_BASE, cmd);
}
// 系统主循环
void System_MainLoop(void) {
uint8_t radar_buffer[20];
uint8_t radar_index = 0;
float temperature, humidity;
uint16_t smoke_value;
while(1) {
// 读取温湿度
if(AHT20_Read(&temperature, &humidity)) {
// 检测温湿度异常(地滑风险)
if(humidity > 85.0) {
LED_Control(1); // 高湿度警示
}
}
// 读取烟雾浓度
smoke_value = ADC_Read(SMOKE_ADC_CHANNEL);
if(smoke_value > 800) { // 阈值可调整
system_state = STATE_ALARMING;
Beep_Control(1);
Send_Alarm_SMS("13800000000", "Warning: Smoke detected!");
}
// 处理毫米波雷达数据
if(USART_SR(USART2_BASE) & 0x0020) { // RXNE
uint8_t ch = USART_DR(USART2_BASE);
radar_buffer[radar_index++] = ch;
if(radar_index >= sizeof(radar_buffer)) {
Radar_ParseData(radar_buffer, radar_index);
radar_index = 0;
}
}
// 状态机处理
switch(system_state) {
case STATE_FALL_DETECTED:
if((system_tick - fall_timer) > 5000) { // 5秒倒计时
system_state = STATE_COUNTDOWN;
Beep_Control(1); // 启动声光报警
}
break;
case STATE_COUNTDOWN:
// 倒计时30秒
if((system_tick - fall_timer) > 35000) { // 5秒 + 30秒
system_state = STATE_ALARMING;
Send_Alarm_SMS("13800000000", "Emergency: Fall detected!");
Make_Phone_Call("13800000000");
}
break;
case STATE_ALARMING:
// 报警状态,等待人工干预
if((system_tick % 1000) < 500) { // LED闪烁
LED_Control(1);
} else {
LED_Control(0);
}
break;
default:
LED_Control(0);
Beep_Control(0);
break;
}
delay_ms(100);
}
}
// main.c
#include "main.h"
#include "stm32f10x_reg.h"
// 中断服务函数
void EXTI0_IRQHandler(void) __attribute__((interrupt));
void SysTick_Handler(void) __attribute__((interrupt));
void EXTI0_IRQHandler(void) {
// 紧急按钮按下,取消报警
if(EXTI_PR & 0x00000001) {
system_state = STATE_NORMAL;
LED_Control(0);
Beep_Control(0);
EXTI_PR = 0x00000001; // 清除中断标志
}
}
void SysTick_Handler(void) {
system_tick++;
}
int main(void) {
// 系统初始化
SystemClock_Config();
GPIO_Init();
USART1_Init(115200); // 4G模块
USART2_Init(256000); // 毫米波雷达
ADC_Init();
I2C_Init();
EXTI_Init();
SysTick_Init();
// 初始化4G模块
USART_SendString(USART1_BASE, "AT\r\n");
delay_ms(1000);
USART_SendString(USART1_BASE, "AT+CPIN?\r\n");
delay_ms(1000);
USART_SendString(USART1_BASE, "AT+CSQ\r\n");
delay_ms(1000);
// 系统主循环
System_MainLoop();
return 0;
}
// startup_stm32f10x_md.s (部分关键汇编代码)
.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler
.word PVD_IRQHandler
.word TAMPER_IRQHandler
.word RTC_IRQHandler
.word FLASH_IRQHandler
.word RCC_IRQHandler
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
.word EXTI2_IRQHandler
.word EXTI3_IRQHandler
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.word DMA1_Channel2_IRQHandler
.word DMA1_Channel3_IRQHandler
.word DMA1_Channel4_IRQHandler
.word DMA1_Channel5_IRQHandler
.word DMA1_Channel6_IRQHandler
.word DMA1_Channel7_IRQHandler
.word ADC1_2_IRQHandler
.word USB_HP_CAN_TX_IRQHandler
.word USB_LP_CAN_RX_IRQHandler
.word CAN_RX1_IRQHandler
.word CAN_SCE_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word TIM4_IRQHandler
.word I2C1_EV_IRQHandler
.word I2C1_ER_IRQHandler
.word I2C2_EV_IRQHandler
.word I2C2_ER_IRQHandler
.word SPI1_IRQHandler
.word SPI2_IRQHandler
.word USART1_IRQHandler
.word USART2_IRQHandler
.word USART3_IRQHandler
.word EXTI15_10_IRQHandler
.word RTCAlarm_IRQHandler
.word USBWakeUp_IRQHandler
.size g_pfnVectors, .-g_pfnVectors
.text
.thumb
.thumb_func
.align 2
Reset_Handler:
ldr sp, =_estack
bl SystemInit
bl main
bx lr
.pool
.size Reset_Handler, .-Reset_Handler
这个代码框架提供了完整的寄存器级别STM32开发代码,包含了:
- 系统时钟配置 - 72MHz主频
- GPIO控制 - LED、蜂鸣器、按钮
- USART通信 - 毫米波雷达和4G模块
- ADC采集 - 烟雾传感器
- I2C通信 - 温湿度传感器
- 中断系统 - 紧急按钮响应
- 系统定时 - SysTick定时器
- 状态机逻辑 - 跌倒检测流程控制
注意事项:
- 需要根据实际硬件连接调整引脚定义
- 毫米波雷达数据解析需要根据LD2410C实际协议调整
- 4G模块AT指令需要根据Air724UG文档调整
- 阈值参数需要根据实际环境校准
- 错误处理和异常情况需要进一步完善
项目核心代码
#include "stm32f10x.h"
#include "system_stm32f10x.h"
// 硬件模块初始化函数声明(假设已实现)
void MMWave_Init(void); // 毫米波雷达初始化
void MMwave_GetData(uint16_t* activity, uint16_t* breath_rate);
void EnvSensor_Init(void); // 环境传感器初始化
void EnvSensor_GetData(float* temp, float* humi, uint16_t* smoke);
void GSM_Init(void); // 4G模块初始化
void GSM_CallNumber(const char* phone_num);
void GSM_SendSMS(const char* phone_num, const char* msg);
void Buzzer_LED_Init(void); // 声光报警初始化
void Buzzer_Control(FunctionalState state);
void LED_Control(FunctionalState state);
void EmergencyBtn_Init(void); // 紧急按钮初始化
uint8_t EmergencyBtn_Read(void);
// 系统状态定义
typedef enum {
SYS_NORMAL = 0,
SYS_FALL_DETECTED,
SYS_COUNTDOWN,
SYS_ALARMING,
SYS_ENV_ALARM
} SystemState;
// 全局变量
volatile SystemState sys_state = SYS_NORMAL;
volatile uint32_t fall_timer = 0;
volatile uint8_t alarm_cancel_flag = 0;
const uint32_t COUNTDOWN_TIME = 30; // 30秒倒计时
const char* EMERGENCY_PHONE = "13800138000";
// 延时函数
void Delay_ms(uint32_t nms) {
uint32_t i, j;
for(i=0; i<nms; i++)
for(j=0; j<8000; j++);
}
// 系统初始化
void System_Init(void) {
// 时钟初始化
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN |
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN;
// 禁用JTAG,释放PB3、PB4、PA15
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_1;
// 初始化各模块
MMwave_Init();
EnvSensor_Init();
Buzzer_LED_Init();
EmergencyBtn_Init();
GSM_Init();
// 配置SysTick定时器(1ms中断)
SysTick->LOAD = 72000 - 1; // 72MHz/1000
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
// 使能全局中断
__enable_irq();
}
// 跌倒检测算法
uint8_t Fall_Detection(uint16_t activity, uint16_t breath_rate) {
static uint16_t activity_history[5] = {0};
static uint8_t index = 0;
// 更新活动历史记录
activity_history[index] = activity;
index = (index + 1) % 5;
// 检测条件:
// 1. 当前活动值突降为0
// 2. 历史活动值较高(表示之前有活动)
// 3. 呼吸频率在正常范围内(排除无人情况)
if(activity == 0 && breath_rate > 8 && breath_rate < 30) {
// 检查历史活动值
uint8_t has_activity = 0;
for(uint8_t i = 0; i < 5; i++) {
if(activity_history[i] > 50) {
has_activity = 1;
break;
}
}
return has_activity;
}
return 0;
}
// 环境异常检测
uint8_t Env_Abnormal_Detection(float temp, float humi, uint16_t smoke) {
// 温湿度检测地滑风险
if(humi > 80.0) return 1; // 湿度过高,可能地滑
// 烟雾检测火灾风险
if(smoke > 800) return 2; // 烟雾浓度过高
// 温度检测火灾风险
if(temp > 50.0) return 3; // 温度过高
return 0;
}
// 生成报警短信
void Generate_Alarm_SMS(char* buffer, uint8_t alarm_type) {
const char* loc = "卫生间";
switch(alarm_type) {
case 1: // 跌倒
sprintf(buffer, "紧急!检测到人员跌倒,位置:%s", loc);
break;
case 2: // 火灾
sprintf(buffer, "紧急!检测到火灾风险,位置:%s", loc);
break;
case 3: // 地滑
sprintf(buffer, "警告!环境湿度过高,地滑风险,位置:%s", loc);
break;
default:
sprintf(buffer, "紧急报警,位置:%s", loc);
}
}
// SysTick中断服务函数
void SysTick_Handler(void) {
static uint32_t env_check_timer = 0;
if(sys_state == SYS_COUNTDOWN) {
if(fall_timer > 0) {
fall_timer--;
// 倒计时结束,触发报警
if(fall_timer == 0 && !alarm_cancel_flag) {
sys_state = SYS_ALARMING;
}
}
}
// 每5秒检查一次环境
if(env_check_timer++ >= 5000) {
env_check_timer = 0;
// 环境检测标记
static uint8_t env_alarm_flag = 0;
if(!env_alarm_flag) {
float temp, humi;
uint16_t smoke;
EnvSensor_GetData(&temp, &humi, &smoke);
uint8_t env_status = Env_Abnormal_Detection(temp, humi, smoke);
if(env_status > 0) {
sys_state = SYS_ENV_ALARM;
env_alarm_flag = 1;
// 立即发送环境报警
char sms_buffer[128];
Generate_Alarm_SMS(sms_buffer, env_status);
GSM_SendSMS(EMERGENCY_PHONE, sms_buffer);
// 声光报警
Buzzer_Control(ENABLE);
LED_Control(ENABLE);
}
}
}
}
int main(void) {
System_Init();
// 传感器数据变量
uint16_t activity = 0, breath_rate = 0;
float temperature = 0, humidity = 0;
uint16_t smoke_value = 0;
// 报警取消检查计数器
uint32_t alarm_cancel_check = 0;
while(1) {
// 1. 读取毫米波雷达数据
MMwave_GetData(&activity, &breath_rate);
// 2. 状态机处理
switch(sys_state) {
case SYS_NORMAL:
// 检测跌倒
if(Fall_Detection(activity, breath_rate)) {
sys_state = SYS_FALL_DETECTED;
fall_timer = COUNTDOWN_TIME * 1000; // 转换为ms
alarm_cancel_flag = 0;
}
break;
case SYS_FALL_DETECTED:
// 启动声光报警和倒计时
Buzzer_Control(ENABLE);
LED_Control(ENABLE);
sys_state = SYS_COUNTDOWN;
break;
case SYS_COUNTDOWN:
// 检查紧急按钮
if(EmergencyBtn_Read()) {
alarm_cancel_flag = 1;
Buzzer_Control(DISABLE);
LED_Control(DISABLE);
sys_state = SYS_NORMAL;
}
break;
case SYS_ALARMING:
// 拨打紧急电话
GSM_CallNumber(EMERGENCY_PHONE);
// 发送报警短信
char sms_buffer[128];
Generate_Alarm_SMS(sms_buffer, 1);
GSM_SendSMS(EMERGENCY_PHONE, sms_buffer);
// 持续声光报警
Buzzer_Control(ENABLE);
LED_Control(ENABLE);
sys_state = SYS_NORMAL; // 返回正常状态,等待下次检测
break;
case SYS_ENV_ALARM:
// 环境报警处理
if(alarm_cancel_check++ > 10000) { // 10秒后检查是否取消
alarm_cancel_check = 0;
if(EmergencyBtn_Read()) {
Buzzer_Control(DISABLE);
LED_Control(DISABLE);
sys_state = SYS_NORMAL;
}
}
break;
}
// 3. 读取环境传感器数据(用于环境检测,SysTick中断中处理)
EnvSensor_GetData(&temperature, &humidity, &smoke_value);
// 4. 延时等待(实际项目中应使用RTOS或更精确的调度)
Delay_ms(100);
}
}
// 中断优先级配置(在启动文件中配置)
// 这里省略NVIC配置代码,实际项目中需要配置
总结
本文所述系统旨在通过先进的传感器技术与智能控制逻辑,实现对卫生间环境及人体状态的全面监测与应急响应。其核心功能包括利用毫米波雷达非接触式监测人体活动与生命体征,并在检测到疑似跌倒时触发声光报警与倒计时机制;若倒计时结束未收到解除信号,系统能通过4G通信自动拨打电话并发送带位置的报警短信,确保及时救援。此外,系统集成了温湿度与烟雾传感器,以辅助判断地滑或火灾等环境异常,进一步提升安全性,同时配备一键紧急呼叫按钮,支持手动取消误报警,增强了使用的灵活性与可靠性。
在硬件实现上,该系统以STM32F103RCT6单片机作为主控核心,协调各模块高效运行。人体感知依赖于LD2410C毫米波雷达传感器,环境监测通过AHT20温湿度传感器和MQ-2烟雾传感器完成,而远程通信则由Air724UG 4G模块负责,确保数据传输的稳定性。交互与电源部分包括LED指示灯、有源蜂鸣器、紧急按钮及AMS1117稳压电路,共同构建了用户友好的操作界面和稳定的供电基础。
整体而言,该系统通过多模块集成与智能化设计,实现了对卫生间内安全风险的主动预警与快速响应,体现了现代物联网技术在健康监护与安防领域的创新应用。其结合非接触监测、环境感知与远程通信,不仅提升了独居老人或特殊需求人群的安全保障水平,也为智能家居的发展提供了实用参考。
- 点赞
- 收藏
- 关注作者
评论(0)