DS1820 - Programming the User EEPROM and Calculating the CRC



/* Program 1820_3.C
**
** Illustrates how to write to and read from the two user EEPROM locations
** on the Dallas DS1820.  These might be used to store trips points, but
** may be used in any application where user defined parameters must be
** stored.
**
** For illustration 0x4f and 0x3a are written to the user EEPROM.  This is
** then read and displayed on the console.
**
** Note that the error handling has been improved;
**
**    In _1w_init(), TRUE or FALSE is returned if the sensor was
**       or wasn't detected.
**
**    An 8-bit cyclic redundancy check is performed on the nine bytes
**       received from the DS1820.  A discussion of the CRC appears
**       at http://www.phanderson.com/PIC/
**
** copyright, Peter H. Anderson, Towanda Malone, Baltimore, MD, Oct, '00
*/

#include <stdio.h>
#include <dos.h>
#include <conio.h>

#define SEG 0xf000
#define P2_OFFSET 0xff10
#define PM2_OFFSET 0xff11
#define PMC2_OFFSET 0xff12

#define TRUE !0
#define FALSE 0

#define DEBUG

typedef unsigned char byte;

byte write_user_bytes(byte sensor, byte ub1, byte ub2);
byte read_user_bytes(byte sensor, byte *p_ub1, byte *p_ub2);
byte calc_crc(byte buff[], byte num_vals);

byte _1w_init(byte sensor);
byte _1w_in_byte(byte sensor);
void _1w_out_byte(byte sensor, byte d);
void _1w_pin_hi(byte sensor);
void _1w_pin_low(byte sensor);
void _1w_strong_pull_up(byte sensor);

byte far *p2, far *pm2, far *pmc2;    /* note global */

void main(void)
{
    byte ub1, ub2;

    p2 = MK_FP(SEG, P2_OFFSET);
    pm2 = MK_FP(SEG, PM2_OFFSET);
    pmc2 = MK_FP(SEG, PMC2_OFFSET);

    *pmc2 = 0x00;
    *pm2 = 0xff;     /* all of port 2 are inputs */

    clrscr();
    if (!write_user_bytes(0, 0x4f, 0x3a))
    {
        printf("Write Failed\n");
        exit(0);
    }
    if (!read_user_bytes(0, &ub1, &ub2))
    {
        printf("Read Failed\n");
        exit(0);
    }
    printf("%0.2x  %0.2x\n", ub1, ub2);
}

byte write_user_bytes(byte sensor, byte ub1, byte ub2)
{
   if (!_1w_init(sensor))
   {
       return(FALSE);      /* no sensor detected */
   }
   _1w_out_byte(sensor, 0xcc);  /* skip ROM */
   _1w_out_byte(sensor, 0x4e);  /* write to scratch pad */
   _1w_out_byte(sensor, ub1);
   _1w_out_byte(sensor, ub2);

   if (!_1w_init(sensor))
   {
       return(FALSE);
   }
   _1w_out_byte(sensor, 0xcc);  /* skip ROM */
   _1w_out_byte(sensor, 0x48);  /* scratch pad to eeprom */
   _1w_strong_pull_up(sensor);
   return(TRUE);
}


byte read_user_bytes(byte sensor, byte *p_ub1, byte *p_ub2)
{
   byte buff[9], crc, n;
   if (!_1w_init(sensor))
   {
      return(FALSE);
   }
   _1w_out_byte(sensor, 0xcc);  /* skip ROM */
   _1w_out_byte(sensor, 0xb8);  /* EEPROM to scrath pad */


   if (!_1w_init(sensor))
   {
      return(FALSE);
   }
   _1w_out_byte(sensor, 0xcc);  /* skip ROM */
   _1w_out_byte(sensor, 0xbe);  /* EEPROM to scratch pad */

   for (n=0; n<9; n++)
   {
       buff[n] = _1w_in_byte(sensor);
#ifdef DEBUG
       printf("%0.2x ", buff[n]);
#endif
   }
#ifdef DEBUG
   printf("\n");
#endif
   crc = calc_crc(buff, 9);
   if (crc)       /* if it is non zero, there must have been an error */
   {
       printf("%0.2x ...........\n", crc);
       return(FALSE);
   }

   *p_ub1 = buff[2];
   *p_ub2 = buff[3];
   return(TRUE);
}

byte calc_crc(byte buff[], byte num_vals)
{
   byte shift_reg=0, data_bit, sr_lsb, fb_bit, i, j;

   for (i=0; i<num_vals; i++) /* for each byte */
   {
      for(j=0; j<8; j++)   /* for each bit */
      {
         data_bit = (buff[i]>>j)&0x01;
         sr_lsb = shift_reg & 0x01;
         fb_bit = (data_bit ^ sr_lsb) & 0x01;
         shift_reg = shift_reg >> 1;
         if (fb_bit)
         {
            shift_reg = shift_reg ^ 0x8c;
         }
      }
   }
   return(shift_reg);
}

byte _1w_init(byte sensor)
{

/* brings DQ low for 500 usecs and then back to high Z.  Returns
** TRUE if presence pulse dected from DS1820 */
   byte i, j;
   _1w_pin_low(sensor);
   for(i=167; i>0; i--)  ;    /* bring low for 500 us */

   _1w_pin_hi(sensor);
   for (j=0; j<100; j++)
   {
      if ((*(p2) & 0x01) == 0)  /* if it goes to zero, it is present */
      {
         for(i=167; i>0; i--)  ;    /* assure high for 500 us */
         return(TRUE);
      }
   }
   return (FALSE);   /* DS1820 never went to zero */
}

byte _1w_in_byte(byte sensor)
{
   byte m, n, i_byte=0, temp, mask_0, mask_1;
   mask_1 = 0x01<<sensor;
   mask_0 = ~mask_1;
   for (n=0; n<8; n++)
   {
      *p2 = 0x00;
      *pm2 = mask_0;
      *pm2 = 0xff;

      temp = *p2;

      if (temp & mask_1)
      {
        i_byte=(i_byte>>1) | 0x80;  /* least sig bit first  */
      }
      else
      {
        i_byte=i_byte >> 1;
      }
      for(m=19; m>0; m--)  /* 60 us */  ;
   }
   return(i_byte);
}

void _1w_out_byte(byte sensor, byte d)
{
   byte m, n, mask_0, mask_1;
   mask_1 = 0x01<<sensor;
   mask_0 = ~mask_1;
   for(n=0; n<8; n++)
   {
      if (d&0x01)
      {
         *p2 = 0x00;
         *pm2 = mask_0;
         *pm2 = 0xff;
         for(m=19; m>0; m--)  /* 60 us */  ;
      }

      else
      {
         *p2 = 0x00;
         *pm2 = mask_0;
         for(m=19; m>0; m--)  /* 60 us */  ;
         *pm2 = 0xff;
      }
      d=d>>1;
   }
}

void _1w_pin_hi(byte sensor)
{
   *pm2 = 0xff;
}

void _1w_pin_low(byte sensor)
{
   byte mask_0, mask_1;
   mask_1 = 0x01 << sensor;
   mask_0 = ~mask_1;
   *p2 = mask_0;
   *pm2 = mask_0;
}

void _1w_strong_pull_up(byte sensor)
{
   byte mask_0, mask_1;
   mask_1 = 0x01 << sensor;
   mask_0 = ~mask_1;
   *p2 = mask_1;     /* bring bit to a hard logic one */
   *pm2 = mask_0;    /* dirs configured as output */
   delay(500);
   *pm2 = 0xff;
}