ENGLISH 简体中文 日本語 한국어  


アプリケーションノート120

1-Wireマスタを介した通信

要約:このアプリケーションノートでは、実際の例を示すため、1-Wire®マスタのあらゆる機能を利用した架空の状況を仮定し、この状況について段階を追って説明します。1-Wireマスタ(1WM)は、お客様のASICに組み込まれているものと想定し、ホストCPUはこれを使用して1-Wire温度センサから温度を抽出します。ここに示したソースコードは、1WMを使用して4つの熱センサに、温度を変換してその値を報告するように命令を出します。ここでは読者が、DS18B20熱センサ、DS1WM 1-Wireマスタ、およびダラスセミコンダクタの1-Wireプロトコルの知識があるものと想定しています。

はじめに

DS1WM 1-Wireマスタは、ビットタイミングを気にせずにホストCPUが1-Wireバス上のデバイスと容易に通信できるように作成されたものです。このアプリケーションノートでは、実際の例を示すため、1-Wireマスタのあらゆる機能を利用した架空の状況を仮定し、この状況について段階を追って説明します。ここでは読者が、DS18B20熱センサ、DS1WM 1-Wireマスタ、及びダラスセミコンダクタの1-Wireプロトコルの知識があるものと想定しています。詳細については、「Book of iButton Standards」 (PDF)、DS1WMのデータシートDS18B20のデータシート、「アプリケーションノート119:1-Wireマスタの組込み」を参照してください。

図1. 回路例
図1. 回路例

図1は、この例で使用する回路構成を示しています。1-Wireマスタはお客様のASICに組み込まれており、ホストCPUはこれを使用して4つの熱センサに、温度を変換してその値を報告するように命令を出します。1-Wireバス及びINTRラインには、それぞれ標準の5kのプルアップ抵抗が接続されています。50MHzシステムクロックは、CLKピンを通じて1-Wireマスタのタイミングを駆動します。1-Wireマスタは、CPUのポートアドレス空間にメモリマッピングされています。

概要

この例で使用するコードはCで記述されています。メイン関数はGetTemperaturesという名前です。メイン関数は、1-Wireマスタを初期化し、1-Wireバス上のすべてのデバイスを検出し、これらのデバイスに温度を測定するように要求し、これらの温度値を保存します。この関数は、バス上にデバイスがなければ1を返し、あれば0を返します。その他のすべての関数については、以下で詳細に説明します。この例の定数BASEは、1-Wireマスタがメモリマッピングされているベースアドレスを参照しています。TEMPS及びROMSは、どこからでも参照できるグローバル変数です。

//individual Serial #s and readings
#define DEVICES 4
int ROMS[DEVICES][8];
int TEMPS[DEVICES];

int GetTemperatures(int BASE)
{
  // init. the 1-Wire Master
  Initialize(BASE);
  // exit if no devices can be found
  if(Reset(BASE)) return(1);

  // find all individual Serial#s
  FindROMs(BASE);

  // Convert temp. and read devices
  ConvertT(BASE);
  ReadTemps(BASE);

  return(0);
}

動作

ホストは最初に、Clock Divisor Register (クロック除数レジスタ)への書込みを行うことで、DS1WMを初期化して1-Wireバスのタイミングを正しく設定します。50MHzクロック入力の値は、0x0Fh (DS1WMのデータシートを参照)です。ホストは、Interrupt Enable Register (割込みイネーブルレジスタ)に0x3Dhを書き込むことでINTRラインを初期化します。こうすることで、データの送信時とリセットの完了時にINTRピンはアクティブローとなって割り込みが生成されます。

void Initialize(int BASE)
{
  // Divide the clock
  outp(BASE+4,0x0F);

  // Generate INTs on reset and send
  outp(BASE+3,0x09);
}
次にホストは、1-Wireバス上にデバイスがあるかどうかを確認する必要があります。これを実施するため、ホストは0x01をCommand Register (コマンドレジスタ)に書き込んでリセットを発行し、割込みが生成されるのを待ちます。割込みが生成されると、ホストはInterrupt Register (割込みレジスタ)を読み込んで、ビット2がローであることを読み取ることで、スレーブデバイスがプレゼンス検出を生成したことを確認します。ビット2がハイであれば、CPUはバスエラーがあったかデバイスが存在しないと判断し、適切な処置を行います。WaitforInterrupt()関数は、このアプリケーションノートでは定義していません。これは、メインプログラムが待機中に他のタスクを遂行するための1つの方法であり、ユーザがすべてを定義することができます。

int Reset(int BASE)
{
  outp(BASE,0x02);  // send reset
  WaitforInterrupt();

  if(inp(BASE+2) & 0x02)
    return(1);   //no presence found
  else
    return(0);   //presence found
}
ホストは、1-Wireバス上の各デバイスの個別のROMコードを知る必要があります。これは、Search ROMアルゴリズムを実行することで行います。ホストはSearch ROMコマンドをスレーブに送信し、1-WireマスタをSearch ROM Acceleratorモードに置きます。ホストは検出した最後のROM値に基づいた16バイトの検索値を送信します。この16バイトの値は、最初に実行するときは0x00です。返される16バイトには新しいROMコードが含まれ、また、これを使用して次に送信する16バイトも生成します。

このプロセスは、シリアル番号が複写されてすべてのデバイスが検出されるまで繰り返されます。例のケースでは、デバイスは4つだけであり、4つのROMコードに必要十分なメモリしか割り当てられていないため、ループは4回だけ実行されます。RecoverROM関数は新しいデータを生成して送信し、受信したばかりのデータから新しいROMコードを抽出します。この関数は、受信したデータを初期化するため、一度だけNULLポインタを用いて呼び出す必要があります。RecoverROM関数についての詳細は、このアプリケーションノートの最後に記載しています。Search ROM Acceleratorのプロセスについては、DS1WMのデータシートに詳細に説明しています。
int FindROMs(int BASE)
{
  int loop;
  int dev;
  int TData[16];
  int RData[16];

  // reset RecoverROM and generate the
  // starting TData
  RecoverROM(NULL,TData,NULL);

  //run once for each device
  for(dev=0;dev<4;dev++)
  {
    outp(BASE,0x01);   // send reset
    WaitforInterrupt();
    outp(BASE+1,0xF0);   // send SeachROM
    WaitforInterrupt();

    // enter Accelerator mode
    outp(BASE,0x02);

    // transmit the TDATA and receive
    // the RDATA.
    for(loop=0;loop<16;loop++)
    {
      outp(BASE+1,TData[loop]);
      WaitforInterrupt();
      inp(BASE+1,RData[loop]);
    }

    //decode recovered ROM and generate
    //next Search value
    RecoverROM(RDATA,TData,ROMS[dev]);
  }
}
検出した一意のシリアル番号は、後にスレーブデバイスから個別のデータを読み出すために使用します。すべてのデバイスにグローバルコマンドを書き込むためには、これらの番号は必要ありません。ホストは、0x44hを書き込むことで、温度変換を実施するようにすべてのスレーブに命令します。このコマンドは、バスのリセットの直後に、Skip ROMコマンド0xCCを送信した後、4つのデバイスのすべてに同時に送信することができます。

int ConvertT(int BASE)
{
  outp(BASE,0x01);   // send reset
  WaitforInterrupt();

  outp(BASE+1,0xCC);   // skip ROM
  WaitforInterrupt();

  outp(BASE+1,0x44);   // convert Temp.
  WaitforInterrupt();
DS18B20は、待ち時間が必要ないほどの速さで温度を変換します。この時点でホストは、各デバイスを個別にアドレス指定して温度値を読み取る必要があります。バスをリセットした後、ホストはMatch ROMコマンドを発行し、それに続けて64ビットのシリアル番号を発行し、次にRead Scratchpadコマンドを発行します。ホストは次に、2バイトの温度データを読み取ります。1-Wireバス上でデータを読み取るためには、ホストは0xFFhを最初に送信する必要があります。これによって2バイトのデータが結合されて全16ビットの温度値が生成されます。各デバイスごとにこのプロセスを繰り返します。
int ReadTemps(int BASE)
{
  int dev,loop;
  int LSB,MSB;

  for(dev=0;dev<4;dev++)
  {
    outp(BASE,0x01);   // send reset
    WaitforInterrupt();
    outp(BASE+1,0x55);   // match ROM
    WaitforInterrupt();

    // send 8 bytes of ROM code
    for(loop=0;loop<8;loop++)
    {
      outp(BASE+1,ROMS[dev][loop]);
      WaitforInterrupt();
    }

    outp(BASE+1,0xBE);   // read memory
    WaitforInterrupt();

    outp(BASE+1,0xFF);   // read LSB
    WaitforInterrupt();
    LSB = inp(BASE+1);

    outp(BASE+1,0xFF);   // read MSB
    WaitforInterrupt();
    MSB = inp(BASE+1);

    TEMPS[dev] = MSB<<8 + LSB;
  }
}
プロセスはこれで完了です。GetTemperaturesは、バス上にデバイスが検出されなかったことを伝える1を返すか、4つのデバイスのそれぞれから検出した値でROMSとTEMPSを更新します。

デバイスのROMコードが前もってわかっている場合は、Search ROMのプロセスを完全に省いてしまうことができます。バス上にデバイスが1つしかない場合は、シリアル番号を検出する必要はなく、各処理でSkip ROMコマンドを使用することができます。

割り込みラインが利用できない場合、WaitforInterrupt関数を記述し、Interrupt Register (割り込みレジスタ)をポーリングしてコマンドを完了することができます。ただし、この処理を行うと、CPUは拘束されて1-Wireマスタが動作を終了するまで待機することになります。

RecoverROMのソースコード

次の2ページに示すソースコードをユーザのコードに組み込めば、Search ROM処理中に16バイトの送信値を生成し、16バイトの受信値から最新のROMコードを抽出することができます。

この関数は、16バイトの受信データ配列、16バイトの送信データ配列(書込み先)、及び8バイトのROMコード配列(これも書込み先)へのポインタを必要とします。この関数は、1-Wireバス上にまだ不明なデバイスがある場合は0を返し、バス上のすべてのデバイスが検出された場合は1を返します。

上記の例では、この機能は使用していません。この関数はエラーチェックを行いません。デバイスがない状態で使用した場合、検出されたROMコードは誤っています。
/////////////////////////////////////////////////////////////////////////////////
// RecoverROM performs two functions. Given 16 bytes of receive data taken from
// the 1-Wire Master during a Search ROM function, it will extract the ROM code
// found into an 8 byte array and it will generate the next 16 bytes to be trans-
// mitted during the next Search ROM.
// RecoverROM must be initialized by sending a NULL pointer in ReceivedData. It
// will write 16 bytes of zeros into TransmitData and clear the discrepancy tree.
// The discrepancy tree keeps track of which ROM discrepancies have already been
// explored.
// RecoverROM also returns a value telling whether there are any more ROM codes to
// be found. If a zero is returned, there are still discrepancies. If a one is
// returned all ROMs on the bus have been found. Running RecoverROM again in this
// case will result in repeating ROM codes already found
////////////////////////////////////////////////////////////////////////////////

int RecoverROM(int* ReceiveData, int* TransmitData, int* ROMCode)
{
  int loop;
  int result;
  int TROM[64];   // the transmit value being generated
  int RROM[64];   // the ROM recovered from the received data
  int RDIS[64];   // the discrepancy bits in the received data

  static int TREE[64];   // used to keep track of which discrepancy bits have
                         // already been flipped.

  // If receivedata is NULL, this is the first run. Transmit data should be all
  // zeros, and the discrepancy tree must also be reset.

  if(ReceiveData == NULL)
  {
    for(loop = 0; loop < 64; loop++) TREE[loop] = 0;
    for(loop = 0; loop < 16; loop++) TransmitData[loop] = 0;
    return 1;
  }
  // de-interleave the received data into the new ROM code and the discrepancy bits
  for(loop = 0; loop < 16; loop++)
  {
    if((ReceiveData[loop] & 0x02) == 0x00) RROM[loop*4] = 0; else RROM[loop*4 ] = 1;
    if((ReceiveData[loop] & 0x08) == 0x00) RROM[loop*4+1] = 0; else RROM[loop*4+1] = 1;
    if((ReceiveData[loop] & 0x20) == 0x00) RROM[loop*4+2] = 0; else RROM[loop*4+2] = 1;
    if((ReceiveData[loop] & 0x80) == 0x00) RROM[loop*4+3] = 0; else RROM[loop*4+3] = 1;

    if((ReceiveData[loop] & 0x01) == 0x00) RDIS[loop*4] = 0; else RDIS[loop*4 ] = 1;
    if((ReceiveData[loop] & 0x04) == 0x00) RDIS[loop*4+1] = 0; else RDIS[loop*4+1] = 1;
    if((ReceiveData[loop] & 0x10) == 0x00) RDIS[loop*4+2] = 0; else RDIS[loop*4+2] = 1;
    if((ReceiveData[loop] & 0x40) == 0x00) RDIS[loop*4+3] = 0; else RDIS[loop*4+3] = 1;
  }

  // initialize the transmit ROM to the recovered ROM

  for(loop = 0; loop < 64; loop++) TROM[loop] = RROM[loop];

  // work through the new transmit ROM backwards setting every bit to 0 until the
  // most significant discrepancy bit which has not yet been flipped is found.
  // The transmit ROM bit at that location must be flipped.

  for(loop = 63; loop >= 0; loop--)
  {
    // This is a new discrepancy bit. Set the indicator in the tree, flip the
    // transmit bit, and then break from the loop.

    if((TREE[loop] == 0) && (RDIS[loop] == 1) && (TROM[loop] == 0))
    {
      TREE[loop] = 1;
      TROM[loop] = 1;
      break;
    }
    if((TREE[loop] == 0) && (RDIS[loop] == 1) && (TROM[loop] == 1))
    {
      TREE[loop] = 1;
      TROM[loop] = 0;
      break;
    }

    // This bit has already been flipped, remove it from the tree and continue
    // setting the transmit bits to zero.

    if((TREE[loop] == 1) && (RDIS[loop] == 1)) TREE[loop] = 0;
    TROM[loop] = 0;
  }
  result = loop;   // if loop made it to -1, there are no more discrepancy bits
                   // and the search can end.

  // Convert the individual transmit ROM bit into a 16 byte format
  // every other bit is don't care.

  for(loop = 0; loop < 16; loop++)
  {
    TransmitData[loop] = (TROM[loop*4]<<1) +
                         (TROM[loop*4+1]<<3) +
                         (TROM[loop*4+2]<<5) +
                         (TROM[loop*4+3]<<7);
  }

  // Convert the individual recovered ROM bits into an 8 byte format

  for(loop = 0; loop < 8; loop++)
  {
    ROMCode[loop] = (RROM[loop*8]) +
                    (RROM[loop*8+1]<<1) +
                    (RROM[loop*8+2]<<2) +
                    (RROM[loop*8+3]<<3) +
                    (RROM[loop*8+4]<<4) +
                    (RROM[loop*8+5]<<5) +
                    (RROM[loop*8+6]<<6) +
                    (RROM[loop*8+7]<<7);
  }
  if(result == -1) return 1;   // There are no DIS bits that haven't been flipped
                               // Tell the main loop the search is over
  return 0;   // else continue
}

1-WireはMaxim Integrated Products, Inc.の登録商標です。

We Want Your Feedback!


フィードバックをお寄せください。
内容に満足されましたか、あるいは満足されていませんか?もっと良いページにできると思いますか?あるいは、単なるコメントでも結構です。フィードバックをお待ちしています。—マキシムはお客様からいただく訂正、提案を元に改善していきます。 このページを評価し、フィードバックを送信する。


自動アップデート
お客様が関心のある分野でアプリケーションノートが新規に掲載された際に自動通知Eメールの受信を希望する場合は、EE-Mail™にご登録ください。



その他の情報  APP 120: Sep 28, 2004
DS18B20 プログラマブル分解能1-Wireディジタルサーモメータ フルデータシート
(PDF, 224kB)
無料
サンプル
DS1WM 合成可能な1-Wireバスマスタ フルデータシート
(PDF, 464kB)
DS2408 1-Wire、8チャネル、アドレス指定可能なスイッチ フルデータシート
(PDF, 420kB)
無料
サンプル
DS2502-E48 48ビットノードアドレスチップ フルデータシート
(PDF, 48kB)
無料
サンプル
 

ダウンロード、PDFフォーマットダウンロード、PDFフォーマット (46kB)
 AN120, AN 120, APP120, Appnote120, Appnote 120


      プライバシーポリシー    法的お知らせ

      Copyright © 2008 by Maxim Integrated Products, Dallas Semiconductor