Raspberry Pi Pico(d_05)DS18B20 1wire 温度センサー(2)
DS18B20 1wire 温度センサー
MAXIM Programmable Resolution 1-Wire Digital Thermometer
DS18B20は1-Wireディジタル温度計です。記事d_04ではds18x20モジュールをインポートで簡単に温度測定が出来ました。
その代わりに1-Wireデバイスの基礎的な把握が出来ませんでした。DS18B20のデータシートにあるROMコマンド、FUNCTIONコマンドの使い方も分かりません。ds18x20モジュールをインポートしないでDS18B20の温度測定をしてみようと思います。接続図や実体図は記事d_04を参照ください。
※開発環境はThonnyです。ThonnyでMicroPythonをRaspberry Pi Pico with RP2040にインストールして使っています。
1-Wireの通信
素人なのであまり詳しくは書けません。雰囲気だけです。
通信方式は
「バスリセット>rom-code(64bit)を送ってデバイスを指定する>実行するコマンドを送る」
でワンセットです。
実行コマンドを送るには
「バスリセット>ROMコマンド>DEVICEコマンド」
でセットです。
ROMコマンドは1-Wireデバイスで共通のようです。そのため同じバス上の複数のデバイスをrom-codeで指定して操作するようです。
DS18B20のデータシートからROMコマンドとDEVICEコマンドを以下に列挙します。詳細はデータシートを参照ください。
ROMコマンド
SEARCH ROM [F0h] バス上デバイスのrom-codeを調べます。
READ ROM [33h] デバイスが1つのならrom-codeを読出しできます。
MATCH ROM [55h] rom-codeでデバイスを指定します。
SKIP ROM [CCh] デバイスが1つならrom-codeを省いてデバイスを指定します。
ALARM SEARCH [ECh] アラーム フラグが設定されたデバイスのみが応答します。
FUNCTION(DEVICE)コマンド
CONVERT T [44h] 温度データをSCRATCHPADに書込む
WRITE SCRATCHPAD [4Eh] SCRATCHPADに3bytes書込む
READ SCRATCHPAD [BEh] SCRATCHPAD 9bytesを読込む
COPY SCRATCHPAD [48h] SCRATCHPADの3bytesをEEPROMにコピーする
RECALL E2 [B8h] EEPROMから3bytesを読込む
READ POWER SUPPLY [B4h] parasite(0)/externally(1)をbitで返す
※3bytes(TH,TL,Config)データ
onewireモジュールを読込みます。class ‘OneWire’があります。Pin(12)で通信します。
ow = onewire.OneWire(Pin(12))
でオブジェクトを作ります。
OneWireには、ROM コマンドのSKIP_ROM、SEARCH_ROM、MATCH_ROMの定数やreset、scan、select_rom、readbit、readbyte、readinto、writebit、write、writebyteのメソッドがあります。
ROM CODEを取得
ROMコマンドのSEARCH_ROM等を使ってデバイスを検索して、全ての1wireデバイスのrom-codeを収集するのですが、素人の私では荷が重いのでscan()で取得します。
スクリプト
スクリプトは以下のようにしました。
pico_ds18b20_01b_rom.py
from machine import Pin
import onewire
## DS18B20 Programmable Resolution 1-Wire Digital Thermometer
# 8-BIT FAMILY CODE DS18B20 (28h)
# GPIO 12 で OneWire バスを作成
ow = onewire.OneWire(Pin(12))
# バス上のrom-codeをリストデータで返す
s=ow.scan() # GPIO 12のデバイスROM
rom_code = s[0] # ここではデバイスは1つだけなのでs[0] 2つ目ならs[1]
family_code=s[0][0] # FAMILY CODEはs[0][0] bytearray(8)の[0]
print('scan data=',s)
print('rom code =',rom_code)
print('family code=', family_code)
実行結果
以下のようになりました。※Thonnyのshellに表示されます。
DS18B20のrom codeは bytearray(b'(\xffe\xf8\x93\x16\x05S’)でした。
pico_ds18b20_01b_rom.py
>>> %Run -c $EDITOR_CONTENT
scan data= [bytearray(b'(\xffe\xf8\x93\x16\x05S')]
rom code = bytearray(b'(\xffe\xf8\x93\x16\x05S')
family code= 40 #hex(40)=0x28
>>>
ちなみに、1wireデバイスがDS18B20しか接続されてなければ、READ_ROM[33h]でもrom codeを取得できます。
※Thonnyのshellで実行
>>> import onewire
>>> buf = bytearray(8)
>>> ow = onewire.OneWire(Pin(12))
>>> ow.reset(True)
True
>>> ow.writebyte(0x33) #READ_ROM = 0x33
>>> ow.readinto(buf)
>>> buf
bytearray(b'(\xffe\xf8\x93\x16\x05S')
>>>
温度測定
DS18B20のSCRATCHPADを読んで温度データから摂氏温度に変換して表示してみます。
スクリプト
スクリプトは以下のようにしました。
pico_ds18b20_02b_temp.py
from machine import Pin
import onewire
import time
#符号計算
def comp(dat,bit_num):
if dat >= (2**(bit_num-1)):
dat=dat-(2**bit_num)
#print(bin(dat), dat, bin(dat & 0xf))
return dat
## DS18B20 Programmable Resolution 1-Wire Digital Thermometer
ow = onewire.OneWire(Pin(12)) # GPIO 12 で OneWire バスを作成
s=ow.scan() # ROMCODE
rom_code = s[0] # デバイスは1つだけなのでs[0]がDS18B20のROMCODE
## ROM COMMANDS
#SEARCH_ROM = 0xF0 #240 (ow.SEARCH_ROMでも可)
#READ_ROM = 0x33
MATCH_ROM = 0x55 # 85 (ow.MATCH_ROMでも可)
#SKIP_ROM = 0xCC # 204(ow.SKIP_ROMでも可)
## DEVICE COMMANDS
CONVERT = 0x44 #CONVERT T [44h]
RD_SCRATCH =0xBE #READ SCRATCHPAD [BEh]
#WR_SCRATCH =0x4E #WRITE SCRATCHPAD [4Eh]
## CONVERT T rom-codeの整合(MATCH_ROM)>整合したデバイスへ送る
ow.reset(True)
ow.writebyte(MATCH_ROM) #ow.MATCH_ROMでも可
ow.write(rom_code) #8bytes
ow.writebyte(CONVERT) #温度データをSCRATCHPADに書込む
time.sleep_ms(750)
## READ SCRATCHPAD レジスタデータ読出し 9bytes
buf = bytearray(9)
#ow.select_rom(rom_code)
ow.reset(True) #select_romはreset~writeと同じ
ow.writebyte(MATCH_ROM)
ow.write(rom_code)
ow.writebyte(RD_SCRATCH) #RD_SCRATCH=0xBE READ SCRATCHPAD
ow.readinto(buf)
print('bytearray(9)=',buf)
## 温度に変換
# SCRATCHPADのbyte0,byte1が温度データ 2bytesを符号付き10bitにする
t_reg=(buf[1] & 0x0f)<<8 | buf[0]
t_dat=comp(t_reg,12) # 符号計算(データ,bit数)
temp=t_dat*0.0625 # config 12bitなら 0.0625/bit
print('temp=',temp)
補足です。
rom_codeを送信してデバイスを指定する以下の部分は、select_rom(rom_code)で置き換えができます。
ow.reset(True)
ow.writebyte(MATCH_ROM)
ow.write(rom_code)
ちなみに1wireデバイスがDS18B20だけなので「## CONVERT T」の部分はrom_codeの送信なし(SKIP_ROM)でも可能です。rom_code取得も不要です。
## CONVERT T
# ow.reset(True)
# ow.writebyte(SKIP_ROM) #ow.SEARCH_ROMでも可
# ow.writebyte(CONVERT)
# time.sleep_ms(750)
実行結果
実行すると以下のようになりました。※Thonnyのshellに表示されます。
SCRATCHPADのデータと温度が表示されています。
pico_ds18b20_02b_temp.py
>>> %Run -c $EDITOR_CONTENT
bytearray(9)= bytearray(b'\xe6\x01 \x15\x7f\xff\x7f\x10\x16')
temp= 30.375
>>>
その他
他のDEVICE(FUNCTION)コードの使用例です。実行例などは省いています。
WRITE SCRATCHPAD
bufで指定した値をSCRATCHPADのTH,TL, Configurationレジスタに書込みします。※TH,TLレジスタはアラームで使うレジスタのようですが、USERレジスタとしても使えるようです。
##WRITE SCRATCHPAD 3bytes
buf = bytearray(3)
buf[0]=0x20 #TH Register
buf[1]=0x15 #TL Register
buf[2]=0x7f #Configuration Register
ow.reset(True)
ow.reset(True)
ow.writebyte(MATCH_ROM)
ow.write(rom_code)
ow.writebyte(0x4e) #WRITE SCRATCHPAD [4Eh]
ow.write(buf)
COPY SCRATCHPAD
SCRATCHPADのTH,TL, Configurationレジスタの値をEEPROMに書込む(保存)します。
## COPY SCRATCHPAD
ow.reset(True)
ow.writebyte(MATCH_ROM)
ow.write(rom_code) #8bytes
ow.writebyte(0x48) #COPY SCRATCHPAD [48h]
time.sleep_ms(10)
RECALL E2
EEPROMからSCRATCHPADのTH,TL, Configurationレジスタに書込みます。
## RECALL E2
ow.reset(True)
ow.writebyte(MATCH_ROM)
ow.write(rom_code) #8bytes
ow.writebyte(0xb8) #RECALL E2 [B8h]
#time.sleep_ms(10)
READ POWER SUPPLY
電源供給の状態を調べます。PARASITEなら(0)外部電源なら(1)を返します。
## Read Power Supply readbit
ow.reset(True)
ow.writebyte(MATCH_ROM)
ow.write(rom_code) #8bytes
ow.writebyte(0xb4) #READ POWER SUPPLY[B4h]
print(ow.readbit()) #parasite(0)/externally(1)
まとめ
Raspberry Pi PicoでMicroPythonを使って1wireデバイスDS18B20での温度測定が出来ました。ds18x20のモジュールのインポートなしでも温度測定が出来ました。
1-Wireデバイスへのコマンド送信は「リセット>ROMコマンド>DEVICEコマンドの繰返し」であることが大まかに分かりました。