開發(fā)實(shí)踐:從硬件選型到遠(yuǎn)程監(jiān)控)
簡介這是一份基于STM32的智能魚缸控制系統(tǒng)完整設(shè)計(jì)與實(shí)現(xiàn)資料適合具備一定電子和編程基礎(chǔ)、對(duì)嵌入式與物聯(lián)網(wǎng)感興趣的初學(xué)者、中級(jí)開發(fā)者及養(yǎng)魚愛好者。系統(tǒng)以STM32F103C8T6為控制核心集成溫度、水位、光照、濁度和pH檢測傳感器驅(qū)動(dòng)水泵、加熱棒、增氧泵、步進(jìn)電機(jī)等執(zhí)行器并借助ESP8266-12F模塊實(shí)現(xiàn)手機(jī)APP遠(yuǎn)程監(jiān)控與控制可有效降低傳統(tǒng)養(yǎng)魚管理難度并提升魚兒存活率。壓縮包內(nèi)共1個(gè)PDF文檔大小10.32MB內(nèi)容覆蓋系統(tǒng)總體方案、傳感器選型與電路設(shè)計(jì)、主控最小系統(tǒng)、各功能模塊軟硬件流程、實(shí)物焊接調(diào)試、常見問題排查及后續(xù)優(yōu)化建議目錄層級(jí)清晰從需求分析到軟硬件實(shí)現(xiàn)均有詳細(xì)說明還包含材料清單、原理圖與程序源碼的文字描述很適合作為課程設(shè)計(jì)或畢業(yè)設(shè)計(jì)的參考范例。該資源已有203人學(xué)習(xí)可作為快速上手STM32綜合項(xiàng)目并理解物聯(lián)網(wǎng)架構(gòu)的實(shí)用參考。 我養(yǎng)魚養(yǎng)了差不多五年。從30cm小缸一路折騰到60cm草缸中間死過不少魚也總結(jié)出一條鐵律觀賞魚出問題的原因里水溫波動(dòng)、喂食不規(guī)律、水質(zhì)惡化占了八成以上。后來工作忙經(jīng)常要出差每次出門都提心吊膽——加熱棒會(huì)不會(huì)失控把魚煮熟自動(dòng)喂食器卡了沒有水里的溶質(zhì)濃度是不是又飆升了于是萌生了一個(gè)想法干脆自己動(dòng)手做一套基于STM32的智能魚缸控制系統(tǒng)把這些“看不見的風(fēng)險(xiǎn)”變成可監(jiān)測、可控制、可遠(yuǎn)程告警的明確信號(hào)。這套系統(tǒng)我前前后后做了兩版。第一版用Arduino功能能跑通但穩(wěn)定性一般第二版換到STM32F103C8T6重新梳理了硬件電路和軟件架構(gòu)連續(xù)運(yùn)行至今沒出過大問題。這篇文章把第二版完整的設(shè)計(jì)思路、硬件選型、軟件實(shí)現(xiàn)和調(diào)試過程里踩過的坑都整理出來。如果你正在準(zhǔn)備類似的畢業(yè)設(shè)計(jì)或者想給家里的魚缸加一套智能控制這篇文章應(yīng)該能幫你少走很多彎路。1. 需求拆解一臺(tái)魚缸真正需要哪些“智能”1.1 從養(yǎng)魚痛點(diǎn)倒推功能需求先說結(jié)論智能魚缸不是功能越多越好而是每個(gè)功能都能解決一個(gè)真實(shí)痛點(diǎn)。我在規(guī)劃前把自己養(yǎng)魚遇到的場景列了一遍水溫魚是變溫動(dòng)物短時(shí)間內(nèi)溫差超過3℃就可能生病。加熱棒雖然有自帶溫控但壞了根本不知道夏天水溫過高也沒人發(fā)現(xiàn)。喂食上班族早上趕時(shí)間容易忘周末一不留神又喂太多出差幾天更是沒人管。水質(zhì)水渾了換水換完又渾沒有一個(gè)量化的參考數(shù)據(jù)。燈光草缸需要每天定時(shí)開燈6到8小時(shí)手動(dòng)開關(guān)很難長期堅(jiān)持。人在外地以上問題疊加到一起你只能干著急。圍繞這些痛點(diǎn)第一版功能清單確定為DS18B20實(shí)時(shí)采集水溫并控制加熱棒繼電器實(shí)現(xiàn)自動(dòng)恒溫浮球開關(guān)檢測低水位缺水時(shí)聲光報(bào)警并強(qiáng)制關(guān)閉加熱棒防止干燒TDS傳感器監(jiān)測水中可溶性固體總量作為換水時(shí)機(jī)的參考舵機(jī)驅(qū)動(dòng)儲(chǔ)料倉實(shí)現(xiàn)每天定時(shí)定量喂食MOS管控制水草燈按時(shí)開關(guān)OLED本地顯示實(shí)時(shí)狀態(tài)ESP8266連接Wi-Fi實(shí)現(xiàn)遠(yuǎn)程查看數(shù)據(jù)和下發(fā)控制指令。這個(gè)組合不多不少每一個(gè)功能都有對(duì)應(yīng)的使用場景。畢業(yè)設(shè)計(jì)答辯時(shí)老師問“為什么做這個(gè)功能”你也能講出背后的真實(shí)需求。1.2 哪些功能建議砍掉做項(xiàng)目最容易犯的毛病是堆功能。我規(guī)劃時(shí)明確劃掉了幾項(xiàng)PH傳感器首先被砍。工業(yè)級(jí)PH探頭校準(zhǔn)繁瑣買現(xiàn)成模塊的電極壽命又短淡水觀賞魚更需要的其實(shí)是規(guī)律換水而不是盯著PH數(shù)字焦慮。自動(dòng)換水也暫時(shí)不做這需要電磁閥、雙水位傳感器、復(fù)雜的加水邏輯漏水風(fēng)險(xiǎn)大對(duì)第一版系統(tǒng)來說得不償失。視頻監(jiān)控同理ESP8266的帶寬不夠要清晰畫面不如直接買幾十塊錢的網(wǎng)絡(luò)攝像頭??车暨@三項(xiàng)之后系統(tǒng)復(fù)雜度大幅下降穩(wěn)定性和可維護(hù)性反而上來了。這個(gè)取舍本身就代表一種設(shè)計(jì)能力——你是在做一套長期運(yùn)行的家用設(shè)備而不是在參加“誰集成模塊多誰贏”的比賽。2. 硬件選型與電路連接搭一套少出問題的底子2.1 傳感器與執(zhí)行器選型對(duì)照硬件選型的原則只有三個(gè)字易獲取、便宜、資料多。這決定了后期調(diào)試效率。下面是我逐個(gè)對(duì)比后定下來的方案。器件我選的型號(hào)備選方案選擇理由MCUSTM32F103C8T6STM32F401、GD3272MHz主頻、64KB Flash、20KB SRAM資料全網(wǎng)最多溫度傳感器DS18B20防水探頭NTC 10KADC單總線協(xié)議接線只需3根教學(xué)和實(shí)用價(jià)值兼具水位檢測塑料浮球開關(guān)電極式探頭結(jié)構(gòu)簡單不受水垢和離子濃度影響水質(zhì)參考TDS模塊不測只能測溶質(zhì)總量但作為換水提示完全夠用執(zhí)行開關(guān)繼電器模塊MOS管加熱棒220V必須繼電器隔離LED燈帶用MOS管喂食執(zhí)行MG90S舵機(jī)28BYJ步進(jìn)電機(jī)舵機(jī)自帶位置反饋控制出料角度更直接顯示0.96寸OLED SSD1306LCD1602I2C接口只占兩根線顯示內(nèi)容豐富通信ESP8266-01sHC-05藍(lán)牙Wi-Fi可以遠(yuǎn)程控制可玩性高得多關(guān)于MCU多說一句F103C8T6雖然老但性能和接口數(shù)量對(duì)這個(gè)項(xiàng)目綽綽有余。市面上的核心板只要十幾塊錢自帶最小系統(tǒng)和USB轉(zhuǎn)串口非常適合第一版原型驗(yàn)證。真要做到成品批量再換F103RCT6這種更大封裝的型號(hào)也不遲。2.2 電源與驅(qū)動(dòng)的幾個(gè)關(guān)鍵點(diǎn)整套系統(tǒng)的供電分配是新手最容易翻車的地方。我的方案是外部12V/2A開關(guān)電源統(tǒng)一供電后級(jí)分三路12V直接給水泵和LED燈帶12V經(jīng)AMS1117-3.3降壓給STM32、DS18B20、OLED加熱棒獨(dú)立走220V回路由繼電器控制與低壓部分完全隔離。實(shí)際測試發(fā)現(xiàn)ESP8266-01s連接Wi-Fi時(shí)的瞬時(shí)電流可以達(dá)到300mAAMS1117在12V轉(zhuǎn)3.3V的大壓差下發(fā)熱很明顯瞬間掉壓會(huì)導(dǎo)致MCU復(fù)位。后來我把ESP8266從3.3V主回路拆出去單獨(dú)用一塊AMS1117從5V電源降壓供電掉線問題基本消失。繼電器控制加熱棒是整套系統(tǒng)里唯一涉及強(qiáng)電的部分必須做嚴(yán)格隔離。我買的繼電器模塊自帶光耦控制信號(hào)和220V部分在物理上分離。水泵是直流電機(jī)屬于感性負(fù)載需要在電機(jī)兩端并聯(lián)一個(gè)1N4007二極管來吸收反向電動(dòng)勢(shì)否則每次啟停都會(huì)產(chǎn)生尖峰干擾MCU。水位浮球接線要特別注意常開和常閉觸點(diǎn)。我第一次就接反了低水位成了高水位折騰了很久才發(fā)現(xiàn)。正確做法是浮球下沉?xí)r接通的觸點(diǎn)用來做低水位報(bào)警上浮時(shí)接通的觸點(diǎn)留給高水位提示。接線前用萬用表量一下浮球不同位置的導(dǎo)通狀態(tài)比接到板上再猜省時(shí)間得多。2.3 總體連接結(jié)構(gòu)一句話說清STM32F103C8T6的PA0接TDS模擬輸出PB1接DS18B20數(shù)據(jù)腳PB10/PB11接OLED的I2CPA2/PA3接ESP8266串口PA4至PA7分別控制繼電器和MOS通斷PA8輸出舵機(jī)PWMPB12接浮球開關(guān)輸入PB13接蜂鳴器。建議第一版直接用核心板加杜邦線搭建不要急著畫PCB。等所有功能驗(yàn)證完畢、邏輯確認(rèn)無誤再畫一塊集成板把飛線問題一次性解決。我就是先洞洞板飛線跑通確認(rèn)整體方案后才打板省去了反復(fù)改板的麻煩。3. 軟件架構(gòu)裸機(jī)任務(wù)調(diào)度、狀態(tài)機(jī)與通信協(xié)議3.1 工程搭建與代碼目錄規(guī)劃軟件部分我用STM32CubeMX生成HAL庫工程配置要點(diǎn)時(shí)鐘切換到外部8MHz晶振保留SWD調(diào)試口USART1連接ESP8266波特率115200USART2接調(diào)試日志I2C1接OLEDTIM2的CH1輸出50Hz PWM控制舵機(jī)ADC1的IN0采集TDS電壓若干GPIO控制繼電器、MOS管、浮球輸入和蜂鳴器。代碼目錄我習(xí)慣分成四塊BSP放板級(jí)驅(qū)動(dòng)APP放應(yīng)用邏輯COMM放通信協(xié)議SYSTEM放延時(shí)和任務(wù)調(diào)度。這個(gè)分層看起來簡單但調(diào)試時(shí)能幫你快速定位問題。比如水溫不對(duì)先去查BSP里的DS18B20讀取函數(shù)而不是在幾百行的邏輯代碼里找線索。3.2 主循環(huán)時(shí)間片調(diào)度不追RTOS也夠用這套系統(tǒng)要同時(shí)處理溫度控制、喂食定時(shí)、按鍵掃描、OLED刷新、ESP8266收發(fā)任務(wù)數(shù)量雖然不少但都不重沒必要引入FreeRTOS。我用一個(gè)1ms軟件定時(shí)器作為時(shí)基維護(hù)了一個(gè)簡單的任務(wù)表。typedef struct { uint32_t period; // 執(zhí)行周期單位ms uint32_t lastRun; // 上次執(zhí)行時(shí)間 void (*func)(void); // 任務(wù)函數(shù) } TaskItem; TaskItem tasks[] { {10, 0, KeyScan}, {100, 0, UpdateDisplay}, {500, 0, CheckWaterLevel}, {1000, 0, ReadTemperature}, {2000, 0, CheckHeater}, {60000, 0, FeedTask}, };主循環(huán)里就是遍歷任務(wù)表判斷當(dāng)前時(shí)間減上次運(yùn)行時(shí)間是否大于等于周期滿足則執(zhí)行。這是裸機(jī)版的定時(shí)任務(wù)機(jī)制代碼量少邏輯直觀也不會(huì)因?yàn)槟硞€(gè)任務(wù)阻塞影響全局。要注意DS18B20一次溫度轉(zhuǎn)換需要750ms12位分辨率如果直接放在1000ms任務(wù)里調(diào)用阻塞式讀取會(huì)把整個(gè)調(diào)度拖死。我的做法是把讀溫度流程改成狀態(tài)機(jī)發(fā)起轉(zhuǎn)換、等待完成、讀取數(shù)據(jù)三步拆開由1000ms任務(wù)定期驅(qū)動(dòng)。這樣既不阻塞主循環(huán)溫度值也穩(wěn)定。3.3 溫度滯回控制與喂食狀態(tài)機(jī)加熱棒控制的坑在于繼電器不能頻繁通斷。如果寫成“低于25℃開高于25℃關(guān)”溫度在目標(biāo)值附近抖動(dòng)時(shí)會(huì)反復(fù)吸合繼電器壽命迅速縮水火花干擾也會(huì)影響其他模塊。滯回控制能解決這個(gè)問題目標(biāo)25℃回差0.5℃那么低于24.5℃開啟加熱高于25.5℃關(guān)閉加熱。if (temp target - 0.5f) heaterOn(); else if (temp target 0.5f) heaterOff();中間區(qū)間保持上一次狀態(tài)不動(dòng)。滯回的本質(zhì)是把“要不要?jiǎng)幼鳌钡呐袛喾秶蟊苊庠谂R界點(diǎn)反復(fù)橫跳。這個(gè)思路不僅適用于加熱棒風(fēng)扇散熱、水泵啟停這些開關(guān)控制都能復(fù)用。喂食模塊我設(shè)計(jì)成一個(gè)小狀態(tài)機(jī)。正常處于IDLE定時(shí)時(shí)間一到進(jìn)入ROTATE舵機(jī)從初始角度轉(zhuǎn)到出料角度保持1秒后回到初始角度隨后進(jìn)入LOCK5分鐘內(nèi)不響應(yīng)任何喂食指令防止手動(dòng)誤觸連續(xù)投喂。狀態(tài)機(jī)全部用switch-case實(shí)現(xiàn)狀態(tài)遷移只依賴時(shí)間和角度條件邏輯非常直觀。3.4 與ESP8266的通信協(xié)議ESP8266在我的方案里定位是“透傳網(wǎng)關(guān)”。它連上路由器后定期向上位服務(wù)器上報(bào)數(shù)據(jù)收到下行指令則通過串口轉(zhuǎn)發(fā)給STM32。STM32這邊只需要維護(hù)一套輕量協(xié)議就夠了。協(xié)議幀格式定義為幀頭(0xAA 0x55) 長度(1字節(jié)) 命令字(1字節(jié)) 數(shù)據(jù)區(qū)(N字節(jié)) 累加和校驗(yàn)(1字節(jié)) 幀尾(0x0D 0x0A)上行命令字0x01表示上報(bào)狀態(tài)數(shù)據(jù)區(qū)固定為溫度、水位、TDS、加熱狀態(tài)、喂食狀態(tài)共5字節(jié)下行命令字0x11表示控制加熱數(shù)據(jù)區(qū)為開關(guān)。STM32串口按幀解析校驗(yàn)通過才執(zhí)行執(zhí)行后回發(fā)ACK。這段自定義協(xié)議不復(fù)雜但在答辯時(shí)能清楚展示你對(duì)通信格式、校驗(yàn)機(jī)制的理解算是一個(gè)不錯(cuò)的亮點(diǎn)。4. 調(diào)試實(shí)錄五個(gè)最值得記錄的坑與排查過程4.1 DS18B20讀回85℃不是傳感器壞了第一版上電后OLED一直顯示85℃我第一反應(yīng)是探頭壞了換了一只新的還是一樣。隨后量VCC和GND電壓正常拿邏輯分析儀抓單總線波形發(fā)現(xiàn)芯片根本沒有完成ROM指令握手。排查后發(fā)現(xiàn)是上拉電阻和線長的問題。DS18B20數(shù)據(jù)線雖然開發(fā)板上有內(nèi)建上拉但接了一根30cm的延長線后總線電容偏大信號(hào)上升沿太慢單片機(jī)總是復(fù)位識(shí)別失敗。解決辦法是在數(shù)據(jù)線和3.3V之間外接一個(gè)4.7kΩ上拉電阻把探頭延長線縮短到20cm內(nèi)問題立刻消失。DS18B20的單總線協(xié)議對(duì)線長和上拉非常敏感這是我每次做項(xiàng)目都會(huì)重新踩一遍的坑這次特意記錄了下來。4.2 繼電器一吸合MCU立刻重啟第一版調(diào)試時(shí)出現(xiàn)一個(gè)恐怖現(xiàn)象溫度低于下限繼電器吸合OLED閃一下熄滅串口日志顯示MCU復(fù)位。用示波器觀察3.3V電源軌發(fā)現(xiàn)繼電器吸合瞬間出現(xiàn)接近1V的跌落尖峰。12V電源被繼電器線圈的瞬態(tài)沖擊拖垮殃及后面的穩(wěn)壓器。我做了三處修改12V輸入端加470uF電解電容和0.1uF陶瓷電容吸收瞬態(tài)繼電器控制信號(hào)與MCU之間用光耦隔離控制線遠(yuǎn)離傳感器線水泵電機(jī)兩端并聯(lián)續(xù)流二極管。三管齊下后無論怎么切換負(fù)載MCU供電都穩(wěn)定如初。4.3 ESP8266掉線根源在3.3V供電能力ESP8266連上Wi-Fi后運(yùn)行幾分鐘到幾小時(shí)不等串口和TCP數(shù)據(jù)就會(huì)丟失有時(shí)直接重啟。我一開始懷疑是路由器信號(hào)問題但換位置后沒改善。后來用萬用表盯住模塊3.3V供電端發(fā)現(xiàn)在重啟瞬間電壓掉到2.6V以下。原因就是AMS1117-3.3在大壓差場景下帶不動(dòng)ESP8266的脈沖電流。解決方式前面提過改成5V獨(dú)立電源給ESP8266供電CH_PD使能腳接3.3V拉高串口信號(hào)串聯(lián)1kΩ電阻限流。改完后連續(xù)跑了72小時(shí)沒掉過線屬于成本極低但回報(bào)極高的一個(gè)改動(dòng)。4.4 舵機(jī)抖動(dòng)喂食量忽多忽少M(fèi)G90S每次啟動(dòng)時(shí)抖兩下出料角度不穩(wěn)定。排查發(fā)現(xiàn)兩個(gè)疊加原因舵機(jī)供電取自控制板的3.3V而MG90S堵轉(zhuǎn)電流能到700mA以上3.3V供電力矩不足位置反饋?zhàn)匀话l(fā)散另外PWM參數(shù)不對(duì)MG90S要求50Hz周期也就是20ms脈寬0.5ms到2.5ms對(duì)應(yīng)0°到180°。把舵機(jī)供電改成5V獨(dú)立回路用TIM2按20ms周期輸出正確占空比后抖動(dòng)消失出料角度每次都準(zhǔn)。4.5 斷電后喂食時(shí)間全亂家里一次臨時(shí)停電半小時(shí)RTC時(shí)間歸零恢復(fù)供電后喂食任務(wù)在00:00立刻執(zhí)行了一次魚被投喂了兩遍。STM32內(nèi)部RTC依賴VBAT備份電池我第一版沒接斷電即丟。解決有兩個(gè)方案初級(jí)方案是STM32上電后主動(dòng)向ESP8266請(qǐng)求一次網(wǎng)絡(luò)時(shí)間校準(zhǔn)RTC更可靠的方案是外接DS3231高精度時(shí)鐘模塊也就幾塊錢斷電后時(shí)間照樣準(zhǔn)。對(duì)魚缸這種需要長期運(yùn)行的設(shè)備強(qiáng)烈建議直接上DS3231。5. 實(shí)測數(shù)據(jù)、成本清單與后續(xù)還能做什么5.1 連續(xù)運(yùn)行30天的關(guān)鍵數(shù)據(jù)系統(tǒng)搭好后我在60cm淡水草缸上連續(xù)運(yùn)行了30天記錄了幾個(gè)關(guān)鍵指標(biāo)。指標(biāo)實(shí)測數(shù)據(jù)說明溫度控制精度目標(biāo)25.0℃實(shí)測24.6~25.4℃滯回控制效果穩(wěn)定水位報(bào)警響應(yīng)浮球觸發(fā)后500ms內(nèi)蜂鳴器響帶軟件濾波防誤報(bào)喂食準(zhǔn)確性30天共投喂90次每天準(zhǔn)點(diǎn)時(shí)間基準(zhǔn)來自DS3231除加熱棒外整機(jī)功耗水泵、燈帶、控制電路約0.2度/天單片機(jī)整體功耗較低遠(yuǎn)程控制延遲MQTT指令1秒內(nèi)到達(dá)ESP8266家庭Wi-Fi環(huán)境下從數(shù)據(jù)看這套方案對(duì)中小型魚缸完全夠用。溫度波動(dòng)范圍比普通加熱棒自帶溫控更小原因在于加熱棒內(nèi)置溫控精度通常只有±1.5℃左右而DS18B20配合滯回算法能把波動(dòng)壓得更窄。5.2 整機(jī)成本逐項(xiàng)拆解按量產(chǎn)一版集成PCB的實(shí)際花費(fèi)不算人工參考價(jià)格如下器件規(guī)格參考價(jià)格STM32F103C8T6最小系統(tǒng)板藍(lán)板帶USB轉(zhuǎn)串口12元DS18B20防水探頭3線1米5元0.96寸OLED SSD1306I2C 4針9元TDS水質(zhì)檢測模塊探頭加調(diào)理電路12元塑料浮球開關(guān)常開型2元MG90S舵機(jī)金屬齒輪9g9元ESP8266-01s帶轉(zhuǎn)接板10元4路繼電器模塊帶光耦隔離6元AMS1117-3.3模塊兩個(gè)2元12V/2A電源適配器品牌電源15元PCB打樣10x10cm五片25元接線端子、排針、線材雜項(xiàng)20元合計(jì)大約127元加上加熱棒、水泵和LED燈帶這三樣魚缸已有或另購的配置整機(jī)能控制在200元出頭。對(duì)比市面上成品智能魚缸設(shè)備動(dòng)輒五六百的價(jià)格這個(gè)成本很有競爭力而且所有控制邏輯都在自己手里想改哪里改哪里。5.3 我認(rèn)為值得繼續(xù)做的三個(gè)擴(kuò)展這套系統(tǒng)做完以后我梳理了三個(gè)后續(xù)方向。第一把TDS數(shù)據(jù)接進(jìn)云端在手機(jī)上畫趨勢(shì)曲線。TDS值不能直接代表水質(zhì)好壞但趨勢(shì)很有參考價(jià)值。如果換水后一周內(nèi)TDS持續(xù)爬升說明過濾系統(tǒng)負(fù)荷偏大該洗濾筒了。第二加水泵轉(zhuǎn)速閉環(huán)。用驅(qū)動(dòng)芯片通過PID把水流控制在設(shè)定值對(duì)草缸的CO2溶解率和過濾效果會(huì)有明顯改善。第三把喂食器升級(jí)成雙倉結(jié)構(gòu)一個(gè)倉放顆粒飼料一個(gè)倉放液肥通過按鍵或遠(yuǎn)程分別控制。最后再分享一個(gè)我養(yǎng)成的習(xí)慣整個(gè)調(diào)試過程最不值得省的就是串口日志。日志從第一版就一直保留每次出異常翻日志比重新測電路快得多。這個(gè)項(xiàng)目做到現(xiàn)在已經(jīng)不只是給魚缸用更是一個(gè)練手的好平臺(tái)。動(dòng)手做起來你會(huì)發(fā)現(xiàn)很多東西比你想象的復(fù)雜但也比你想象的值得。本文還有配套的精品資源點(diǎn)擊獲取