National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 10

I2C 匯流排與感測器

掃描位址、讀取暫存器與換算數值
Interaction 25 minute(s)

Learning Objectives

  • 說明 I2C 為什麼兩條線就能接好幾個裝置,以及位址的作用
  • 用 i2c.scan() 找出匯流排上的裝置,並用十六進位表示位址
  • 用 readfrom_mem 讀取感測器暫存器,把收到的位元組拼成數值
  • 用二補數的規則把讀值轉成負數,並換算成溫度、加速度等實際單位

兩條線接很多個裝置

上一課的 OLED 只用了 SCL、SDA 兩條訊號線。如果還要接溫度感測器、加速度計,需要再多幾支腳位嗎?不用。 I2C(Inter-Integrated Circuit)是一種匯流排:好幾個裝置並聯在同一組兩條線上,各自有一個位址, 開發板(控制端,controller)先喊位址,被叫到的裝置(目標裝置,target)才回應。

這一課要回答:

  1. I2C 怎麼接線?怎麼知道匯流排上有哪些裝置?
  2. 什麼是感測器的「暫存器」?怎麼讀?
  3. 感測器回傳的是一串位元組,怎麼變成「25.5°C」這樣的數字?

接線

線 全名 作用
SCL Serial Clock 時脈:由控制端產生,決定每個位元什麼時候讀取
SDA Serial Data 資料:雙向,控制端與目標裝置輪流使用
3.3V、GND 電源,所有裝置共地
ESP32 GPIO18 (SCL) ──┬────────┬────────┬───
ESP32 GPIO19 (SDA) ──┼──┬─────┼──┬─────┼──┬
                    OLED     TMP102    MPU-6050
                    0x3C      0x48      0x68

兩條線都需要上拉電阻接到 3.3V(MicroPython 文件建議約 1~10 kΩ)。常見的感測器模組板多半已經焊好上拉電阻, 如果接上去之後 scan() 什麼都找不到,上拉電阻是要檢查的項目之一。

I2C 規格(NXP UM10204)定義了幾種速度,最常見的是標準模式 100 kbit/s 與快速模式 400 kbit/s; MicroPython 建立 I2C 時用 freq= 指定,預設是 400 kHz。

逐步看:掃描匯流排上的裝置

scan() 會對 0x08~0x77 每個位址都喊一次,把有回應的位址放進串列。 位址是 7 位元的數字,習慣用十六進位寫:0x3C 和十進位的 60 是同一個數。

暫存器:感測器裡的小表格

每個 I2C 感測器內部都有一組暫存器(register),可以想成一張編了號碼的小表格,每一格存一個位元組: 有的格子放量測結果,有的格子放設定(量測範圍、省電模式…)。哪一格是什麼,要查感測器的規格書(datasheet)。

讀暫存器的步驟是:喊裝置位址 → 告訴它要從第幾號暫存器開始 → 讀回幾個位元組。MicroPython 把這三步包成一個函式:

data = i2c.readfrom_mem(裝置位址, 暫存器編號, 位元組數)   # 回傳 bytes
i2c.writeto_mem(裝置位址, 暫存器編號, bytes([值]))       # 寫入設定

裝置沒有回應時(位址寫錯、線沒接好),會發生 OSError,常見的訊息是 ENODEV。

位元組怎麼變成數字

一個位元組只有 0~255,感測器的讀值常常比這個大,所以會分成兩個位元組傳回來,程式要自己拼起來。 以 TMP102 溫度感測器為例(依 TI 的規格書):溫度暫存器是 0x00,讀 2 個位元組,前 12 個位元是溫度, 每 1 單位代表 0.0625°C:

第 1 個位元組      第 2 個位元組
0001 1001         1000 0000
└──────┬──────────┘└─┬─┘
   12 位元:0001 1001 1000 = 408      後 4 位元不用
   408 × 0.0625 = 25.5°C

用位元運算寫:(data[0] << 4) | (data[1] >> 4)。<< 往左移(乘 2 的次方),>> 往右移,| 把兩段合起來。

逐步看:讀 TMP102 溫度暫存器

模擬中第二次讀取時溫度已經降到零下(像把感測器放進冰箱)。注意第二次收到的位元組, 以及第 12~13 行怎麼把它變成負數。

二補數:位元組裡的負數

位元組本身沒有正負號,感測器用二補數(two's complement)表示負數:最高位元是 1 就代表負數, 把讀到的值減掉 2 的「位元數」次方,就得到真正的值。

位元數 最高位元是 1 的條件 減掉
8 位元 值 ≥ 128 256
12 位元(TMP102) 值 ≥ 2048(raw & 0x800) 4096
16 位元(MPU-6050) 值 ≥ 32768 65536

上一個範例第二次讀到 [252, 192],拼成 4044,大於 2048,所以是 4044 - 4096 = -52,乘 0.0625 是 -3.25°C。 忘了這一步的話,程式會印出 252.75°C,這是讀感測器時很常見的錯誤。

先寫入設定,再讀資料

有些感測器開機時處於睡眠狀態,要先寫暫存器叫醒它。下一個範例的 MPU-6050(三軸加速度計+陀螺儀) 位址是 0x68;依規格書,要先在電源管理暫存器 0x6B 寫入 0,再從 0x3B 開始連讀 6 個位元組, 依序是 X、Y、Z 軸各 2 個位元組(高位在前)。在 ±2g 的量程下,16384 代表 1g(一個重力加速度)。

逐步看:讀 MPU-6050 三軸加速度

模擬的感測器是傾斜放置的,所以重力分到三個軸上。看 to_int16 怎麼把兩個位元組拼成有正負號的 16 位元整數。

互動練習:修好會讀錯的溫度計

起始程式每 0.5 秒讀一次 TMP102,但沒有處理負數。模擬中的溫度會從 4°C 慢慢降到 -4°C。依序完成任務:

  1. 先直接執行,看輸出:溫度降到 0°C 以下時,印出的數字對嗎?
  2. 加上二補數的處理,讓零下的溫度正確印出負數。
  3. 溫度低於 0°C 時,在同一行後面多印「結冰」兩個字。
  4. 回答一個問題。

「輸入設定」的滑桿可以改開始與結束溫度,改完再執行一次看看。

小測驗:匯流排與位址

1.

i2c.scan() 回傳 [60, 104],下面哪一個說法正確?

2.

I2C 匯流排上的每一個裝置,SDA 和 SCL 怎麼接?

3.

下面的程式會印出什麼?

for a in [60, 72, 104]:
    print(hex(a), end=" ")
第 1 次作答

小測驗:位元組換算

1.

下面的程式會印出什麼?

data = bytes([0x01, 0x2C])
v = (data[0] << 8) | data[1]
print(v)
2.

下面的程式會印出什麼?(16 位元的二補數)

v = (0xFF << 8) | 0x38
if v >= 32768:
    v -= 65536
print(v)
3.

MPU-6050 在 ±2g 量程下,Z 軸讀到 8192,代表多少 g?

第 1 次作答

重點整理

  • I2C 用 SCL(時脈)、SDA(資料)兩條線,所有裝置並聯,兩條線都要有上拉電阻;常見速度 100 kHz、400 kHz。
  • 每個裝置有 7 位元位址,i2c.scan() 找出有回應的位址;用 hex() 對照規格書。
  • 感測器的資料與設定放在暫存器:readfrom_mem(位址, 暫存器, 位元組數) 讀、writeto_mem(位址, 暫存器, bytes) 寫。
  • 多個位元組用 <<、| 拼成一個數;最高位元是 1 時減掉 2 的位元數次方,就是二補數表示的負數。
  • 依規格書換算單位:TMP102 每單位 0.0625°C;MPU-6050 在 ±2g 時 16384 代表 1g。

下一課介紹另一種常見的序列通訊:UART,GPS、藍牙序列模組都用它。

這一課完成了!
Next lesson:UART 序列通訊
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。