網(wǎng)智能家居監(jiān)測控制系統(tǒng)設(shè)計與實現(xiàn))
最近在指導(dǎo)本科畢業(yè)設(shè)計選題時很多同學(xué)都在問同一個問題想做一個“物聯(lián)網(wǎng)智能家居監(jiān)測控制系統(tǒng)”但又怕難度太高做不完或者做完以后只是簡單點燈沒什么說服力。如果把整體方案拆解清楚其實這類題目很適合作為單片機類畢業(yè)設(shè)計它能覆蓋傳感器采集、數(shù)據(jù)處理、無線通信、執(zhí)行控制、上位機/云平臺展示等多個環(huán)節(jié)同時難度又可以自己控制不管是入門級的51單片機還是主流的STM32都能找到合適的實現(xiàn)路徑。這篇文章就以“物聯(lián)網(wǎng)智能家居監(jiān)測控制系統(tǒng)”為完整主線結(jié)合我實際做項目時常用的硬件選型和代碼框架梳理一套可落地的設(shè)計思路。內(nèi)容包括系統(tǒng)總體架構(gòu)、硬件選型、傳感器與繼電器控制、ESP8266聯(lián)網(wǎng)與云端上報、核心代碼實現(xiàn)、常見問題和工程建議。無論你是準備畢業(yè)設(shè)計、課程設(shè)計還是想自己動手搭一套智能家居Demo都可以參考這套方案。1. 項目背景與系統(tǒng)概述1.1 為什么選擇智能家居監(jiān)測控制系統(tǒng)作為畢業(yè)設(shè)計智能家居是物聯(lián)網(wǎng)技術(shù)最典型、也最容易展示成果的應(yīng)用場景之一。它的核心并不復(fù)雜利用各種傳感器采集室內(nèi)環(huán)境數(shù)據(jù)通過主控單片機分析與判斷再根據(jù)預(yù)設(shè)邏輯控制家電設(shè)備同時把數(shù)據(jù)上報到云端或手機App實現(xiàn)遠程監(jiān)測和控制。這類題目的優(yōu)勢很明顯技術(shù)覆蓋面廣方便在論文中體現(xiàn)工作量硬件成本相對可控適合學(xué)生預(yù)算可深可淺基礎(chǔ)版可以做本地采集與控制進階版可以接云平臺、微信小程序演示效果好答辯時能直觀展示溫濕度變化、燈光/風(fēng)扇聯(lián)動等效果。1.2 系統(tǒng)能實現(xiàn)哪些功能本文給出的系統(tǒng)設(shè)計以“環(huán)境監(jiān)測 設(shè)備控制 遠程通信”為核心具體功能劃分如下環(huán)境數(shù)據(jù)采集實時采集室內(nèi)溫度、濕度、煙霧濃度、光照強度等參數(shù)。本地顯示通過LCD1602液晶屏或OLED屏幕循環(huán)顯示溫濕度、煙霧值、設(shè)備狀態(tài)。自動控制邏輯溫度過高時自動打開風(fēng)扇煙霧濃度超過閾值時聲光報警并打開排風(fēng)扇光照過低時可以自動開燈。手動控制通過按鍵切換自動/手動模式手動模式下可獨立控制風(fēng)扇、燈光、報警器等設(shè)備。無線通信通過ESP8266模塊連接WiFi把傳感器數(shù)據(jù)上傳到云平臺支持遠程查看數(shù)據(jù)。遠程控制通過云平臺或手機端下發(fā)指令控制繼電器開關(guān)。1.3 系統(tǒng)總體方案與架構(gòu)系統(tǒng)從整體上可以分為四層傳感器采集層 - 主控MCU層 - 無線通信層 - 云平臺/App層 DHT11 STM32F103C8T6 ESP8266 MQTT協(xié)議 MQ-2煙霧傳感器 數(shù)據(jù)處理與判斷 WiFi聯(lián)網(wǎng) 阿里云/騰訊云/OneNET BH1750光照傳感器 繼電器控制 AT指令/MQTT 可視化面板這里的主控芯片推薦使用STM32F103C8T6。它是一款基于ARM Cortex-M3內(nèi)核的入門級MCU主頻72MHz擁有豐富的外設(shè)資源包括ADC、定時器、USART、I2C、GPIO等足夠支撐本項目的全部功能。如果環(huán)境溫度、煙霧傳感器使用ADC采集也可以通過GPIO模擬讀取。對于51單片機來說這套架構(gòu)同樣成立只是需要留意RAM和Flash容量以及ADC通道數(shù)量的限制。整體工作流程是傳感器周期采集數(shù)據(jù)主控解析數(shù)據(jù)并進行閾值判斷自動模式下由程序直接控制繼電器手動模式下由按鍵輸入控制繼電器每個采集周期主控通過串口把數(shù)據(jù)交給ESP8266模塊ESP8266通過MQTT協(xié)議將數(shù)據(jù)發(fā)布到云平臺手機端訂閱云平臺主題即可實時看到數(shù)據(jù)并下發(fā)控制指令。2. 環(huán)境準備與硬件選型2.1 硬件清單在設(shè)計系統(tǒng)前先列出一份完整硬件清單。這個清單是我在實際項目中使用過的最低成本組合適合學(xué)生設(shè)計和實驗室搭建。名稱型號/規(guī)格數(shù)量用途主控MCUSTM32F103C8T6最小系統(tǒng)板1核心控制與數(shù)據(jù)處理溫濕度傳感器DHT111采集溫濕度煙霧/可燃氣體傳感器MQ-21檢測煙霧濃度及可燃氣體光照傳感器BH17501I2C接口數(shù)字光照傳感器WiFi模塊ESP8266-01S1無線聯(lián)網(wǎng)與云平臺通信顯示屏LCD1602I2C轉(zhuǎn)接板1顯示環(huán)境參數(shù)和狀態(tài)繼電器模塊5V低電平觸發(fā)繼電器3-4路控制風(fēng)扇、燈光、排風(fēng)扇等蜂鳴器模塊5V有源蜂鳴器1煙霧報警按鍵模塊輕觸按鍵4模式切換與手動控制電源5V/2A USB電源或鋰電池組1系統(tǒng)供電杜邦線/面包板若干若干接線調(diào)試2.2 軟件開發(fā)環(huán)境軟件開發(fā)環(huán)境可以根據(jù)大家熟悉的工具來選不必強求統(tǒng)一。本文以常見的STM32開發(fā)環(huán)境為例環(huán)境版本需要根據(jù)你的項目實際情況調(diào)整下面列出的是一套可行組合操作系統(tǒng)Windows 10/11 或 Ubuntu 20.04集成開發(fā)環(huán)境Keil MDK 5也可以使用STM32CubeIDE固件庫STM32 HAL 庫或標準外設(shè)庫本文代碼以HAL庫為參考代碼生成工具STM32CubeMX用于初始化時鐘、GPIO、串口、ADC、I2C串口調(diào)試工具XCOM、SSCOM 或 MobaXterm燒錄工具ST-Link 或 USB轉(zhuǎn)TTL串口需要接BOOT0啟動。如果你是51單片機方案則使用Keil C51工程代碼邏輯類似只是寄存器操作方式和引腳定義不同。2.3 項目文件結(jié)構(gòu)規(guī)劃實際工程中建議按功能模塊劃分文件不要把所有代碼都寫在main.c里。下面是一個推薦的文件組織結(jié)構(gòu)SmartHome/ ├── Core/ │ ├── Inc/ │ │ ├── main.h │ │ ├── dht11.h │ │ ├── mq2.h │ │ ├── bh1750.h │ │ ├── relay.h │ │ ├── buzzer.h │ │ └── esp8266.h │ └── Src/ │ ├── main.c │ ├── dht11.c │ ├── mq2.c │ ├── bh1750.c │ ├── relay.c │ ├── buzzer.c │ └── esp8266.c ├── Drivers/ │ └── STM32F1xx_HAL_Driver/ └── SmartHome.ioc這樣拆分的好處是每個模塊獨立成文件出錯便于定位論文中寫“模塊化設(shè)計”時有真實代碼支撐后續(xù)增刪傳感器不需要改動主程序結(jié)構(gòu)。3. 核心模塊設(shè)計詳解3.1 主控芯片選擇與環(huán)境搭建STM32F103C8T6俗稱“C8T6”或“藍丸”是目前大學(xué)生項目中使用率較高的芯片之一也是學(xué)習(xí)單片機比較友好的一款器件。它擁有64KB Flash20KB RAM37個GPIO口2個12位ADC最多10個通道3個USART、2個I2C、2個SPI4個16位定時器支持SWD調(diào)試接口。在STM32CubeMX中創(chuàng)建工程時基礎(chǔ)配置建議如下外設(shè)引腳/通道功能RCCHSE外部晶振系統(tǒng)時鐘72MHzSYSSWD調(diào)試下載USART1PA9/PA10調(diào)試打印USART2PA2/PA3與ESP8266通信I2C1PB6/PB7驅(qū)動BH1750光照傳感器ADC1PA0 或 PA1采集MQ-2煙霧傳感器GPIO輸出PB0-PB3控制繼電器與蜂鳴器GPIO輸入PB4-PB7讀取按鍵狀態(tài)DHT11PA4單總線數(shù)據(jù)讀取需要注意實際引腳分配可以在CubeMX中按硬件接線靈活調(diào)整。本項目的DHT11使用的是單總線協(xié)議也可以通過普通GPIO模擬時序?qū)崿F(xiàn)。3.2 DHT11溫濕度傳感器驅(qū)動設(shè)計DHT11是一款性價比很高的數(shù)字溫濕度傳感器。它使用單總線協(xié)議數(shù)據(jù)幀由40位組成包括8位濕度整數(shù)部分、8位濕度小數(shù)部分、8位溫度整數(shù)部分、8位溫度小數(shù)部分以及8位校驗和。讀取一次DHT11數(shù)據(jù)的基本時序如下主機拉低數(shù)據(jù)線至少18ms再釋放總線DHT11響應(yīng)拉低80us再拉高80us之后每一位數(shù)據(jù)都以50us低電平開始高電平持續(xù)26~28us表示“0”高電平持續(xù)70us表示“1”連續(xù)讀取40位數(shù)據(jù)校驗通過后保存溫濕度結(jié)果。這里有一個常見坑點DHT11的數(shù)據(jù)讀取對時序比較敏感如果在主程序中使用延時函數(shù)讀取實時性會受到影響。最好是給DHT11單獨設(shè)計一個讀取函數(shù)并且在主循環(huán)中每2秒才讀取一次不要在每次循環(huán)中都去讀。核心代碼思路如下以HAL庫為例文件路徑Core/Src/dht11.c#include dht11.h #include main.h #define DHT11_PORT GPIOA #define DHT11_PIN GPIO_PIN_4 static uint8_t dht11_data[5]; static void DHT11_Start(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; // 配置為輸出模式 GPIO_InitStruct.Pin DHT11_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DHT11_PORT, GPIO_InitStruct); // 主機拉低至少18ms HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET); HAL_Delay(20); // 釋放總線拉高 HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET); HAL_Delay(30); } static uint8_t DHT11_ReadBit(void) { uint8_t cnt 0; // 等待低電平結(jié)束 while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_SET); while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_RESET); // 高電平持續(xù)時間判斷 0 或 1 while (HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) GPIO_PIN_SET) { cnt; HAL_Delay(1); if (cnt 60) return 0; // 超時保護 } return (cnt 30) ? 1 : 0; // 70us高電平為128us高電平為0 }這段代碼用延時來估算高電平寬度雖然有一定誤差但在教學(xué)項目場景中足夠穩(wěn)定。如果你想提高穩(wěn)定性可以把延時換成定時器輸入捕獲方式或者使用微秒級延時函數(shù)。示例思路如下需按實際版本調(diào)整。3.3 MQ-2煙霧傳感器與ADC采樣MQ-2傳感器在智能家居系統(tǒng)中的作用是檢測煙霧和可燃氣體濃度。它有一個模擬量輸出引腳AO可以接MCU的ADC采集也有一個數(shù)字量輸出引腳DO接比較器閾值輸出。在實際項目中我推薦把AO引腳接入STM32的ADC這樣可以根據(jù)環(huán)境變化動態(tài)調(diào)整報警閾值而DO引腳只能輸出“是否超過固定閾值”的數(shù)字信號靈活性稍差。ADC采樣代碼思路如下文件路徑Core/Src/mq2.c#include mq2.h #include main.h extern ADC_HandleTypeDef hadc1; uint16_t MQ2_GetValue(void) { uint16_t adc_value 0; HAL_ADC_Start(hadc1); if (HAL_ADC_PollForConversion(hadc1, 100) HAL_OK) { adc_value HAL_ADC_GetValue(hadc1); } HAL_ADC_Stop(hadc1); return adc_value; } float MQ2_GetPercent(void) { uint16_t adc_value MQ2_GetValue(); // 假設(shè)ADC為12位滿量程4096將采樣值轉(zhuǎn)換為0.0~100.0的百分比 return (float)adc_value * 100.0f / 4096.0f; }這里需要強調(diào)的是MQ-2傳感器的輸出和氣體濃度并不是嚴格線性關(guān)系直接用百分比作為“濃度”是簡化處理。論文中可以寫“本設(shè)計以ADC采樣值百分比形式表征煙霧濃度相對大小”不要寫成“甲烷濃度ppm值”否則抗不住評委細問。如果確實需要精確氣體濃度需要使用更專業(yè)的電化學(xué)傳感器同時做溫濕度補償和標定。3.4 BH1750光照傳感器驅(qū)動BH1750是I2C接口的數(shù)字光照傳感器量程為1~65535 lux很適合智能家居中的“白天/夜晚”自動判斷場景。它只需要兩根信號線與STM32的I2C外設(shè)相連即可。BH1750的工作流程比較簡單向設(shè)備寫入上電指令0x01寫入測量模式指令本文使用連續(xù)高分辨率模式指令為0x10等待測量完成高分辨率模式下約120ms連續(xù)讀取2字節(jié)數(shù)據(jù)計算出光照值。核心代碼思路如下文件路徑Core/Src/bh1750.c#include bh1750.h #include main.h #define BH1750_ADDR 0x46 // 8位地址左移一位后的地址 extern I2C_HandleTypeDef hi2c1; uint8_t BH1750_Init(void) { uint8_t cmd 0x01; // 上電指令 return HAL_I2C_Master_Transmit(hi2c1, BH1750_ADDR, cmd, 1, 100); } uint16_t BH1750_ReadLux(void) { uint8_t cmdH 0x10; // 連續(xù)高分辨率模式 uint8_t buf[2] {0}; uint16_t lux 0; HAL_I2C_Master_Transmit(hi2c1, BH1750_ADDR, cmdH, 1, 100); HAL_Delay(180); if (HAL_I2C_Master_Receive(hi2c1, BH1750_ADDR, buf, 2, 100) HAL_OK) { lux (buf[0] 8) | buf[1]; lux (uint16_t)(lux / 1.2f); // 根據(jù)數(shù)據(jù)手冊高分辨率模式轉(zhuǎn)換 } return lux; }I2C設(shè)備的地址在不同參考代碼中可能不同使用時一定要對照模塊數(shù)據(jù)手冊并檢查是7位地址還是8位地址。HAL庫中的HAL_I2C_Master_Transmit使用的是8位地址也就是7位地址左移一位后的值。3.5 繼電器控制與系統(tǒng)安全設(shè)計繼電器模塊在電路中的作用是隔離控制。單片機IO口不能直接驅(qū)動220V交流負載因此需要使用繼電器作為開關(guān)元件。本項目中的風(fēng)扇、燈光、排風(fēng)扇都通過繼電器控制。這里有一個非常重要的設(shè)計原則單片機控制電路和強電負載電路之間要保持隔離。在選擇繼電器模塊時優(yōu)先選擇帶光耦隔離的模塊模塊的JD-VCC跳線帽如果用于隔離供電需要單獨供電。強電接線部分一定要使用端子排避免裸露導(dǎo)線和杜邦線直接連接220V。繼電器驅(qū)動代碼比較簡單但需要定義清晰的控制狀態(tài)// 文件路徑Core/Src/relay.c #include relay.h #include main.h void RELAY_Control(uint8_t ch, uint8_t state) { GPIO_PinState pinState (state RELAY_ON) ? GPIO_PIN_RESET : GPIO_PIN_SET; switch (ch) { case RELAY_FAN: // 風(fēng)扇 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, pinState); break; case RELAY_LIGHT: // 燈光 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, pinState); break; case RELAY_EXHAUST: // 排風(fēng)扇 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, pinState); break; case RELAY_OTHER: // 備用設(shè)備 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, pinState); break; default: break; } }注意代碼中使用的低電平觸發(fā)邏輯GPIO_PIN_RESET表示輸出低電平此時繼電器吸合。這是由常見5V低電平觸發(fā)繼電器模塊決定的。如果你的模塊是高電平觸發(fā)需要反轉(zhuǎn)邏輯。3.6 自動與手動控制邏輯設(shè)計系統(tǒng)需要支持兩種控制模式自動模式主控根據(jù)傳感器數(shù)據(jù)自動控制設(shè)備手動模式用戶通過按鍵直接控制設(shè)備開關(guān)。這里比較推薦采用“模式狀態(tài)機 按鍵中斷/掃描”的思路實現(xiàn)。主程序維護一個模式標志位和四個按鍵標志位每個循環(huán)周期判斷當(dāng)前模式。自動控制邏輯可以這樣設(shè)計如果 溫度 30℃ 且 溫度 50℃ 打開風(fēng)扇 否則 進入延時判斷避免繼電器頻繁動作 關(guān)閉風(fēng)扇 如果 煙霧濃度 40% 打開排風(fēng)扇 打開蜂鳴器 // 報警 否則 關(guān)閉排風(fēng)扇 關(guān)閉蜂鳴器 如果 光照 50 lux 且 已處于夜間 打開燈光 否則 關(guān)閉燈光這里的關(guān)鍵點是繼電器不能頻繁通斷。如果溫度在臨界值上下波動程序就會不斷開關(guān)風(fēng)扇影響繼電器壽命。實際項目中需要在每個閾值判斷中增加“遲滯區(qū)間”。例如風(fēng)扇開啟閾值為30℃關(guān)閉閾值為26℃中間相差4℃這樣可以避免臨界抖動。4. 無線通信與云平臺接入4.1 ESP8266模塊的基礎(chǔ)配置ESP8266是智能家居項目中常用的低成本W(wǎng)iFi模塊其核心是樂鑫ESP8266芯片。在本項目中它負責(zé)把STM32采集到的數(shù)據(jù)通過WiFi上傳到云平臺同時接收平臺下發(fā)的控制指令。ESP8266通常支持兩種開發(fā)方式AT指令模式STM32通過串口向ESP8266發(fā)送AT指令配置模塊連接WiFi然后進行TCP或MQTT通信。這種方式開發(fā)簡單適合畢業(yè)設(shè)計和快速原型。SDK二次開發(fā)模式直接在ESP8266上編寫固件邏輯可以獨立完成傳感器采集與上傳但開發(fā)周期較長調(diào)試難度也更高。對于單片機畢業(yè)設(shè)計使用AT指令模式即可滿足要求。使用前需要把ESP8266固件升級為支持MQTT的AT固件如AT 1.7.4以上版本或者使用配備了MQTT透傳固件的安信可ATK-MW8266D模塊。4.2 使用AT指令連接WiFi和MQTT串口配置建議如下波特率115200部分模塊默認是9600需要先用AT指令調(diào)整數(shù)據(jù)位8位停止位1位校驗位無。連接WiFi的核心AT指令如下AT OK ATE0 OK ATCWMODE1 OK ATCWJAP你的WiFi名稱,你的WiFi密碼 WIFI CONNECTED WIFI GOT IP OK ATMQTTUSERCFG0,1,clientID,username,password,0,0, OK ATMQTTCONN0,broker.emqx.io,1883,1 OK這里需要說明云平臺地址需要根據(jù)你實際使用的平臺地址填寫。如果你使用阿里云物聯(lián)網(wǎng)平臺需要先創(chuàng)建產(chǎn)品和設(shè)備獲得ProductKey、DeviceName和DeviceSecret然后使用阿里云提供的MQTT簽名工具生成username和password。如果你本地有EMQX或其他公共MQTT Broker也可以直接使用。4.3 MQTT協(xié)議在一個簡單項目中的角色MQTT是一種輕量級的發(fā)布/訂閱消息傳輸協(xié)議特別適合物聯(lián)網(wǎng)設(shè)備在低帶寬、不穩(wěn)定網(wǎng)絡(luò)環(huán)境下傳輸數(shù)據(jù)。在本系統(tǒng)中設(shè)備端STM32ESP8266向主題發(fā)布傳感器數(shù)據(jù)例如device/smart_home/data消息體格式{temp:26,humi:60,smoke:20,light:300}設(shè)備端訂閱另一個主題例如device/smart_home/control手機端向該主題發(fā)布控制指令{fan:on}設(shè)備端收到指令后解析JSON執(zhí)行對應(yīng)控制動作。STM32端解析JSON推薦使用cJSON庫文件較小且已經(jīng)非常成熟。在STM32工程中可以通過Keil的包管理器或手動添加cJSON.c和cJSON.h的方式集成。JSON解析的核心思路如下#include cJSON.h void ParseControlCommand(char *msg) { cJSON *root cJSON_Parse(msg); if (root NULL) return; cJSON *fan cJSON_GetObjectItem(root, fan); if (fan ! NULL cJSON_IsString(fan)) { if (strcmp(fan-valuestring, on) 0) { RELAY_Control(RELAY_FAN, RELAY_ON); } else { RELAY_Control(RELAY_FAN, RELAY_OFF); } } cJSON_Delete(root); }這段代碼要注意STM32的RAM有限不要頻繁創(chuàng)建和刪除大體積JSON對象收到指令后再解析即可。另外串口接收數(shù)據(jù)時需要設(shè)置一個接收緩沖區(qū)和幀結(jié)束標志位通常以\n作為一條指令的結(jié)束符。4.4 云平臺配置流程建議云平臺選擇上比較推薦OneNET或阿里云物聯(lián)網(wǎng)平臺它們都有免費試用額度而且文檔和示例代碼很多對在校生比較友好。以阿里云物聯(lián)網(wǎng)平臺為例基本配置流程如下登錄物聯(lián)網(wǎng)平臺控制臺創(chuàng)建產(chǎn)品選擇“自定義品類”節(jié)點類型為“設(shè)備”添加設(shè)備獲取設(shè)備三元組ProductKey、DeviceName、DeviceSecret使用阿里云官方工具“設(shè)備端簽名計算”生成MQTT連接參數(shù)在物聯(lián)網(wǎng)平臺的“消息轉(zhuǎn)發(fā)”或“AMQP服務(wù)端訂閱”中配置數(shù)據(jù)轉(zhuǎn)發(fā)把設(shè)備上報的數(shù)據(jù)流轉(zhuǎn)到數(shù)據(jù)庫或可視化面板。需要注意的是阿里云物聯(lián)網(wǎng)平臺配置過程中涉及的產(chǎn)品名、地域、設(shè)備名稱等參數(shù)都會影響連接結(jié)果一定要對照自己的控制臺信息填寫。網(wǎng)絡(luò)請求和認證也會變教程中的截圖和參數(shù)只能作為參考。5. 完整主程序設(shè)計5.1 主循環(huán)架構(gòu)主程序采用“一個主循環(huán) 多個功能模塊”的結(jié)構(gòu)。主循環(huán)中依次執(zhí)行按鍵掃描DHT11周期讀取MQ-2 ADC采集BH1750光照讀取自動/手動控制邏輯LCD顯示刷新數(shù)據(jù)上報與指令接收。主程序中的定時輪詢建議使用定時器標志位而不是直接在循環(huán)中延時。比如使用定時器中斷每隔2秒置位一個數(shù)據(jù)采集標志主循環(huán)檢測到標志后再執(zhí)行采集和上報這樣可以避免阻塞式延時影響按鍵響應(yīng)。核心代碼框架如下文件路徑Core/Src/main.c 部分核心代碼#include main.h #include dht11.h #include mq2.h #include bh1750.h #include relay.h #include buzzer.h #include esp8266.h #include lcd1602.h volatile uint8_t flag_2s 0; volatile uint8_t flag_500ms 0; int main(void) { uint8_t mode_auto 1; // 默認自動模式 float temperature 0, humidity 0; uint16_t smoke 0, light 0; HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); MX_I2C1_Init(); MX_ADC1_Init(); DHT11_Init(); BH1750_Init(); LCD1602_Init(); ESP8266_Init(); ESP8266_JoinAP(WiFi名稱, WiFi密碼); ESP8266_MQTT_Connect(); while (1) { // 按鍵掃描 Key_Scan(mode_auto); // 每2秒采集并上報一次 if (flag_2s) { flag_2s 0; DHT11_ReadData(temperature, humidity); smoke MQ2_GetValue(); light BH1750_ReadLux(); // 更新LCD顯示 LCD1602_ShowTempHumi(temperature, humidity); LCD1602_ShowSmokeLight(smoke, light); // 自動控制邏輯 if (mode_auto) { AutoControl(temperature, humidity, smoke, light); } // 組裝并上報數(shù)據(jù) ESP8266_ReportData(temperature, humidity, smoke, light); } // 每500ms檢查一次遠程控制指令 if (flag_500ms) { flag_500ms 0; ESP8266_CheckCommand(); } } }Delay函數(shù)如HAL_Delay在定時器中斷回調(diào)中不要使用否則容易出現(xiàn)嵌套調(diào)用問題。主循環(huán)內(nèi)盡量不要出現(xiàn)長時間阻塞。5.2 自動控制函數(shù)實現(xiàn)void AutoControl(float temp, float humi, uint16_t smoke, uint16_t light) { // 風(fēng)扇控制溫度高于30℃開啟低于26℃關(guān)閉 if (temp 30.0f) { RELAY_Control(RELAY_FAN, RELAY_ON); } else if (temp 26.0f) { RELAY_Control(RELAY_FAN, RELAY_OFF); } // 煙霧報警控制 if (smoke 1200) // 閾值可根據(jù)實驗室環(huán)境標定 { RELAY_Control(RELAY_EXHAUST, RELAY_ON); BUZZER_ON(); } else { RELAY_Control(RELAY_EXHAUST, RELAY_OFF); BUZZER_OFF(); } // 燈光控制光照低于50lux時開燈 if (light 50) { RELAY_Control(RELAY_LIGHT, RELAY_ON); } else { RELAY_Control(RELAY_LIGHT, RELAY_OFF); } }需要注意的是這里的“1200”是ADC采樣原始值閾值不是百分比。在實際調(diào)試中需要先打印不同環(huán)境下的ADC值再根據(jù)煙霧泄露實驗確定合適的閾值。如果沒有實驗條件可以先按ADC滿量程的30%~40%設(shè)定論文中說明是“經(jīng)驗閾值”。5.3 按鍵與手動控制實現(xiàn)按鍵控制使用GPIO外部中斷或輪詢均可。外部中斷更適合對響應(yīng)速度要求高的場景但本項目按鍵數(shù)量不多輪詢掃描已經(jīng)完全夠用。按鍵掃描時要做消抖處理通常可以這樣處理void Key_Scan(uint8_t *mode_auto) { // 按鍵1切換自動/手動模式 if (HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) GPIO_PIN_RESET) { HAL_Delay(20); // 簡單消抖 if (HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) GPIO_PIN_RESET) { *mode_auto !(*mode_auto); LCD1602_ShowMode(*mode_auto); } while (HAL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN) GPIO_PIN_RESET); // 等待釋放 } // 如果處于手動模式按鍵2控制風(fēng)扇 if (!(*mode_auto)) { if (HAL_GPIO_ReadPin(KEY2_PORT, KEY2_PIN) GPIO_PIN_RESET) { HAL_Delay(20); if (HAL_GPIO_ReadPin(KEY2_PORT, KEY2_PIN) GPIO_PIN_RESET) { RELAY_Control(RELAY_FAN, !currentFanState); currentFanState !currentFanState; } } // 按鍵3控制燈光、按鍵4控制排風(fēng)扇邏輯類似 } }寫按鍵邏輯時最需要避免的是“按下一次按鍵程序卻翻轉(zhuǎn)了多次狀態(tài)”。上述代碼在松開按鍵前一直卡在while循環(huán)中是一種簡單但有效的方法。在實際項目中可以考慮使用狀態(tài)機實現(xiàn)更友好的短按/長按區(qū)分但初版設(shè)計不必過度設(shè)計。5.4 LCD顯示與數(shù)據(jù)格式化LCD1602是本項目的本地顯示設(shè)備建議使用I2C轉(zhuǎn)接板版本這樣可以節(jié)省GPIO資源只需要兩根線就能完成顯示。I2C LCD1602的驅(qū)動通常只需要實現(xiàn)四個函數(shù)LCD1602_Init()初始化屏幕和I2CLCD1602_SetCursor(uint8_t col, uint8_t row)設(shè)置光標位置LCD1602_PrintString(char *str)打印字符串LCD1602_Clear()清屏。顯示溫濕度時要注意使用sprintf格式化浮點數(shù)在STM32平臺上建議使用“%.1f”格式但需要注意開啟串口浮點打印支持MicroLIB。為了減少浮點運算開銷也可以把溫度值乘以10存為整數(shù)顯示時手動加小數(shù)點。6. 系統(tǒng)調(diào)試與運行驗證6.1 硬件調(diào)試順序硬件調(diào)試不建議一次性把所有模塊都接上再上電否則出問題很難定位。推薦按以下順序逐步調(diào)試先燒錄一個“GPIO點燈”程序驗證最小系統(tǒng)板和開發(fā)環(huán)境正常單獨調(diào)試LCD1602顯示確認I2C地址和初始化流程沒問題單獨調(diào)試DHT11讀取溫濕度觀察串口打印值是否合理單獨調(diào)試MQ-2采樣對著傳感器哈氣或使用打火機氣體注意安全觀察ADC值變化調(diào)試繼電器控制確認GPIO高低電平與繼電器動作方向一致最后再接入ESP8266先把串口AT指令調(diào)試通再切換到STM32自動發(fā)送數(shù)據(jù)模式。6.2 串口打印觀察數(shù)據(jù)調(diào)試階段務(wù)必開啟一個串口打印通道通過USART1把關(guān)鍵數(shù)據(jù)打印到電腦的串口助手上。打印內(nèi)容建議包括溫濕度原始值A(chǔ)DC采樣值光照值當(dāng)前模式AT指令返回內(nèi)容。這樣做的最大好處是某一項數(shù)據(jù)異常時可以快速判斷是傳感器問題、接線問題還是通信問題而不是等到整機調(diào)試時一片混亂。6.3 云平臺查看數(shù)據(jù)在云平臺上當(dāng)設(shè)備正常上電并聯(lián)網(wǎng)后應(yīng)該能在“設(shè)備列表”中看到設(shè)備狀態(tài)變?yōu)椤霸诰€”并且實時設(shè)備日志中出現(xiàn)“發(fā)布消息”記錄。手機端如果使用阿里云官方的“IoT Studio”或第三方小程序還可以調(diào)用接口讀取數(shù)據(jù)。需要提醒的是第一次接入云平臺時最常見的報錯是“認證失敗”大概率是MQTT參數(shù)計算錯誤比如ProductKey或DeviceName拼寫多了空格或者設(shè)備密鑰填寫錯誤。排查時可以先不修改代碼直接在電腦上用MQTT客戶端軟件如MQTTX測試確認連接參數(shù)無誤后再去修改單片機程序。7. 常見問題與排查思路在開發(fā)這類單片機畢業(yè)設(shè)計時大家最容易踩到的問題集中在傳感器讀取、WiFi通信和電源供電三個方面。下面整理了一個排查表方便遇到問題時快速定位。問題現(xiàn)象常見原因解決思路DHT11一直讀不到數(shù)據(jù)引腳接線錯誤或上拉電阻缺失使用萬用表測量數(shù)據(jù)線電壓確認接好必要時在數(shù)據(jù)線與VCC之間接一個4.7kΩ上拉電阻DHT11數(shù)據(jù)偶爾跳變讀取間隔太短或主循環(huán)有阻塞延時DHT11讀取間隔至少1秒讀取期間避免其他中斷干擾MQ-2采樣值始終是4095AO引腳沒接對或模塊上電預(yù)熱時間不足確認AO引腳連接預(yù)熱3~5分鐘后觀察MQ-2采樣值始終是0模塊供電電壓不足或模塊損壞獨立供電測試檢查ADC配置確認ADC通道對應(yīng)關(guān)系繼電器吸合瞬間單片機重啟繼電器線圈反向電動勢或供電不足使用光耦隔離繼電器模塊給繼電器單獨供電加強濾波電容繼電器一直無法吸合低電平觸發(fā)/高電平觸發(fā)邏輯寫反查看模塊絲印說明翻轉(zhuǎn)GPIO輸出電平測試ESP8266連接WiFi失敗SSID或密碼錯誤、模塊供電不足串口調(diào)試AT指令確認模塊返回WIFI CONNECTED及WIFI GOT IPESP8266接收不到MQTT數(shù)據(jù)訂閱主題錯誤或QoS不匹配使用MQTTX客戶端確認主題和QoS設(shè)置再回看單片機代碼云平臺設(shè)備顯示離線設(shè)備端主動斷開或網(wǎng)絡(luò)不穩(wěn)定檢查串口日志中MQTT連接是否成功考慮增加斷線重連機制LCD1602只顯示方塊I2C地址不正確或初始化失敗掃描I2C設(shè)備地址確認模塊地址是0x27還是0x3F系統(tǒng)剛上電時蜂鳴器亂響GPIO默認電平導(dǎo)致繼電器/蜂鳴器誤動作初始化時先將所有控制引腳設(shè)置為默認安全電平再初始化外設(shè)程序燒錄失敗ST-Link驅(qū)動問題或BOOT0跳線狀態(tài)不對確認驅(qū)動和接線必要時按住復(fù)位鍵燒錄以上項目中需要特別注意的是電源問題。ESP8266啟動瞬間電流很大如果直接從STM32最小系統(tǒng)板的3.3V引腳供電很容易出現(xiàn)電壓跌落、模塊復(fù)位、WiFi連接失敗等問題。正確的做法是使用獨立的3.3V穩(wěn)壓模塊或使用5V供電把ESP8266的VCC和GND單獨接在電源輸出端。8. 最佳實踐與工程建議8.1 模塊化編程規(guī)范在整個項目開發(fā)中模塊化編程不僅是為了代碼好看更是為了調(diào)試方便。每個硬件的驅(qū)動文件都應(yīng)該保留清晰的頭文件接口例如// 文件路徑Core/Inc/dht11.h #ifndef __DHT11_H #define __DHT11_H #include main.h uint8_t DHT11_Init(void); uint8_t DHT11_ReadData(float *temperature, float *humidity); #endif這樣在論文中寫軟件設(shè)計時可以直接說明“系統(tǒng)采用模塊化設(shè)計思想將傳感器驅(qū)動、控制邏輯、通信協(xié)議分離降低模塊間耦合度”這是答辯時比較加分的設(shè)計點。8.2 增加看門狗與斷線重連機制在演示過程中如果程序意外卡死或WiFi斷開系統(tǒng)會失去響應(yīng)。為了提高系統(tǒng)的魯棒性建議在工程中增加兩個機制IWDG獨立看門狗在主循環(huán)中不斷喂狗一旦程序卡死系統(tǒng)自動復(fù)位。ESP8266斷線重連每次上報數(shù)據(jù)后檢查模塊狀態(tài)如果返回錯誤則重新執(zhí)行MQTT連接流程。在STM32CubeMX中開啟IWDG比較簡單設(shè)置溢出時間例如為2秒主循環(huán)內(nèi)調(diào)用HAL_IWDG_Refresh()即可。8.3 數(shù)據(jù)上報格式與頻率優(yōu)化畢業(yè)設(shè)計演示時數(shù)據(jù)上報間隔建議設(shè)置為5秒以上不要每100ms就上報一次。這既符合實際智能家居的采集頻率又能避免觸發(fā)云平臺限流。數(shù)據(jù)格式建議統(tǒng)一為JSON方便后續(xù)擴展。最低成本的格式是{t:26.4,h:60.1,s:12,l:356}這樣字段短解析快但可讀性差。如果論文中強調(diào)易用性可以使用完整字段{temperature:26.4,humidity:60.1,smoke:12,light:356}8.4 強電安全與演示注意事項智能家居系統(tǒng)通常會控制220V交流設(shè)備這里必須遵守安全原則。在實驗演示階段建議使用小功率設(shè)備或LED燈板代替真實強電設(shè)備。如果確實需要演示真實風(fēng)扇或臺燈盡量使用帶有CCC認證的成品負載并且接線后要使用絕緣膠帶包裹端子。任何時刻都不要在帶電情況下插拔杜邦線不要使用劣質(zhì)排插連接大功率設(shè)備。論文和答辯時可以提“系統(tǒng)在實驗室環(huán)境下已驗證實際家庭部署需由專業(yè)人員操作”這是負責(zé)任的做法。8.5 論文與答辯材料準備畢業(yè)設(shè)計不只是做實物還要把設(shè)計過程沉淀成論文。建議開發(fā)過程中同步整理以下材料需求分析系統(tǒng)要解決什么問題用戶角色是什么方案對比為什么選擇STM32而不是51、ESP32為什么選擇MQTT而不是HTTP硬件設(shè)計圖標注每個傳感器的引腳連接軟件流程圖主流程、中斷流程、自動控制邏輯測試記錄不同環(huán)境條件下的測量數(shù)據(jù)表演示視頻把系統(tǒng)完整跑起來的視頻答辯時非常有用。在這些材料中測試記錄尤其重要。你可以在一個表格中記錄這樣的數(shù)據(jù)時間溫度(℃)濕度(%RH)煙霧ADC值光照(lux)系統(tǒng)動作10:0025.358.2320500無動作10:0531.255.0350460風(fēng)扇打開10:1028.456.71300420排風(fēng)扇打開蜂鳴器報警這樣的表格會讓評委覺得你的設(shè)計經(jīng)過了充分驗證不只是“能跑”。9. 總結(jié)與項目交付建議到這里整個物聯(lián)網(wǎng)智能家居監(jiān)測控制系統(tǒng)的設(shè)計思路、硬件選型、軟件框架、代碼實現(xiàn)、調(diào)試方法和常見問題都梳理得比較完整了。這類項目的核心收獲不只是“做了一個東西”而是通過一個完整鏈路把單片機、傳感器、無線通信和云平臺串了起來這也是很多公司物聯(lián)網(wǎng)開發(fā)崗位日常工作內(nèi)容的縮小版。如果是在做畢業(yè)設(shè)計我建議最后幾周把重心放在三件事上第一把系統(tǒng)代碼整理得干凈一點尤其是main.c不要堆得太亂。即使項目功能和別人類似清晰的代碼結(jié)構(gòu)和注釋會讓評分觀感好很多。第二把系統(tǒng)測試數(shù)據(jù)補全最好分“白天/夜間”“無煙/有煙”“低溫/高溫”多組場景每組都記錄傳感器數(shù)據(jù)和執(zhí)行結(jié)果。這部分內(nèi)容在論文里很有說服力。第三做一份可靠的產(chǎn)品演示流程。實際操作時先用強光手電照光照傳感器產(chǎn)生光照變化再用手靠近DHT11呵氣觀察溫濕度變化最后使用打火機氣體不要點燃靠近MQ-2觀察報警和排風(fēng)扇動作。這樣一次演示基本能把所有功能都展示出來。如果你在按照這套方案搭建的過程中遇到其他問題比如MQTT連接不上、DHT11時序不穩(wěn)定、LCD顯示亂碼等歡迎在評論區(qū)把報錯現(xiàn)象和接線方式發(fā)出來我可以根據(jù)反饋再整理更細的調(diào)試筆記。也可以把這篇文章收藏備用等動手接線的時候再來對照檢查。祝大家項目順利調(diào)試一次通過。