How to add (and remove) Tmp102 sensor to Raspberry Pi 4

(註: 此圖截自SparkFun文章: Python Programming Tutorial: Getting Started with the Raspberry Pi, 本文的接線方式和此相似, 只是GND接到Pin 9, 而不是Pin 6, 因為Pin 6被散熱風扇佔走! )

將TMP102温度感測器連接到Raspberry Pi (R-pi), 之後就可以利用R-pi來監測環境温度。只是簡單的把環境温度記錄到log檔, 或者儲存到雲端讓人們隨時可透過網路查詢; 或者加上觸發條件在温度高於或低於特定值時可進行通知的動作。這些都是可以做的。本文先嘗試踏出第一步, 將TMP102接上R-pi, 讓系統可以存取其感測到的温度值, 也讓我們可以寫Python程式來存取温度值。

Raspberry Pi temperature sensor using TMP102這篇貼文, 其實就在說明如何將TMP102連接到R-pi, 但因為Raspberry Pi出來很多年了, 出的板子種類也很多(2, 3, 4, Zero, Zero 2, etc), 同樣的在其上跑的OS也很多, 有官方的Raspberry Pi OS, Ubuntu, Freebsd, 等等。所以, 這文章以現在來說,有一些需要小修改的地方。

本文針對Raspberry Pi 4B, 使用官方Raspberry OS 64bit的環境,嘗試加入TMP102,基於以上所提文章做一些補充。

先進行以下設定:

1. Enable I2C

$ sudo raspi-config


選3 Interface Options


然後選I5 I2C, 接下來會問你要enable I2C嗎? 選是.

往下記得重開機!

2. 安裝以下套件:

$ sudo apt-get install lm-sensors   (出現一些問題, 但不用管它!)

$ sudo apt-get install i2c-tools


==================

硬體接線

==================

TMP102模塊上的4支腳(VCC, SDA, SCL, GND), 分別接到Raspberry Pi GPIO的(1,3,5,9), 如上圖, 都在上面左方, 我打勾的4個腳位。記得接線前, 先把Raspberry Pi關機, 拔掉電源, 再接。

重開機後, 下i2cdetect -y 1指令:

可以看到有scan 到0x48這個位址, 這就是TMP102的I2C slave address. 如此就成功了, 基本上硬體已經被認到了。

接下來, 照著前面提到的文章的作法做:
$ echo tmp102 0x48 > /sys/class/i2c-adapter/i2c-1/new_device
結果出現錯誤訊息, 基本上沒有寫入的權限! 用ls -l 指令查看此檔, 發現預設只有root才有寫入的權限, 但即使在echo 之前加入sudo, 也沒用! 後來用以下指令解決:
$ sudo chmod 666 /sys/class/i2c-adapter/i2c-1/new_device
然後再下:
$ echo tmp102 0x48 > /sys/class/i2c-adapter/i2c-1/new_device
就可以了!

現在可以使用sensors指令:

可以看到除了原來CPU的温度(上圖的30.7 C)外, 多出了一個tmp102-i2c-1-48的温度(上圖的24.7 C)。

但是此時下i2cdetect -y 1指令, 會發現原來的48變成UU, 也就是被系統使用! 此時, 你如果使用Python程式去取得TMP102的温度值, 會發現出現資源被佔用的錯誤。即使你把TMP102拔走, 再插回來, 也沒有用! 



解決方法, 就是下指令把它移除:
$ sudo chmod 666 /sys/class/i2c-adapter/i2c-1/delete_device
$ echo 0x48 > /sys/class/i2c-adapter/i2c-1/delete_device

(這裡我google不到有人提到應該怎麼做,但我想應該和加入新設備的方式差不多,所以嘗試可能的指令後試出來的!
圖中圈起來部份, 就是錯誤嘗試的部份! )

這樣, 再下i2cdetect -y 1指令, 或sensors指令, 就會看到沒有加入TMP102 sensor之前的狀態。此時用Python程式去讀TMP102温度值, 也會正常。

以下Python程式, 由TMP102 sensor and Raspberry Pi python example貼文取得, 可讀取TMP102温度值, 原貼文格式和一些文字亂掉, 在此有做一些修正。(註:後來發現,這支Python程式在SparkFun文章:Python Programming Tutorial: Getting Started with the Raspberry Pi就有一模一樣的, 真是天下文章一大抄!)

import time
import smbus

i2c_ch = 1

# TMP102 address on the I2C bus
i2c_address = 0x48

# Register addresses
reg_temp = 0x00
reg_config = 0x01

# Calculate the 2’s complement of a number
def twos_comp(val, bits):
    if (val & (1 << (bits - 1))) != 0:
        val = val - (1 << bits)
    return val

# Read temperature registers and calculate Celsius
def read_temp():
    # Read temperature registers
    val = bus.read_i2c_block_data(i2c_address, reg_temp, 2)
    temp_c = (val[0] << 4) | (val[1] >> 5)

    # Convert to 2s complement (temperatures can be negative)
    temp_c = twos_comp(temp_c, 12)

    # Convert registers value to temperature (C)
    temp_c = temp_c * 0.0625

    return temp_c

# Initialize I2C (SMBus)
bus = smbus.SMBus(i2c_ch)

# Read the CONFIG register (2 bytes)
val = bus.read_i2c_block_data(i2c_address, reg_config, 2)
print("Old CONFIG:", val)

# Set to 4 Hz sampling (CR1, CR0 = 0b10)
val[1] = val[1] & 0b00111111
val[1] = val[1] | (0b10 << 6)

# Write 4 Hz sampling back to CONFIG
bus.write_i2c_block_data(i2c_address, reg_config, val)

# Read CONFIG to verify that we changed it
val = bus.read_i2c_block_data(i2c_address, reg_config, 2)
print("New CONFIG:", val)

# Print out temperature every second
while True:
    temperature = read_temp()
    print(round(temperature, 2), "C")
    time.sleep(1)
為什麼自已寫Python程式讀取TMP102的温度值要寫這麼多代碼? 但用sensors指令, 卻只要找到I2C slave address並寫入/sys/class/i2c-adapter/i2c-1/new_device這個特定的檔案, 然後sensors指令就可以正確的解讀出温度值來呢? 

一定有小精靈在背後幫忙做這個換算的工作, 否則sensors指令怎麼知道要讀取那個暫存器, 然後要左移或右移幾位, 接著還要做2的補數, 再乘以某個數呢? 這個小精靈就是Kernel space driver for TMP102!

反過來說, 我拿BOSCH BME280感測器, 同樣以I2C接線方式連接, 再下i2cdetect -y 1, 也可以看到有scan到0x76這個位址。那麼依照上文所提方法, 下指令:
$ echo bme280 0x76 > /sys/class/i2c-adapter/i2c-1/new_device
是成功了, 沒有錯誤訊息! 但下sensors指令, 卻沒看到有多出bme280的數值!
下lsmod查看:

圖中圈起來部份, 顯示系統有抓到裝置, 但是卻將之視為BMP280, 這一顆只有壓力和温度感測沒有溼度, 而且顯然和BME280不太相容! 所以系統讀不到數值。

那麼如果就是想使用BME280, 然後要讓sensors指令可以讀到它的數值呢? 烏克蘭朋友Eduard Malokhvii, 為BME280寫了Kernel space driver, 有興趣的朋友可以試試: Kernel space driver for Bosch Sensortec BME280

留言

這個網誌中的熱門文章

D-BUS學習筆記

Cisco Switch學習筆記: EtherChannel

Cisco Switch學習筆記: interface的封包錯誤統計