1 概要
1-Wireは、Maxim Integrated(現アナログ・デバイセズ)が開発した、1本の信号線と接地線(GND)だけで通信と電力供給の両方を実現する独自の低速シリアル通信規格です。
今回はDS18B20と言うデジタル温度計をRISC-V系のMPUで使用するために調査してみた。
今回はDS18B20と言うデジタル温度計をRISC-V系のMPUで使用するために調査してみた。
2 特徴

2.1 配線が簡素
信号線とGNDのわずか2本の配線で通信可能。
配線を2本に出来るのは、データラインを通じて通信だけでなく、デバイスの動作に必要な電力も供給できる。
通信線で電源を供給できない場合は、電源供給用の線が1本増え合計3本の線が必要となる。
配線を2本に出来るのは、データラインを通じて通信だけでなく、デバイスの動作に必要な電力も供給できる。
通信線で電源を供給できない場合は、電源供給用の線が1本増え合計3本の線が必要となる。
2.2 遠距離の通信が可能
500メートル程度までの長距離通信をリピーター不要で実現できる。
2.3 複数機器の接続
通信ラインには1つのマスターデバイスに対して、複数のスレーブデバイスを並列に接続できる。
2.4 デバイス信頼上の注意点
スレーブディバイスには64bitの固有の登録番号を持っている。
8bitのファミリーコードと48bitの固有コードを持っているので無限に接続しても識別が可能となっている
現在上記コードの管理は (Dallas Semiconductor→Maxim Integrated→) Analog Devices で行っている。
私は Analog Devices 社の製品か確認する方法がわからないので、デバイスを使用する場合はコードを必ず確認することにする。
8bitのファミリーコードと48bitの固有コードを持っているので無限に接続しても識別が可能となっている
現在上記コードの管理は (Dallas Semiconductor→Maxim Integrated→) Analog Devices で行っている。
非正規品のデバイスを購入した場合はこのコードが重複している可能性が有るため、3項で説明した 複数のデバイスが接続できない可能性が発生するので正規品の購入が必要。
私は Analog Devices 社の製品か確認する方法がわからないので、デバイスを使用する場合はコードを必ず確認することにする。
3 64bit ROMコード
3.1 コードの構造
DS18B20のデータシートには

と記載されていた。

と記載されていた。
3.2 各コード概要
3.2.1 8bit CRC
次以降に説明する56bitの巡回冗長検査 CRC を行いこの8bitに収めます。
多項式関数は CRC = X8 + X5 + X4 + 1
多項式関数は CRC = X8 + X5 + X4 + 1
3.2.2 48bit 固有コード
48bitで表すことが出来る10進数値は 280兆 らしいので、280兆個の識別が出来る。
3.2.3 8bit ファミリーコード
ファミリーコード例
| コード | 品 番 例 | 用 途 |
|---|---|---|
| 0x01 | DS2401, DS1990A | シリコンシリアルナンバー (ROM IDのみ) |
| 0x04 | DS2431 | 1Kb EEPROM |
| 0x06 | DS2406, DS2407 | I/Oエキスパンダ、スイッチ |
| 0x10 | DS18S20, DS1820 | 温度センサー |
| 0x12 | DS2438 | スマートバッテリーモニター、湿度センサー |
| 0x23 | DS2416 | デュアルチャンネルアドレサブルスイッチ |
| 0x26 | DS2760 | バッテリーパックモニター |
| 0x28 | DS18B20, MAX31826 | 高分解能温度センサー |
| 0x30 | DS2413 | デュアルチャンネルPIO |
| 0x81 | DS28E01 | 1Kb ECC EEPROMセキュア認証 |
4 データ並び
4.1 データの格納方法
1-Wireはリトルエンディアン(Little Endian)を採用していると思われる。
1-WireのEPROMはリトルエンディアンだと言うことをGoogle AIで確認した。
| Little Endian | Big Endian | |
|---|---|---|
| 格納順位 | データの最下位バイトが先頭アドレスに格納される。 | データの最上位バイトが先頭アドレスに格納される。 |
| 例 0x12345678 | メモリ上では 78 56 34 12 の順に格納される。 | メモリ上では 12 34 56 78 の順に格納される。 |
| 採用例 | Intel系 (x86) やARM。現在の一般的なPCやサーバーの多く。 | かつての大型汎用機、ネットワークプロトコル (TCP/IP)。 |
4.2 シリアル通信のビット順番
ビット順番はLSBファーストと思われる。
データシートなどに記載が無いが、DS18B20のROMコードを読んだ場合は最初にファミリーコードでLSB値が先頭になっていた。
次に送られてきたデータは固有コード、CRC値の順だった。
5 基本通信手順
通信手順は(マスターから見て)
1.初期化
2.コマンド送信
3.データ受信
ここではデータシートを読んで私なりに理解したものを書いているので、間違っていたらお教えください。
この信号を RESET AND PRESENCE PULSES と言う。
(1)リセット信号 T0 500(us)とする。
マスターから最初にこの期間 Lo 信号を出力する。
DS18B20では最小480(us)から余裕をみる。
(2)プレゼンス信号待ち時間
マスターのリセット復帰からスレーブのプレゼンス信号を送信するまでの待ち時間 15〜60(us)
この間はバスは Hi 状態。
(3)プレゼンス信号
(4)プレゼンス信号確認時間 T1 90(us)とする。
(5)次信号までの待ち時間 T3 410(us)とする。
この信号を書き込みスロットと言っている。
私は下記のように時間を決めている。
(1)データ送信開始信号 TSO 2(us) とする。
(2)スレーブデータ読出し時間
(4)マスターのデータ送信 TS5 60(us) とする。
(5)次信号までの待ち時間 TREC 2(us) とする。
この信号を読み込みスロットと言っている。
私は下記のように時間を決めている。
(1)データ受信開始信号 TRO 2(us) とする。
(2)スレーブデータ送信
(3)スレーブデータ信号確認時間 TR3 6(ns)とする
(4)読み込みデータ待ち時間 TR4 56(ns)とする。
(5)次信号までの待ち時間 TREC 2(us) とする。
1.初期化
2.コマンド送信
3.データ受信
ここではデータシートを読んで私なりに理解したものを書いているので、間違っていたらお教えください。
5.1初期化
(1)リセット信号 T0 500(us)とする。
マスターから最初にこの期間 Lo 信号を出力する。
DS18B20では最小480(us)から余裕をみる。
(2)プレゼンス信号待ち時間
マスターのリセット復帰からスレーブのプレゼンス信号を送信するまでの待ち時間 15〜60(us)
この間はバスは Hi 状態。
(3)プレゼンス信号
スレーブ機器が反応して 60〜240(us)の間 Lo 信号を出力する。
(4)プレゼンス信号確認時間 T1 90(us)とする。
マスターがリセット信号を出し終わってから 上記期間後にバス電圧を確認する。
正常なら Lo である。
T1 = tPDHIGH(max) + (tPDLOW(min) / 2) ≒90(us) とした。
正常なら Lo である。
T1 = tPDHIGH(max) + (tPDLOW(min) / 2) ≒90(us) とした。
(5)次信号までの待ち時間 T3 410(us)とする。
マスターがリセット信号を出し終わってからの時間。
DS18B20では tRSTH > 480(us)になっており、 T3 = tRSTH(480) ー T1(90) + α(20)
DS18B20では tRSTH > 480(us)になっており、 T3 = tRSTH(480) ー T1(90) + α(20)
5.2コマンド送信 Write Time Slot
私は下記のように時間を決めている。
(1)データ送信開始信号 TSO 2(us) とする。
マスターからスレーブに対し書き込むデータを送るということを知らせるための信号だ。
マスターが 1(us) 以上 Lo 信号を出力することになっているので余裕をみた。
マスターが 1(us) 以上 Lo 信号を出力することになっているので余裕をみた。
(2)スレーブデータ読出し時間
マスターが Lo 信号をだしてから15(us)〜60(us)の間で読み出している。
DS18B20では標準的な読み出し時間は 30(us) と記載があった。
DS18B20では標準的な読み出し時間は 30(us) と記載があった。
(4)マスターのデータ送信 TS5 60(us) とする。
DS18B20のTS1〜TS3の値から TS5 = TS1 + TS2 + TS3 -TR0 = 58(us)
なおデータとして bit値 0 でバス電圧 Lo 、bit値 1 でバス電圧 Hi の信号となる。
なおデータとして bit値 0 でバス電圧 Lo 、bit値 1 でバス電圧 Hi の信号となる。
(5)次信号までの待ち時間 TREC 2(us) とする。
TREC は TS0 と同じ考え方で 2(us)とするが、マスターで処理が遅れた場合は最大時間として60(us)とする。
DS18B20には次のデータを送るまでの時間として最大 ∞ と書いている。
しかし私は最大 60(us) としてプログラムする。
DS18B20には次のデータを送るまでの時間として最大 ∞ と書いている。
しかし私は最大 60(us) としてプログラムする。
5.3データ受信 Read Time Slot
私は下記のように時間を決めている。
(1)データ受信開始信号 TRO 2(us) とする。
マスターからスレーブに対し読み込むデータを送ってくれということを知らせるための信号だ。
マスターが 1(us) 以上 Lo 信号を出力することになっているので余裕をみた。
マスターが 1(us) 以上 Lo 信号を出力することになっているので余裕をみた。
(2)スレーブデータ送信
スレーブはデータbit値が 0 の場合、マスターの開始信号(Lo)を1(us)程度で確認しすぐ、バスの Lo 状態に途切れなくデータ信号(Lo)を出している。
これはDS18B20の信号により確認ができた。
この後スレーブのデータ信号が復帰する時間はマスターがLo信号を出してから 15(us)〜60(us)となっている。
なおスレーブのデータとしてマスターと同じ bit値 0 は Lo、bit値 1 は Hi の信号となる。
これはDS18B20の信号により確認ができた。
この後スレーブのデータ信号が復帰する時間はマスターがLo信号を出してから 15(us)〜60(us)となっている。
なおスレーブのデータとしてマスターと同じ bit値 0 は Lo、bit値 1 は Hi の信号となる。
(3)スレーブデータ信号確認時間 TR3 6(ns)とする
スレーブのデータ最小復帰時間の前に検出する必要がある。
TR3 = (TR1 / 2) ー TR0 = 5(us)とする。
TR3 = (TR1 / 2) ー TR0 = 5(us)とする。
(4)読み込みデータ待ち時間 TR4 56(ns)とする。
マスターがスレーブデータを読み込んだ後、スレーブがデータ送信復帰最大時間を待つ時間。
TR4 = TR1 + TR2 ー TR0 ー TR3 = 52(us)から余裕をとる。
TR4 = TR1 + TR2 ー TR0 ー TR3 = 52(us)から余裕をとる。
(5)次信号までの待ち時間 TREC 2(us) とする。
TREC は TS0 と同じ考え方で 2(us)とするが、マスターで処理が遅れた場合は最大時間として60(us)とする。
DS18B20には次のデータを送るまでの時間として最大 ∞ と書いている。
しかし私は最大 60(us) としてプログラムする。
DS18B20には次のデータを送るまでの時間として最大 ∞ と書いている。
しかし私は最大 60(us) としてプログラムする。
6 その他通信手順
6.1 ROM検索
DS18B20の場合:SEARCH ROM [0xF0] となっているが、全ての1-Wireスレーブが当てはまるか確認していない。
参考URLは1-Wire 検索アルゴリズム
私が解釈した概略フローは
参考URLは1-Wire 検索アルゴリズム
私が解釈した概略フローは
[1]マスターから初期化コマンドを送信(6.1.1参照)
↓
[2]マスターから検索コード[0xF0]を送信(6.1.2参照)
↓
[3]各スレーブから自分のRomCodeのLSB+N(N=繰返し数で最初は0)値を送信
※[5]から来た場合は[4]のRomCodeと同じ場合にLSB+Nのコード値を送信する。
1回目は各スレーブから自分のコードを送信
2回目は各スレーブから自分のコードを反転して送信
この2回の信号により先の4種類を検出する。(6.1.3項参照)
↓※[5]から来た場合は[4]のRomCodeと同じ場合にLSB+Nのコード値を送信する。
1回目は各スレーブから自分のコードを送信
2回目は各スレーブから自分のコードを反転して送信
この2回の信号により先の4種類を検出する。(6.1.3項参照)
[4]マスター側で決定したLSB+N(N=繰返し数で最初は0)の値を送信(6.1.4参照)
↓
[5]最後のROM Code bit(64)まで[3]へ繰り返す(6.1.5参照)
6.1.1 初期化
6.1.2 コマンド送信1Byte (0X0F)
5.2 コマンド送信 Write Time Slot × 8bit を使用して送信
6.1.3 コマンド受信 :2bit
5.3 データ受信 Read Time Slot × 2nbit を使用して受信
BUSに接続されている各スレーブから自分のRomCodeが同時にファミリーコードのLSBから順に最後のCRC MSBまで送信されるが
各スレーブには4種類の状態があり1回の答えでは判らないため2回=2bitの信号送ることにしている。
BUSに接続されている各スレーブから自分のRomCodeが同時にファミリーコードのLSBから順に最後のCRC MSBまで送信されるが
各スレーブには4種類の状態があり1回の答えでは判らないため2回=2bitの信号送ることにしている。
1回目
しかし、信号には2値(電圧Loと電圧Hi)しか無いので、4種類を区別することができない。 このため2回目には各スレーブから自分のコードを反転して送信
1回目の値と2回目の値を組み合わせることにより4種類に別ける事ができるようになる。
これをbit値として判りやすく順に並べた表にすると
| スレーブの値 | Bus電圧 | マスターが取得する値 |
| 全て0 | Lo | 0 |
| 全て1 | Hi | 1 |
| 0と1が混在 | Lo | 0 |
| 対象なし | Hi | 1 |
しかし、信号には2値(電圧Loと電圧Hi)しか無いので、4種類を区別することができない。 このため2回目には各スレーブから自分のコードを反転して送信
| スレーブの値 | Bus電圧 | マスターが取得する値 |
| 全て0 | Hi | 1 |
| 全て1 | Lo | 0 |
| 0と1が混在 | Lo | 0 |
| 対象なし | Hi | 1 |
1回目の値と2回目の値を組み合わせることにより4種類に別ける事ができるようになる。
| スレーブの値 | マスターが取得する値 | |
| 1回目 | 2回目 | |
|---|---|---|
| 全て0 | 0 | 1 |
| 全て1 | 1 | 0 |
| 0と1が混在 | 0 | 0 |
| 対象なし | 1 | 1 |
これをbit値として判りやすく順に並べた表にすると
| Bit(1) | Bit(2) | 内容 |
|---|---|---|
| 0 | 0 | 関係するROM番号の現在のビット位置には0と1の両方があります。 |
| 0 | 1 | 参加する ROM 番号のビットには 0 のみがあります。 |
| 1 | 0 | 参加する ROM 番号のビットには 1 のみが含まれます。 |
| 1 | 1 | 検索に参加しているデバイスはありません。 |
6.1.4 6.1.3項の2bitデータを確認して処理
11なら
00,01,10なら
最初の64bitROMコードのLSBなら:検索コマンド終了処理[正常終了]
以外なら:検索コマンド終了処理 [異常(途中でスレーブが消えた)処理]
以外なら:検索コマンド終了処理 [異常(途中でスレーブが消えた)処理]
00,01,10なら
00の場合は種類のスレーブがいるので、どれでも選択しても良いがここではb0 値とする
b1のスレーブは次の初期化まで沈黙する。
該当する最初のbit値を64bitROMコードのデータに加える。
b1のスレーブは次の初期化まで沈黙する。
該当する最初のbit値を64bitROMコードのデータに加える。
上記bit値をコマンド送信 マスター:1bit bx値
5.2 コマンド送信 Write Time Slot × 1 を使用して送信6.1.5 64bitROMコード完成か確認
未完なら63bit分は3項へループ処理
64bit分終わったら
64bitROMコードをEEPROMの配列へ記録する。
スレーブの接続制限個数内なら
64bit分終わったら
64bitROMコードをEEPROMの配列へ記録する。
スレーブの接続制限個数内なら
1項 初期化へ戻る
スレーブの接続個数制限値なら検索コマンド終了処理[制限値である処理]6.1.6 具体的なプログラム内容
(1)プログラム変数
(2)エラーコード
(3)プログラム説明
| 型名 | 変数名 | 初期値 | 説明 |
|---|---|---|---|
| uint8_t | FamilyCode | 0x28 | DS18B20のファミリーコード |
| uint8_t | dfSlaveMax | 8 | スレーブの最大接続数 |
| uint8_t | SearchRomSlaveNo | 0 | サーチromCodeしているスレーブNo(No=最大dfSlaveMax) |
| uint8_t | bitPos[SearchRomSlaveNo] | 0 | ROM Codeが決まっているbit位置0~63 LSB=0 |
| uint64_t | RomCode64[SearchRomSlaveNo] | 0 | スレーブのRomCode |
| uint8_t | SlaveValue | 0 | サーチしたスレーブ数-1 |
| uint64_t | RomCodeD | 0 | 1次RomCode |
| uint64_t | bit1 | 0 | First受信データ 最大64bitシフトをするためuint64_t |
| uint8_t | bit3 | 0 | Second受信データ |
| uint8_t | bit2 | 0 | LSB+1=bit1、LSB=bit3 6.1.3参照 |
| uint8_t | errcode | 0 | エラーコード |
(2)エラーコード
| エラーコード | 説明 |
|---|---|
| 0b00000001 | 接続が無い |
| 0b00000010 | bit2=3 検索に参加しているデバイスが無い |
(3)プログラム説明
SlaveValue = 0 ; //スレーブ数クリア:初期値
RomCode64[0 ~ dfSlaveMax-1] = 0; //全スレーブROM Codeのクリア
RomCode64[0]=FamilyCode;//最初のスレーブ検索にファミリーコード条件を入力
bitPos[0]=7;//最初のスレーブROMCodeの決定しているbitポジション(ファミリーコード 8Bit-1= 7 )設定
while ( SearchRomSlaveNo < dfSlaveMax )
//以下内容をスレーブ最大数まで繰り返す
return errcode;
RomCode64[0 ~ dfSlaveMax-1] = 0; //全スレーブROM Codeのクリア
RomCode64[0]=FamilyCode;//最初のスレーブ検索にファミリーコード条件を入力
bitPos[0]=7;//最初のスレーブROMCodeの決定しているbitポジション(ファミリーコード 8Bit-1= 7 )設定
while ( SearchRomSlaveNo < dfSlaveMax )
//以下内容をスレーブ最大数まで繰り返す
●RESET AND PRESENCE PULSE
RomCodeD = 0;
●Write Time Slot 0xF0 (SearchROM)
for( i1 = 0 ; i1 < 64 ; ++i1 )
// 以下内容を64回繰り返す:最初のbitはLSBから始まる。
if( SearchRomSlaveNo == SlaveValue ){ break; }
++SearchRomSlaveNo;
end_loop:RomCodeD = 0;
●Write Time Slot 0xF0 (SearchROM)
for( i1 = 0 ; i1 < 64 ; ++i1 )
// 以下内容を64回繰り返す:最初のbitはLSBから始まる。
●Read Time Slot bit1
●Read Time Slot bit3
bit2 = bit1➡LBS+1、bit3➡LSB
if ( bitPos[SearchRomSlaveNo] >= i1)
●Write Time Slot bit1
RomCode64[SearchRomSlaveNo]=RomCodeD;●Read Time Slot bit3
bit2 = bit1➡LBS+1、bit3➡LSB
if ( bitPos[SearchRomSlaveNo] >= i1)
bit1 = (RomCode64[SearchRomSlaveNo] >> i1) & 0x01;
//決まっているbitポジションならマスターが送信するbitを決まっているコードにする。
else
switch(bit2)
//決まってないなら、スレーブのデータを解析する。
RomCodeD |= bit1 << i1; //bitデータを64bitデータへ入力//決まっているbitポジションならマスターが送信するbitを決まっているコードにする。
else
switch(bit2)
//決まってないなら、スレーブのデータを解析する。
case 0x00: //他にCodeが有り:
if ( SlaveValue < dfSlaveMax - 1 )
//スレーブが制限1個前を超えない(追加しても良い)場合の処理
case 0x03: //対象がいなくなった処理//スレーブが制限1個前を超えない(追加しても良い)場合の処理
++SlaveValue; //RomCodeスレーブ数を+1(検索スレーブを追加)
RomCode64[SlaveValue] = RomCodeD ; //今までのRomCodeを追加するスレーブにコピー
RomCode64[SlaveValue] |= 1UUL << i1 ;//マスターが決定する値と反対の値を入れる
bitPos[SlaveValue] = i1 ; //追加したスレーブの決定したbil数を入れる
RomCode64[SlaveValue] = RomCodeD ; //今までのRomCodeを追加するスレーブにコピー
RomCode64[SlaveValue] |= 1UUL << i1 ;//マスターが決定する値と反対の値を入れる
bitPos[SlaveValue] = i1 ; //追加したスレーブの決定したbil数を入れる
RomCode64[SearchRomSlaveNo] = 0;
errcode = 0x02;
goto end_loop;
errcode = 0x02;
goto end_loop;
●Write Time Slot bit1
if( SearchRomSlaveNo == SlaveValue ){ break; }
++SearchRomSlaveNo;
return errcode;
6.1.7 動作確認
テスト状況
右図はオシロ波形 ➡
水色線が 1-Wire (DS18B20)の信号
赤色線が1-Wire の 1bit信号で 値が1 のときにHiになる。
青色線が1-Wire の 1bit分の信号でその間はHiになっている。
全8スレーブの検索で 133(ms) かかっている。
1スレーブ分の拡大オシロ波形
水色線について(左側から)
・RESET AND PRESENCE PULSE
・Write Time Slot 0xF0
・下記信号が64
・スレーブ信号 2
・マスター決定信号 1
もう少し拡大信号
以上です!(続きは CH32V test_ModBusで応用例を記載する。
右図はオシロ波形 ➡
水色線が 1-Wire (DS18B20)の信号
赤色線が1-Wire の 1bit信号で 値が1 のときにHiになる。
青色線が1-Wire の 1bit分の信号でその間はHiになっている。
全8スレーブの検索で 133(ms) かかっている。
1スレーブ分の拡大オシロ波形水色線について(左側から)
・RESET AND PRESENCE PULSE
・Write Time Slot 0xF0
・下記信号が64
・スレーブ信号 2
・マスター決定信号 1
もう少し拡大信号
以上です!(続きは CH32V test_ModBusで応用例を記載する。