PIC C, Interfacing with a Dallas DS2401 Silicon Serial Number



// Program 2401_1.C (CCS PCM, PIC16F84)
//
// Illustrates use of DS2401 Silicon Serial Number.
//
// Reads 64 bit serial number, saves in 8-bit data buffer and displays
// on serial PIC-an-LCD in the form XXXX YYYY where X or Y is a two digit
// hex number.
//
//   PIC16F84                      DS2401
//
// PWR_ON (RA.1, term 18) --
//                        |
//                       4.7K
//                        |
// ID_DQ (RB.0, term 6) -------------------- DQ
//
// Note that power to the DS2401 is only turned on when reading the
// ID.  Such power savings might be important in data logging
// applications.
//
// Note that the 1-Wire routines may be used with any Dallas 1-W Device;
// e.g., DS1820.
//
// copyright, P. H. Anderson, Georgetown Co, SC, Mar, '99

#case

#include <16F84.h>
#include <string.h>
#include <defs_f84.h>

#define TxData 0	// RA.0 - interface to serial LCD

#define PWR_ON_PIN ra1	// RA.1 - power to DS2401
#define PWR_ON_DIR trisa1

#define ID_DQ_PIN rb0		// RB.0 - DQ for DS2401
#define ID_DQ_DIR trisb0

void read_2401_id(int sensor, int *buff);

// 1-wire prototypes
void _1w_init(int sensor);
int _1w_in_byte(int sensor);
void _1w_out_byte(int d, int sensor);
void _1w_pin_hi(int sensor);
void _1w_pin_low(int sensor);
void _1w_strong_pull_up(int sensor);	// not used in this routine

// delay routines
void delay_ms(long t);
void delay_10us(int t);

// LCD routines
void lcd_init(void);
void out_RAM_str(int *s);
void lcd_hex_byte(int val);
void lcd_dec_byte(int val, int digits);
int num_to_char(int val);
void lcd_char(int ch);
void lcd_new_line(void);

void main(void)
{
   int buff[8], n, ch;
   read_2401_id(0, buff);	// fetch the silicon ID

   lcd_init();
   for (n=0; n<4; n++)		// display the first 4 bytes
   {
      lcd_hex_byte(buff[n]);
   }
   lcd_char(' ');		// followed by a space
   for (n=4; n<8; n++)
   {
      lcd_hex_byte(buff[n]);	// last four bytes
   }
}

void read_2401_id(int sensor, int *buff)
{
   int n;
   // turn on power, set ID_DQ to high impedance
   PWR_ON_DIR = 0;
   PWR_ON_PIN = 1;
   
   ID_DQ_DIR = 1;

   delay_ms(500);  // wait for 500 ms to be sure the device
    		       // has stabilized.
   _1w_init(sensor);
   _1w_out_byte(0x33, sensor);	// read ROM

   for (n=0; n<8; n++)
   {
      buff[n]=_1w_in_byte(sensor);
   }

// turn off power and be sure ID_DQ is in high impedance state
    PWR_ON_PIN = 0;
    PWR_ON_DIR = 1;
    ID_DQ_DIR = 1;

}  // note that 8-byte ID is returned in array buff

// The following are standard 1-Wire routines.

void _1w_init(int sensor)
{
   _1w_pin_hi(sensor);
   _1w_pin_low(sensor);
   delay_10us(50);

   _1w_pin_hi(sensor);
   delay_10us(50);
}

int _1w_in_byte(int sensor)
{
   int n, i_byte, temp, mask;
   mask = 0xff & (~(0x01<<sensor));
   for (n=0; n<8; n++)
   {
      PORTB=0x00;
      TRISB=mask;
      TRISB=0xff;
   #asm
      CLRWDT
      NOP
      NOP
   #endasm
      temp=PORTB;
      if (temp & ~mask)
      {
        i_byte=(i_byte>>1) | 0x80;	// least sig bit first
      }
      else
      {
        i_byte=i_byte >> 1;
      }
      delay_10us(6);
   }
   return(i_byte);
}

void _1w_out_byte(int d, int sensor)
{
   int n, mask;
   mask = 0xff & (~(0x01<<sensor));
   for(n=0; n<8; n++)
   {
      if (d&0x01)
      {
         PORTB=0;
         TRISB=mask;		// momentary low
         TRISB=0xff;
         delay_10us(6);
      }

      else
      {
          PORTB=0;
          TRISB=mask;
	       delay_10us(6);
          TRISB=0xff;
      }
      d=d>>1;
   }
}

void _1w_pin_hi(int sensor)
{
   TRISB = 0xff;
}

void _1w_pin_low(int sensor)
{
   PORTB = 0x00;
   TRISB = 0xff & (~(0x01 << sensor));
}

void _1w_strong_pull_up(int sensor)
{
   PORTB = 0x01 << sensor;
   TRISB = 0xff & (~(0x01 << sensor));
   delay_ms(250);
   TRISB = 0xff;
}

void delay_10us(int t)
{
#asm
      BCF STATUS, RP0
DELAY_10US_1:
      CLRWDT
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      DECFSZ t, F
      GOTO DELAY_10US_1
#endasm
}

void delay_ms(long t)	// delays t millisecs
{
   do
   {
     delay_10us(100);
   } while(--t);
}

int num_to_char(int val)	// converts val to hex character
{
   int ch;
   if (val < 10)
   {
     ch=val+'0';
   }
   else
   {
     val=val-10;
     ch=val + 'A';
   }
   return(ch);
}

void lcd_char(int ch)	// serial output to PIC-n-LCD, 9600 baud
{
   int n, dly;
   		// start bit + 8 data bits

  #asm
       BCF STATUS, RP0
       MOVLW 9
       MOVWF n
       BCF STATUS, C

  LCD_CHAR_1:

       BTFSS STATUS, C
       BSF PORTA, TxData
       BTFSC STATUS, C
       BCF PORTA, TxData
       MOVLW 32
       MOVWF dly

  LCD_CHAR_2:
       DECFSZ dly, F
       GOTO LCD_CHAR_2
       RRF ch, F
       DECFSZ n, F
       GOTO LCD_CHAR_1

       BCF PORTA, TxData
       CLRWDT
       MOVLW 96
       MOVWF dly

  LCD_CHAR_3:
       DECFSZ dly, F
       GOTO LCD_CHAR_3
       CLRWDT
   #endasm
}

// LCD routines

void lcd_init(void)	// sets TxData in idle state and resets PIC-n-LCD
{
  #asm
        BCF STATUS, RP0
        BCF PORTA, TxData
        BSF STATUS, RP0
        BCF TRISA, TxData
        BCF STATUS, RP0
   #endasm
   lcd_char(0x0c);
   delay_ms(250);
}

void lcd_new_line(void)	// outputs 0x0d, 0x0a
{
   lcd_char(0x0d);
   delay_ms(10);	// give the PIC-n-LCD time to perform the
   lcd_char(0x0a);	// new line function
   delay_ms(10);
}


void out_RAM_str(int s)
{
   while(*s)
   {
      lcd_char(*s);
      ++s;
   }
}

void lcd_hex_byte(int val) // displays val in hex format
{
   int ch;
   ch = num_to_char((val>>4) & 0x0f);
   lcd_char(ch);
   ch = num_to_char(val&0x0f);
   lcd_char(ch);
}

void lcd_dec_byte(int val, int digits)
// displays byte in decimal as either 1, 2 or 3 digits
{
   int d;
   int ch;
   if (digits == 3)
   {
      d=val/100;
      ch=num_to_char(d);
      lcd_char(ch);
   }
   if (digits >1)	// take the two lowest digits
   {
       val=val%100;
       d=val/10;
       ch=num_to_char(d);
       lcd_char(ch);
   }
   if (digits == 1)	// take the least significant digit
   {
       val = val%100;
   }

   d=val % 10;
   ch=num_to_char(d);
   lcd_char(ch);
}