[DS2401] Silicon Serial Number

Pozostałe układy mikrokontrolerów, układy peryferyjne i inne, nie mieszczące się w powyższych kategoriach.
Awatar użytkownika
gaweł
Geek
Geek
Posty: 1333
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

[DS2401] Silicon Serial Number

Postautor: gaweł » sobota 30 maja 2026, 14:16

DS2401
bądź unikalny i niepowtarzalny


ds2401_00.jpg


W moje ręce trafiło kilka ciekawych scalaków. Są to układy zawierające 48-bitowe unikalne numery seryjne. Do komunikacji ze światem zewnętrznym wykorzystany jest interfejs 1 wire. Wszyscy znamy popularne układy do pomiaru temperatury DS1820 również posługujące się tym interfejsem. Jednak ten różni się tym, że wykorzystuje dwa piny (w mierniku temperatury można wykorzystać pin do niezależnego zasilania). Układ DS2401 nie posiada wydzielonego pinu do zasilania. By działać potrzebuje energii i do tego wykorzystuje linię danych DQ, mówiąc inaczej pasożytuje na zasilaniu z mikrokontrolera.
Zrobiłem układ badawczy w oparciu o procek ATMEGA32 (kiedyś skonstruowałem moduł do różnych eksperymentów). Schemat pokazuje rysunek:
DS2401_01.png

Układ jest w obudowie SOT-223. Ponieważ różne faktorie numerują piny po swojemu, dodałem rysunek obudowy (z arkusza danych Maxim).
Środowisko testowe:
DS2401_02.png

Testowy program:

Kod: Zaznacz cały

#define F_CPU 7372800UL

#include <avr/io.h>

#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include "ds2401.h"

#define USART_Speed          47

static const uint8_t HelloText [ ] PROGMEM      = "Prezentacja obslugi DS2401\r\n" ;
static const uint8_t NotPresentText [ ] PROGMEM = "\r\nBrak ukladu DS2401\r\n" ;
static const uint8_t ReadyText [ ] PROGMEM      = "Gotowe, numer seryjny: " ;

uint8_t Rom [ 8 ] ;

#define nop() __asm__ __volatile__ ("nop")

#define IdleState                       0
#define BusyState                       1

#define TXDBuffSize                     64
#define RXDBuffSize                     16

typedef struct { uint8_t CycFr ;
                 uint8_t CycTo ;
                 uint8_t State ;
                 uint8_t Buffer [ TXDBuffSize ] ;
               } TXDRecT ;

typedef struct { uint8_t CycFr ;
                 uint8_t CycTo ;
                 uint8_t Buffer [ RXDBuffSize ] ;
               } RXDRecT ;

static volatile TXDRecT TXDRec ;
static volatile RXDRecT RXDRec ;

SIGNAL ( USART_RXC_vect )
{
  uint8_t RecVCh ;
  /*---------------------------------------------------*/
  RecVCh = UDR ;
  RXDRec . Buffer [ RXDRec . CycTo ] = RecVCh ;
  RXDRec . CycTo ++ ;
  if ( RXDRec . CycTo >= RXDBuffSize )
    RXDRec . CycTo = 0 ;
} /* USART_RXC_vect */

SIGNAL ( USART_TXC_vect )
{
  /*---------------------------------------------------*/
  if ( TXDRec . CycFr == TXDRec . CycTo )
  {
    TXDRec . State = IdleState ;
  } /* if ... */
  else
  {
    UDR = TXDRec . Buffer [ TXDRec . CycFr ] ;
    TXDRec . CycFr ++ ;
    if ( TXDRec . CycFr >= TXDBuffSize )
      TXDRec . CycFr = 0 ;
  } /* if ... else */ ;
} /* USART_TXC_vect */

static void USARTSoftwareInit ( void )
{
  /*---------------------------------------------------*/
  RXDRec . CycFr = 0 ;
  RXDRec . CycTo = 0 ;
  TXDRec . CycFr = 0 ;
  TXDRec . CycTo = 0 ;
  TXDRec . State = IdleState ;
} /* USARTSoftwareInit */

static void SendSerial ( uint8_t SerialCh )
{
  uint8_t NextInx ;
  /*---------------------------------------------------*/
  cli ( ) ;
  if ( TXDRec . State == IdleState )
  {
    TXDRec . State = BusyState ;
    UDR = SerialCh ;
    sei ( ) ;
  } /* if ... */
  else
  {
    for ( ; ; )
    {
      NextInx = TXDRec . CycTo + 1 ;
      if ( NextInx >= TXDBuffSize )
        NextInx = 0 ;
      if ( NextInx != TXDRec . CycFr )
        break ;
      sei ( ) ;
      nop ( ) ;
      nop ( ) ;
      cli ( ) ;
    } /* for */ ;
    TXDRec . Buffer [ TXDRec . CycTo ] = SerialCh ;
    TXDRec . CycTo ++ ;
    if ( TXDRec . CycTo >= TXDBuffSize )
      TXDRec . CycTo = 0 ;
    sei ( ) ;
  } /* if ... else */ ;
} /* SendSerial */

static void SendSerialFlashTxt ( uint16_t String )
{
  uint8_t Data ;
  /*---------------------------------------------------*/
  for ( ; ; )
  {
    Data = pgm_read_byte_near ( String ) ;
    if ( Data )
      SendSerial ( Data ) ;
    else
      break ;
    String ++ ;
  } /* for */ ;
} /* SendSerialFlashTxt */

static uint8_t SerialDataPresent ( void )
{
  /*---------------------------------------------------*/
  if ( RXDRec . CycFr == RXDRec . CycTo )
    return ( 0 ) ;
  else
    return ( 1 ) ;
} /* SerialDataPresent */

static uint8_t GetSerial ( void )
{
  uint8_t Ch ;
  /*---------------------------------------------------*/
  Ch = RXDRec . Buffer [ RXDRec . CycFr ] ;
  RXDRec . CycFr ++ ;
  if ( RXDRec . CycFr >= RXDBuffSize )
    RXDRec . CycFr = 0 ;
  return Ch ;
} /* GetSerial */

static void HardwareInit ( void )
{
  /*---------------------------------------------------*/
  UCSRA = 0 ;
  UCSRB = ( 1 << RXCIE ) | ( 1 << TXCIE ) | ( 1 << RXEN ) | ( 1 << TXEN ) ;
  UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 ) ;
  UBRRH = ( uint8_t ) ( ( USART_Speed >> 8 ) & 0xFF ) ;
  UBRRL = ( uint8_t ) ( USART_Speed & 0xFF ) ;
} /* HardwareInit */

static void InitEnvir ( void )
{
  /*---------------------------------------------------*/
  OneWirePort &= ~ ( 1 << OneWireBit ) ;
} /* InitEnvir */

static uint8_t HexCh ( uint8_t Value )
{
  /*---------------------------------------------------*/
  Value &= 0x0F ;
  switch ( Value )
  {
    case 0x00 :
      return ( '0' ) ;
    case 0x01 :
      return ( '1' ) ;
    case 0x02 :
      return ( '2' ) ;
    case 0x03 :
      return ( '3' ) ;
    case 0x04 :
      return ( '4' ) ;
    case 0x05 :
      return ( '5' ) ;
    case 0x06 :
      return ( '6' ) ;
    case 0x07 :
      return ( '7' ) ;
    case 0x08 :
      return ( '8' ) ;
    case 0x09 :
      return ( '9' ) ;
    case 0x0A :
      return ( 'A' ) ;
    case 0x0B :
      return ( 'B' ) ;
    case 0x0C :
      return ( 'C' ) ;
    case 0x0D :
      return ( 'D' ) ;
    case 0x0E :
      return ( 'E' ) ;
    case 0x0F :
      return ( 'F' ) ;
  } /* switch */ ;
  return ( '?' ) ;
} /* HexCh */

static void DispByte ( uint8_t DataByte )
{
  /*---------------------------------------------------*/
 SendSerial ( HexCh ( DataByte >> 4 ) ) ;
 SendSerial ( HexCh ( DataByte & 0x0F ) ) ;
 SendSerial ( ' ' ) ;
} /* DispByte */

int main ( void )
{
  /*---------------------------------------------------*/
  HardwareInit ( ) ;
  USARTSoftwareInit ( ) ;
  InitEnvir ( ) ;
  sei ( ) ;
  SendSerialFlashTxt ( ( uint16_t ) HelloText ) ;
  if ( DS2401ReadRom ( Rom ) )
  {
    // poprawny odczyt
    // rom[0] = family code
    // rom[1..6] = serial
    // rom[7] = CRC
    SendSerialFlashTxt ( ( uint16_t ) ReadyText ) ;
    DispByte ( Rom [ 0 ] ) ;
    DispByte ( Rom [ 1 ] ) ;
    DispByte ( Rom [ 2 ] ) ;
    DispByte ( Rom [ 3 ] ) ;
    DispByte ( Rom [ 4 ] ) ;
    DispByte ( Rom [ 5 ] ) ;
    DispByte ( Rom [ 6 ] ) ;
    DispByte ( Rom [ 7 ] ) ;
    SendSerial ( '\r' ) ;
    SendSerial ( '\n' ) ;
  } /* if ... */
  else
  {
    SendSerialFlashTxt ( ( uint16_t ) NotPresentText ) ;
  } /* if ... else */ ;
  for ( ; ; ) { } ;
}

Do obsługi układu DS2401 napisałem dedykowany moduł, plik nagłówkowy:

Kod: Zaznacz cały

#ifndef _DS2401_
#define _DS2401_
#include <avr/io.h>

#define OneWirePort       PORTD
#define OneWirePin        PIND
#define OneWireConfigPort DDRD
#define OneWireBit        PD7

extern uint8_t OW_Reset ( void ) ;
extern void OW_WriteBit ( uint8_t Bit ) ;
extern uint8_t OW_ReadBit ( void ) ;
extern void OW_WriteByte ( uint8_t Data ) ;
extern uint8_t OW_ReadByte ( void ) ;
extern uint8_t OW_Crc8 ( uint8_t * Data ,
                         uint8_t Lgt ) ;
extern uint8_t DS2401ReadRom ( uint8_t * Rom ) ;

#endif

oraz plik implementacji:

Kod: Zaznacz cały

#define F_CPU 7372800UL

#include "DS2401.h"
#include <util/delay.h>
#include <avr/interrupt.h>

static inline void ow_low ( void )
{
  /*---------------------------------------------------*/
  OneWireConfigPort |= ( 1 << OneWireBit ) ;
  OneWirePort &= ~ ( 1 << OneWireBit ) ;
} /* ow_low */

static inline void ow_release ( void )
{
  /*---------------------------------------------------*/
  OneWireConfigPort &= ~ ( 1 << OneWireBit ) ;
} /* ow_release */

static inline uint8_t ow_read_pin ( void )
{
  /*---------------------------------------------------*/
  return ( OneWirePin & ( 1 << OneWireBit ) ) ;
} /* ow_read_pin */

uint8_t OW_Reset ( void )
{
  uint8_t Presence ;
  /*---------------------------------------------------*/
  cli ( ) ;
  ow_low ( ) ;
  _delay_us ( 500 ) ;
  ow_release ( ) ;
  _delay_us ( 70 ) ;
  Presence = ! ow_read_pin ( ) ;
  _delay_us ( 410 ) ;
  sei ( ) ;
  return Presence ;
} /* OW_Reset */

void OW_WriteBit ( uint8_t Bit )
{
  /*---------------------------------------------------*/
  cli ( ) ;
  ow_low ( ) ;
  if ( Bit )
  {
    _delay_us ( 6 ) ;
    ow_release ( ) ;
    _delay_us (64 ) ;
  } /* if ... */
  else
  {
    _delay_us ( 60 ) ;
    ow_release ( ) ;
    _delay_us ( 10 ) ;
  } /* if ... else */ ;
  sei ( ) ;
} /* OW_WriteBit */

uint8_t OW_ReadBit ( void )
{
  uint8_t Bit ;
  /*---------------------------------------------------*/
  cli ( ) ;
  ow_low ( ) ;
  _delay_us ( 6 ) ;
  ow_release ( ) ;
  _delay_us ( 9 ) ;
  Bit = ow_read_pin ( ) ? 1 : 0 ;
  _delay_us ( 55 ) ;
  sei ( ) ;
  return Bit ;
} /* OW_ReadBit */

void OW_WriteByte ( uint8_t Data )
{
  uint8_t Loop ;
  /*---------------------------------------------------*/
  for ( Loop = 0 ; Loop < 8 ; Loop ++ )
  {
    OW_WriteBit ( Data & 0x01 ) ;
    Data >>= 1 ;
  } /* for */ ;
} /* OW_WriteByte */

uint8_t OW_ReadByte ( void )
{
  uint8_t Loop ;
  uint8_t Data ;
  /*---------------------------------------------------*/
  Data = 0 ;
  for ( Loop = 0 ; Loop < 8 ; Loop ++ )
  {
    if ( OW_ReadBit ( ) )
    {
      Data |= ( 1 << Loop ) ;
    } /* if */ ;
  } /* for */ ;
  return Data ;
} /* OW_ReadByte */

uint8_t OW_Crc8 ( uint8_t * Data ,
                  uint8_t Lgt )
{
  uint8_t Loop ;
  uint8_t IntLoop ;
  uint8_t Crc ;
  uint8_t Inbyte ;
  uint8_t Mix ;
  /*---------------------------------------------------*/
  Crc = 0 ;
  for ( Loop = 0 ; Loop < Lgt ; Loop ++ )
  {
    Inbyte = Data [ Loop ] ;
    for ( IntLoop = 0 ; IntLoop < 8 ; IntLoop ++ )
    {
      Mix = ( Crc ^ Inbyte ) & 0x01 ;
      Crc >>= 1 ;
      if ( Mix )
      {
        Crc ^= 0x8C ;
      } /* if */ ;
      Inbyte >>= 1 ;
    } /* for */ ;
  } /* for */ ;
  return Crc ;
} /* OW_Crc8 */

uint8_t DS2401ReadRom ( uint8_t * Rom )
{
  uint8_t Loop ;
  /*---------------------------------------------------*/
  if ( ! OW_Reset ( ) )
  {
    return 0 ;
  } /* if */ ;
  OW_WriteByte ( 0x33 ) ;
  for ( Loop = 0 ; Loop < 8 ; Loop ++ )
  {
    Rom [ Loop ] = OW_ReadByte ( ) ;
  } /* for */ ;
  if ( OW_Crc8 ( Rom , 7 ) != Rom [ 7 ] )
  {
    return 0 ;
  } /* if */ ;
  return 1 ;
} /* DS2401ReadRom */

Odczytany numer seryjny wysłany jest via serial (w PC użyłem popularny program Tera-term).
DS2401_03.png

Teraz jak zbuduję jakieś urządzenie z wykorzystaniem tego numeru, to będę miał unikalny niepowtarzalny numer (przykładowo można użyć jako adres MAC w interfejsie ethernetowym).

Kompletny projekt w Atmet Studio 7:
DS2401.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Wróć do „Inne mikroklocki, również peryferyjne”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 3 gości