1月も中旬ですが新年1発目、明けましておめでとうございます。
今年の抱負は代表作を作ることとその製品化、さらに販売してここのサーバー代くらい捻出したい。。。これ毎回、言ってるな。
さて、屋外に複数配置する環境データ取得デバイスが作りたいものの一つですが、デバイス間の通信を1-Wireにしたいと考え、1-WireをI2C/SPIに変換するIC、DS28E18を試しています。
1-Wireスレーブ-I2C/SPIマスターブリッジデバイスモジュールキット
https://akizukidenshi.com/catalog/g/gK-15790/
現状、まだ使いこなせてませんが、ログだけ残しときます。
内容としては、公式のチュートリアルのコマンドの例をRaspberryPi PicoのMicroPythonでトレースしたっというだけになります。
■ 構成
【デバイス】
・Raspberry Pi Pico
・AE-DS28E18(1-Wireスレーブモジュール)
【配線】
RPi Pico AE-DS28E18 3V3 (36pin)------1WPU(1pin) GP22(29pin)------1WIO(2pin) GND (28pin)------GND (3pin)
チュートリアルの条件としては、温度湿度センサーSHTC3とDS28E18が接続されているべきですが、持っていないのでつけていません。
■ プログラム
下記のしたチュートリアルのI2Cのサンプルコマンドを、MicroPythonで記述しました。
The Basics of Using the DS28E18
https://www.analog.com/en/design-notes/the-basics-of-using-the-ds28e18.html
from machine import Pin
import utime
import onewire
ow = onewire.OneWire(Pin(22))
roms = ow.scan()
rom = roms[0]
def init_step1():
# ダミーの Write GPIO Configuration (83h) コマンドを実行して
# 1-Wire ライン上のすべてのデバイスの一意の ROM ID を入力する
# (結果は無視する)
print('Step1: Sending a dummy Write GPIO Configuration Command------------')
ow.reset()
ow.writebyte(0xCC) # Skip ROM
ow.writebyte(0x66) # Command Start
ow.writebyte(5) # Length Byte
ow.writebyte(0x83) # Write GPIO Configuration
ow.writebyte(0x0B) # Sets Access to the GPIO control Register
ow.writebyte(0x03) # Only value allowed
ow.writebyte(0xA5) # GPIO_CTRL_HI Value
ow.writebyte(0x0F) # GPIO_CTRL_LO Value
ow.writebyte(0x75) # CRC16
ow.writebyte(0x02) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 01: Length Byte
print(hex(ow.readbyte())) # 77:
print(hex(ow.readbyte())) # BE:
print(hex(ow.readbyte())) # 49:
def init_step2():
# ROM コマンドの検索を実行して、バスに接続されている
# 各DS28E18 デバイスを見つける
print('Step2: Search ROM Command to find each DS28E18 device--------------')
roms = ow.scan()
print(roms)
def init_step3():
# Write GPIO Configuration コマンドを発行して、GPIO を既知の状態に設定する
print('Step3: Write GPIO Configuration------------------------------------')
ow.reset()
ow.select_rom(rom)
ow.writebyte(0x66) # Command Start
ow.writebyte(5) # Length Byte
ow.writebyte(0x83) # Write GPIO Configuration
ow.writebyte(0x0B) # Sets Access to the GPIO control Register
ow.writebyte(0x03) # Only value allowed
ow.writebyte(0xA5) # GPIO_CTRL_HI Value
ow.writebyte(0x0F) # GPIO_CTRL_LO Value
ow.writebyte(0x75) # CRC16
ow.writebyte(0x02) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 01: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
print(hex(ow.readbyte())) # 7E: CRC16
print(hex(ow.readbyte())) # 10: CRC16
def init_step4():
# デバイス ステータス コマンドを実行して、
# POR ステータス ビットをクリアする
print('Step4: Device Status Command (Clear POR)---------------------------')
ow.reset()
ow.select_rom(rom)
ow.writebyte(0x66) # Command Start
ow.writebyte(1) # Length Byte
ow.writebyte(0x7A) # Device Status Command
ow.writebyte(0x9F) # CRC16
ow.writebyte(0x93) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 05: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
print(hex(ow.readbyte())) # 02: POR Has occurred
print(hex(ow.readbyte())) # 00: Device Version
print(hex(ow.readbyte())) # E6: CRC16
print(hex(ow.readbyte())) # 0A: CRC16
def init_step5():
# Read Configuration コマンドを実行して、既存のデバイス設定を確認する
print('Step5: Read Configuration Command ---------------------------------')
ow.reset()
ow.select_rom(rom)
ow.writebyte(0x66) # Command Start
ow.writebyte(1) # Length Byte
ow.writebyte(0x6A) # Read Configuration Command
ow.writebyte(0x9E) # CRC16
ow.writebyte(0x5F) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 02: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
print(hex(ow.readbyte())) # 01: Configuration Register Value
print(hex(ow.readbyte())) # E1: CRC16
print(hex(ow.readbyte())) # 5F: CRC16
def init_step6_i2c_1():
# Write Configurationコマンドを実行して、I2C 速度を 1MHz に設定する
# (デフォルトで既にI2C モードに設定されているが、練習として実施)
print('Step6-1: Write Configuration Command to set the I2C speed to 1MHz--')
ow.reset()
ow.writebyte(0xCC) # Skip ROM (With one divice on the bus)
ow.writebyte(0x66) # Command Start
ow.writebyte(2) # Length Byte
ow.writebyte(0x55) # Write Configuration Command
ow.writebyte(0x02) # onfiguration Register
# PROT:I2C INACK:Do not ignore SPD:1MHz
ow.writebyte(0xFE) # CRC16
ow.writebyte(0x26) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 02: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
print(hex(ow.readbyte())) # E1: CRC16
print(hex(ow.readbyte())) # 5F: CRC16
def init_step6_i2c_2():
# Read ConfigurationコマンドでI2C速度が1MHzに設定されているか確認する
print('Step6-2: Read Configuration Command to check the speed is set to 1MHz')
ow.reset()
ow.select_rom(rom) # Match ROM
ow.writebyte(0x66) # Command Start
ow.writebyte(1) # Length Byte
ow.writebyte(0x6A) # Read Configuration Command
ow.writebyte(0x9E) # CRC16
ow.writebyte(0x5F) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 02: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
print(hex(ow.readbyte())) # 02: Configuration Register Value
print(hex(ow.readbyte())) # A1: CRC16
print(hex(ow.readbyte())) # 5E: CRC16
def i2c_step1():
# コマンド シーケンスを構築し、シーケンサーを書き込む
# 1. ウェイクアップ コマンド 0x3517 を送信する
# 2. 測定コマンド 0x5C24 を送信する
# 3. 6 バイトのデータを読み戻す
print('Step1: Build the command sequence and write the sequencer----------')
ow.reset()
ow.writebyte(0xCC) # Skip ROM
ow.writebyte(0x66) # Command Start
ow.writebyte(34) # Length Byte
ow.writebyte(0x11) # Write Sequencer Command
ow.writebyte(0x00) # ADDR_LO
ow.writebyte(0x00) # ADDR_HI
ow.writebyte(0x02) # I2C Start – This is the start of the sequencer data
ow.writebyte(0xE3) # I2C Write Data – DS28E18 Sequencer Command
ow.writebyte(3) # Write Length – Number of Bytes – 3 bytes sent to the SHTC3
# i2c command
ow.writebyte(0xE0) # SHTC3 I2C Write Address
ow.writebyte(0x35) # SHTC3 Wakeup Command byte 1
ow.writebyte(0x17) # SHTC3 Wakeup Command byte 2
# -----
ow.writebyte(0x03) # I2C Stop
ow.writebyte(0xDD) # DS28E18 Delay Command – SHTC2 Wakeup Delay
ow.writebyte(0x00) # 1ms delay
ow.writebyte(0x02) # I2C Start – This is the start of the sequencer data
ow.writebyte(0xE3) # I2C Write Data – DS28E18 Sequencer Command
ow.writebyte(3) # Write Length – Number of Bytes – 3 bytes sent to the SHTC3
# i2c command
ow.writebyte(0xE0) # SHTC3 I2C Write Address
ow.writebyte(0x5C) # Measure Command byte 1
ow.writebyte(0x24) # Measure Command byte 1
# -----
ow.writebyte(0x03) # I2C Stop
ow.writebyte(0xDD) # DS28E18 Delay Command – SHTC2 Measurement Delay
ow.writebyte(0x04) # 16ms delay
ow.writebyte(0x02) # I2C Start – This is the start of the sequencer data
ow.writebyte(0xE3) # I2C Write Data – DS28E18 Sequencer Command
ow.writebyte(1) # Write Length – Number of Bytes – 1 byte will be sent to the SHTC3
# i2c command
ow.writebyte(0xE1) # SHTC3 I2C Read Address
# -----
ow.writebyte(0xD4) # DS28E18 I2C Read Data Command
ow.writebyte(0x06) # Number of Bytes to Read
ow.writebyte(0xFF) # Place holder for Byte 1 – DS28E18 will read the data back and put it in here
ow.writebyte(0xFF) # Place holder for Byte 2
ow.writebyte(0xFF) # Place holder for Byte 3
ow.writebyte(0xFF) # Place holder for Byte 4
ow.writebyte(0xFF) # Place holder for Byte 5
ow.writebyte(0xFF) # Place holder for Byte 6
ow.writebyte(0x03) # I2C Stop
ow.writebyte(0x9E) # CRC16
ow.writebyte(0x5F) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 01: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
print(hex(ow.readbyte())) # 7E: CRC16
print(hex(ow.readbyte())) # 10: CRC16
def i2c_step2():
# Read Sequencer コマンドを発行して、データを読み戻す
print('Step2: Read Sequencer Command to read back the data----------------')
ow.reset()
ow.writebyte(0xCC) # Skip ROM
ow.writebyte(0x66) # Command Start
ow.writebyte(3) # Number of Bytes
ow.writebyte(0x22) # Read Sequencer Command
ow.writebyte(0x00) # ADDR_LO
ow.writebyte(0x3E) # SLEN:ADDR_HI
ow.writebyte(0xD6) # CRC16
ow.writebyte(0x69) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 20: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
datablock = ''
for i in range(31):
datablock += hex(ow.readbyte())
print(datablock)
print(hex(ow.readbyte())) # 14: CRC16
print(hex(ow.readbyte())) # F1: CRC16
def i2c_step3():
# Run Sequencer コマンドを発行して、シーケンスを実行する
#(シーケンサーが正しく構築されていない場合、このコマンドはエラーになる)
print('Step3: Run Sequencer Command to execute the sequence---------------')
ow.reset()
ow.writebyte(0xCC) # Skip ROM
ow.writebyte(0x66) # Command Start
ow.writebyte(0x04) # Number of Bytes
ow.writebyte(0x33) # Read Sequencer Command
ow.writebyte(0x00) # ADDR_LO
ow.writebyte(0x3E) # SLEN_LO:ADDR_HI
ow.writebyte(0x00) # SLEN_HI
ow.writebyte(0xD6) # CRC16
ow.writebyte(0x69) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 01: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
print(hex(ow.readbyte())) # 14: CRC16
print(hex(ow.readbyte())) # F1: CRC16
def i2c_step4():
# 読み取りシーケンサー コマンドを発行して、DS28E18 シーケンサー アドレス
# 0x0018 ~ 0x001D から格納された湿度と温度のデータを読み取る
print('Step4: Read Sequencer Command to read back the stored data---------')
ow.reset()
ow.writebyte(0xCC) # Skip ROM
ow.writebyte(0x66) # Command Start
ow.writebyte(0x03) # Number of Bytes
ow.writebyte(0x22) # Read Sequencer Command
ow.writebyte(0x18) # ADDR_LO
ow.writebyte(0x0C) # SLEN:ADDR_HI
ow.writebyte(0xD6) # CRC16
ow.writebyte(0x69) # CRC16
ow.writebyte(0xAA) # Release Byte
utime.sleep_ms(10)
print(hex(ow.readbyte())) # FF: Dummy Byte
print(hex(ow.readbyte())) # 07: Length Byte
print(hex(ow.readbyte())) # AA: Result Byte - Success
datablock = ''
for i in range(6):
datablock += hex(ow.readbyte())
print(datablock) # [73][CB][3A][65][38][DF]
print(hex(ow.readbyte())) # 14: CRC16
print(hex(ow.readbyte())) # F1: CRC16
def setup():
init_step1()
init_step2()
init_step3()
init_step4()
init_step4()
init_step5()
init_step6_i2c_1()
init_step6_i2c_2()
i2c_step1()
i2c_step2()
def measure():
i2c_step3()
i2c_step4()
def main():
setup()
for i in range(10):
measure()
utime.sleep(1)
if __name__ == '__main__':
main()
温度湿度センサーSHTC3はもっていないので、i2c_step3以降がちゃんと実行できるかは試していません。
それまでのコマンドはDS28E18からは成功を返してくるので、操作は出来ていると思ってます。
コマンドを変えて、手持ちのI2C温度湿度センサーDHT20との通信を試みましたが、今だ成功していません。
既にノーアイディアでできる気がしませんが、2本線で長距離、並列接続可能というのは諦めきれない。。。もうちょい粘ってデータシートを熟読してみよう。。。
