ESP32-C3 二氧化碳偵測器 DIY:SCD41+1.3 吋 OLED 接線與 Arduino IDE 教學
房間裡的二氧化碳(CO₂)變高,想自己看見通風前後的變化?這篇帶你用 ESP32-C3 SuperMini、Sensirion SCD41 和 1.3 吋 OLED,做一台顯示 CO₂、溫度、濕度的桌上型教學原型。從零件清單、I²C 接線、Arduino IDE 安裝到完整程式,依順序查找;沒有示範虛構讀值。
先看結論:SCD41 負責量測、ESP32-C3 負責讀取、OLED 顯示資訊;三者共地,兩個周邊都以 3.3 V 供電,SDA 接 GPIO4、SCL 接 GPIO5。這套配置供學習與觀察通風趨勢,不是醫療器材、消防警報器或一氧化碳偵測器。如果只想知道室內是否該換氣、不想接線或寫程式,選擇成品 CO₂ 監測器會更簡單。
驗證狀態先說清楚:下方程式僅通過使用模擬標頭的 C++ 語法與函式介面初步檢查,尚未以官方 ESP32-C3 Arduino 核心完成編譯,也尚未接實物上電測試;各批 OLED 控制晶片、I²C 位址和模組上拉電壓必須現場核對,不能把程式當成已實測保證可用的韌體。本文為教學參考,不應在安全關鍵場合使用。
CO₂ 數值升高就有毒嗎?先用來看通風趨勢
平常室內 CO₂ 上升,首先是提醒檢查人數與換氣,而不是依單一數值診斷身體狀況。英國 HSE 將有人房間持續高於 1,500 ppm 視為通風欠佳的線索,但這並非台灣住宅的法定安全門檻。ASHRAE 也不把 1,000 ppm 定為普遍健康上限;CO₂ 不能代表所有空氣污染物。極高濃度暴露確實可能導致頭痛、呼吸困難乃至更嚴重後果,但職業暴露數字不能直接套用為家用警報設定。遇到疑似危險環境或有人意識異常,先離開並求助,不要等 DIY 螢幕判讀。[8][9][10]
材料清單:ESP32-C3、SCD41 和 1.3 吋 OLED
- 主板:ESP32-C3 SuperMini 加強板套件,EDB-014326,包含擴展底板。使用 USB-C 資料線上傳程式。本文用 GPIO4(SDA)、GPIO5(SCL);擴展底板 VCC1/VCC2 的原廠預設輸出為 3.3 V,但仍要看收到的板子設定。[1][12]
- 感測:SCD41 感測板,SNA-014373,商品列 I²C 位址
0x62與 Qwiic 接頭。先確認你拿到的是開發板、有可以正確連到VDD/GND/SDA/SCL的接點或相容線材,以及板上拉高的電壓。不要把只有裸 SMD 晶片的版本當成四線模組。[2][13] - 顯示:1.3 吋藍字 I²C OLED、已焊接針腳版,LCR-001627,128×64 點。商品頁中文版列 SH1106、支援 3.3–5 V、插針標示
GND/VCC/SCL/SDA;但頁面英文通用段落寫「SH1106 或 SSD1306」,因此驅動晶片並未從實物確認。本範例先按商品頁明確列出的 SH1106 撰寫;若 I²C 可掃到而螢幕不顯示,要查實際批次驅動晶片,不能只改位址就當作已解決。[3][5]
供電決策:本教學把 OLED 也接到 3.3 V。商品頁只說可用 3.3–5 V,沒有逐批明確給出 SDA/SCL 的上拉電路與預設電壓;上電前查實物,分段上電後量 SDA/SCL 空閒高電位,必須落在 3.3 V 域,不能升到 5 V。不要因為標示「5V 兼容」就用 5 V 餵 OLED 然後把 SDA/SCL 直連 C3。[1][3]

四條網路,依「腳位名稱」接
| ESP32-C3 SuperMini | SCD41 感測板 | 1.3 吋 OLED | 說明 |
|---|---|---|---|
3V3 | VDD | VCC | 兩周邊都用 3.3 V;先確認板子與穩壓器電流餘裕。 |
GND | GND | GND | 三者共地。 |
GPIO4 | SDA | SDA | 資料線並接,不是串接。 |
GPIO5 | SCL | SCL | 時脈線並接,不要與 SDA 反接。 |
先拔掉 USB再改線;斷電檢查 3V3 沒短路到 GND,確認實際插針順序和模組背面的絲印。USB 供電時先只測主板 3V3,再分段加感測板和 OLED,量測匯流排空閒時 SDA/SCL 的高電位與 3.3 V 穩定性。SCD41 模組量測尖峰電流可能高於平均值,供電餘裕要按實際載板與來源核實。不要把外部電源與 USB 同時接到主板;nologo.tech 對此有互斥提醒。[1][2][12]
OLED 常見 I²C 位址 0x3C 或 0x3D,但本站商品頁沒有承諾出貨位址。程式先掃描這兩個位址,掃不到便停下供排錯;SCD41 通常在 0x62。掃到位址不能證明供電/訊號電壓安全,也無法判別 SH1106 還是 SSD1306。[2][3][5]
Arduino IDE 如何安裝 ESP32-C3 開發板?
- 到 Arduino 官方網站安裝 Arduino IDE 2.x;把 C3 接上 USB-C 資料線。若埠沒有出現,先排除只有充電功能的線材。[6]
- IDE「偏好設定 → 其他開發板管理員網址」加入 Espressif 穩定版索引:
https://espressif.github.io/arduino-esp32/package_esp32_index.json。在「開發板管理員」安裝 Espressif Systems 的esp32。[4] - 選「工具 → 開發板 → esp32 → ESP32C3 Dev Module」,設定 USB CDC On Boot → Enabled,再選新出現的連接埠;序列監控速率設 115200 baud。[1][4][14]
- 若無法進入下載模式,按住 BOOT → 按一下 RESET → 放開 RESET → 放開 BOOT,重新選埠再上傳。先做無周邊的最小上傳,可縮小排查範圍。[1][14]
要安裝哪些 Arduino 函式庫?
Sensirion I2C SCD4x,作者 Sensirion;相依的Sensirion Core依 IDE 提示一併安裝。範例 API 依 Sensirion 官方 Arduino 函式庫。[7]U8g2,作者 olikraus;程式使用U8G2_SH1106_128X64_NONAME_F_HW_I2C驅動器和英文/數字字型,介面經官方 U8g2 文件核對。只裝函式庫不會自動辨識實際 OLED 的控制晶片。[5]Wire由 ESP32 Arduino 核心提供,不用再安裝第三方同名套件。
ESP32-C3+SCD41+OLED 完整 Arduino 範例程式
建立名為 ESP32_C3_SCD41_OLED13 的 Sketch,資料夾與 .ino 名稱保持一致。程式先掃描 I²C,找不到 OLED 或 SCD41 會停止並在 115200 序列監控輸出原因;通過後啟動 SCD41 週期量測,OLED 以圖形字型顯示 CO₂ 大字、溫度與濕度。螢幕上的英文字不是中文 OLED 字庫;不會因文章用中文就自動顯示中文字。[2][5][7]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | // EDB-014326 ESP32-C3 SuperMini + 3.3V SCD41 board + LCR-001627 1.3in OLED. // OLED store listing says SH1106, but also contains generic SSD1306 copy; // verify the actual batch/controller if I2C scan succeeds yet nothing renders. // Both peripheral modules and SDA/SCL must be in the 3.3V domain. #include <Arduino.h> #include <Wire.h> #include <SensirionI2cScd4x.h> #include <U8g2lib.h> constexpr int SDA_PIN = 4; constexpr int SCL_PIN = 5; constexpr uint8_t SCD41_ADDR = 0x62; // U8g2's hardware-I2C constructor takes CLOCK before DATA, unlike Wire.begin. U8G2_SH1106_128X64_NONAME_F_HW_I2C oled(U8G2_R0, U8X8_PIN_NONE, SCL_PIN, SDA_PIN); SensirionI2cScd4x scd41; uint32_t lastPoll = 0; bool responds(uint8_t address) { Wire.beginTransmission(address); return Wire.endTransmission() == 0; } void scanBus() { Serial.println("I2C 7-bit addresses:"); for (uint8_t address = 0x08; address <= 0x77; ++address) { if (responds(address)) Serial.printf(" 0x%02X\n", address); } } void showText(const char* first, const char* second) { oled.clearBuffer(); oled.setFont(u8g2_font_6x12_tf); // ASCII only; no Chinese glyphs promised. oled.drawStr(0, 20, first); oled.drawStr(0, 42, second); oled.sendBuffer(); } void sensorError(int16_t error, const char* operation) { if (error == 0) return; char detail[64]; errorToString(error, detail, sizeof(detail)); Serial.printf("%s failed: %s\n", operation, detail); } void setup() { Serial.begin(115200); delay(700); Wire.begin(SDA_PIN, SCL_PIN); Wire.setClock(100000); Serial.println("ESP32-C3 / SCD41 / 1.3in OLED SH1106"); scanBus(); uint8_t oledAddress = 0; if (responds(0x3C)) oledAddress = 0x3C; else if (responds(0x3D)) oledAddress = 0x3D; if (oledAddress == 0) { Serial.println("OLED absent at 0x3C/0x3D: check 3.3V/GND/SDA/SCL and actual address."); while (true) delay(1000); } // U8g2 expects the 7-bit scan result shifted left by one. oled.setI2CAddress(oledAddress << 1); oled.setBusClock(100000); oled.begin(); // U8g2 initializes Wire on the same GPIO4/GPIO5 supplied above. showText("CO2 monitor", "Starting..."); if (!responds(SCD41_ADDR)) { Serial.println("SCD41 not found at 0x62; verify supply and shared I2C bus."); showText("Check SCD41", "See Serial"); while (true) delay(1000); } scd41.begin(Wire, SCD41_ADDR); // An idle sensor can report an error to stop; still attempt a new start. sensorError(scd41.stopPeriodicMeasurement(), "stopPeriodicMeasurement"); delay(500); int16_t error = scd41.startPeriodicMeasurement(); if (error != 0) { sensorError(error, "startPeriodicMeasurement"); showText("Sensor error", "See Serial"); while (true) delay(1000); } Serial.println("Waiting for SCD41 measurement (~5 seconds per sample)..."); } void loop() { if (millis() - lastPoll < 1000) return; lastPoll = millis(); bool ready = false; int16_t error = scd41.getDataReadyStatus(ready); if (error != 0) { sensorError(error, "getDataReadyStatus"); return; } if (!ready) return; uint16_t co2 = 0; float temperature = 0.0f, humidity = 0.0f; error = scd41.readMeasurement(co2, temperature, humidity); if (error != 0) { sensorError(error, "readMeasurement"); return; } if (co2 == 0) { Serial.println("No valid CO2 sample yet"); return; } char number[8]; char detail[28]; snprintf(number, sizeof(number), "%u", co2); snprintf(detail, sizeof(detail), "T:%4.1fC RH:%2.0f%%", temperature, humidity); oled.clearBuffer(); oled.setFont(u8g2_font_6x12_tf); oled.drawStr(0, 11, "CO2 monitor"); oled.setFont(u8g2_font_logisoso24_tn); oled.drawStr(0, 44, number); oled.setFont(u8g2_font_6x12_tf); oled.drawStr(93, 42, "ppm"); oled.drawStr(0, 61, detail); oled.sendBuffer(); Serial.printf("CO2=%u ppm Temp=%.1f C RH=%.1f %%\n", co2, temperature, humidity); } |
此程式每秒查詢是否有新資料,但 SCD41 標準週期模式約五秒才產生一筆新樣本。setI2CAddress() 在 U8g2 使用的是左移一位的格式,不能把 I²C 掃描顯示的 0x3C 原樣直接傳入;範例已轉換。[2][5]
上傳後如何看懂 CO₂、溫度和濕度?
- 先做電源與空閒 SDA/SCL 電位檢查,再按 IDE 的「✓ 驗證」和「→ 上傳」。編譯通過不表示接線已確認安全。[6]
- 115200 序列監控先應顯示 I²C 掃描位址(預期
0x62,及 OLED 的0x3C或0x3D);數秒後開始輸出CO2=... ppm Temp=... C RH=... %。OLED 顯示CO2 monitor、CO₂ 數值和 T/RH。這些是預期格式,不是本次已量到的數據。 - 放在可代表房間氣流的位置,不要緊貼呼吸口、窗戶或出風口。觀察趨勢並搭配人數與通風狀況判讀;這不是醫療器材或生命安全警報器。
常見問題:感測器抓不到、OLED 黑屏怎麼辦?
- 序列埠找不到/上傳失敗:先確認資料線、板型、USB CDC On Boot、BOOT/RESET 操作。先拔除周邊只測主板。[1][14]
- 只掃到
0x62、OLED 不顯示:斷電查 OLED 3.3V/GND、GPIO4/5 對應 SDA/SCL、四線接點及共地;上電分段量 SDA/SCL 高電位;查實際地址是否非0x3C/0x3D。[3] - OLED 有
0x3C/0x3D回應卻黑屏或畫面偏移:掃描只能證明 I²C ACK,無法確定控制晶片。商品中文規格為 SH1106,英文通用段落卻提 SSD1306;核對收到板子的控制器後,才考慮把程式中 U8g2 的SH1106建構器改為對應的SSD1306建構器。也要查供電與總線。[3][5] - 只掃到 OLED、沒有
0x62:查 SCD41 載板供電、Qwiic/轉接線針序、是否為真 SCD41 開發板、3V3 電流餘裕及共地。[2][13] - 一直在 Starting 或數字不更新:看序列監控是否有
startPeriodicMeasurement、getDataReadyStatus、readMeasurement錯誤;正常更新約每五秒一次。溫度受板上發熱與安裝位置影響。[2][7]
從桌面原型到實際應用:先釐清限制
先把桌面原型穩定跑起來,再考慮外殼散熱、供電與接線可靠性、歷史資料或 MQTT。感測讀值不能單獨診斷疾病或替代一氧化碳警報器;若要控制排風設備,須另外設計隔離、額定功率與故障保護電路,不能直接用 GPIO 接市電。
常見問答
SCD41 和 OLED 能共用 ESP32-C3 的 SDA、SCL 嗎?
可以在符合 3.3V 電壓域、共地、位址不衝突的前提下,將兩者並接同一組 I²C:GPIO4=SDA、GPIO5=SCL。先量測實際模組上拉電位,再上電測試。
OLED 掃到 0x3C,為什麼還是黑屏?
掃到位址只表示 I²C 有回應,不代表控制晶片相符。本站商品中文敘述為 SH1106,英文通用說明則同時提到 SSD1306;須核對實際出貨批次、供電及程式的 U8g2 建構子。
CO₂ 達到 1,000 ppm 就會中毒嗎?
不能這樣推論。一般室內讀值主要協助看換氣趨勢;1,000 ppm 不是普遍適用的急性中毒門檻,也不能替代對其他污染物或個人症狀的評估。[8][9]
這份程式已經在 ESP32-C3 實機跑過嗎?
還沒有。它經過模擬標頭的語法檢查,但沒有官方 ESP32-C3 核心編譯或實物接線驗證。請先核對批次、電壓與控制晶片,再在 Arduino IDE 驗證、上傳與測試。
下一步:依商品批次核對並準備材料
商品照片用於辨認型號;接線以實際板上標示、規格與量測為準。開始焊接或接線前先斷電,並確認 3.3 V 供電與上拉電壓。
參考資料與規格來源
[1] 本站 EDB-014326:ESP32-C3 SuperMini 套件
[2] Sensirion:SCD4x 資料表
[3] 本站 LCR-001627:1.3 吋藍字 I²C OLED
[4] Espressif:Arduino ESP32 安裝
[5] U8g2 官方建構器列表與用法;API 參考
[6] Arduino:IDE 2 入門
[7] Sensirion:arduino-i2c-scd4x
[8] HSE:以 CO₂ 監測輔助換氣判讀
[9] ASHRAE:室內 CO₂ 立場文件
[10] NIOSH:二氧化碳暴露資料
[11] EPA:低價室內監測器用途與限制
[12] nologo.tech:SuperMini 原理圖與腳位;擴展底板
[13] 本站 SNA-014373:SCD41 感測板
[14] Espressif:USB CDC 刷機說明
圖片說明:文章首圖為 ImageGen 創作的情境示意,不是商品或實測照片;接線圖中的商品外觀採本站商品照片,文字與電氣網路為另外繪製。任何畫面均不代表已有實機量測。

發佈留言
很抱歉,必須登入網站才能發佈留言。