戰(zhàn)指南)
1. 從零上手GY-30為什么選它做ESP32的光照搭檔如果你剛開(kāi)始玩ESP32想找一個(gè)便宜、好用、資料多、接線又簡(jiǎn)單的傳感器來(lái)練手GY-30幾乎是繞不開(kāi)的一個(gè)選擇。它本質(zhì)上是一塊基于BH1750FVI芯片的光照強(qiáng)度采集模塊輸出的是直接可讀的數(shù)字量單位是勒克斯lx。和光敏電阻那種模擬量方案比起來(lái)GY-30不需要你自己標(biāo)定也不受ADC精度和參考電壓漂移的折磨插上I2C就能讀數(shù)對(duì)新手非常友好。我當(dāng)初選它的原因很直接一是價(jià)格低幾塊錢(qián)就能拿到二是它走I2C總線只需要兩根信號(hào)線就能和ESP32通信省下來(lái)的引腳可以接別的外設(shè)三是BH1750FVI這顆芯片本身精度不錯(cuò)量程覆蓋0到65535 lx室內(nèi)照明、室外陰天、甚至晴天直射光都能測(cè)日常做智能家居、自動(dòng)調(diào)光、植物補(bǔ)光監(jiān)控這些場(chǎng)景完全夠用。對(duì)于“零基礎(chǔ)學(xué)ESP32”這個(gè)階段的人來(lái)說(shuō)能快速看到串口打印出真實(shí)的光照數(shù)值這種正反饋比什么都重要。不過(guò)便宜好用的東西往往也有它的脾氣。GY-30模塊在市面上版本很多有的帶電平轉(zhuǎn)換有的不帶有的地址引腳默認(rèn)拉低有的懸空供電電壓標(biāo)稱(chēng)3.3V到5V但實(shí)際接ESP32時(shí)到底怎么接才穩(wěn)很多人第一次都會(huì)踩坑。這篇文章我就按自己實(shí)際調(diào)試的順序把GY-30和ESP32配合使用的完整流程拆開(kāi)講清楚包括I2C的底層邏輯、接線細(xì)節(jié)、代碼實(shí)現(xiàn)、參數(shù)計(jì)算以及那些文檔里不會(huì)寫(xiě)但實(shí)際一定會(huì)遇到的問(wèn)題。適合讀這篇內(nèi)容的人有三類(lèi)完全沒(méi)碰過(guò)I2C傳感器的新手、已經(jīng)會(huì)點(diǎn)Arduino但想搞懂底層原理的進(jìn)階玩家、以及想把光照數(shù)據(jù)接入自己ESP32項(xiàng)目比如自動(dòng)窗簾、補(bǔ)光燈、環(huán)境監(jiān)測(cè)的開(kāi)發(fā)者。不管你是哪一類(lèi)只要跟著把接線和代碼走一遍基本都能讓GY-30在ESP32上穩(wěn)定跑起來(lái)。2. GY-30與BH1750FVI的核心原理拆解2.1 BH1750FVI到底是怎么測(cè)光的很多人拿到GY-30只知道它能讀光照但不知道它內(nèi)部干了什么。BH1750FVI的核心是一個(gè)接近人眼視覺(jué)響應(yīng)曲線的高精度光電二極管配合一個(gè)16位ADC把光電流轉(zhuǎn)換成數(shù)字量。它內(nèi)部有一套固定的轉(zhuǎn)換流程光電二極管接收光線產(chǎn)生電流電流經(jīng)過(guò)積分放大再由ADC量化最后通過(guò)I2C把16位數(shù)據(jù)吐出來(lái)。這里有個(gè)關(guān)鍵點(diǎn)BH1750FVI的輸出不是線性的原始ADC值而是已經(jīng)經(jīng)過(guò)內(nèi)部計(jì)算、直接對(duì)應(yīng)勒克斯的數(shù)值。也就是說(shuō)你讀到的兩個(gè)字節(jié)拼起來(lái)除以1.2基本就是當(dāng)前光照的lx值。這個(gè)1.2是芯片手冊(cè)里給出的典型換算系數(shù)后面講代碼時(shí)我會(huì)具體說(shuō)怎么用。它的測(cè)量模式主要有幾種連續(xù)高分辨率模式、連續(xù)低分辨率模式、單次高分辨率模式、單次低分辨率模式。高分辨率模式下最小能分辨1 lx左右轉(zhuǎn)換時(shí)間典型值120ms低分辨率模式轉(zhuǎn)換時(shí)間只要16ms左右但精度降到4 lx。對(duì)于大多數(shù)環(huán)境監(jiān)測(cè)場(chǎng)景我建議用連續(xù)高分辨率模式讀出來(lái)的數(shù)值穩(wěn)定響應(yīng)也夠快。2.2 I2C通信在GY-30上的具體體現(xiàn)GY-30模塊對(duì)外只有四個(gè)引腳VCC、GND、SCL、SDA。SCL是時(shí)鐘線SDA是數(shù)據(jù)線ESP32作為主機(jī)GY-30作為從機(jī)。I2C的通信過(guò)程其實(shí)很像兩個(gè)人打電話(huà)主機(jī)先撥號(hào)發(fā)送從機(jī)地址從機(jī)接聽(tīng)?wèi)?yīng)答然后主機(jī)說(shuō)指令命令字節(jié)從機(jī)執(zhí)行并返回?cái)?shù)據(jù)。BH1750FVI的7位從機(jī)地址是0x23前提是模塊上的ADDR引腳接地。如果ADDR接VCC地址變成0x5C。市面上大部分GY-30模塊默認(rèn)ADDR是懸空或者下拉的所以實(shí)際用0x23居多。這里要注意Arduino的Wire庫(kù)使用的是7位地址所以代碼里寫(xiě)0x23就行不需要左移。I2C的時(shí)序里有兩個(gè)關(guān)鍵概念起始條件和停止條件。起始條件是SCL高電平時(shí)SDA從高變低停止條件是SCL高電平時(shí)SDA從低變高。數(shù)據(jù)位在SCL低電平時(shí)變化在SCL高電平時(shí)被采樣。這些底層細(xì)節(jié)你不需要手動(dòng)去翻轉(zhuǎn)GPIOWire庫(kù)已經(jīng)封裝好了但理解它們有助于你在通信失敗時(shí)判斷問(wèn)題出在哪。還有一個(gè)容易被忽略的點(diǎn)I2C總線需要上拉電阻。GY-30模塊板上通常已經(jīng)自帶了4.7kΩ或10kΩ的上拉電阻所以直接接ESP32一般能通信。但如果你接的線比較長(zhǎng)或者總線上掛了多個(gè)從機(jī)上拉電阻的阻值可能需要調(diào)整。線長(zhǎng)超過(guò)20厘米時(shí)我建議把上拉電阻換成2.2kΩ左右波形會(huì)更干凈。2.3 為什么ESP32和GY-30是低門(mén)檻組合ESP32的I2C外設(shè)非常靈活幾乎任意GPIO都可以通過(guò)矩陣映射成SCL和SDA。Arduino核心默認(rèn)用GPIO21做SDA、GPIO22做SCL這兩個(gè)引腳在大多數(shù)ESP32開(kāi)發(fā)板上都引出來(lái)了接線方便。而且ESP32的IO口是3.3V電平GY-30模塊在3.3V供電時(shí)I2C電平也是3.3V兩者天然匹配不需要額外的電平轉(zhuǎn)換。對(duì)比一下用STM32或者51單片機(jī)STM32的I2C硬件外設(shè)配置起來(lái)步驟多新手容易卡在時(shí)鐘配置和引腳復(fù)用上51單片機(jī)沒(méi)有硬件I2C得用軟件模擬時(shí)序容易出錯(cuò)。ESP32用Arduino框架Wire庫(kù)幾行代碼就能跑起來(lái)這就是它適合零基礎(chǔ)的地方。另外ESP32的算力和內(nèi)存足夠你在讀取光照的同時(shí)跑WiFi、藍(lán)牙或者OLED顯示不會(huì)因?yàn)橐粋€(gè)傳感器就把資源吃滿(mǎn)。我實(shí)測(cè)過(guò)在讀取GY-30的同時(shí)開(kāi)WiFi上傳數(shù)據(jù)到本地服務(wù)器循環(huán)周期穩(wěn)定在200ms左右完全不影響光照采集。3. 接線與硬件準(zhǔn)備別讓第一步就翻車(chē)3.1 物料清單與選型建議開(kāi)始之前先把東西備齊。下面這張表是我實(shí)際用過(guò)的配置供你參考物料型號(hào)/規(guī)格數(shù)量備注主控板ESP32 DevKit V11任意ESP32開(kāi)發(fā)板均可光照模塊GY-30 / BH17501注意看板載是否有上拉電阻杜邦線母對(duì)母4根建議用短一點(diǎn)的減少干擾數(shù)據(jù)線Micro USB或Type-C1根根據(jù)開(kāi)發(fā)板接口選電腦任意1臺(tái)裝好Arduino IDE選GY-30的時(shí)候有個(gè)細(xì)節(jié)有些模塊標(biāo)的是GY-30但實(shí)際芯片是BH1750FVI這是正常的GY-30就是基于BH1750FVI的模塊代號(hào)。你拿到手可以看模塊背面芯片絲印上如果有BH1750字樣就沒(méi)問(wèn)題。如果買(mǎi)到的是BH1750的裸芯片自己焊的板子要確認(rèn)有沒(méi)有加上拉電阻沒(méi)有的話(huà)得自己補(bǔ)兩個(gè)4.7kΩ電阻到3.3V。3.2 接線步驟與引腳對(duì)應(yīng)關(guān)系接線本身不復(fù)雜但順序和對(duì)應(yīng)關(guān)系要記牢。我按ESP32 DevKit V1的默認(rèn)I2C引腳來(lái)說(shuō)GY-30的VCC接到ESP32的3.3V引腳GY-30的GND接到ESP32的GNDGY-30的SCL接到ESP32的GPIO22GY-30的SDA接到ESP32的GPIO21這里有個(gè)非常重要的提醒不要把VCC接到5V。雖然GY-30模塊標(biāo)稱(chēng)支持3.3V到5V但ESP32的IO口是3.3V電平如果模塊用5V供電I2C信號(hào)線可能被模塊內(nèi)部電路拉到5V長(zhǎng)期下來(lái)會(huì)損傷ESP32的IO。穩(wěn)妥起見(jiàn)統(tǒng)一用3.3V供電。接完線之后先別急著上電。用萬(wàn)用表蜂鳴檔測(cè)一下VCC和GND之間有沒(méi)有短路確認(rèn)沒(méi)有再接USB。我見(jiàn)過(guò)有人把VCC和GND接反上電瞬間模塊就發(fā)燙雖然GY-30一般有保護(hù)但沒(méi)必要冒這個(gè)險(xiǎn)。3.3 上電前的檢查清單上電之前按下面這幾條過(guò)一遍確認(rèn)VCC接的是3.3V不是5V確認(rèn)GND和ESP32的GND共地確認(rèn)SCL和SDA沒(méi)有接反確認(rèn)杜邦線插緊沒(méi)有虛接確認(rèn)ESP32開(kāi)發(fā)板沒(méi)有其他短路如果用的是帶OLED的擴(kuò)展板還要注意I2C地址沖突。GY-30默認(rèn)0x23常見(jiàn)OLED是0x3C或0x3D一般不沖突。但如果你的OLED模塊地址可調(diào)最好確認(rèn)一下避免兩個(gè)設(shè)備搶總線。4. Arduino IDE環(huán)境搭建與庫(kù)的選擇4.1 ESP32開(kāi)發(fā)板支持包的安裝如果你還沒(méi)裝ESP32的Arduino支持這一步不能跳過(guò)。打開(kāi)Arduino IDE進(jìn)“文件”-“首選項(xiàng)”在“附加開(kāi)發(fā)板管理器網(wǎng)址”里填入ESP32的板管理器地址。然后進(jìn)“工具”-“開(kāi)發(fā)板”-“開(kāi)發(fā)板管理器”搜索esp32安裝最新版本。這里有個(gè)實(shí)際經(jīng)驗(yàn)安裝過(guò)程對(duì)網(wǎng)絡(luò)環(huán)境比較敏感如果一直卡在下載階段可以嘗試換一個(gè)時(shí)間段或者手動(dòng)下載離線包。網(wǎng)上有現(xiàn)成的ESP32離線包下載后放到Arduino的硬件目錄里也能用。我自己的做法是先用在線安裝如果超過(guò)十分鐘沒(méi)動(dòng)靜就換離線方案不浪費(fèi)時(shí)間。安裝完成后在“工具”-“開(kāi)發(fā)板”里選擇“ESP32 Dev Module”。端口選擇你實(shí)際插上的那個(gè)COM口。如果看不到端口檢查數(shù)據(jù)線是不是只能充電不能傳數(shù)據(jù)的那種換一根線試試。4.2 BH1750庫(kù)的安裝與替代方案讀取GY-30最省事的方法是裝一個(gè)現(xiàn)成的庫(kù)。在Arduino IDE的“庫(kù)管理器”里搜索BH1750會(huì)出來(lái)好幾個(gè)版本。我常用的是Christopher Laws維護(hù)的那個(gè)名字就叫BH1750接口簡(jiǎn)單支持連續(xù)和單次模式。裝好庫(kù)之后直接調(diào)用lightMeter.begin()和lightMeter.readLightLevel()就能讀數(shù)。但如果你想搞懂底層我建議也試著自己用Wire庫(kù)直接寫(xiě)一遍不依賴(lài)第三方庫(kù)。這樣你能清楚每一步在干什么遇到問(wèn)題時(shí)也知道從哪排查。如果你不想裝庫(kù)用Wire庫(kù)手動(dòng)實(shí)現(xiàn)也不難。核心就是三個(gè)操作發(fā)送電源開(kāi)啟命令、發(fā)送測(cè)量模式命令、讀取兩個(gè)字節(jié)并換算。后面我會(huì)給出完整的手動(dòng)實(shí)現(xiàn)代碼。4.3 串口監(jiān)視器的配置代碼燒錄進(jìn)去之后需要看串口輸出。Arduino IDE的串口監(jiān)視器波特率要和代碼里Serial.begin()設(shè)置的一致我一般用115200。打開(kāi)監(jiān)視器之后如果看到一堆亂碼八成是波特率不對(duì)如果什么都沒(méi)有檢查代碼里有沒(méi)有加Serial.print以及開(kāi)發(fā)板有沒(méi)有復(fù)位。還有一個(gè)細(xì)節(jié)ESP32有些開(kāi)發(fā)板在打開(kāi)串口監(jiān)視器時(shí)會(huì)自動(dòng)復(fù)位這是正?,F(xiàn)象。如果你不想讓它復(fù)位可以在代碼里加上Serial.setTimeout()或者用外部電源供電。不過(guò)對(duì)于調(diào)試光照傳感器來(lái)說(shuō)復(fù)位一下反而方便每次打開(kāi)監(jiān)視器都能看到從頭開(kāi)始的數(shù)據(jù)。5. 代碼實(shí)現(xiàn)從最簡(jiǎn)讀到穩(wěn)定讀5.1 使用BH1750庫(kù)的最簡(jiǎn)代碼先上最簡(jiǎn)版本讓你五分鐘內(nèi)看到數(shù)據(jù)#include Wire.h #include BH1750.h BH1750 lightMeter; void setup() { Serial.begin(115200); Wire.begin(21, 22); if (!lightMeter.begin()) { Serial.println(BH1750初始化失敗檢查接線); while (1); } Serial.println(BH1750初始化成功); } void loop() { float lux lightMeter.readLightLevel(); Serial.print(光照: ); Serial.print(lux); Serial.println( lx); delay(1000); }這段代碼的邏輯很直白初始化I2C初始化傳感器然后每秒讀一次。Wire.begin(21, 22)顯式指定了SDA和SCL引腳避免不同開(kāi)發(fā)板默認(rèn)引腳不一樣導(dǎo)致的困惑。lightMeter.begin()如果返回false說(shuō)明I2C通信沒(méi)建立起來(lái)這時(shí)候先查接線再查地址。5.2 不依賴(lài)庫(kù)的Wire底層實(shí)現(xiàn)想搞懂原理的看這段手動(dòng)實(shí)現(xiàn)#include Wire.h #define BH1750_ADDR 0x23 void setup() { Serial.begin(115200); Wire.begin(21, 22); Wire.beginTransmission(BH1750_ADDR); Wire.write(0x01); // 電源開(kāi)啟 Wire.endTransmission(); delay(10); Wire.beginTransmission(BH1750_ADDR); Wire.write(0x10); // 連續(xù)高分辨率模式 Wire.endTransmission(); delay(180); } void loop() { Wire.requestFrom(BH1750_ADDR, 2); if (Wire.available() 2) { uint16_t raw Wire.read() 8 | Wire.read(); float lux raw / 1.2; Serial.print(原始值: ); Serial.print(raw); Serial.print( 光照: ); Serial.print(lux); Serial.println( lx); } delay(1000); }這里的關(guān)鍵是命令字節(jié)。0x01是電源開(kāi)啟0x10是連續(xù)高分辨率模式。讀取時(shí)一次讀兩個(gè)字節(jié)高字節(jié)在前拼成16位整數(shù)再除以1.2得到勒克斯。這個(gè)1.2就是前面提到的換算系數(shù)芯片手冊(cè)里寫(xiě)的典型值。5.3 參數(shù)計(jì)算與模式選擇不同測(cè)量模式的參數(shù)對(duì)比如下模式命令字節(jié)分辨率轉(zhuǎn)換時(shí)間適用場(chǎng)景連續(xù)高分辨率0x101 lx120ms常規(guī)環(huán)境監(jiān)測(cè)連續(xù)高分辨率20x110.5 lx120ms需要更高精度連續(xù)低分辨率0x134 lx16ms快速刷新單次高分辨率0x201 lx120ms低功耗場(chǎng)景如果你做的是電池供電的項(xiàng)目單次模式更省電需要讀數(shù)時(shí)發(fā)一次命令等轉(zhuǎn)換完讀一次然后讓傳感器進(jìn)入斷電模式。連續(xù)模式雖然方便但芯片一直在轉(zhuǎn)換功耗會(huì)高一些。換算公式再?gòu)?qiáng)調(diào)一遍lux raw / 1.2。這個(gè)1.2是典型值實(shí)際芯片會(huì)有個(gè)體差異但誤差在可接受范圍內(nèi)。如果你需要更精確的絕對(duì)值可以用標(biāo)準(zhǔn)光源標(biāo)定不過(guò)對(duì)于大多數(shù)DIY項(xiàng)目沒(méi)必要做到那個(gè)程度。6. 實(shí)測(cè)數(shù)據(jù)與常見(jiàn)問(wèn)題排查6.1 典型場(chǎng)景下的讀數(shù)參考我在幾個(gè)常見(jiàn)環(huán)境下實(shí)測(cè)了一輪數(shù)據(jù)如下場(chǎng)景讀數(shù)范圍lx說(shuō)明夜晚室內(nèi)關(guān)燈0 - 5接近傳感器下限室內(nèi)日光燈150 - 300與燈的距離有關(guān)室內(nèi)靠窗白天500 - 2000陰天和晴天差異大室外陰天3000 - 8000無(wú)直射陽(yáng)光室外晴天陰影處8000 - 20000避免直射室外晴天直射30000 - 60000接近量程上限這些數(shù)值不是絕對(duì)標(biāo)準(zhǔn)但可以幫你判斷讀數(shù)是否合理。如果你在室內(nèi)開(kāi)燈的情況下讀到0或者室外晴天讀到幾百那基本可以確定通信有問(wèn)題或者模式設(shè)置錯(cuò)了。6.2 常見(jiàn)問(wèn)題速查表現(xiàn)象可能原因排查方法串口無(wú)輸出代碼沒(méi)燒錄成功檢查開(kāi)發(fā)板選擇和端口初始化失敗接線錯(cuò)誤或地址不對(duì)用I2C掃描程序找地址讀數(shù)一直是0模式命令沒(méi)發(fā)對(duì)確認(rèn)發(fā)送了0x10或0x20讀數(shù)跳變嚴(yán)重電源不穩(wěn)或線太長(zhǎng)縮短線長(zhǎng)加濾波電容讀數(shù)明顯偏高傳感器被強(qiáng)光直射加柔光罩或改變安裝角度I2C掃描不到設(shè)備上拉電阻缺失檢查模塊是否有上拉I2C掃描程序很簡(jiǎn)單幾行就能跑#include Wire.h void setup() { Serial.begin(115200); Wire.begin(21, 22); for (byte addr 1; addr 127; addr) { Wire.beginTransmission(addr); if (Wire.endTransmission() 0) { Serial.print(發(fā)現(xiàn)設(shè)備地址: 0x); Serial.println(addr, HEX); } } } void loop() {}跑一遍這個(gè)如果能看到0x23說(shuō)明硬件連接沒(méi)問(wèn)題問(wèn)題在后面的代碼邏輯如果什么都掃不到那就是接線或者供電的問(wèn)題。6.3 實(shí)操避坑經(jīng)驗(yàn)第一個(gè)坑杜邦線質(zhì)量。我買(mǎi)過(guò)一批便宜的杜邦線插上去看著沒(méi)問(wèn)題實(shí)際內(nèi)部斷芯時(shí)通時(shí)斷。表現(xiàn)就是串口數(shù)據(jù)偶爾正常偶爾報(bào)錯(cuò)。后來(lái)?yè)Q了好一點(diǎn)的線問(wèn)題消失。所以如果你遇到莫名其妙的通信失敗先換線試試。第二個(gè)坑供電不足。有些ESP32開(kāi)發(fā)板用USB供電時(shí)3.3V輸出能力有限如果同時(shí)接了OLED、溫濕度傳感器和GY-30可能出現(xiàn)電壓跌落。表現(xiàn)是GY-30讀數(shù)不穩(wěn)定或者初始化失敗。解決辦法是用外部3.3V穩(wěn)壓供電或者減少同時(shí)掛載的設(shè)備。第三個(gè)坑光照角度。BH1750FVI的感光面有方向性如果你把它裝在殼子里開(kāi)孔太小或者角度不對(duì)讀數(shù)會(huì)明顯偏低。我建議安裝時(shí)讓感光面朝上或者朝向主要光源方向避免遮擋。第四個(gè)坑I2C地址沖突。如果你同時(shí)接了多個(gè)I2C設(shè)備一定要確認(rèn)地址不重復(fù)。GY-30是0x23有些氣壓傳感器是0x76或0x77OLED是0x3C一般不會(huì)沖突但如果你用了地址可調(diào)的模塊就要仔細(xì)核對(duì)。7. 從讀數(shù)到應(yīng)用光照數(shù)據(jù)的進(jìn)階用法7.1 自動(dòng)調(diào)光與閾值控制讀到光照值之后最簡(jiǎn)單的應(yīng)用就是做閾值控制。比如當(dāng)光照低于100 lx時(shí)打開(kāi)補(bǔ)光燈高于300 lx時(shí)關(guān)閉。代碼邏輯就是加一個(gè)if判斷if (lux 100) { digitalWrite(LED_PIN, HIGH); } else if (lux 300) { digitalWrite(LED_PIN, LOW); }這里要注意加一個(gè)遲滯區(qū)間避免在閾值附近來(lái)回抖動(dòng)。比如開(kāi)燈閾值設(shè)100關(guān)燈閾值設(shè)300中間200的區(qū)間就是遲滯。如果不加遲滯光照在100附近波動(dòng)時(shí)燈會(huì)頻繁開(kāi)關(guān)既影響壽命又看著難受。7.2 數(shù)據(jù)平滑與濾波處理原始讀數(shù)偶爾會(huì)有跳變尤其是電源不穩(wěn)或者光線突變時(shí)。我常用的方法是滑動(dòng)平均濾波開(kāi)一個(gè)數(shù)組存最近10次讀數(shù)每次取平均值輸出。這樣數(shù)據(jù)曲線會(huì)平滑很多代價(jià)是響應(yīng)速度稍微變慢。const int N 10; float buf[N]; int idx 0; float smooth(float newVal) { buf[idx] newVal; idx (idx 1) % N; float sum 0; for (int i 0; i N; i) sum buf[i]; return sum / N; }如果你想要更快的響應(yīng)可以用中值濾波取最近幾次讀數(shù)的中間值對(duì)脈沖干擾的抑制效果更好。7.3 接入物聯(lián)網(wǎng)平臺(tái)的思路光照數(shù)據(jù)上傳到本地服務(wù)器或者云平臺(tái)是很多人的下一步。ESP32自帶WiFi用HTTP或者M(jìn)QTT協(xié)議都能發(fā)。我一般用MQTT因?yàn)閿?shù)據(jù)量小、實(shí)時(shí)性好。流程是ESP32連WiFi連MQTT服務(wù)器每隔一段時(shí)間把lux值發(fā)布到指定主題服務(wù)器端訂閱后存數(shù)據(jù)庫(kù)或者展示在網(wǎng)頁(yè)上。這里不展開(kāi)具體平臺(tái)的操作因?yàn)椴煌脚_(tái)配置差異大。核心思路就是采集-濾波-打包-發(fā)送。發(fā)送頻率不用太高光照變化本身是慢過(guò)程一分鐘發(fā)一次足夠了。發(fā)太快除了增加網(wǎng)絡(luò)負(fù)擔(dān)沒(méi)有實(shí)際意義。8. 我踩過(guò)的坑與最后分享的幾個(gè)技巧第一個(gè)技巧先用I2C掃描確認(rèn)地址。不管你多自信接線沒(méi)問(wèn)題跑一遍掃描程序只要幾秒鐘能省掉后面大量排查時(shí)間。我現(xiàn)在的習(xí)慣是任何I2C設(shè)備第一次上電先掃描再寫(xiě)業(yè)務(wù)代碼。第二個(gè)技巧給GY-30加一個(gè)遮光罩。如果你發(fā)現(xiàn)讀數(shù)在室內(nèi)燈光下偏高可以用一段黑色熱縮管套在傳感器上只留頂部感光孔。這樣能減少側(cè)面雜散光的干擾讀數(shù)更接近實(shí)際環(huán)境照度。第三個(gè)技巧注意ESP32的I2C引腳可以重映射。默認(rèn)是21和22但如果你這兩個(gè)引腳被其他外設(shè)占了可以在Wire.begin()里換成別的引腳比如Wire.begin(18, 19)。ESP32的IO矩陣幾乎支持任意引腳非常靈活。第四個(gè)技巧長(zhǎng)時(shí)間運(yùn)行要加看門(mén)狗。如果你把ESP32放在無(wú)人值守的環(huán)境里連續(xù)采集光照建議開(kāi)啟硬件看門(mén)狗防止I2C總線死鎖導(dǎo)致程序卡死。Arduino核心里有esp_task_wdt相關(guān)接口配置一下就行。第五個(gè)技巧讀數(shù)單位統(tǒng)一。有些庫(kù)返回的是float有些返回uint16混用的時(shí)候注意類(lèi)型轉(zhuǎn)換。我一般統(tǒng)一用float存lux值顯示和上傳都用這個(gè)避免整數(shù)除法丟精度。最后說(shuō)一個(gè)我自己的體會(huì)GY-30這個(gè)模塊雖然簡(jiǎn)單但它把I2C通信、傳感器數(shù)據(jù)讀取、參數(shù)換算這幾個(gè)嵌入式開(kāi)發(fā)的核心環(huán)節(jié)都串起來(lái)了。你把它玩透后面換別的I2C傳感器比如溫濕度、氣壓、加速度計(jì)基本就是換個(gè)地址和命令字節(jié)的事。所以別急著跳過(guò)基礎(chǔ)把這一套流程走扎實(shí)后面學(xué)什么都快。