∿ MBC 通用 I2C 協議 v2
MBC-Pro 全系列的「通用 I2C 版」感應器都用同一套規則:暫存器編號就是值的編號,寫一個編號、讀回一個或連續好幾個 16 位元整數。學會一款,其他款照著用就好;每款產品的值表請看它的 指令參考。
適用主機:Arduino UNO / Nano / Mega / R4、ESP32、micro:bit、Raspberry Pi,以及任何能當 I2C 主機的控制板。
提示
不會寫程式也能用: 每款產品都有可以直接複製上傳的 Arduino 範例,請從 🔰 第一次用 Arduino 開始;micro:bit 請用 MakeCode 擴充;MBC 圖控編程與 jBot 網頁版有現成積木。
重要
這是 2026-10 起的 v2 協議(協議版本 2,
F1讀回 2)。2026-10 以前的韌體是 v1(0x01 版本包、0x11 合併包、高位元組在前),舊程式不相容;舊版檔案保留在 下載中心 的舊版區。
產品位址總覽
| 產品 | I2C 位址 | hw[0] | 型號 | 值表 | 指令參考 | 新手範例 |
|---|---|---|---|---|---|---|
| 神攝手 學校版(舊版,停止支援) | 0x4C |
1 |
CAMSCH |
I2C | 參考 | Arduino |
| 神攝手 WRO 版(HUE12)(舊版,停止支援) | 0x4C |
2 |
HUE12 |
I2C | 參考 | Arduino |
| IMU 陀螺儀 | 0x6A |
1 |
IMU |
I2C | 參考 | Arduino |
| 循行者 16 路 | 0x16 |
16 |
LINE16 |
I2C | 參考 | Arduino |
| 循行者 8 路 | 0x16 |
8 |
LINE8 |
I2C | 參考 | Arduino |
| 掌控者 PS2 | 0x42 |
1 |
PS2 |
I2C | 參考 | Arduino |
| 掌控者 PS4/PS5 接收器 | 0x42 |
2 |
PS4 |
I2C | 參考 | Arduino |
| 測距者 2 路 | 0x29 |
2 |
LASER2 |
I2C | 參考 | Arduino |
| 測距者 8 路 | 0x29 |
8 |
LASER8 |
I2C | 參考 | Arduino |
注意
- 目前的神攝手 也是
0x4C,hw0=3,每個值放哪一格看 神攝手讀值參考。上表標「舊版」的學校版/WRO 版已停止支援。- MBC EXP6 六路馬達擴充器(適用 SPIKE™)不走 I2C:主機接頭有隔離保護,Arduino 要用序列埠(UART)控制,請看 EXP6 Arduino 範例。
- 同一條 SDA/SCL 上,位址相同的產品不能同時接(循行者 8 路和 16 路、測距者 2 路和 8 路、PS2 和 PS4、神攝手與舊版神攝手)。要同時接就先用
F8把其中一台換位址。- 同一類產品共用一個位址,用
F0的高位元組(hw0)分辨款式:循行者 8/16、測距者 2/8、PS2=1/PS4=2、神攝手=3(舊版學校版=1/WRO 版=2)。
接線與電壓
- 依感應器排針標示接 SCL、SDA、VCC、GND(SPIKE/EV3 接頭的 4P 線:TX 腳=SCL、RX 腳=SDA)。
- 支援 100 kHz(建議,Arduino 預設)與 400 kHz。
- STM32 產品(循行者、測距者、PS2、陀螺儀)可直接接 5 V 主機;ESP32 產品(PS4/PS5 接收器、神攝手)腳位不耐 5 V,接 UNO 等 5 V 主機時上拉電阻要接 3.3 V。
- STM32 產品會「時脈延展」(clock stretching);Arduino、ESP32 都支援。Raspberry Pi 的硬體 I2C 處理時脈延展有已知問題,讀值不穩時把速度降到 10~50 kHz 或改用
i2c-gpio。micro:bit V2 若讀值不穩請回報,韌體有「不延展」選項。
讀取:寫編號、等 2 ms、讀 2×k 個 byte
- 主機寫 1 byte:值的編號(例如
0x01)。 - 等 2 ms(ESP32 產品需要;STM32 產品不等也可以,函式庫一律等,代價很小)。
requestFrom(位址, 2×k):從該編號起連續 k 個值(k ≤ 16,也就是最多 32 byte)。- 每個值是 int16,低位元組在前(little-endian),與樂高、MATRIX、mBlock 一致。
- 沒有定義的編號回 −32768(
0x00 0x80);跨過空號連續讀也沒關係,空號就是 −32768。 - 模組每 10 ms 更新一次快照,一次連續讀到的值保證是同一瞬間的。
- 數值直接是使用者要的數字:線位置 −8
+8(負=線在左)、搖桿 −100+100、距離 cm/mm、色相 −1=黑白灰。不用再減 100、減 50。
寫入命令(E0~EE)
主機寫 [命令編號][參數…];參數長度依命令(沒有參數就只寫 1 byte)。命令是非同步執行的(校準、寫 EEPROM),用 F3 狀態旗標確認完成。各產品的命令在它的指令參考頁,例如循行者 E0 切黑線、E2 黑色校準、E4 [門檻];PS4 E5 [強度] 震動、E6 [R][G][B] 燈條;IMU E0 航向歸零。
共用暫存器(所有產品都有)
| 編號 | 讀寫 | 名稱 | 說明 |
|---|---|---|---|
F0 |
R | 裝置 ID | 低 byte = 出廠 I2C 位址(換位址後不變),高 byte = hw[0](通道數/顆數/類別) |
F1 |
R | 協議版本 | 本版 = 2(SPIKE 模式 8 v[1]、EV3 ID 封包同一個數字)(2) |
F2 |
R | 韌體版本 | 主版×100 + 次版(例 102 = 1.2) |
F3 |
R | 狀態旗標 | b0 就緒,其餘各產品定義(見各產品 flags)(bit) |
F4 |
R | 更新序號 | 每 10 ms 快照 +1,0 |
F5 |
R | 開機秒數 | 開機後秒數,到 32767 停住(約 9 小時);數字變小 = 重開機過(0~32767) |
F8 |
W | 換 I2C 位址 | [F8][新位址 0x08 |
EF |
W | 重新開機 | [EF][0xA5];mBlock 先回 ACK 再重開;參數:確認碼 0xA5 |
建議主機流程: 開機讀 F0(認產品與款式)→ 讀 F3 等 bit0 = 1(就緒)→ 開始連續讀值。
換位址: 寫 [F8][新位址][新位址取反](例如改成 0x17:F8 17 E8),重新開機後生效;寫 [F8][00][FF] 回出廠位址。F0 的低位元組永遠回出廠位址,所以換過位址也認得出是哪一款。
Arduino 共用函式
每支範例的底部都有這一段,單檔就能用:
#include <Wire.h>
const int16_t MBC_NONE = -32768; // 空號/沒回應
// 從編號 id 起連續讀 k 個值(k ≤ 16)。回傳 false = 裝置沒回應
bool mbcReadMany(uint8_t addr, uint8_t id, uint8_t k, int16_t *out) {
if (k < 1) k = 1; if (k > 16) k = 16;
Wire.beginTransmission(addr);
Wire.write(id);
if (Wire.endTransmission() != 0) return false;
delay(2); // ESP32 產品需要;其他產品不等也可以
if (Wire.requestFrom(addr, (uint8_t)(2 * k)) != 2 * k) return false;
for (uint8_t i = 0; i < k; i++) {
uint16_t lo = Wire.read(), hi = Wire.read();
out[i] = (int16_t)(lo | (hi << 8)); // 低位元組在前
}
return true;
}
int16_t mbcRead(uint8_t addr, uint8_t id) { // 讀 1 個值
int16_t v; return mbcReadMany(addr, id, 1, &v) ? v : MBC_NONE;
}
bool mbcWrite(uint8_t addr, uint8_t id, const uint8_t *p = NULL, uint8_t n = 0) { // 命令/換位址/重開機
Wire.beginTransmission(addr);
Wire.write(id);
for (uint8_t i = 0; i < n; i++) Wire.write(p[i]);
return Wire.endTransmission() == 0;
}
bool mbcWaitReady(uint8_t addr, uint16_t ms) { // 等 F3 bit0
uint32_t t0 = millis();
while (millis() - t0 < ms) { int16_t s = mbcRead(addr, 0xF3); if (s != MBC_NONE && (s & 1)) return true; delay(20); }
return false;
}範例:辨識接上的產品
void setup() {
Serial.begin(115200);
Wire.begin();
int16_t id = mbcRead(0x16, 0xF0); // 0x16 = 循線系列
if (id == MBC_NONE) { Serial.println("找不到裝置,請檢查接線與位址"); return; }
Serial.print("出廠位址 0x"); Serial.print(id & 0xFF, HEX);
Serial.print(",款式 hw0 = "); Serial.println(id >> 8); // 8 = 8 路、16 = 16 路
int16_t fw = mbcRead(0x16, 0xF2);
Serial.print("韌體 "); Serial.print(fw / 100); Serial.print('.'); Serial.println(fw % 100);
}
void loop() {}注意
通用 I2C 版與 SPIKE 版、EV3 版是不同的硬體版本,接頭不同、不能互換。購買前請確認版本,詳情請 聯絡我們。