ENGLISH 简体中文 日本語 한국어  


애플리케이션 노트  120

1-Wire 마스터를 이용한 통신

개요: 이 애플리케이션 노트는 예제를 제공하기 위해 1-Wire® 마스터의 모든 기능을 이용하는 이론적 상황을 단계별로 설명한다. 1-Wire 마스터 (1WM)는 고객의 ASIC 안에 설계되는 것으로 가정되며, 호스트 PC는 이를 사용하여 1-Wire 온도 센서로부터 온도를 추출한다. 또한 이 문서에는 1WM을 사용하여 4개의 열 센서 (thermal sensor)에 온도를 변환하여 그 값을 보고하도록 지시하는 소스 코드가 제공된다. 이 글을 읽는 독자는 DS18B20 열 센서, DS1WM 1-Wire 마스터 및 Dallas Semiconductor의 1-Wire 프로토콜에 대한 지식을 갖추고 있다고 가정한다.

소개

DS1WM 1-Wire 마스터는 비트 타이밍 문제를 걱정할 필요 없이 1-Wire 버스를 통해 디바이스와 용이한 호스트 CPU 통신을 제공하기 위해 개발되었다. 이 애플리케이션 노트는 예제를 제공하기 위해 1-Wire 마스터의 모든 기능을 이용하는 이론적 상황을 단계별로 설명한다. 이 글을 읽는 독자는 DS18B20 열 센서, DS1WM 1-Wire 마스터 및 Dallas Semiconductor의 1-Wire 프로토콜에 대한 지식을 갖추고 있다고 가정한다. 이에 대한 자세한 내용은 iButton 표준 서적 (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);
}

동작

호스트는 클록 분배 레지스터에 값을 써서 적절한 1-Wire 버스 타이밍으로 DS1WM을 초기화한다. 50MHz 클록 입력 값은 0x0Fh이다 (DS1WM 데이터 시트 참조). 호스트는 인터럽트 인에이블 레지스터에 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을 써서 리셋을 발생시키고, 인터럽트가 발생될 때까지 기다려야 한다. 인터럽트가 발생되면, 호스트는 인터럽트 레지스터를 읽고, 이 경우 비트 2를 로우로 읽으면 슬레이브 디바이스에서 존재 검출이 발생되었다는 것을 나타낸다. 비트 2가 하이이면, CPU는 버스 에러가 존재하거나 또는 디바이스가 존재하지 않는다는 결정을 내리고 적절한 조치를 취한다. 이 문서에서 WaitforInterrupt () 함수는 정의하지 않는다. 이 함수는 메인 프로그램이 기다리는 동안 다른 작업을 수행하는 하나의 방식이므로, 사용자가 완벽하게 정의할 수 있다.

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 코드를 알아야 한다. 이것은 ROM 검색 알고리즘을 실행하여 수행된다. 호스트는 ROM 검색 명령을 슬레이브에 내리고, 1-Wire 마스터를 ROM 검색 가속기 모드에 놓는다. 호스트는 발견된 가장 최근의 ROM 값에 따라 16바이트 검색 값을 전송한다. 이 16바이트는 처음 실행될 때 0x00이다. 리턴된 16바이트는 새로운 ROM 코드를 포함하며, 또한 전송할 다음 16바이트를 발생시키는데 사용된다.

이 프로세스는 모든 디바이스를 찾기 위해 일련 번호가 복제될 때까지 반복된다. 이 경우, 디바이스가 4개 뿐이라는 것을 알고 있으며 충분한 메모리가 4개의 ROM 코드에 할당되었기 때문에 루프는 단지 4회로 완료된다. RecoverROM 함수는 새로운 데이터를 발생시켜 전송하고, 방금 수신된 데이터로부터 새로운 ROM 코드를 추출한다. 이 함수는 수신된 데이터를 초기화하기 위해 NULL 포인터를 사용하여 한 번만 호출해야 한다. 이 애플리케이션 노트의 끝에는 전체 RecoverROM 함수가 수록되어 있다. ROM 검색 가속기 프로세스는 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 코드를 미리 알고 있는 경우, ROM 검색 프로세스 전체를 건너 뛸 수 있다. 버스에 1개의 디바이스만 있는 경우, 일련 번호를 알 필요가 없으며, 따라서 모든 트랜잭션에서 Skip ROM 명령을 사용할 수 있다.

인터럽트 라인이 없는 경우, 명령을 완료하기 위해 WaitforInterrupt 함수를 써서 인터럽트 레지스터를 연결할 수 있다. 그러나 이러한 조치는 1-Wire 마스터가 동작을 완료할 때까지 CPU를 대기 상태로 만든다.

RecoverROM 소스 코드

다음 두 페이지에 제공되는 소스 코드는 사용자의 코드에 포함시켜 ROM 검색 (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 seach is over
  return 0;   // else continue
}

1-Wire는 Maxim Integrated Products, Inc.의 등록상표이다.

We Want Your Feedback!


의견을 보내주세요!
위 내용이 도움이 되셨나요?
여러분의 의견을 기다립니다 — Maxim은 보내주신 정정이나 제안사항을 반영하고 있습니다. 이 페이지를 평가하고 의견을 보내주십시오.


자동 업데이트
관심있는 분야의 애플리케이션 노트가 나올 때 자동으로 업데이트 받고 싶으세요? 그렇다면 EE-Mail™을 신청하십시오.



추가 정보  APP 120: Jul 13, 2005
DS18B20 분해능 프로그래밍이 가능한 1-Wire 디지털 온도계 전체 데이터 시트
(PDF, 188kB)
무료 샘플
DS1WM 동기화 가능한 1-Wire 버스 마스터 전체 데이터 시트
(PDF, 124kB)
DS2408 1-Wire 8채널 주소지정이 가능한 스위치 전체 데이터 시트
(PDF, 656kB)
무료 샘플
DS2502-E48 48비트 노드 어드레스 칩 전체 데이터 시트
(PDF, 48kB)
무료 샘플
 

다운로드, PDF 형식다운로드, PDF 형식 (46kB)
 AN120, AN 120, APP120, Appnote120, Appnote 120


      개인정보보호 정책    법적 고지

      Copyright © 2008 by Maxim Integrated Products, Dallas Semiconductor