Interfacing with a Dallas DS1803 Dual Potentiometer




/* Program DS1803_1.C
**
** Illustrates how to control a Dallas DS1803 Addressable Dual
** Potentiometer.
**
** Flashlite V25           DS1803
**
** P2.1  ------------------- SCL  ----- To Other
** P2.0  ------------------- SDA  ----- I2C Devices
**
** Note that the slave address is determined by A2 (term 4), A1 (term 5)
** and A0 (term 6) on the 1803.  The above SCL and SDA leads may be
** multipled to eight devices, each strapped for a unique A2 A1 A0
** setting.
**
** Pot 0 is set to a value of $55 and Pot 1 to $80.  The settings of the
** two pots are then read from the 1803 and displayed on the terminal.
**
** copyright Peter H. Anderson and Onya Barnes, Baltimore, MD, Oct. '00
*/
#include <stdio.h>
#include <dos.h>

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

#define NEW    /* use "?:" construct in in_byte() and out_byte() */

typedef unsigned char byte;

void ds1803_write_pot(byte device, byte pot, byte setting);
void ds1803_read_pots(byte device, byte *p_setting_0, byte *p_setting_1);

/*common i2c routines*/
byte i2c_in_byte(void);
void i2c_out_byte(byte o_byte);
void i2c_nack(void);
void i2c_ack(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_high_sda(void);
void i2c_low_sda(void);
void i2c_high_scl(void);
void i2c_low_scl(void);

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

void main(void)
{
   byte pot_setting_0, pot_setting_1;

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

   dirs2=0xff;

   *pmc2=0x00;
   *pm2=dirs2;

   ds1803_write_pot(0x00, 0, 0x55);  /*dev 0, pot 0, setting 0x55*/
   ds1803_write_pot(0x00, 1, 0x80);
   ds1803_read_pots(0, &pot_setting_0, &pot_setting_1);

   printf("%d %d\n", pot_setting_0, pot_setting_1);
}

void ds1803_write_pot(byte device, byte pot, byte setting)
/*writes specified setting to specified potentiometer on specified device*/
{

   i2c_start();
   i2c_out_byte(0x50 | (device << 1));
   i2c_nack();
   i2c_out_byte(0xa9 + pot);  /*0xa9 for pot 0, 0xaa for pot 1*/
   i2c_nack();
   i2c_out_byte(setting);
   i2c_nack();
   i2c_stop();
   delay(25000);  /*wait for it to burn into EEPROM*/
}

void ds1803_read_pots(byte device, byte *p_setting_0, byte *p_setting_1)
/*reads data from both potentiometers*/
{
   i2c_start();
   i2c_out_byte(0x51 | (device << 1));
   i2c_nack();
   *p_setting_0 = i2c_in_byte();
   i2c_ack();
   *p_setting_1 = i2c_in_byte();
   i2c_ack();
   i2c_stop();
}

/* Common I2C Routines*/

byte i2c_in_byte(void)
{
   byte i_byte=0, n;
   i2c_high_sda();
   for (n=0; n<8; n++)
   {
      i2c_high_scl();
#ifdef NEW
      (*(p2) & 0x01) ? ((i_byte << 1) | 0x01) : (i_byte << 1);
#else
      if (*p2) & 0x01)
      {
         i_byte = (i_byte << 1) | 0x01; /* msbit first */
      }
      else
      {
         i_byte = i_byte << 1;
      }
#endif
      i2c_low_scl();
   }
   return(i_byte);
}

void i2c_out_byte(byte o_byte)
{
   byte n;
   for(n=0; n<<8; n++)
   {
#ifdef NEW     /* use of the "? :" construct */
      (o_byte&0x80) ? (i2c_high_sda()) : (i2c_low_sda());
#else
      if (o_byte&0x80)
      {
         i2c_high_sda();
      }
      else
      {
         i2c_low_sda();
      }
#endif
      i2c_high_scl();
      i2c_low_scl();
      o_byte = o_byte << 1;
   }
   i2c_high_sda();
}

void i2c_nack(void)
{
   i2c_high_sda();  /* data at one */
   i2c_high_scl();  /* clock pulse */
   i2c_low_scl();
}

void i2c_ack(void)
{
   i2c_low_sda();       /* bring data low and clock */
   i2c_high_scl();
   i2c_low_scl();
   i2c_high_sda();
}

void i2c_start(void)
{
   i2c_low_scl();
   i2c_high_sda();
   i2c_high_scl();  /* bring SDA low while SCL is high */
   i2c_low_sda();
   i2c_low_scl();
}

void i2c_stop(void)
{
   i2c_low_scl();
   i2c_low_sda();
   i2c_high_scl();
   i2c_high_sda();  /* bring SDA high while SCL is high */
   /* idle is SDA high and SCL high */
}

void i2c_high_sda(void)
{
   dirs2 = dirs2 | 0x01;
   *pm2 = dirs2;
#ifdef D    /* used for debugging */
   printf("SDA_HIGH %x\n", dirs2);
   delay(500);
#endif
}

void i2c_low_sda(void)
{
   outs2 = outs2 & (~0x01); /* zero the output pin */
   *p2 = outs2;
   dirs2 = dirs2 & (~0x01);    /* and output */
   *pm2 = dirs2;
#ifdef D
   printf("SDA_LOW %x\n", dirs2);
   delay(500);
#endif
}

void i2c_high_scl(void)
{
   dirs2 = dirs2 | 0x02;  /* bring SCL to high impedance */
   *pm2 = dirs2;
#ifdef D
   printf("SCL_HIGH %x\n", dirs2);
   delay(500);
#endif
}

void i2c_low_scl(void)
{
   outs2 = outs2 & (~0x02);
   *p2 = outs2;             /* zero the output pin */
   dirs2 = dirs2 & (~0x02);    /* and output */
   *pm2 = dirs2;
#ifdef D
   printf("SCL_LOW %x\n", dirs2);
   delay(500);
#endif
}