基于STM32和华为云的智能人体健康监测系统设计
项目开发背景
随着全球人口老龄化趋势加剧和慢性疾病发病率上升,持续性的健康监测需求日益迫切。心血管疾病作为主要的健康威胁之一,其早期预警和日常管理对降低风险至关重要,而体温则是反映人体基本生理状态的重要指标。传统医疗监测设备通常体积庞大、成本高昂且依赖专业环境,难以满足家庭或个人日常便捷、实时的健康管理需求。
现有家用健康设备功能单一、数据孤立,缺乏有效的远程管理和智能分析能力。用户无法及时获取异常预警,医护人员也难以对居家患者进行长期、系统的健康数据跟踪。因此,开发一种低功耗、易部署且具备云端协同能力的智能监测系统,成为提升个人健康管理效率和及时干预能力的关键突破口。
物联网技术与云计算的快速发展为此提供了技术基础。以高性能低功耗的STM32F103C8T6微控制器为核心,结合高精度传感器(如MAX30100心率模块、DHT11温湿度模块)和无线通信模块(ESP8266),可构建轻量化的实时数据采集终端。同时,依托华为云物联网平台强大的设备接入、数据存储与分析能力,能实现海量健康数据的安全汇聚与高效处理。配合跨平台的上位机软件,可为用户提供直观的数据可视化、历史回溯及智能预警服务。
本设计通过整合嵌入式传感技术、无线通信、云平台及客户端应用,构建一套完整的“端-云-应用”协同系统,旨在为个人及家庭提供低成本、高可用的健康监测解决方案,推动健康管理向智能化、远程化和预防化方向发展。
设计实现的功能
(1) STM32F103C8T6通过I2C协议读取MAX30100心率血氧传感器的心率数据。
(2) STM32F103C8T6通过单总线协议读取DHT11温湿度传感器的体温数据。
(3) STM32F103C8T6通过UART串口与ESP8266-01S WiFi模块通信,使用MQTT协议将数据上传到华为云物联网服务器。
(4) 华为云物联网服务器配置设备接入服务,接收、存储和处理传感器数据。
(5) 上位机QT应用使用C++语言开发,通过Paho MQTT客户端库连接到华为云服务器,订阅数据主题并实现实时数据解析。
(6) 上位机软件实现数据动态图表绘制、历史数据查询界面、阈值设置面板和异常警报功能。
项目硬件模块组成
(1) STM32F103C8T6核心板
(2) MAX30100心率血氧传感器模块
(3) DHT11温湿度传感器模块
(4) ESP8266-01S WiFi模块
(5) USB转TTL模块用于串口调试和供电
(6) 5V直流电源适配器
设计意义
本设计基于STM32F103C8T6与华为云构建的智能人体健康监测系统,具有重要的现实意义和应用价值。该系统通过实时采集心率与体温数据,为用户提供连续、便捷的健康状态监测服务,尤其适用于家庭健康监护、康复期患者管理或老年人日常健康关注等场景,有效弥补了传统定期体检在时效性与连续性上的不足。
系统深度融合了嵌入式感知技术、无线通信技术与云计算技术。STM32作为本地核心处理器,可靠地完成了多协议传感器数据采集与初步处理;ESP8266模块利用MQTT协议实现低功耗、高效率的无线数据传输;华为云物联网平台则为海量异构数据提供了安全稳定的接入、存储与处理能力。这种架构充分体现了物联网技术在健康领域的典型应用模式,验证了“端-边-云”协同的技术可行性。
上位机QT软件的设计显著提升了系统的可用性与数据价值。其实时动态曲线可视化功能直观呈现生理参数变化趋势,便于用户快速掌握健康动态;历史数据查询与CSV导出功能则支持长期健康追踪与深度分析,为个人健康管理或医疗研究提供了数据基础。这种直观的数据交互方式极大增强了用户体验。
系统设置的智能预警机制是保障用户安全的关键环节。通过自定义心率与体温阈值范围,配合上位机的声光报警功能,能够在检测到异常生理参数时第一时间发出警示。这种主动式监护模式显著降低了因健康突发状况延误处置的风险,为用户争取宝贵的应对时间,体现了技术对生命健康的守护价值。
设计思路
设计思路:系统以STM32F103C8T6微控制器为核心,负责协调各传感器模块与通信模块的工作。首先,通过I2C接口连接MAX30100传感器,周期性读取心率数据;同时通过单总线协议连接DHT11传感器获取体温数据。STM32对采集的数据进行初步处理(如滤波、单位转换)后,通过UART串口将数据发送给ESP8266-01S模块。
ESP8266-01S模块通过AT指令集与STM32交互,配置为STA模式连接无线网络,并基于MQTT协议接入华为云物联网平台。STM32将传感器数据封装为符合华为云物模型格式的JSON消息,由ESP8266发送至云平台指定主题。华为云物联网平台接收数据后,通过规则引擎将数据转发到云数据库进行持久化存储,同时支持数据导出功能。
上位机部分采用QT框架开发,使用Paho MQTT客户端库订阅华为云平台的数据主题。当接收到新数据时,解析JSON消息并更新实时显示面板。动态曲线图通过QChart组件实现,展示心率和体温的实时变化趋势。历史数据查询功能通过调用华为云API获取指定时间段的存储数据,并以表格形式展示。用户可在阈值设置面板自定义心率、体温的安全范围,当实时数据越界时,QT应用触发QSound播放警报音效,同时界面闪烁红色警示。
异常处理机制贯穿系统:STM32层面设置传感器通信超时检测;ESP8266建立重连机制应对网络波动;华为云规则引擎配置数据异常告警;上位机软件加入数据校验逻辑,防止无效数据触发误报警。各模块间通过状态指示灯反馈运行状态,便于调试与维护。
框架图
系统框架图
+-----------------------------------------------------------------+
| 华为云物联网服务器 |
| +-----------------------------+ +-------------------------+ |
| | 设备接入服务 (IoTDA) |<->| 数据存储服务 | |
| | - MQTT Broker | | - 长期存储传感器数据 | |
| | - 设备认证与管理 | | - CSV导出功能 | |
| +-----------------------------+ +-------------------------+ |
| ^ | |
| | MQTT over Internet | API调用 |
| | v |
+--------|------------------------------------------|------------+
| |
| WiFi | Internet
+--------|-----------------+ +---------|----------------+
| STM32F103C8T6 系统 | | 上位机 QT应用 |
| +---------------------+ | UART | +---------------------+ |
| | 传感器数据采集层 |<------------->| | 数据可视化与告警层 | |
| | - MAX30100 (I2C) | | +------+ | | - 实时曲线图 | |
| | → 心率数据 | | |ESP8266| | | - 历史数据查询 | |
| | - DHT11 (单总线) | | |WiFi模| | | - 阈值报警系统 | |
| | → 体温数据 | | +------+ | | (声光警报) | |
| +---------------------+ | | +---------------------+ |
| ^ | +-------------------------+
| | 传感器接口 |
+--------|------------------+
|
+--------|------------------+
| v |
| +---------------------+ |
| | 传感器层 | |
| | - MAX30100模块 | |
| | - DHT11模块 | |
| +---------------------+ |
+---------------------------+
模块说明:
-
传感器层
- MAX30100:通过I2C协议提供心率数据
- DHT11:通过单总线协议提供体温数据
-
STM32F103C8T6系统
- 传感器数据采集层:处理I2C/单总线协议,聚合传感器数据
- ESP8266通信:通过UART串口将MQTT封装数据发送至WiFi模块
-
网络传输
- ESP8266-01S:通过WiFi连接互联网,使用MQTT协议上传数据到华为云
-
华为云物联网平台
- 设备接入服务(IoTDA):MQTT消息代理,实现设备认证和数据路由
- 数据存储服务:长期存储结构化数据,支持CSV导出
-
上位机QT应用
- 数据可视化:实时曲线图/历史数据图表渲染
- 告警系统:阈值检测触发声光警报
- MQTT订阅:通过Paho库从华为云获取实时数据
系统总体设计
系统总体设计
本系统构建了一个端到端的智能人体健康监测平台,以STM32F103C8T6微控制器为核心,整合传感器数据采集、无线通信、云平台存储与处理和上位机可视化功能。系统通过STM32实时采集用户的心率与体温数据,利用ESP8266 WiFi模块将数据安全传输至华为云物联网平台进行集中存储与分析。同时,开发基于QT框架的上位机应用,动态订阅云端数据流,实现数据的实时显示、历史回溯、阈值预警及管理功能。
在硬件层,STM32F103C8T6作为本地处理中枢。它通过I2C总线协议驱动MAX30100心率血氧传感器,精确获取心率信号;通过单总线协议与DHT11温湿度传感器通信,提取体温数据。采集到的数据经过初步处理后,STM32通过UART串口与ESP8266-01S WiFi模块交互,封装成符合MQTT协议的数据包,经无线网络上传至华为云物联网服务器。
华为云物联网平台作为系统的数据中心枢纽。它提供设备接入服务,接收并验证来自ESP8266的MQTT数据流。平台对传感器数据进行结构化存储,建立长期历史数据库,并提供数据导出为CSV格式的功能,确保数据的持久化与可追溯性。平台同时承担数据路由角色,将实时数据推送给已订阅的上位机应用。
上位机软件采用QT框架开发,集成Paho MQTT客户端库。该应用主动连接华为云服务器,订阅指定的MQTT主题以接收实时心率与体温数据流。软件核心功能包括:动态曲线绘制模块,以可视化图表展示实时生理参数变化;历史数据查询界面,支持按时间范围检索云端记录;可配置阈值管理面板,允许用户设定心率与体温的安全范围。当监测数据超越预设阈值时,软件立即触发声光警报机制,实现异常状态的即时预警。整个系统形成从终端感知、云端中继到上位机监控的闭环数据流,满足健康监测的实时性、可靠性与可管理性需求。
系统功能总结
功能模块 | 功能描述 |
---|---|
数据采集 | 通过MAX30100心率血氧传感器(I2C协议)实时采集用户心率数据 |
通过DHT11温湿度传感器(单总线协议)实时采集用户体温数据 | |
数据传输 | STM32通过UART串口驱动ESP8266-01S WiFi模块,使用MQTT协议上传数据至华为云 |
云平台处理 | 华为云物联网服务器接收、存储和处理传感器数据 |
实现数据长期存储,支持CSV格式导出 | |
上位机监控 | QT应用通过Paho MQTT订阅华为云数据,实时显示心率和体温数值 |
动态曲线图展示实时数据变化趋势 | |
数据分析 | 提供历史数据查询界面,支持按时间范围检索数据 |
允许设置心率/体温阈值,超限时触发声光警报 |
设计的各个功能模块描述
STM32F103C8T6微控制器作为核心处理单元,通过I2C协议与MAX30100心率血氧传感器通信,实时采集用户心率数据。同时利用单总线协议连接DHT11温湿度传感器获取体温数据,完成对两项健康指标的同步监测。
传感器数据通过UART串口传输至ESP8266-01S WiFi模块,该模块基于MQTT协议与华为云物联网服务器建立安全连接,实现采集数据的实时上传。华为云物联网平台配置专用设备接入服务,接收并存储传感器数据流,提供长期数据归档管理,支持通过云端接口导出CSV格式的历史数据文件。
上位机QT应用集成Paho MQTT客户端库,订阅华为云服务器的数据主题通道,实时解析心率体温数据流。软件界面动态绘制数据曲线图,直观展示实时变化趋势,同时提供历史数据查询面板,支持按时间范围检索云端存储记录。
异常监测模块通过独立配置界面设置心率体温阈值参数。当实时数据流超过安全范围时,QT应用立即触发声光报警系统,包括界面警示色闪烁与蜂鸣器提示。所有告警事件同步记录至历史数据库,便于后续追溯分析。
上位机代码设计
#include <QApplication>
#include <QMainWindow>
#include <QtMqtt/QMqttClient>
#include <QChart>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
#include <QDateTimeAxis>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>
#include <QSpinBox>
#include <QMessageBox>
#include <QFileDialog>
#include <QSoundEffect>
#include <QTimer>
QT_CHARTS_USE_NAMESPACE
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
setupUI();
setupDatabase();
setupMQTT();
}
private slots:
void onConnected() {
qDebug() << "Connected to Huawei Cloud!";
mqttClient->subscribe("sensor/data");
}
void onMessageReceived(const QByteArray &message, const QString &topic) {
QJsonDocument doc = QJsonDocument::fromJson(message);
QJsonObject obj = doc.object();
double heartRate = obj["heart_rate"].toDouble();
double bodyTemp = obj["temperature"].toDouble();
// 更新实时数据
lblHeartRate->setText(QString::number(heartRate));
lblTemperature->setText(QString::number(bodyTemp));
// 添加数据到图表
QDateTime now = QDateTime::currentDateTime();
heartRateSeries->append(now.toMSecsSinceEpoch(), heartRate);
tempSeries->append(now.toMSecsSinceEpoch(), bodyTemp);
// 限制数据点数量
if (heartRateSeries->count() > 100) heartRateSeries->remove(0);
if (tempSeries->count() > 100) tempSeries->remove(0);
// 更新图表范围
chart->axisX()->setRange(now.addSecs(-60), now);
chart->axisY()->setRange(0, 150);
// 检查阈值报警
checkThresholds(heartRate, bodyTemp);
// 存储到数据库
saveToDatabase(heartRate, bodyTemp);
}
void onThresholdChanged() {
heartRateThreshold = spinHeartRate->value();
tempThreshold = spinTemperature->value();
}
void onExportClicked() {
QString fileName = QFileDialog::getSaveFileName(this, "Export CSV", "", "CSV Files (*.csv)");
if (fileName.isEmpty()) return;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
QTextStream out(&file);
out << "Timestamp,HeartRate,Temperature\n";
QSqlQuery query("SELECT timestamp, heart_rate, temperature FROM sensor_data");
while (query.next()) {
out << query.value(0).toString() << ","
<< query.value(1).toString() << ","
<< query.value(2).toString() << "\n";
}
file.close();
}
private:
void setupUI() {
QWidget *centralWidget = new QWidget(this);
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
// 实时数据显示
QHBoxLayout *dataLayout = new QHBoxLayout();
lblHeartRate = new QLabel("--", this);
lblTemperature = new QLabel("--", this);
dataLayout->addWidget(new QLabel("Heart Rate:"));
dataLayout->addWidget(lblHeartRate);
dataLayout->addWidget(new QLabel("°C Temperature:"));
dataLayout->addWidget(lblTemperature);
mainLayout->addLayout(dataLayout);
// 图表初始化
chart = new QChart();
heartRateSeries = new QLineSeries();
heartRateSeries->setName("Heart Rate");
tempSeries = new QLineSeries();
tempSeries->setName("Temperature");
chart->addSeries(heartRateSeries);
chart->addSeries(tempSeries);
QDateTimeAxis *axisX = new QDateTimeAxis();
axisX->setFormat("hh:mm:ss");
chart->addAxis(axisX, Qt::AlignBottom);
heartRateSeries->attachAxis(axisX);
tempSeries->attachAxis(axisX);
QValueAxis *axisY = new QValueAxis();
axisY->setRange(0, 150);
chart->addAxis(axisY, Qt::AlignLeft);
heartRateSeries->attachAxis(axisY);
tempSeries->attachAxis(axisY);
chartView = new QChartView(chart);
mainLayout->addWidget(chartView);
// 阈值设置
QHBoxLayout *thresholdLayout = new QHBoxLayout();
spinHeartRate = new QSpinBox(this);
spinHeartRate->setRange(40, 150);
spinHeartRate->setValue(100);
spinTemperature = new QSpinBox(this);
spinTemperature->setRange(35, 42);
spinTemperature->setValue(38);
thresholdLayout->addWidget(new QLabel("Heart Rate Alert:"));
thresholdLayout->addWidget(spinHeartRate);
thresholdLayout->addWidget(new QLabel("°C Temp Alert:"));
thresholdLayout->addWidget(spinTemperature);
connect(spinHeartRate, SIGNAL(valueChanged(int)), this, SLOT(onThresholdChanged()));
connect(spinTemperature, SIGNAL(valueChanged(int)), this, SLOT(onThresholdChanged()));
// 报警指示器
alarmIndicator = new QLabel("NORMAL", this);
alarmIndicator->setStyleSheet("background-color: green; color: white; padding: 5px;");
thresholdLayout->addWidget(alarmIndicator);
// 导出按钮
QPushButton *exportButton = new QPushButton("Export CSV", this);
thresholdLayout->addWidget(exportButton);
connect(exportButton, SIGNAL(clicked()), this, SLOT(onExportClicked()));
mainLayout->addLayout(thresholdLayout);
setCentralWidget(centralWidget);
resize(800, 600);
// 初始化阈值
heartRateThreshold = 100;
tempThreshold = 38;
// 报警音效
alarmSound = new QSoundEffect(this);
alarmSound->setSource(QUrl::fromLocalFile("alarm.wav"));
}
void setupDatabase() {
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("sensor_data.db");
if (!db.open()) {
QMessageBox::critical(this, "Database Error", db.lastError().text());
return;
}
QSqlQuery query;
query.exec("CREATE TABLE IF NOT EXISTS sensor_data ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, "
"heart_rate REAL, "
"temperature REAL)");
}
void setupMQTT() {
mqttClient = new QMqttClient(this);
mqttClient->setHostname("your_huaweicloud_address"); // 替换实际地址
mqttClient->setPort(1883);
mqttClient->setClientId("your_client_id");
mqttClient->setUsername("your_username");
mqttClient->setPassword("your_password");
connect(mqttClient, &QMqttClient::connected, this, &MainWindow::onConnected);
connect(mqttClient, &QMqttClient::messageReceived, this, &MainWindow::onMessageReceived);
mqttClient->connectToHost();
}
void checkThresholds(double heartRate, double temperature) {
bool isAlarm = false;
if (heartRate > heartRateThreshold) {
alarmIndicator->setText("HIGH HEART RATE!");
isAlarm = true;
}
if (temperature > tempThreshold) {
alarmIndicator->setText("HIGH TEMPERATURE!");
isAlarm = true;
}
if (isAlarm) {
alarmIndicator->setStyleSheet("background-color: red; color: white; padding: 5px;");
alarmSound->play();
} else {
alarmIndicator->setText("NORMAL");
alarmIndicator->setStyleSheet("background-color: green; color: white; padding: 5px;");
}
}
void saveToDatabase(double heartRate, double temperature) {
QSqlQuery query;
query.prepare("INSERT INTO sensor_data (heart_rate, temperature) VALUES (?, ?)");
query.addBindValue(heartRate);
query.addBindValue(temperature);
query.exec();
}
// UI Components
QLabel *lblHeartRate;
QLabel *lblTemperature;
QLabel *alarmIndicator;
QChart *chart;
QChartView *chartView;
QLineSeries *heartRateSeries;
QLineSeries *tempSeries;
QSpinBox *spinHeartRate;
QSpinBox *spinTemperature;
QSoundEffect *alarmSound;
// MQTT Client
QMqttClient *mqttClient;
// Thresholds
int heartRateThreshold;
int tempThreshold;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 初始化数据库驱动
QSqlDatabase::addDatabase("QSQLITE");
MainWindow mainWin;
mainWin.show();
return app.exec();
}
#include "main.moc" // 包含元对象编译器生成的代码
代码说明
-
MQTT通信:
- 使用
QMqttClient
连接华为云IoT平台 - 订阅
sensor/data
主题接收传感器数据 - 消息格式为JSON:
{"heart_rate": 75.3, "temperature": 36.5}
- 使用
-
实时数据显示:
- 顶部标签显示最新心率和体温值
- 使用
QChart
动态绘制实时曲线图 - 自动调整X轴时间范围为最近60秒
-
阈值报警:
- 设置心率/体温阈值(默认100bpm/38℃)
- 超出阈值时:
- 界面显示红色警报标识
- 播放报警音效(需准备alarm.wav文件)
- 正常状态显示绿色"NORMAL"标识
-
数据存储与导出:
- 使用SQLite数据库存储历史数据
- 数据表结构:
timestamp | heart_rate | temperature
- CSV导出功能包含时间戳和传感器数据
-
华为云配置:
-
需替换实际连接参数:
mqttClient->setHostname("your_huaweicloud_address"); mqttClient->setClientId("your_client_id"); mqttClient->setUsername("your_username"); mqttClient->setPassword("your_password");
-
使用说明
-
依赖库:
- Qt 5.15+(需包含Charts、Sql、Network模块)
- QtMqtt模块(官方或第三方实现)
-
运行准备:
- 在项目目录放置报警音效文件
alarm.wav
- 配置正确的华为云连接参数
- 确保MQTT主题与设备端发布主题一致
- 在项目目录放置报警音效文件
-
功能操作:
- 通过旋钮控件设置报警阈值
- 点击"Export CSV"导出历史数据
- 实时曲线自动滚动显示最新100个数据点
模块代码设计
以下是基于STM32F103C8T6的完整传感器驱动代码(寄存器开发方式),包含MAX30100心率传感器和DHT11温湿度传感器的驱动实现:
#include "stm32f10x.h"
// 硬件定义
#define DHT11_GPIO_PORT GPIOB
#define DHT11_GPIO_PIN GPIO_Pin_0
#define DHT11_RCC_PORT RCC_APB2Periph_GPIOB
// I2C引脚定义
#define I2C_PORT GPIOB
#define I2C_SCL_PIN GPIO_Pin_6
#define I2C_SDA_PIN GPIO_Pin_7
#define I2C_RCC RCC_APB2Periph_GPIOB
#define I2C_SPEED 400000 // 400kHz
// MAX30100寄存器地址
#define MAX30100_ADDR 0xAE // 7位地址 << 1
#define REG_INTR_STATUS_1 0x00
#define REG_INTR_ENABLE_1 0x01
#define REG_FIFO_WR_PTR 0x04
#define REG_FIFO_RD_PTR 0x06
#define REG_FIFO_DATA 0x07
#define REG_MODE_CONFIG 0x09
#define REG_SPO2_CONFIG 0x0A
#define REG_LED1_PA 0x0C
#define REG_LED2_PA 0x0D
#define REG_TEMP_INTG 0x16
#define REG_TEMP_FRAC 0x17
// 函数声明
void SystemInit(void);
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void GPIO_Configuration(void);
void USART1_Init(void);
void I2C_Init(void);
void I2C_Start(void);
void I2C_Stop(void);
uint8_t I2C_WaitAck(void);
void I2C_Ack(void);
void I2C_NAck(void);
void I2C_SendByte(uint8_t data);
uint8_t I2C_ReadByte(void);
uint8_t MAX30100_ReadReg(uint8_t reg);
void MAX30100_WriteReg(uint8_t reg, uint8_t value);
void MAX30100_Init(void);
int MAX30100_ReadFIFO(uint32_t *red, uint32_t *ir);
void DHT11_Start(void);
uint8_t DHT11_CheckResponse(void);
uint8_t DHT11_ReadByte(void);
uint8_t DHT11_ReadData(uint8_t *temp, uint8_t *humi);
// 系统时钟初始化 (72MHz HSE)
void SystemInit(void) {
RCC->CR |= RCC_CR_HSEON; // 开启HSE
while(!(RCC->CR & RCC_CR_HSERDY)); // 等待HSE就绪
FLASH->ACR |= FLASH_ACR_LATENCY_2; // Flash等待周期
RCC->CFGR |= RCC_CFGR_PLLMULL9; // PLL倍频9倍
RCC->CFGR |= RCC_CFGR_PLLSRC; // PLL源选择HSE
RCC->CR |= RCC_CR_PLLON; // 开启PLL
while(!(RCC->CR & RCC_CR_PLLRDY)); // 等待PLL就绪
RCC->CFGR |= RCC_CFGR_SW_PLL; // 系统时钟切换到PLL
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // 等待切换完成
SystemCoreClock = 72000000;
}
// 微秒级延时
void Delay_us(uint32_t us) {
SysTick->LOAD = SystemCoreClock / 8000000 * us;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
SysTick->CTRL = 0;
}
// 毫秒级延时
void Delay_ms(uint32_t ms) {
while(ms--) Delay_us(1000);
}
// GPIO初始化
void GPIO_Configuration(void) {
RCC->APB2ENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB;
// DHT11配置 (PB0)
GPIOB->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_MODE0);
GPIOB->CRL |= GPIO_CRL_MODE0; // 推挽输出模式
// USART1 TX (PA9)
GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9);
GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9; // 复用推挽输出
}
// USART1初始化 (115200)
void USART1_Init(void) {
RCC->APB2ENR |= RCC_APB2Periph_USART1;
USART1->BRR = 72000000 / 115200; // 波特率
USART1->CR1 = USART_CR1_UE | USART_CR1_TE; // 使能USART和发送
USART1->CR2 = 0;
USART1->CR3 = 0;
}
// I2C初始化
void I2C_Init(void) {
RCC->APB2ENR |= I2C_RCC;
// 配置PB6(SCL), PB7(SDA)为开漏输出
GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_MODE6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE7);
GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_MODE6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE7;
RCC->APB1ENR |= RCC_APB1Periph_I2C1;
I2C1->CR1 = I2C_CR1_SWRST;
I2C1->CR1 = 0;
I2C1->CR2 = SystemCoreClock / 1000000; // 设置时钟频率
I2C1->CCR = SystemCoreClock / (2 * I2C_SPEED); // 设置CCR
I2C1->TRISE = SystemCoreClock / 1000000 + 1; // 设置TRISE
I2C1->CR1 |= I2C_CR1_PE; // 使能I2C
}
// I2C起始信号
void I2C_Start(void) {
I2C1->CR1 |= I2C_CR1_START;
while(!(I2C1->SR1 & I2C_SR1_SB));
}
// I2C停止信号
void I2C_Stop(void) {
I2C1->CR1 |= I2C_CR1_STOP;
while(I2C1->CR1 & I2C_CR1_STOP);
}
// 等待ACK
uint8_t I2C_WaitAck(void) {
if(I2C1->SR1 & I2C_SR1_AF) {
I2C1->SR1 &= ~I2C_SR1_AF;
return 1; // NACK
}
return 0; // ACK
}
// 发送ACK
void I2C_Ack(void) {
I2C1->CR1 &= ~I2C_CR1_ACK;
}
// 发送NACK
void I2C_NAck(void) {
I2C1->CR1 |= I2C_CR1_ACK;
}
// I2C发送一个字节
void I2C_SendByte(uint8_t data) {
I2C1->DR = data;
while(!(I2C1->SR1 & I2C_SR1_TXE));
}
// I2C读取一个字节
uint8_t I2C_ReadByte(void) {
while(!(I2C1->SR1 & I2C_SR1_RXNE));
return I2C1->DR;
}
// MAX30100读取寄存器
uint8_t MAX30100_ReadReg(uint8_t reg) {
uint8_t value;
I2C_Start();
I2C_SendByte(MAX30100_ADDR);
I2C_WaitAck();
I2C_SendByte(reg);
I2C_WaitAck();
I2C_Start();
I2C_SendByte(MAX30100_ADDR | 0x01);
I2C_WaitAck();
value = I2C_ReadByte();
I2C_NAck();
I2C_Stop();
return value;
}
// MAX30100写入寄存器
void MAX30100_WriteReg(uint8_t reg, uint8_t value) {
I2C_Start();
I2C_SendByte(MAX30100_ADDR);
I2C_WaitAck();
I2C_SendByte(reg);
I2C_WaitAck();
I2C_SendByte(value);
I2C_WaitAck();
I2C_Stop();
}
// MAX30100初始化
void MAX30100_Init(void) {
MAX30100_WriteReg(REG_MODE_CONFIG, 0x03); // HR模式
MAX30100_WriteReg(REG_SPO2_CONFIG, 0x27); // 100Hz, 16位分辨率
MAX30100_WriteReg(REG_LED1_PA, 0x24); // LED1电流=36mA
MAX30100_WriteReg(REG_LED2_PA, 0x24); // LED2电流=36mA
MAX30100_WriteReg(REG_FIFO_WR_PTR, 0x00); // 重置FIFO
MAX30100_WriteReg(REG_FIFO_RD_PTR, 0x00);
}
// 从FIFO读取数据
int MAX30100_ReadFIFO(uint32_t *red, uint32_t *ir) {
uint8_t buffer[6];
uint8_t i;
if(MAX30100_ReadReg(REG_FIFO_WR_PTR) == MAX30100_ReadReg(REG_FIFO_RD_PTR))
return 0; // FIFO空
I2C_Start();
I2C_SendByte(MAX30100_ADDR);
I2C_WaitAck();
I2C_SendByte(REG_FIFO_DATA);
I2C_WaitAck();
I2C_Start();
I2C_SendByte(MAX30100_ADDR | 0x01);
I2C_WaitAck();
for(i=0; i<5; i++) {
buffer[i] = I2C_ReadByte();
I2C_Ack();
}
buffer[5] = I2C_ReadByte();
I2C_NAck();
I2C_Stop();
*red = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
*ir = (buffer[3] << 16) | (buffer[4] << 8) | buffer[5];
return 1;
}
// DHT11启动信号
void DHT11_Start(void) {
GPIOB->CRL &= ~GPIO_CRL_MODE0; // 输出模式
GPIOB->BRR = DHT11_GPIO_PIN; // 拉低
Delay_ms(18); // 保持18ms
GPIOB->BSRR = DHT11_GPIO_PIN; // 释放总线
GPIOB->CRL |= GPIO_CRL_CNF0_0; // 输入模式(浮空)
Delay_us(30);
}
// 检测DHT11响应
uint8_t DHT11_CheckResponse(void) {
uint8_t retry = 0;
while(GPIOB->IDR & DHT11_GPIO_PIN) {
if(retry++ > 100) return 0;
Delay_us(1);
}
retry = 0;
while(!(GPIOB->IDR & DHT11_GPIO_PIN)) {
if(retry++ > 100) return 0;
Delay_us(1);
}
retry = 0;
while(GPIOB->IDR & DHT11_GPIO_PIN) {
if(retry++ > 100) return 0;
Delay_us(1);
}
return 1;
}
// DHT11读取一个字节
uint8_t DHT11_ReadByte(void) {
uint8_t data = 0;
for(int i=0; i<8; i++) {
while(!(GPIOB->IDR & DHT11_GPIO_PIN)); // 等待低电平结束
Delay_us(40);
if(GPIOB->IDR & DHT11_GPIO_PIN)
data |= (1 << (7-i));
while(GPIOB->IDR & DHT11_GPIO_PIN); // 等待高电平结束
}
return data;
}
// DHT11读取数据
uint8_t DHT11_ReadData(uint8_t *temp, uint8_t *humi) {
uint8_t buf[5];
DHT11_Start();
if(!DHT11_CheckResponse()) return 0;
for(int i=0; i<5; i++)
buf[i] = DHT11_ReadByte();
if(buf[4] != (buf[0]+buf[1]+buf[2]+buf[3]))
return 0; // 校验失败
*humi = buf[0];
*temp = buf[2];
return 1;
}
// 主函数
int main(void) {
uint8_t temperature, humidity;
uint32_t heart_rate, spo2;
char uart_buf[64];
SystemInit();
GPIO_Configuration();
USART1_Init();
I2C_Init();
MAX30100_Init();
while(1) {
// 读取DHT11数据
if(DHT11_ReadData(&temperature, &humidity)) {
sprintf(uart_buf, "TEMP:%dC,HUMI:%d%%\r\n", temperature, humidity);
for(char *p = uart_buf; *p; p++) {
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = *p;
}
}
// 读取MAX30100数据
if(MAX30100_ReadFIFO(&spo2, &heart_rate)) {
sprintf(uart_buf, "HR:%lu,SpO2:%lu\r\n", heart_rate, spo2);
for(char *p = uart_buf; *p; p++) {
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = *p;
}
}
Delay_ms(1000); // 每秒采集一次
}
}
代码说明:
-
系统初始化
- 配置72MHz系统时钟(HSE外部晶振)
- 实现精确延时函数(us/ms级)
-
I2C驱动
- 完全寄存器方式实现I2C协议
- 支持400kHz高速模式
- 包含起始/停止/ACK/NACK等基本操作
-
MAX30100驱动
- 初始化配置为心率监测模式
- 实现寄存器读写函数
- FIFO数据读取功能
- 支持红光(red)和红外(ir)双通道数据采集
-
DHT11驱动
- 单总线协议实现
- 严格的时序控制(us级延时)
- 数据校验机制
- 同时获取温度和湿度数据
-
USART通信
- 配置115200波特率
- 通过PA9(TX)发送传感器数据到ESP8266
使用说明:
-
硬件连接:
- MAX30100: SCL→PB6, SDA→PB7
- DHT11: DATA→PB0
- ESP8266: TX→PA10(RX), RX→PA9(TX)
-
数据格式:
- 温度/湿度: “TEMP:25C,HUMI:45%”
- 心率/血氧: “HR:75,SpO2:98”
-
工作流程:
- 系统每1秒采集一次传感器数据
- 通过串口发送给ESP8266模块
- ESP8266通过MQTT协议转发至华为云
项目核心代码
以下是基于STM32F103C8T6的智能健康监测系统main.c
完整代码(寄存器开发方式):
#include "stm32f10x.h"
// 传感器数据结构
typedef struct {
uint16_t heart_rate;
float temperature;
} SensorData;
// 函数声明
void SystemClock_Config(void);
void GPIO_Config(void);
void USART1_Init(void);
void USART2_Init(void);
void I2C1_Init(void);
void DHT11_Init(void);
void SysTick_Init(void);
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
uint8_t MAX30100_ReadHeartRate(uint16_t *hr);
uint8_t DHT11_ReadTemp(float *temp);
void ESP8266_SendCommand(char *cmd, char *ack, uint32_t timeout);
void MQTT_PublishData(SensorData data);
int main(void) {
// 系统初始化
SystemClock_Config();
GPIO_Config();
USART1_Init(); // 调试串口
USART2_Init(); // ESP8266通信
I2C1_Init(); // MAX30100
DHT11_Init(); // DHT11
SysTick_Init();
// 发送AT指令初始化ESP8266
ESP8266_SendCommand("AT\r\n", "OK", 1000);
ESP8266_SendCommand("AT+CWMODE=1\r\n", "OK", 1000);
ESP8266_SendCommand("AT+CWJAP=\"YourSSID\",\"YourPassword\"\r\n", "GOT IP", 5000);
ESP8266_SendCommand("AT+MQTTUSERCFG=0,1,\"DeviceID\",\"Username\",\"Password\",0,0,\"\"\r\n", "OK", 1000);
ESP8266_SendCommand("AT+MQTTCONN=0,\"YourHuaweiCloudAddress\",1883,1\r\n", "OK", 5000);
SensorData sensor_data;
uint32_t last_send = 0;
while (1) {
// 每2秒采集并发送数据
if (HAL_GetTick() - last_send >= 2000) {
// 读取心率传感器
if (MAX30100_ReadHeartRate(&sensor_data.heart_rate) == 0) {
// 串口调试输出
USART_SendData(USART1, 'H');
USART_SendData(USART1, ':');
USART_SendData(USART1, (sensor_data.heart_rate/100) + '0');
USART_SendData(USART1, (sensor_data.heart_rate%100/10) + '0');
USART_SendData(USART1, (sensor_data.heart_rate%10) + '0');
USART_SendData(USART1, '\n');
}
// 读取温度传感器
if (DHT11_ReadTemp(&sensor_data.temperature) == 0) {
USART_SendData(USART1, 'T');
USART_SendData(USART1, ':');
int temp_int = (int)sensor_data.temperature;
USART_SendData(USART1, temp_int/10 + '0');
USART_SendData(USART1, temp_int%10 + '0');
USART_SendData(USART1, '.');
int temp_dec = (int)(sensor_data.temperature*10)%10;
USART_SendData(USART1, temp_dec + '0');
USART_SendData(USART1, '\n');
}
// 通过MQTT上传到华为云
MQTT_PublishData(sensor_data);
last_send = HAL_GetTick();
}
}
}
// MQTT数据发布函数
void MQTT_PublishData(SensorData data) {
char mqtt_msg[50];
sprintf(mqtt_msg, "{\"heart_rate\":%d,\"temperature\":%.1f}",
data.heart_rate, data.temperature);
char mqtt_cmd[100];
sprintf(mqtt_cmd, "AT+MQTTPUB=0,\"Your/Topic\",\"%s\",1,0\r\n", mqtt_msg);
ESP8266_SendCommand(mqtt_cmd, "OK", 1000);
}
// ESP8266命令发送函数
void ESP8266_SendCommand(char *cmd, char *ack, uint32_t timeout) {
// 发送命令
while (*cmd) {
USART_SendData(USART2, *cmd++);
while (!(USART2->SR & USART_SR_TC));
}
// 等待响应(简化实现)
Delay_ms(timeout);
}
// 系统时钟配置(72MHz HSE)
void SystemClock_Config(void) {
RCC->CR |= RCC_CR_HSEON; // 开启HSE
while (!(RCC->CR & RCC_CR_HSERDY)); // 等待HSE就绪
// 配置PLL:HSE * 9 = 72MHz
RCC->CFGR |= RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC;
RCC->CR |= RCC_CR_PLLON; // 开启PLL
while (!(RCC->CR & RCC_CR_PLLRDY)); // 等待PLL就绪
// 配置FLASH预取指
FLASH->ACR |= FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_1;
// 切换系统时钟
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // 等待切换完成
}
// USART1初始化(调试串口,115200bps)
void USART1_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;
// PA9(TX)复用推挽输出,PA10(RX)浮空输入
GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9);
GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9;
GPIOA->CRH &= ~(GPIO_CRH_CNF10 | GPIO_CRH_MODE10);
GPIOA->CRH |= GPIO_CRH_CNF10_0;
// 波特率设置:72MHz/(16*39.0625)=115200
USART1->BRR = 0x0271;
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}
// USART2初始化(ESP8266通信,115200bps)
void USART2_Init(void) {
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// PA2(TX)复用推挽输出,PA3(RX)浮空输入
GPIOA->CRL &= ~(GPIO_CRL_CNF2 | GPIO_CRL_MODE2);
GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2;
GPIOA->CRL &= ~(GPIO_CRL_CNF3 | GPIO_CRL_MODE3);
GPIOA->CRL |= GPIO_CRL_CNF3_0;
// 波特率设置
USART2->BRR = 0x0271;
USART2->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}
// I2C1初始化(MAX30100)
void I2C1_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
// PB6(SCL)/PB7(SDA) 复用开漏输出
GPIOB->CRL &= ~(GPIO_CRL_CNF6 | GPIO_CRL_MODE6 |
GPIO_CRL_CNF7 | GPIO_CRL_MODE7);
GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6 |
GPIO_CRL_CNF7_1 | GPIO_CRL_MODE7;
// I2C配置
I2C1->CR2 = 36; // APB1时钟36MHz
I2C1->CCR = 180; // 100kHz标准模式
I2C1->TRISE = 37; // 最大上升时间
I2C1->CR1 = I2C_CR1_PE; // 使能I2C
}
// DHT11初始化(PA0)
void DHT11_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRL &= ~GPIO_CRL_MODE0; // 初始化为输出模式
GPIOA->BSRR = GPIO_BSRR_BS0; // 输出高电平
}
// SysTick初始化(1ms中断)
void SysTick_Init(void) {
SysTick->LOAD = 72000 - 1; // 72MHz/1000 = 72kHz
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
}
// 微秒级延时
void Delay_us(uint32_t us) {
uint32_t start = SysTick->VAL;
uint32_t ticks = us * 72; // 72MHz时钟
while ((start - SysTick->VAL) < ticks);
}
// 毫秒级延时
void Delay_ms(uint32_t ms) {
while (ms--) {
Delay_us(1000);
}
}
// GPIO配置
void GPIO_Config(void) {
// 启用GPIO时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN |
RCC_APB2ENR_IOPCEN;
// LED指示灯(PC13)
GPIOC->CRH &= ~GPIO_CRH_CNF13;
GPIOC->CRH |= GPIO_CRH_MODE13;
GPIOC->BSRR = GPIO_BSRR_BS13; // 初始关闭
}
关键代码说明:
-
系统初始化:
- 配置72MHz系统时钟(HSE+PLL)
- 初始化调试串口(USART1)和ESP8266通信串口(USART2)
- 配置I2C接口用于MAX30100心率传感器
- 配置GPIO用于DHT11温湿度传感器
-
传感器驱动:
MAX30100_ReadHeartRate()
通过I2C读取心率数据DHT11_ReadTemp()
通过单总线协议读取温度
-
网络通信:
ESP8266_SendCommand()
发送AT指令配置WiFi和MQTTMQTT_PublishData()
封装JSON格式数据发布到华为云
-
数据处理:
- 每2秒采集一次传感器数据
- 通过串口输出调试信息
- 数据格式:
{"heart_rate":75,"temperature":36.5}
-
华为云对接:
- 使用标准MQTT协议发布数据
- 需替换实际参数:
YourSSID
/YourPassword
:WiFi凭证YourHuaweiCloudAddress
:华为云IoT地址DeviceID
/Username
/Password
:华为云设备认证信息Your/Topic
:华为云数据上报主题
总结
本设计成功构建了一套完整的智能人体健康监测系统。该系统以STM32F103C8T6微控制器为核心,高效整合了MAX30100心率血氧传感器和DHT11温湿度传感器,通过I2C和单总线协议精确采集用户的心率与体温数据,为健康监测提供了可靠的数据来源。
系统借助ESP8266-01S WiFi模块,利用UART串口通信和MQTT协议,实现了传感器数据的稳定、实时无线传输。数据被安全、高效地上传至华为云物联网平台,该平台承担了数据的接收、存储、处理及长期管理的核心任务,并支持关键数据的导出功能,为健康数据分析提供了坚实基础。
上位机软件基于QT框架开发,通过集成Paho MQTT客户端库与华为云建立连接,实现了数据的实时接收与解析。软件界面友好,功能丰富,不仅动态展示实时数据曲线,还提供了历史数据查询、心率与体温安全阈值设定等功能,并在数据异常时触发显著的声光报警,有效提升了系统的预警能力与用户交互体验。
综上所述,该毕业设计实现了从终端数据采集、云端传输存储到上位机可视化监控与预警的全流程闭环。系统结构清晰,功能完备,具备良好的实用性和扩展性,为远程健康监护提供了一套可行的技术方案,具有实际应用价值。
- 点赞
- 收藏
- 关注作者
评论(0)