戰(zhàn):非接觸式水位傳感器HS-S37A與OLED顯示系統(tǒng))
作為一個(gè)在嵌入式圈子里泡了快十年的老開(kāi)發(fā)我其實(shí)挺少專門為一顆水位傳感器寫一篇完整實(shí)驗(yàn)筆記的。但 HS-S37A 這顆模塊有點(diǎn)特別它屬于非接觸式電容水位檢測(cè)和傳統(tǒng)把兩根電極泡進(jìn)水里的浮子式、電阻式傳感器完全兩碼事接線只有兩三根卻能直接掛在 STM32 上配合 OLED 做出一套看得見(jiàn)、摸得著的顯示系統(tǒng)。這篇文章就把我實(shí)際踩過(guò)的坑、調(diào)過(guò)的參數(shù)和最終的代碼邏輯全部攤開(kāi)講適合剛學(xué)完 STM32 基礎(chǔ)外設(shè)、想搞一個(gè)綜合小項(xiàng)目的朋友直接照著做。1. 為什么用 HS-S37A 做這個(gè)水位檢測(cè)實(shí)驗(yàn)1.1 這個(gè)實(shí)驗(yàn)解決什么問(wèn)題先說(shuō)清楚 HS-S37A 在項(xiàng)目里的定位它不是一個(gè)用來(lái)精確測(cè)量“水位高度”的高精度液位計(jì)而是一個(gè)用來(lái)判斷“有沒(méi)有水”的開(kāi)關(guān)型傳感器部分型號(hào)還會(huì)額外輸出一路模擬電壓用來(lái)粗略估算水量多少。它的核心優(yōu)勢(shì)是非接觸式傳感器探頭貼在塑料水箱、水管或玻璃容器外壁就能檢測(cè)到內(nèi)部液體狀態(tài)不直接接觸水體所以不存在電極腐蝕、污染液體、結(jié)垢短路之類的問(wèn)題在食品、醫(yī)療、凈水器這類場(chǎng)合特別吃香。做這個(gè)實(shí)驗(yàn)的意義不只是“點(diǎn)亮一個(gè) OLED”而是把一條完整的信號(hào)鏈路跑通物理量變化先被傳感器轉(zhuǎn)換成電信號(hào)STM32 再通過(guò) ADC 和 GPIO 讀進(jìn)來(lái)最后經(jīng)過(guò)邏輯處理和顯示驅(qū)動(dòng)把結(jié)果呈現(xiàn)在屏幕上。這一套流程幾乎覆蓋了 STM32 開(kāi)發(fā)中最常用的三大外設(shè)GPIO、ADC、I2C做完之后你對(duì)多外設(shè)協(xié)同工作的理解會(huì)明顯上一個(gè)大臺(tái)階。我對(duì)這套組合的評(píng)價(jià)是難度適中、成本極低、出效果快特別適合作為學(xué)習(xí) HAL 庫(kù)開(kāi)發(fā)的里程碑項(xiàng)目。1.2 器件選型背后的邏輯傳感器選 HS-S37A主要是看中它的通用性和上手成本。市面上水位傳感器五花八門電極式的雖然便宜但要在水里通電用久了陽(yáng)極氧化特別明顯浮子式的機(jī)械結(jié)構(gòu)容易卡死超聲波和激光式的精度倒是高但價(jià)格和調(diào)試復(fù)雜度都上去了。HS-S37A 屬于電容式非接觸檢測(cè)邏輯輸出直接給高低電平MCU 拿來(lái)做“有水/無(wú)水”判斷幾乎零成本。部分模塊還帶一個(gè) AO 模擬輸出腳能讓我在實(shí)驗(yàn)里順帶演示 ADC 采集所以選它做教學(xué)特別合適。主控選 STM32F103C8T6 也是多年的老朋友了。這顆芯片號(hào)稱電子 DIY 界的“萬(wàn)金油”72MHz 主頻自帶 ADC、I2C、USART、SPI網(wǎng)上參考資料多得看不完。OLED 則選了最常見(jiàn)的 0.96 寸 SSD1306 驅(qū)動(dòng)模塊I2C 版本只要兩根信號(hào)線相比 SPI 版本少接 4 根線代碼資源也最豐富。物聯(lián)網(wǎng)項(xiàng)目里經(jīng)常需要顯示設(shè)備狀態(tài)這個(gè)小屏幾乎成了調(diào)試必備件。整套硬件成本壓到 30 元以內(nèi)完全沒(méi)問(wèn)題實(shí)驗(yàn)失敗頂多損失幾根杜邦線。2. 硬件準(zhǔn)備與接線原理詳解2.1 完整硬件清單這里把我實(shí)際用的配置完整列出來(lái)照著買基本不會(huì)踩坑器件型號(hào)/規(guī)格數(shù)量備注主控板STM32F103C8T6 最小系統(tǒng)板1藍(lán)丸板即可水位傳感器HS-S37A 非接觸式模塊1帶 DO 和 AO 輸出OLED0.96 寸 SSD1306 I2C1四線制 I2C 版本調(diào)試器ST-Link V21SWD 方式下載杜邦線公對(duì)公、公對(duì)母若干線盡量短避免干擾USB 轉(zhuǎn) TTLCH340 模塊1備用串口打印調(diào)試實(shí)驗(yàn)被測(cè)物我建議準(zhǔn)備一個(gè)空塑料水瓶和一滿瓶水或者一段透明塑料軟管加上注射器。注意HS-S37A 檢測(cè)的是“介質(zhì)變化引起的電容變化”金屬容器基本測(cè)不了這一點(diǎn)在第五章實(shí)測(cè)里我會(huì)再詳細(xì)講。2.2 HS-S37A 引腳定義與工作原理HS-S37A 模塊雖然廠家很多但引腳定義基本統(tǒng)一常見(jiàn)的有 3 個(gè)或 4 個(gè)引腳VCC、GND、DO、AO。其中 DO 是數(shù)字量輸出模塊內(nèi)部已經(jīng)集成了閾值比較電路探頭附近沒(méi)有水時(shí)輸出一種電平有水時(shí)輸出另一種電平單片機(jī)只需要讀 GPIO 就行。AO 是模擬量輸出會(huì)隨探頭附近的介質(zhì)變化產(chǎn)生電壓波動(dòng)適合接 ADC 做粗略的水量判斷。它的內(nèi)部原理說(shuō)起來(lái)其實(shí)不復(fù)雜模塊內(nèi)部有一個(gè)高頻振蕩電路探頭部分相當(dāng)于一個(gè)電容極板當(dāng)非金屬容器中的水位上升時(shí)探頭附近的等效介電常數(shù)會(huì)改變從而導(dǎo)致振蕩頻率或幅度變化模塊檢測(cè)到變化后再通過(guò)比較器或邏輯電路輸出對(duì)應(yīng)的電平信號(hào)。你可以把它想象成“用手隔著衣服摸口袋里的鑰匙”不需要真的伸進(jìn)去就能感知到里面有沒(méi)有東西。接線表我直接給出來(lái)HS-S37A 引腳引腳功能接 STM32備注VCC電源正3.3V先確認(rèn)模塊支持電壓很多板子兼容 3.3V/5VGND電源負(fù)GND與 STM32 共地DO數(shù)字輸出PA2讀 GPIO 電平即可AO模擬輸出PA0接 ADC 輸入不用可懸空這里特別提醒不同賣家出貨的模塊絲印順序可能不一樣有的標(biāo)注是 VCC、GND、DO、AO有的卻是 VCC、DO、AO、GND插線前一定仔細(xì)看模塊上的印刷標(biāo)識(shí)。我見(jiàn)過(guò)不止一次把電源和信號(hào)接反導(dǎo)致板子冒煙的案例別問(wèn)我怎么知道的。2.3 OLED 接線與 I2C 地址判斷OLED 這邊就簡(jiǎn)單多了四個(gè)引腳VCC、GND、SCL、SDA。我用的是 STM32 的 I2C1 外設(shè)對(duì)應(yīng)的引腳為 PB6SCL和 PB7SDA直接把 OLED 的 SCL 接到 PB6SDA 接到 PB7VCC 接 3.3VGND 共地。關(guān)于 I2C 地址這里有個(gè)新手最容易懵的點(diǎn)SSD1306 的 7 位地址常見(jiàn)是 0x3C但很多庫(kù)或代碼習(xí)慣把地址寫成 8 位的 0x78。0x3C 左移一位就是 0x78本質(zhì)上是同一個(gè)地址的不同寫法。還有部分模塊把 I2C 地址選擇電阻做了跳線切到另一個(gè)位置就變成 0x7A/0x3D。我第一次實(shí)驗(yàn)白屏查了半天最后發(fā)現(xiàn)是模塊背面的 0Ω 電阻焊錯(cuò)位導(dǎo)致地址是 0x7A。所以在跑通訊之前先用 I2C 掃描函數(shù)確認(rèn)一下設(shè)備真實(shí)地址能省掉大量冤枉時(shí)間。另外 F103 的 PB6/PB7 在 I2C 模式下需要上拉電阻到 3.3V。很多開(kāi)發(fā)板上已經(jīng)自帶上拉電阻但便宜的最小系統(tǒng)板不一定有如果 I2C 一直通信失敗別忘了外接兩個(gè) 4.7kΩ 上拉電阻試試。3. STM32 工程配置CubeMX 里把外設(shè)全點(diǎn)亮3.1 建立工程的基礎(chǔ)配置這個(gè)實(shí)驗(yàn)我用的是 STM32CubeMX 加 Keil MDK 的組合HAL 庫(kù)版本相比于標(biāo)準(zhǔn)外設(shè)庫(kù)CubeMX 的圖形化配置能省掉大量初始化代碼的時(shí)間尤其適合管腳多、外設(shè)多的情況。第一步打開(kāi) CubeMX新建工程選擇芯片 STM32F103C8Tx然后進(jìn)行以下基礎(chǔ)配置配置項(xiàng)設(shè)置值說(shuō)明SYS → DebugSerial Wire保留 SWD 調(diào)試否則下載一次后可能就找不到芯片了RCC → HSECrystal/Ceramic Resonator使用外部 8MHz 晶振Clock ConfigurationSYSCLK 72MHz通過(guò) PLL 倍頻到最高主頻時(shí)鐘樹(shù)配置是很多人容易忽略的細(xì)節(jié)。默認(rèn)配置下 F103 的 SYSCLK 只有 8MHz如果不把 APB1 和 APB2 的分頻系數(shù)設(shè)置好后面 ADC 和 I2C 的工作時(shí)鐘可能達(dá)不到預(yù)期I2C 頻率計(jì)算也會(huì)跟著出問(wèn)題。CubeMX 里直接選擇 HSE 輸入 8MHzPLL 倍頻到 72MHz總線分配它會(huì)自動(dòng)處理我們只需要確認(rèn)最終 SYSCLK 顯示 72MHz 即可。3.2 ADC 配置的細(xì)節(jié)與參數(shù)說(shuō)明ADC 這里我是把 PA0 配置為 ADC1 的 IN0 通道用來(lái)讀取傳感器的模擬電壓輸出。在 CubeMX 的 Analog → ADC1 設(shè)置里把 IN0 勾選上然后打開(kāi)參數(shù)配置Resolution12 bits這是 F103 ADC 的默認(rèn)精度數(shù)值范圍 0~4095AlignmentRight alignment右對(duì)齊即可Continuous ConversionDisabled用單次轉(zhuǎn)換配合輪詢讀取Scan Conversion ModeDisabledSampling Time建議選 55.5 Cycles 或更長(zhǎng)我實(shí)際用 239.5 Cycles采樣時(shí)間這個(gè)參數(shù)值得多說(shuō)兩句。ADC 內(nèi)部等效模型是一個(gè)采樣電容在采樣階段需要從外部信號(hào)源抽取電流如果外部信號(hào)源的輸出阻抗比較高采樣時(shí)間太短會(huì)導(dǎo)致電容還沒(méi)充滿就開(kāi)始轉(zhuǎn)換讀出來(lái)的數(shù)值會(huì)偏小且跳動(dòng)劇烈。HS-S37A 的 AO 輸出本身就不是低阻抗的強(qiáng)驅(qū)動(dòng)輸出加上實(shí)驗(yàn)用的杜邦線又細(xì)又長(zhǎng)導(dǎo)線電阻和分布電容都會(huì)有影響把采樣時(shí)間拉長(zhǎng)可以明顯降低讀數(shù)抖動(dòng)。實(shí)際讀 ADC 的代碼就是我后面主循環(huán)里用的這種輪詢方式uint16_t read_adc_value(void) { uint16_t adc_raw 0; HAL_ADC_Start(hadc1); if (HAL_ADC_PollForConversion(hadc1, 10) HAL_OK) { adc_raw HAL_ADC_GetValue(hadc1); } HAL_ADC_Stop(hadc1); return adc_raw; }每次轉(zhuǎn)換完要主動(dòng)調(diào)用 HAL_ADC_Stop否則外設(shè)會(huì)一直處于使能狀態(tài)干擾后續(xù)的采集流程。這個(gè)習(xí)慣在寫多通道 ADC 時(shí)尤其重要。3.3 GPIO 數(shù)字輸入與去抖邏輯PA2 配置成 GPIO_Input用來(lái)連接 HS-S37A 的數(shù)字輸出 DO 腳。下拉方式我選擇的是上拉這樣傳感器沒(méi)有明確輸出時(shí) GPIO 也能保持在確定電平不至于懸空亂跳。具體在 CubeMX 里的配置是PA2 → GPIO_MODE_INPUTGPIO_Pull 選擇 Pull-up。但 GPIO 配置只是第一步真正需要花心思的是“去抖”。HS-S37A 的 DO 輸出在探頭貼近水管、水流沖擊或者周圍有振動(dòng)時(shí)會(huì)瞬間跳變?nèi)绻蛔鎏幚鞳LED 上的狀態(tài)就會(huì)一直在“有水/無(wú)水”之間閃爍看著特別難受。我的做法是連續(xù)采樣多次只有連續(xù) 5 次結(jié)果一致才更新?tīng)顟B(tài)uint8_t get_water_level_debounced(void) { uint8_t last_sample 0; uint8_t stable_count 0; uint8_t i; for (i 0; i 8; i) { uint8_t sample HAL_GPIO_ReadPin(HS_GPIO_Port, HS_GPIO_Pin); if (sample last_sample) { stable_count; } else { stable_count 0; last_sample sample; } HAL_Delay(1); } if (stable_count 5) { return last_sample; } return current_level; // 返回上一次的穩(wěn)定值 }4. OLED 顯示驅(qū)動(dòng)與水位可視化4.1 SSD1306 驅(qū)動(dòng)移植OLED 驅(qū)動(dòng)用的庫(kù)是網(wǎng)上流傳最廣的 SSD1306 HAL 版本這個(gè)庫(kù)在 GitHub 和各種博客里都能找到基本拿到手改一下 I2C 地址就能用。核心就是把初始化序列、清屏、畫點(diǎn)、畫矩形、顯示字符這些函數(shù)封裝好然后由 SSD1306_UpdateScreen 函數(shù)把顯存中的內(nèi)容一次性刷到屏幕上。這里有一個(gè)原則問(wèn)題先用軟件 I2C 跑通再換硬件 I2C還是直接上硬件 I2C我個(gè)人的實(shí)際經(jīng)驗(yàn)是新手建議先直接用硬件 I2C因?yàn)?CubeMX 已經(jīng)生成好了初始化代碼I2C 發(fā)送函數(shù)也封裝好了如果遇到一直不通的問(wèn)題再退回到模擬 I2C 來(lái)排查反而能更快確認(rèn)是外設(shè)配置問(wèn)題還是上拉電阻問(wèn)題。F103 的硬件 I2C 偶爾會(huì)被傳各種“玄學(xué)”問(wèn)題但絕大多數(shù)情況下只要上拉電阻正常、地址正確跑通是沒(méi)問(wèn)題的。初始化里最容易坑人的是 Charge Pump電荷泵設(shè)置。SSD1306 內(nèi)部需要升壓電路給 OLED 屏幕供電有些庫(kù)的初始化代碼默認(rèn)關(guān)閉這個(gè)功能或者對(duì)比度設(shè)置太低結(jié)果屏幕完全沒(méi)反應(yīng)。務(wù)必確認(rèn)初始化序列中包含下面這兩條命令SSD1306_Command(0x8D); // Charge Pump Setting SSD1306_Command(0x14); // Enable Charge Pump如果屏幕還是不亮再查一下對(duì)比度寄存器 0x81把值調(diào)到 0x7F 再看看效果。4.2 畫面布局?jǐn)?shù)字、文字、圖形條怎么擺我的 OLED 畫面布局是這樣的第一行顯示當(dāng)前狀態(tài)比如“水位狀態(tài)正?!被颉八粻顟B(tài)偏低”第二行顯示 ADC 原始值第三行顯示推算出的水量百分比第四行畫一個(gè)橫向的進(jìn)度條動(dòng)態(tài)反映水量多少。這樣既能看到實(shí)時(shí)數(shù)據(jù)又能直觀地看到圖形反饋比單純打印一串?dāng)?shù)字要形象得多。顯示的核心邏輯其實(shí)就是一個(gè)狀態(tài)機(jī)的思想。傳感器返回的數(shù)字量決定了第一行的文字判斷ADC 采集值經(jīng)過(guò)歸一化后決定百分比和進(jìn)度條寬度。OLED 的顯示更新不要太頻繁否則會(huì)有明顯的閃爍感我把刷新間隔設(shè)置成 200ms 左右人眼看起來(lái)非常流暢。畫進(jìn)度條用的就是 SSD1306 的矩形填充函數(shù)先畫一個(gè)外框再按百分比填充內(nèi)部區(qū)域。關(guān)鍵代碼如下uint8_t percent 0; if (adc_raw EMPTY_ADC) { percent (uint32_t)(adc_raw - EMPTY_ADC) * 100 / (FULL_ADC - EMPTY_ADC); } if (percent 100) percent 100; SSD1306_DrawRectangle(0, 48, 127, 56, SSD1306_NORMAL); SSD1306_DrawRectangle(0, 48, 127 * percent / 100, 56, SSD1306_FILLED); SSD1306_UpdateScreen();這里的 EMPTY_ADC 和 FULL_ADC 是標(biāo)定出來(lái)的閾值不是隨便拍腦袋定的具體標(biāo)定方法我放在第 5 章實(shí)測(cè)環(huán)節(jié)里講。4.3 OLED 漢字顯示思路OLED 標(biāo)配的字庫(kù)只含英文字母和數(shù)字想顯示“水位”“正?!边@類漢字就得自己做字模。常用的工具是 PCtoLCD2002 取模軟件取模方式選擇“逐行式”字體大小用 16×16取模方向、逐行式、低位在前這些參數(shù)要和代碼里的字模讀取函數(shù)匹配上。生成出來(lái)的字模是一個(gè)十六進(jìn)制數(shù)組放進(jìn)工程后調(diào)用畫點(diǎn)函數(shù)逐位掃描就能點(diǎn)出漢字。漢字顯示會(huì)讓作品的專業(yè)感提升非常多也是很多畢業(yè)設(shè)計(jì)里導(dǎo)師愛(ài)看的一個(gè)點(diǎn)。我的建議是只提取自己需要用到的幾個(gè)漢字比如“水”“位”“狀”“態(tài)”“正”“?!薄捌薄暗汀辈灰澏喾駝t flash 空間消耗比較大。顯示函數(shù)本身很簡(jiǎn)單核心就是兩層循環(huán)按 bit 判斷有沒(méi)有點(diǎn)有就在對(duì)應(yīng)坐標(biāo)畫點(diǎn)沒(méi)有就跳過(guò)。5. 完整實(shí)驗(yàn)流程與聯(lián)調(diào)實(shí)測(cè)5.1 分步實(shí)施步驟我習(xí)慣把實(shí)驗(yàn)流程拆成八個(gè)步驟每一步都能驗(yàn)證通過(guò)了再往下走避免最后一次性聯(lián)調(diào)失敗時(shí)不知道是哪個(gè)環(huán)節(jié)出問(wèn)題。按第 2 章的接線表接好全部硬件通電前用萬(wàn)用表確認(rèn)一下 VCC 和 GND 沒(méi)有短路。ST-Link 通過(guò) SWD 接口連接 STM32接線順序是 SWDIO、SWCLK、GND如果需要板載供電就再接一個(gè) 3.3V。打開(kāi) CubeMX按第 3 章的配置建立工程生成 Keil MDK 代碼。先編譯一個(gè)空白工程下載進(jìn)去確認(rèn)芯片能正常下載、調(diào)試器能連接上。把 OLED 驅(qū)動(dòng)加進(jìn)來(lái)寫一個(gè)循環(huán)讓它顯示“Hello STM32”確認(rèn) I2C 通訊完全正常。再寫 ADC 讀取函數(shù)把值通過(guò)串口打印到電腦上確認(rèn)數(shù)據(jù)不再懸空亂跳。最后把 HS-S37A 的 DO 邏輯和 OLED 顯示整合到一起做完整的交互界面。用空瓶、裝一半水的瓶子、裝滿水的瓶子分別做測(cè)試記錄數(shù)據(jù)和閾值。5.2 實(shí)測(cè)數(shù)據(jù)與顯示效果我在實(shí)際操作中拿到的一組典型數(shù)據(jù)如下注意不同批次模塊、不同供電電壓下數(shù)值會(huì)有差異這份數(shù)據(jù)只是用來(lái)幫助你理解標(biāo)定思路測(cè)試場(chǎng)景PA0 ADC 值DO 輸出OLED 顯示結(jié)果探頭懸空無(wú)任何物體1125高電平無(wú)水狀態(tài) 0%探頭貼在空塑料瓶外壁1190高電平無(wú)水狀態(tài) 0%探頭貼在裝 1/3 水的瓶壁2150低電平有水量 35%探頭貼裝滿水的瓶壁3150低電平有水量 78%如果你仔細(xì)觀察就會(huì)發(fā)現(xiàn)空瓶和懸空兩種狀態(tài)的 ADC 值并不完全一樣這是因?yàn)樗芰掀勘诒旧淼慕殡姵?shù)和空氣不同傳感器感知到的“介質(zhì)變化”比單純“有沒(méi)有水”更敏感。這也是為什么我不建議直接在代碼里寫死一個(gè)理論閾值而是一定要手動(dòng)畫出一個(gè)“空瓶基準(zhǔn)值”和一個(gè)“滿水基準(zhǔn)值”然后在這兩個(gè)值之間做百分比映射。這個(gè)標(biāo)定過(guò)程看著不起眼但實(shí)際項(xiàng)目里能否穩(wěn)定工作往往就取決于這個(gè)基準(zhǔn)選得準(zhǔn)不準(zhǔn)。6. 常見(jiàn)問(wèn)題排查與避坑記錄6.1 高頻問(wèn)題速查表現(xiàn)象可能原因解決辦法OLED 完全不亮I2C 地址不對(duì)、Charge Pump 沒(méi)開(kāi)啟、模塊供電不足先用 I2C 掃描確定真實(shí)地址檢查初始化序列I2C 掃描不到設(shè)備SDA/SCL 缺少上拉電阻、接線順序接反、模塊是 SPI 版本外接 4.7kΩ 上拉對(duì)照絲印重新接線DO 輸出一直在抖動(dòng)探頭貼得太緊、周圍有振動(dòng)、電源紋波大程序去抖給模塊單獨(dú)加 100μF104 電容濾波ADC 讀數(shù)跳變嚴(yán)重采樣時(shí)間太短、杜邦線過(guò)長(zhǎng)、供電不穩(wěn)定把采樣時(shí)間調(diào)到 239.5 Cycles換短杜邦線下載一次后找不到目標(biāo)芯片SWD 調(diào)試口被誤配置成普通 GPIOCubeMX 里 SYS 選擇 Serial Wire按住復(fù)位重新下載上電后前 1 秒數(shù)據(jù)偏大傳感器內(nèi)部 RC 振蕩器還沒(méi)穩(wěn)定上電延時(shí) 500ms 后再做首次 ADC 采集6.2 現(xiàn)場(chǎng)排查思路與一個(gè)實(shí)戰(zhàn)案例我調(diào)試這類系統(tǒng)有一個(gè)固定套路先電源再接線最后才是代碼。很多新手一遇到問(wèn)題就反復(fù)改代碼改到天亮也找不出毛病實(shí)際上八成的坑都出在物理層。印象最深的一次是 OLED 白屏我一開(kāi)始懷疑是 I2C 地址配置問(wèn)題把 0x3C、0x78 試了個(gè)遍都沒(méi)用。后來(lái)才發(fā)現(xiàn)模塊背面有兩個(gè)焊盤選擇地址的 0Ω 電阻出廠默認(rèn)是 0x7A和代碼里寫的 0x78 剛好差一位。這種問(wèn)題無(wú)論是看代碼還是換庫(kù)都解決不了最后解決靠的是拿起模塊仔細(xì)看絲印。所以我現(xiàn)在裝機(jī)前都會(huì)先做一件事用 I2C 掃描函數(shù)把所有設(shè)備地址打出來(lái)90% 的通訊故障都能當(dāng)場(chǎng)確定。6.3 老生常談的注意事項(xiàng)傳感器探頭不要直接貼在金屬表面上金屬會(huì)完全改變電容場(chǎng)分布導(dǎo)致輸出混亂甚至永久失效。如果實(shí)驗(yàn)里同時(shí)帶了水泵、繼電器這類大功率器件一定要和傳感器分開(kāi)供電或者在電源上并聯(lián)大電容濾波。共用一個(gè)電壓源時(shí)水泵一啟動(dòng) ADC 值就會(huì)亂跳。傳感器 DO 輸出模塊的閾值電位器出廠值不一定適合你的場(chǎng)景不要迷信默認(rèn)值用螺絲刀微調(diào)后用萬(wàn)用表實(shí)測(cè)輸出電平再定。長(zhǎng)期貼在潮濕環(huán)境使用時(shí)建議給傳感器背面做一個(gè)絕緣隔離貼片防止凝結(jié)水走線短路。7. 后續(xù)還能怎么玩做完這個(gè)基礎(chǔ)實(shí)驗(yàn)?zāi)阋呀?jīng)掌握了“傳感器采集 STM32 處理 OLED 展示”的完整鏈路剩下的就是純粹想象力的活了。我的建議是把這套系統(tǒng)擴(kuò)展成水箱自動(dòng)補(bǔ)水控制在 HS-S37A 判斷缺水時(shí)由 STM32 控制一個(gè)繼電器驅(qū)動(dòng)小型水泵補(bǔ)水水滿后自動(dòng)斷電。OLED 上加一個(gè)倒計(jì)時(shí)或者水泵運(yùn)行狀態(tài)指示放在魚缸或者盆栽自動(dòng)化場(chǎng)景里效果非常直觀。如果還想再上一個(gè)檔次可以把 OLED 換成帶觸摸功能的大屏或者加上 ESP8266/ESP32 模塊把水位狀態(tài)上報(bào)到手機(jī)端。對(duì) RS485 或者 PLC 工業(yè)總線熟悉的朋友也能通過(guò)一個(gè)簡(jiǎn)單的電平轉(zhuǎn)換芯片把 DO 信號(hào)傳給上位機(jī)組成一套多傳感器檢測(cè)網(wǎng)絡(luò)。我個(gè)人的體會(huì)是做這類小項(xiàng)目最重要的是把第一步完整跑通只要傳感器數(shù)據(jù)可信、顯示邏輯清晰后面加通信、加控制都只是時(shí)間問(wèn)題。最后再分享一個(gè)我保留至今的習(xí)慣哪怕只是一個(gè)簡(jiǎn)單 DEMO我也會(huì)在代碼里把閾值標(biāo)定和濾波邏輯單獨(dú)抽成兩個(gè)函數(shù)因?yàn)橐坏浆F(xiàn)場(chǎng)調(diào)設(shè)備的時(shí)候你才會(huì)發(fā)現(xiàn)這些都是能救命的接口。