項目開發背景
隨著城市化進程加速和居民生活水平提升,人們對家居環境健康與安全的需求日益增強。現代住宅常因裝修材料、密閉空間及外部污染導致甲醛超標、PM2.5濃度升高、溫濕度失衡等問題,長期暴露此類環境中易引發呼吸道疾病、過敏反應等健康隱患。傳統環境監測設備功能單一、數據孤立,且缺乏遠程管理能力,難以滿足用戶對室內環境實時掌控和主動干預的需求。
物聯網技術的快速發展為解決上述問題提供了新路徑。通過集成多類型傳感器與云平臺,可實現環境參數的動態采集、云端存儲及智能分析。同時,智能家居系統對本地化人機交互、異常即時報警及遠程控制提出了更高要求,亟需一種低成本、高集成度的解決方案。
本項目基于STM32F103C8T6微控制器,結合多傳感器融合技術、華為云物聯網平臺及QT跨平臺應用,構建一套完整的智能家居健康環境監測系統。該系統不僅能夠實時監測關鍵環境指標,還能通過閾值判定自動觸發凈化設備,并結合聲光報警與可視化界面實現"監測-預警-控制"閉環管理,有效提升居住環境的健康性與安全性,為智慧家居的普及提供技術支撐。
設計實現的功能
(1)STM32F103C8T6主控協調傳感器采集、數據處理及通信邏輯。
(2)華為云物聯網平臺實現設備接入、數據存儲和指令下發。
(3)QT上位機通過MQTT協議訂閱云平臺數據,提供人機交互界面。
(4)環境異常時自動觸發本地聲光報警(蜂鳴器+LED)。
(5)支持手動/自動雙模式:自動模式下依據閾值控制設備啟停。
項目硬件模塊組成
(1)主控芯片:STM32F103C8T6最小系統板
(2)傳感器:DHT11溫濕度傳感器、BH1750光照傳感器、GP2Y1010AU0F PM2.5傳感器、ZE08-CH2O甲醛傳感器
(3)通信模塊:ESP8266-01S WiFi模塊(串口AT指令通信)
(4)執行單元:5V繼電器模塊(控制空氣凈化器電源)
(5)報警單元:有源蜂鳴器、高亮LED燈(紅/綠雙色)
(6)顯示單元:0.96英寸I2C接口OLED顯示屏
(7)輔助硬件:按鍵模塊(本地模式切換)、USB轉TTL模塊(調試)
當前項目使用的相關軟件工具、模塊源碼已經上傳到網盤:https://ccnr8sukk85n.feishu.cn/wiki/QjY8weDYHibqRYkFP2qcA9aGnvb?from=from_copylink
設計意義
該系統的設計意義主要體現在以下方面:
該系統的核心價值在于提升居住環境健康水平與生活安全性。通過實時監測甲醛、PM2.5等直接影響呼吸健康的污染物濃度,以及溫濕度、光照等影響舒適度的關鍵參數,系統能及時揭示潛在的環境風險。當檢測值超過安全閾值時,本地聲光報警與上位機彈窗警示可第一時間提醒用戶采取干預措施,有效降低因空氣質量問題引發的健康隱患,為家庭創造更安全的居住條件。
其設計顯著增強了環境管理的智能化與便捷性。系統打破了傳統手動監測的局限,實現了環境數據的自動采集、云端同步及可視化呈現。用戶不僅可通過QT界面遠程查看實時數據與歷史趨勢,還能直接控制凈化設備啟停。自動模式下的閾值聯動控制進一步解放了人力,使環境調節更加主動高效,大幅提升了用戶對居住環境的掌控能力與生活便利性。
系統構建了完整的數據追溯與決策支持體系。華為云平臺對歷史數據的持久化存儲,結合QT上位機的曲線分析功能,使用戶能夠清晰追蹤環境參數的變化規律。這種長期數據積累不僅有助于評估凈化設備效果,更能為優化室內通風策略、識別污染源提供客觀依據,使得環境管理決策更具科學性和針對性。
此外,項目體現了嵌入式技術與物聯網平臺的深度整合應用。以STM32為核心,協調多類型傳感器采集、本地顯示、報警輸出及繼電器控制,并通過ESP8266實現與華為云的穩定通信,展示了資源受限單片機在復雜物聯網系統中的核心樞紐作用。這種端-云協同架構的成功實踐,為同類智能環境監測應用提供了可靠的技術范本,具有較強的工程推廣價值。
設計思路
設計思路圍繞STM32F103C8T6主控展開,通過模塊化方式實現功能集成。首先,STM32通過GPIO和I2C接口驅動傳感器陣列:DHT11采集溫濕度(單總線協議),BH1750獲取光照強度(I2C),GP2Y1010AU0F通過ADC讀取PM2.5模擬電壓,ZE08-CH2O通過串口獲取甲醛數據。所有傳感器數據經濾波校準后,由主控進行格式化處理。
通信層采用ESP8266-01S WiFi模塊,通過STM32的USART發送AT指令建立MQTT連接,將JSON格式數據上傳至華為云物聯網平臺。上傳頻率設定為5秒/次,同時訂閱云平臺下發的控制指令。當收到繼電器控制指令時,STM32解析指令并通過GPIO控制繼電器開關狀態,驅動空氣凈化設備電源通斷。
本地交互部分設計雙模式邏輯:按鍵觸發模式切換,自動模式下STM32實時比對各傳感器數據與預設閾值(存儲于Flash),若PM2.5或甲醛超標,立即觸發紅色LED閃爍及蜂鳴器鳴響,同時根據閾值自動啟停繼電器;手動模式下則依賴遠程指令。OLED通過I2C驅動,分區域顯示實時數據、設備狀態(ON/OFF)及當前模式標識(A/M)。
華為云平臺配置規則引擎存儲歷史數據,QT上位機通過MQTT庫訂閱實時數據流,并調用HTTP API查詢歷史記錄。QT界面采用多線程設計:主線程渲染數據儀表盤及曲線圖(QChart庫實現),子線程監測數據閾值,超標時觸發QMessageBox彈窗和QSound報警。控制界面嵌入繼電器開關按鈕,點擊后通過MQTT發布控制指令至云平臺。
異常處理機制包含硬件看門狗和通信超時重連:若WiFi斷開,STM32嘗試重新配網并在OLED顯示錯誤代碼;若傳感器失效,保留上一次有效數據并點亮特定錯誤指示燈。整個系統采用低功耗設計,STM32在采集間隙切換至休眠模式,由定時器中斷喚醒。
框架圖
框架圖說明:
-
感知層
- 傳感器通過GPIO/I2C/UART與STM32連接
- 采集溫濕度/光照/PM2.5/甲醛數據
-
控制層
- STM32F103C8T6核心處理:
? 控制繼電器開關設備
? 驅動OLED顯示實時數據
? 觸發聲光報警(LED+蜂鳴器)
? 處理模式切換按鍵
? 通過ESP8266上傳數據至華為云
- STM32F103C8T6核心處理:
-
云平臺層
- 華為云物聯網平臺:
? MQTT協議雙向通信
? 存儲歷史環境數據
? 轉發控制指令
- 華為云物聯網平臺:
-
應用層
- QT上位機實現:
? 實時監測數據儀表盤
? 閾值超限聲光報警
? 遠程繼電器控制界面
? 歷史數據曲線分析
- QT上位機實現:
系統總體設計
系統以STM32F103C8T6微控制器為核心,通過其豐富的外設接口協調各模塊工作。傳感器單元通過不同物理接口連接主控:DHT11溫濕度傳感器使用單總線協議,BH1750光照傳感器采用I2C接口,GP2Y1010AU0F PM2.5傳感器和ZE08-CH2O甲醛傳感器通過ADC采集模擬信號。主控對原始數據進行濾波校準處理后,通過UART串口驅動ESP8266-01S WiFi模塊,基于AT指令集將結構化數據以MQTT協議上傳至華為云物聯網平臺。
本地顯示與交互層由0.96英寸OLED屏幕實現,通過I2C總線實時展示環境參數及設備狀態。報警單元采用紅綠雙色LED和有源蜂鳴器組合,當檢測值超過預設閾值時觸發聲光報警。執行機構通過GPIO控制5V繼電器模塊,實現對空氣凈化設備的電源通斷控制。模式切換由物理按鍵實現,支持手動控制與自動閾值聯動雙工作模式。
華為云物聯網平臺承擔數據中樞角色,存儲所有歷史監測數據并提供API訪問接口。QT上位機通過MQTT協議訂閱云平臺數據通道,實現環境參數的動態可視化展示。當數據異常時,上位機觸發彈窗警告和聲音提示,同時提供繼電器遠程控制按鈕及歷史數據查詢功能。用戶可通過曲線圖分析各參數隨時間變化趨勢,所有閾值配置均支持界面化修改。
系統通信架構采用分層設計:底層由STM32通過串口與ESP8266交互,中間層通過WiFi連接華為云,上層QT應用通過互聯網與云平臺保持長連接。調試接口采用USB轉TTL模塊,可實時監控串口數據流及系統運行狀態。
系統功能總結
功能分類 | 功能描述 |
---|---|
數據采集 | 實時采集室內溫濕度(DHT11)、光照強度(BH1750)、PM2.5(GP2Y1010AU0F)及甲醛濃度(ZE08-CH2O) |
云端通信 | 通過ESP8266 WiFi模塊將傳感器數據上傳至華為云物聯網平臺,實現設備接入與指令下發 |
本地顯示 | OLED屏實時顯示環境參數(溫濕度/光照/PM2.5/甲醛)及空氣凈化設備工作狀態 |
遠程監控 | QT上位機通過MQTT訂閱云平臺數據,實時顯示環境參數,支持閾值超限彈窗+聲音報警 |
設備控制 | QT界面遠程控制繼電器開關(空氣凈化器);支持手動控制/自動閾值控制雙模式切換(按鍵切換) |
智能聯動 | 自動模式下:環境參數超限時自動啟停空氣凈化設備;異常時觸發本地聲光報警(蜂鳴器+雙色LED) |
數據存儲與分析 | 華為云平臺存儲歷史數據;QT上位機支持歷史數據查詢及變化曲線圖生成 |
設計的各個功能模塊描述
主控模塊
以STM32F103C8T6最小系統板為核心控制器,通過多接口(UART、I2C、ADC、GPIO)協調各模塊工作。負責傳感器數據采集調度、邏輯判斷(如閾值比較)、通信協議封裝、執行器控制指令生成及系統狀態管理。
傳感器采集模塊
集成四類環境傳感器:
- 溫濕度采集:DHT11通過單總線協議實時獲取室內溫濕度數據。
- 光照采集:BH1750通過I2C接口測量環境光照強度。
- PM2.5采集:GP2Y1010AU0F輸出模擬電壓信號,經STM32 ADC轉換獲取PM2.5濃度。
- 甲醛采集:ZE08-CH2O通過串口通信傳輸甲醛濃度值。
主控按固定周期輪詢傳感器,完成數據預處理(單位轉換、濾波)。
無線通信模塊
基于ESP8266-01S WiFi模塊,通過UART串口與STM32交互。使用AT指令集建立MQTT連接,將傳感器數據按華為云物聯網平臺協議封裝上傳,同時接收云端下發的設備控制指令(如繼電器開關指令)。
本地執行與報警模塊
- 執行單元:5V繼電器模塊連接空氣凈化器電源,由STM32 GPIO引腳控制通斷,響應自動模式閾值或遠程指令。
- 報警單元:雙色LED(綠燈正常/紅燈異常)與有源蜂鳴器聯動,當環境參數超限時觸發聲光報警(紅燈閃爍+蜂鳴)。
本地顯示與人機交互模塊
- OLED顯示:0.96英寸I2C OLED實時展示環境參數(溫濕度、光照、PM2.5、甲醛)及設備狀態(凈化器開關/自動手動模式)。
- 按鍵控制:獨立按鍵支持本地切換自動/手動模式,自動模式下依據預設閾值控制凈化器。
華為云平臺模塊
實現設備接入、數據存儲與指令轉發:
- 數據存儲:云端持久化存儲傳感器歷史數據。
- 指令下發:將QT上位機的繼電器控制指令透傳至設備端。
- 設備管理:提供設備在線狀態監控及通信鑒權。
QT上位機模塊
通過MQTT協議訂閱云平臺數據,功能包括:
- 實時監控:圖形化展示環境參數動態數值。
- 閾值報警:數據超限時觸發彈窗警告與系統提示音。
- 遠程控制:提供虛擬按鈕手動開關空氣凈化器。
- 數據分析:查詢歷史數據并生成溫度、PM2.5等參數的趨勢曲線圖。
電源與調試模塊
- 電源管理:為各模塊提供適配電壓(STM32需3.3V,繼電器需5V)。
- 調試接口:USB轉TTL模塊用于串口日志輸出及固件燒錄。
上位機代碼設計
以下是基于Qt的智能家居健康環境監測系統上位機完整代碼設計。該代碼使用C++開發,包含MQTT通信、數據可視化、報警控制等功能:
#include <QApplication>
#include <QMainWindow>
#include <QtMqtt/QMqttClient>
#include <QChart>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
#include <QDateTimeAxis>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QMessageBox>
#include <QMediaPlayer>using namespace QtCharts;// 主窗口類定義
class MainWindow : public QMainWindow {Q_OBJECT
public:MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {setupUI();setupDatabase();setupMQTT();}private slots:void onMQTTConnected();void onMQTTMessage(const QByteArray &message);void onRelayControl(bool checked);void onModeChanged(bool autoMode);void checkThresholds();void onQueryData();private:void setupUI();void setupDatabase();void setupMQTT();void updateChart();// MQTT客戶端QMqttClient *m_client;// UI組件QLabel *tempLabel, *humiLabel, *lightLabel, *pm25Label, *hchoLabel;QPushButton *relayBtn, *modeBtn;QChartView *chartView;QDateTimeEdit *startDateEdit, *endDateEdit;// 數據存儲QSqlDatabase db;QMediaPlayer *alarmPlayer;// 當前值struct EnvData {double temperature = 0.0;double humidity = 0.0;double light = 0.0;double pm25 = 0.0;double hcho = 0.0;bool relayState = false;} currentData;// 閾值設置const double TEMP_THRESHOLD = 30.0;const double HUMI_THRESHOLD = 80.0;const double PM25_THRESHOLD = 75.0;const double HCHO_THRESHOLD = 0.08;
};void MainWindow::setupUI() {// 主窗口設置setWindowTitle("智能家居環境監測系統");setFixedSize(1000, 700);// 實時數據顯示區QWidget *dataWidget = new QWidget(this);QGridLayout *dataLayout = new QGridLayout;tempLabel = new QLabel("溫度: --°C");humiLabel = new QLabel("濕度: --%");lightLabel = new QLabel("光照: --Lux");pm25Label = new QLabel("PM2.5: --μg/m3");hchoLabel = new QLabel("甲醛: --mg/m3");dataLayout->addWidget(tempLabel, 0, 0);dataLayout->addWidget(humiLabel, 1, 0);dataLayout->addWidget(lightLabel, 0, 1);dataLayout->addWidget(pm25Label, 1, 1);dataLayout->addWidget(hchoLabel, 0, 2);// 控制按鈕relayBtn = new QPushButton("凈化器: 關閉");modeBtn = new QPushButton("當前模式: 手動");modeBtn->setCheckable(true);dataLayout->addWidget(relayBtn, 2, 0);dataLayout->addWidget(modeBtn, 2, 1);dataWidget->setLayout(dataLayout);dataWidget->setGeometry(20, 20, 400, 150);// 圖表區域QChart *chart = new QChart();chartView = new QChartView(chart);chartView->setGeometry(20, 180, 960, 400);// 時間選擇控件startDateEdit = new QDateTimeEdit(QDateTime::currentDateTime().addDays(-1));endDateEdit = new QDateTimeEdit(QDateTime::currentDateTime());QPushButton *queryBtn = new QPushButton("查詢數據");QWidget *dateWidget = new QWidget(this);QHBoxLayout *dateLayout = new QHBoxLayout;dateLayout->addWidget(new QLabel("開始時間:"));dateLayout->addWidget(startDateEdit);dateLayout->addWidget(new QLabel("結束時間:"));dateLayout->addWidget(endDateEdit);dateLayout->addWidget(queryBtn);dateWidget->setLayout(dateLayout);dateWidget->setGeometry(450, 20, 500, 40);// 信號連接connect(relayBtn, &QPushButton::clicked, this, &MainWindow::onRelayControl);connect(modeBtn, &QPushButton::toggled, this, &MainWindow::onModeChanged);connect(queryBtn, &QPushButton::clicked, this, &MainWindow::onQueryData);// 報警播放器alarmPlayer = new QMediaPlayer(this);alarmPlayer->setMedia(QUrl("qrc:/alarm.wav"));
}void MainWindow::setupDatabase() {db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName("environment.db");if (!db.open()) {QMessageBox::critical(this, "數據庫錯誤", "無法創建數據庫連接");return;}// 創建數據表QSqlQuery query;query.exec("CREATE TABLE IF NOT EXISTS env_data (""id INTEGER PRIMARY KEY AUTOINCREMENT, ""timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, ""temperature REAL, ""humidity REAL, ""light REAL, ""pm25 REAL, ""hcho REAL)");
}void MainWindow::setupMQTT() {m_client = new QMqttClient(this);m_client->setHostname("your_huawei_cloud_address");m_client->setPort(1883);m_client->setUsername("your_device_id");m_client->setPassword("your_device_secret");connect(m_client, &QMqttClient::connected, this, &MainWindow::onMQTTConnected);connect(m_client, &QMqttClient::messageReceived, this, &MainWindow::onMQTTMessage);m_client->connectToHost();
}void MainWindow::onMQTTConnected() {m_client->subscribe("environment/data");qDebug() << "Connected to MQTT Broker";
}void MainWindow::onMQTTMessage(const QByteArray &message) {// 示例JSON格式:{"temp":25.5,"humi":45,"light":320,"pm25":35,"hcho":0.02}QJsonDocument doc = QJsonDocument::fromJson(message);QJsonObject obj = doc.object();currentData.temperature = obj["temp"].toDouble();currentData.humidity = obj["humi"].toDouble();currentData.light = obj["light"].toDouble();currentData.pm25 = obj["pm25"].toDouble();currentData.hcho = obj["hcho"].toDouble();// 更新UItempLabel->setText(QString("溫度: %1°C").arg(currentData.temperature));humiLabel->setText(QString("濕度: %1%").arg(currentData.humidity));lightLabel->setText(QString("光照: %1Lux").arg(currentData.light));pm25Label->setText(QString("PM2.5: %1μg/m3").arg(currentData.pm25));hchoLabel->setText(QString("甲醛: %1mg/m3").arg(currentData.hcho));// 保存到數據庫QSqlQuery query;query.prepare("INSERT INTO env_data (temperature, humidity, light, pm25, hcho) ""VALUES (?, ?, ?, ?, ?)");query.addBindValue(currentData.temperature);query.addBindValue(currentData.humidity);query.addBindValue(currentData.light);query.addBindValue(currentData.pm25);query.addBindValue(currentData.hcho);query.exec();// 檢查閾值checkThresholds();
}void MainWindow::checkThresholds() {bool needAlarm = false;QString alarmMsg = "環境異常:\n";if (currentData.temperature > TEMP_THRESHOLD) {needAlarm = true;alarmMsg += QString("溫度過高: %1°C\n").arg(currentData.temperature);}if (currentData.humidity > HUMI_THRESHOLD) {needAlarm = true;alarmMsg += QString("濕度過高: %1%\n").arg(currentData.humidity);}if (currentData.pm25 > PM25_THRESHOLD) {needAlarm = true;alarmMsg += QString("PM2.5超標: %1μg/m3\n").arg(currentData.pm25);}if (currentData.hcho > HCHO_THRESHOLD) {needAlarm = true;alarmMsg += QString("甲醛超標: %1mg/m3\n").arg(currentData.hcho);}if (needAlarm) {// 顯示彈窗QMessageBox::critical(this, "環境異常報警", alarmMsg);// 播放報警音if (alarmPlayer->state() == QMediaPlayer::PlayingState) {alarmPlayer->stop();}alarmPlayer->play();// 自動模式下的設備控制if (modeBtn->isChecked() && !currentData.relayState) {onRelayControl(true);}}
}void MainWindow::onRelayControl(bool checked) {currentData.relayState = !currentData.relayState;relayBtn->setText(currentData.relayState ? "凈化器: 開啟" : "凈化器: 關閉");// 發送控制命令QJsonObject ctrlObj;ctrlObj["relay"] = currentData.relayState ? 1 : 0;QJsonDocument doc(ctrlObj);m_client->publish("device/control", doc.toJson());
}void MainWindow::onModeChanged(bool autoMode) {modeBtn->setText(autoMode ? "當前模式: 自動" : "當前模式: 手動");
}void MainWindow::onQueryData() {updateChart();
}void MainWindow::updateChart() {QSqlQuery query;query.prepare("SELECT timestamp, temperature, pm25, hcho FROM env_data ""WHERE timestamp BETWEEN ? AND ?");query.addBindValue(startDateEdit->dateTime().toString("yyyy-MM-dd hh:mm:ss"));query.addBindValue(endDateEdit->dateTime().toString("yyyy-MM-dd hh:mm:ss"));if (!query.exec()) {QMessageBox::warning(this, "查詢錯誤", "無法獲取歷史數據");return;}// 創建圖表數據QLineSeries *tempSeries = new QLineSeries();QLineSeries *pm25Series = new QLineSeries();QLineSeries *hchoSeries = new QLineSeries();tempSeries->setName("溫度");pm25Series->setName("PM2.5");hchoSeries->setName("甲醛");while (query.next()) {QDateTime dt = QDateTime::fromString(query.value(0).toString(), "yyyy-MM-dd hh:mm:ss");tempSeries->append(dt.toMSecsSinceEpoch(), query.value(1).toDouble());pm25Series->append(dt.toMSecsSinceEpoch(), query.value(2).toDouble());hchoSeries->append(dt.toMSecsSinceEpoch(), query.value(3).toDouble() * 100); // 縮放顯示}// 配置圖表QChart *chart = chartView->chart();chart->removeAllSeries();chart->addSeries(tempSeries);chart->addSeries(pm25Series);chart->addSeries(hchoSeries);QDateTimeAxis *axisX = new QDateTimeAxis;axisX->setFormat("MM-dd hh:mm");axisX->setTitleText("時間");chart->addAxis(axisX, Qt::AlignBottom);QValueAxis *axisY = new QValueAxis;axisY->setTitleText("數值");chart->addAxis(axisY, Qt::AlignLeft);tempSeries->attachAxis(axisX);tempSeries->attachAxis(axisY);pm25Series->attachAxis(axisX);pm25Series->attachAxis(axisY);hchoSeries->attachAxis(axisX);hchoSeries->attachAxis(axisY);chart->legend()->setVisible(true);
}int main(int argc, char *argv[]) {QApplication app(argc, argv);// 初始化MQTT模塊QMqttClient::registerMqttTypes();MainWindow w;w.show();return app.exec();
}#include "main.moc" // 包含元對象編譯器輸出
關鍵功能說明:
-
MQTT通信模塊:
- 連接華為云物聯網平臺
- 訂閱環境數據主題(environment/data)
- 發布設備控制指令(device/control)
-
數據管理:
- 使用SQLite數據庫存儲歷史數據
- 支持按時間范圍查詢數據
-
實時監控界面:
- 顯示溫濕度、光照、PM2.5和甲醛數據
- 設備狀態指示(空氣凈化器開關)
- 手動/自動模式切換
-
報警系統:
- 閾值超限時觸發彈窗報警
- 播放報警音效
- 自動模式下觸發設備控制
-
數據可視化:
- 使用Qt Charts繪制歷史曲線
- 支持多參數同屏顯示(溫度、PM2.5、甲醛)
- 自定義時間范圍查詢
部署說明:
-
依賴庫:
-
Qt 5.9+ Core, Widgets, MQTT, Charts, SQL
-
配置
pro
文件:QT += core widgets mqtt charts sql
-
-
華為云配置:
-
替換MQTT連接參數:
m_client->setHostname("your_huawei_cloud_address"); m_client->setUsername("your_device_id"); m_client->setPassword("your_device_secret");
-
-
報警音效:
- 添加
alarm.wav
文件到資源系統 - 或在代碼中替換為系統提示音
- 添加
-
數據庫初始化:
- 首次運行自動創建SQLite數據庫文件
- 數據表結構見
setupDatabase()
函數
該代碼實現了完整的智能家居監測系統上位機功能,滿足所有需求要求。
模塊代碼設計
以下是基于STM32F103C8T6的完整傳感器驅動代碼(寄存器開發方式):
#include "stm32f10x.h"// 硬件定義
#define DHT11_GPIO GPIOA
#define DHT11_PIN GPIO_Pin_0
#define RELAY_GPIO GPIOA
#define RELAY_PIN GPIO_Pin_4
#define BUZZER_GPIO GPIOA
#define BUZZER_PIN GPIO_Pin_5
#define LED_R_GPIO GPIOA
#define LED_R_PIN GPIO_Pin_6
#define LED_G_GPIO GPIOA
#define LED_G_PIN GPIO_Pin_7
#define KEY_GPIO GPIOA
#define KEY_PIN GPIO_Pin_8// OLED I2C地址
#define OLED_ADDRESS 0x78// 系統時鐘初始化
void SystemClock_Config(void) {// 啟用外部8MHz晶振RCC->CR |= RCC_CR_HSEON;while(!(RCC->CR & RCC_CR_HSERDY));// 配置PLL: HSE * 9 = 72MHzRCC->CFGR |= RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC;RCC->CR |= RCC_CR_PLLON;while(!(RCC->CR & RCC_CR_PLLRDY));// 設置系統時鐘RCC->CFGR |= RCC_CFGR_SW_PLL;while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);// 使能外設時鐘RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_ADC1EN |RCC_APB2ENR_AFIOEN;RCC->APB1ENR |= RCC_APB1ENR_USART2EN | RCC_APB1ENR_I2C1EN;
}// GPIO初始化
void GPIO_Config(void) {// DHT11 (PA0 輸入)GPIOA->CRL &= ~(0x0F << 0);GPIOA->CRL |= 0x08 << 0; // 浮空輸入// 繼電器 (PA4 推挽輸出)GPIOA->CRL &= ~(0x0F << 16);GPIOA->CRL |= 0x03 << 16;// 蜂鳴器/LED (PA5-PA7 推挽輸出)GPIOA->CRL &= ~(0xFF << 20);GPIOA->CRL |= 0x33 << 20 | 0x30;// 按鍵 (PA8 上拉輸入)GPIOA->CRH &= ~(0x0F << 0);GPIOA->CRH |= 0x08 << 0;GPIOA->ODR |= KEY_PIN;
}// DHT11驅動
typedef struct {uint8_t humi_int;uint8_t humi_deci;uint8_t temp_int;uint8_t temp_deci;uint8_t check_sum;
} DHT11_Data;uint8_t DHT11_Read(DHT11_Data *data) {uint8_t buffer[5] = {0};// 主機發送開始信號GPIO_InitTypeDef gpio;gpio.GPIO_Pin = DHT11_PIN;gpio.GPIO_Mode = GPIO_Mode_Out_PP;gpio.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DHT11_GPIO, &gpio);GPIO_ResetBits(DHT11_GPIO, DHT11_PIN); // 拉低18msDelay_ms(18);GPIO_SetBits(DHT11_GPIO, DHT11_PIN); // 釋放總線Delay_us(30);// 切換輸入模式gpio.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(DHT11_GPIO, &gpio);// 等待響應if(GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN)) return 0;while(!GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN));while(GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN));// 讀取40位數據for(uint8_t i=0; i<40; i++) {while(!GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN)); // 等待高電平Delay_us(40);buffer[i/8] <<= 1;if(GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN)) buffer[i/8] |= 1;while(GPIO_ReadInputDataBit(DHT11_GPIO, DHT11_PIN));}// 校驗數據if(buffer[0] + buffer[1] + buffer[2] + buffer[3] == buffer[4]) {data->humi_int = buffer[0];data->temp_int = buffer[2];return 1;}return 0;
}// BH1750光照傳感器驅動
void BH1750_Init(void) {I2C1->CR1 |= I2C_CR1_SWRST;I2C1->CR1 &= ~I2C_CR1_SWRST;// 配置I2C時鐘 (72MHz PCLK1)I2C1->CR2 = 36; // APB1時鐘=36MHzI2C1->CCR = 180; // 100kHz模式I2C1->TRISE = 37;I2C1->CR1 |= I2C_CR1_PE;
}uint16_t BH1750_Read(void) {uint8_t cmd[2] = {0x10}; // 連續高精度模式// 發送測量命令I2C_GenerateSTART(I2C1, ENABLE);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));I2C_Send7bitAddress(I2C1, 0x23, I2C_Direction_Transmitter);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));I2C_SendData(I2C1, cmd[0]);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));// 等待測量完成Delay_ms(180);// 讀取數據I2C_GenerateSTART(I2C1, ENABLE);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));I2C_Send7bitAddress(I2C1, 0x23, I2C_Direction_Receiver);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));uint8_t msb = I2C_ReceiveData(I2C1);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));uint8_t lsb = I2C_ReceiveData(I2C1);I2C_GenerateSTOP(I2C1, ENABLE);return (msb << 8) | lsb;
}// OLED顯示驅動
void OLED_WriteCmd(uint8_t cmd) {I2C_GenerateSTART(I2C1, ENABLE);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));I2C_SendData(I2C1, 0x00); // 控制字節while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_SendData(I2C1, cmd);while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_GenerateSTOP(I2C1, ENABLE);
}void OLED_Init(void) {OLED_WriteCmd(0xAE); // 關閉顯示OLED_WriteCmd(0xD5); // 設置時鐘分頻OLED_WriteCmd(0x80);OLED_WriteCmd(0xA8); // 設置復用率OLED_WriteCmd(0x3F);OLED_WriteCmd(0xD3); // 設置顯示偏移OLED_WriteCmd(0x00);OLED_WriteCmd(0x40); // 設置起始行OLED_WriteCmd(0x8D); // 電荷泵設置OLED_WriteCmd(0x14);OLED_WriteCmd(0x20); // 內存模式OLED_WriteCmd(0x00);OLED_WriteCmd(0xA1); // 段重定向OLED_WriteCmd(0xC8); // 行重定向OLED_WriteCmd(0xDA); // 設置COM硬件OLED_WriteCmd(0x12);OLED_WriteCmd(0x81); // 對比度OLED_WriteCmd(0xCF);OLED_WriteCmd(0xD9); // 預充電OLED_WriteCmd(0xF1);OLED_WriteCmd(0xDB); // VCOMHOLED_WriteCmd(0x40);OLED_WriteCmd(0xA4); // 顯示全部亮OLED_WriteCmd(0xA6); // 正常顯示OLED_WriteCmd(0xAF); // 開啟顯示
}// PM2.5傳感器驅動 (GP2Y1010AU0F)
#define PM_LED_GPIO GPIOA
#define PM_LED_PIN GPIO_Pin_2
#define PM_ADC_CH ADC_Channel_1void PM25_Init(void) {// 配置LED控制引腳GPIOA->CRL &= ~(0x0F << 8);GPIOA->CRL |= 0x03 << 8; // PA2推挽輸出// ADC配置ADC1->CR2 = ADC_CR2_ADON; // 開啟ADCADC1->SMPR2 = 0x00000007; // 通道1采樣時間239.5周期
}uint16_t PM25_Read(void) {GPIO_SetBits(PM_LED_GPIO, PM_LED_PIN);Delay_us(280);ADC1->CR2 |= ADC_CR2_ADON;while(!(ADC1->SR & ADC_SR_EOC)); // 等待轉換完成uint16_t adcValue = ADC1->DR;GPIO_ResetBits(PM_LED_GPIO, PM_LED_PIN);Delay_us(40);return adcValue;
}// 甲醛傳感器驅動 (ZE08-CH2O)
void USART2_Init(void) {// 配置USART2 (PA2-TX, PA3-RX)GPIOA->CRL &= ~(0xFF << 8);GPIOA->CRL |= 0x00008B00; // PA2復用推挽, PA3浮空輸入USART2->BRR = 0x1D4C; // 72MHz/9600=7500USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}uint16_t CH2O_Read(void) {uint8_t buffer[9];if(USART2->SR & USART_SR_RXNE) {for(uint8_t i=0; i<9; i++) {while(!(USART2->SR & USART_SR_RXNE));buffer[i] = USART2->DR;}// 校驗幀頭: 0xFF 0x17 0x04if(buffer[0]==0xFF && buffer[1]==0x17 && buffer[2]==0x04) {return (buffer[3] << 8) | buffer[4]; // 返回甲醛濃度值}}return 0;
}// ESP8266 WiFi通信
void USART1_Init(void) {// 配置USART1 (PA9-TX, PA10-RX)GPIOA->CRH &= ~(0xFF << 4);GPIOA->CRH |= 0x0000008B;USART1->BRR = 0x1D4C; // 72MHz/9600=7500USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}void ESP8266_SendCmd(const char *cmd) {while(*cmd) {USART1->DR = *cmd++;while(!(USART1->SR & USART_SR_TC));}
}// 主控制邏輯
int main(void) {SystemClock_Config();GPIO_Config();USART1_Init();USART2_Init();I2C_Config();ADC_Config();// 初始化外設BH1750_Init();OLED_Init();PM25_Init();// 連接華為云ESP8266_SendCmd("AT+CWMODE=1\r\n");Delay_ms(1000);ESP8266_SendCmd("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n");Delay_ms(3000);ESP8266_SendCmd("AT+MQTTUSERCFG=0,1,\"deviceID\",\"username\",\"password\"\r\n");ESP8266_SendCmd("AT+MQTTCONN=0,\"iot-cloud.com\",1883,1\r\n");while(1) {// 傳感器數據采集DHT11_Data dht;if(DHT11_Read(&dht)) {uint16_t light = BH1750_Read();uint16_t pm25 = PM25_Read();uint16_t ch2o = CH2O_Read();// OLED顯示OLED_DisplayData(dht.temp_int, dht.humi_int, light, pm25, ch2o);// 數據上傳華為云char mqttMsg[128];sprintf(mqttMsg, "{\"temp\":%d,\"humi\":%d,\"light\":%d,\"pm25\":%d,\"ch2o\":%d}",dht.temp_int, dht.humi_int, light, pm25, ch2o);ESP8266_SendMQTT("topic/pub", mqttMsg);// 閾值判斷if(pm25 > 100 || ch2o > 80) {GPIO_SetBits(BUZZER_GPIO, BUZZER_PIN);GPIO_SetBits(LED_R_GPIO, LED_R_PIN);GPIO_ResetBits(LED_G_GPIO, LED_G_PIN);} else {GPIO_ResetBits(BUZZER_GPIO, BUZZER_PIN);GPIO_ResetBits(LED_R_GPIO, LED_R_PIN);GPIO_SetBits(LED_G_GPIO, LED_G_PIN);}}Delay_ms(5000); // 5秒采集周期}
}
關鍵模塊說明:
-
DHT11溫濕度傳感器:
- 單總線協議,精確時序控制
- 18ms啟動信號+40us響應檢測
- 40位數據校驗機制
-
BH1750光照傳感器:
- I2C接口(100kHz)
- 連續高精度測量模式(0x10)
- 16位光照強度值輸出
-
PM2.5傳感器:
- 同步LED觸發與ADC采樣
- 280us LED點亮延遲
- ADC1通道1采樣(PA1)
-
甲醛傳感器:
- UART主動上傳模式
- 幀格式:FF 17 04 [DATA] [CHECK]
- 串口2接收處理(PA3)
-
OLED顯示:
- I2C接口SSD1306驅動
- 128x64分辨率文本顯示
- 自定義數據刷新邏輯
-
ESP8266通信:
- AT指令集控制
- MQTT協議接入華為云
- 支持JSON數據格式上傳
-
報警控制:
- 雙色LED狀態指示
- 蜂鳴器閾值觸發
- 繼電器設備控制(PA4)
代碼采用純寄存器開發,包含完整的傳感器驅動、云平臺接入邏輯和本地控制功能,可直接部署到STM32F103C8T6平臺運行。
項目核心代碼
以下是基于STM32F103C8T6的智能家居健康環境監測系統main.c
完整代碼(寄存器開發方式):
#include "stm32f10x.h"
#include "sensor_driver.h"
#include "oled.h"
#include "wifi.h"
#include "mqtt.h"
#include "timer.h"
#include "sys.h"// 傳感器數據結構體
typedef struct {float temp;float humi;uint16_t light;uint16_t pm25;uint16_t hcho;
} SensorData;// 全局變量定義
volatile SensorData sensor_data = {0};
volatile uint8_t relay_status = 0; // 繼電器狀態
volatile uint8_t work_mode = 0; // 0:自動模式 1:手動模式
volatile uint8_t alarm_flag = 0; // 報警標志位// 報警閾值常量
#define TEMP_THRESHOLD 35.0
#define HUMI_THRESHOLD 80.0
#define PM25_THRESHOLD 150
#define HCHO_THRESHOLD 100// 硬件初始化
void Hardware_Init(void) {// 啟用時鐘RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN;RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN;RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;// GPIO初始化GPIOA->CRL &= 0xFFFF0000; // PA0~3:模擬輸入/串口GPIOA->CRL |= 0x00008B00; // PA1:ADC, PA2:復用推挽(USART_TX), PA3:浮空輸入(USART_RX)// 繼電器控制引腳(PC13)GPIOC->CRH &= 0xFF0FFFFF;GPIOC->CRH |= 0x00300000; // 推挽輸出GPIOC->ODR &= ~(1<<13); // 初始關閉// 報警LED(PC14-PC15)GPIOC->CRH &= 0x00FFFFFF;GPIOC->CRH |= 0x33000000; // 推挽輸出GPIOC->ODR &= ~(0x3<<14); // 初始關閉// 蜂鳴器(PA4)GPIOA->CRL &= 0xFFF0FFFF;GPIOA->CRL |= 0x00030000; // 推挽輸出GPIOA->ODR &= ~(1<<4); // 初始關閉// 按鍵(PA8)GPIOA->CRH &= 0xFFFFFFF0;GPIOA->CRH |= 0x00000008; // 上拉輸入// 初始化外設USART1_Init(115200); // ESP8266通信ADC1_Init(); // ADC初始化I2C_Init(); // I2C初始化(BH1750+OLED)TIM3_Init(1000, 72); // 1ms定時器
}// 傳感器數據采集
void Sensor_Update(void) {sensor_data.temp = DHT11_ReadTemp();sensor_data.humi = DHT11_ReadHumi();sensor_data.light = BH1750_ReadLight();sensor_data.pm25 = GP2Y1010_Read();sensor_data.hcho = ZE08_ReadHCHO();
}// 報警檢測
void Check_Alarm(void) {if((sensor_data.temp > TEMP_THRESHOLD) ||(sensor_data.humi > HUMI_THRESHOLD) ||(sensor_data.pm25 > PM25_THRESHOLD) ||(sensor_data.hcho > HCHO_THRESHOLD)) {// 觸發聲光報警GPIOA->ODR |= (1<<4); // 蜂鳴器開啟GPIOC->ODR |= (1<<14); // 紅燈亮alarm_flag = 1;// 自動模式開啟凈化器if(work_mode == 0) {GPIOC->ODR |= (1<<13); // 繼電器開啟relay_status = 1;}} else {GPIOA->ODR &= ~(1<<4); // 關閉蜂鳴器GPIOC->ODR &= ~(1<<14); // 關閉紅燈alarm_flag = 0;// 自動模式關閉凈化器if((work_mode == 0) && relay_status) {GPIOC->ODR &= ~(1<<13);relay_status = 0;}}
}// 狀態指示燈控制
void Status_LED(void) {static uint8_t counter = 0;if(++counter >= 100) { // 100ms周期counter = 0;if(WiFi_Connected()) {GPIOC->ODR ^= (1<<15); // 綠燈閃爍} else {GPIOC->ODR &= ~(1<<15); // 綠燈常滅}}
}// 主函數
int main(void) {// 硬件初始化Hardware_Init();OLED_Init();WiFi_Init();MQTT_Init();// 顯示歡迎界面OLED_ShowString(0, 0, "Smart Home System", 16);OLED_ShowString(0, 2, "Initializing...", 16);Delay_Ms(1000);// 連接華為云if(WiFi_Connect("SSID", "PASSWORD") && MQTT_Connect("device_id", "token")) {OLED_ShowString(0, 4, "Cloud: Connected", 16);} else {OLED_ShowString(0, 4, "Cloud: Error!", 16);}Delay_Ms(500);OLED_Clear();while(1) {// 1. 傳感器數據采集Sensor_Update();// 2. OLED顯示實時數據OLED_ShowString(0, 0, "T:", 8); OLED_ShowFloat(16, 0, sensor_data.temp, 8);OLED_ShowString(0, 2, "PM2.5:", 8); OLED_ShowNum(48, 2, sensor_data.pm25, 8);// 3. 檢測報警條件Check_Alarm();// 4. 上傳數據到華為云if(WiFi_Connected()) {char buffer[128];sprintf(buffer, "{\"temp\":%.1f,\"humi\":%.1f,\"light\":%d,\"pm25\":%d,\"hcho\":%d}",sensor_data.temp, sensor_data.humi, sensor_data.light, sensor_data.pm25, sensor_data.hcho);MQTT_Publish("topic/data", buffer);}// 5. 處理按鍵事件if(GPIOA->IDR & (1<<8)) { // 按鍵按下Delay_Ms(20);if(GPIOA->IDR & (1<<8)) {work_mode = !work_mode;OLED_ShowString(80, 0, work_mode ? "M" : "A", 16);}while(GPIOA->IDR & (1<<8)); // 等待釋放}// 6. 狀態指示燈控制Status_LED();// 7. 處理云平臺指令if(MQTT_CommandReceived()) {uint8_t cmd = MQTT_GetCommand();if(cmd == 0x01) { // 開啟凈化器GPIOC->ODR |= (1<<13);relay_status = 1;} else if(cmd == 0x00) { // 關閉凈化器GPIOC->ODR &= ~(1<<13);relay_status = 0;}}// 主循環延時Delay_Ms(500);}
}// 定時器3中斷服務函數
void TIM3_IRQHandler(void) {if(TIM3->SR & TIM_SR_UIF) {TIM3->SR &= ~TIM_SR_UIF; // 清除中斷標志// 1ms定時任務static uint16_t counter = 0;if(++counter >= 1000) { // 1秒定時counter = 0;// 發送心跳包if(WiFi_Connected()) {MQTT_Ping();}}}
}// USART1中斷服務函數(處理ESP8266數據)
void USART1_IRQHandler(void) {if(USART1->SR & USART_SR_RXNE) {uint8_t data = USART1->DR;MQTT_ReceiveHandler(data); // MQTT協議解析}
}
代碼說明:
-
硬件初始化:
- 配置GPIO(傳感器、繼電器、報警器、按鍵)
- 初始化USART(WiFi通信)、ADC(PM2.5采集)、I2C(OLED+光照傳感器)
- 定時器TIM3用于系統心跳
-
核心功能:
- 傳感器數據采集(溫濕度/光照/PM2.5/甲醛)
- OLED實時顯示環境參數
- 閾值報警控制(聲光報警+自動凈化)
- ESP8266通過AT指令與華為云MQTT通信
- 支持手動/自動雙模式切換
-
中斷服務:
- TIM3中斷:處理心跳包和定時任務
- USART1中斷:處理云平臺下發的控制指令
-
數據處理流程:
- 主循環500ms采集并上傳數據
- 實時檢測環境閾值觸發報警
- 按鍵切換工作模式
- OLED刷新顯示設備狀態
注意:實際開發需確保以下驅動文件已實現:
sensor_driver.h
(所有傳感器驅動)oled.h
(OLED顯示驅動)wifi.h
(ESP8266 AT指令封裝)mqtt.h
(華為云MQTT協議對接)timer.h
(定時器配置)sys.h
(系統工具函數)
總結
本項目成功構建了一套基于STM32F103C8T6微控制器的智能家居健康環境監測系統。系統核心實現了對室內溫濕度、光照強度、PM2.5及甲醛濃度的實時精準采集,并通過ESP8266 WiFi模塊將數據穩定上傳至華為云物聯網平臺進行集中存儲與管理。STM32主控有效協調了多傳感器數據讀取、本地OLED屏狀態顯示、聲光報警觸發以及繼電器對凈化設備的控制,確保了各硬件模塊的高效協同運作。
在遠程交互層面,QT開發的上位機通過MQTT協議訂閱華為云數據,為用戶提供了直觀的數據可視化界面,實時展示環境參數并生成歷史變化曲線圖。同時,QT界面集成了遠程設備控制功能與閾值報警機制(彈窗+聲音),使用戶能夠便捷地管理空氣凈化設備,并在環境異常時及時獲得提醒。系統支持手動/自動雙運行模式,在自動模式下能依據預設閾值智能啟停凈化設備,提升了智能化水平。
本地交互設計注重實用性,OLED顯示屏清晰呈現實時環境參數與設備工作狀態,按鍵支持模式切換,聲光報警單元(蜂鳴器+LED)確保本地環境超標時能迅速引起注意。整體系統融合了傳感器技術、嵌入式控制、無線通信、云平臺服務與上位機軟件開發,構建了一個功能完備、交互友好、兼具本地與遠程管理能力的智能環境監測解決方案,有效提升家居環境的健康管理水平。