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本線で長距離、並列接続可能というのは諦めきれない。。。もうちょい粘ってデータシートを熟読してみよう。。。