Overview
The Dallas DS1803 is a dual potentiometer which is controlled using the Philips I2C protocol.
More details on the operation in the context of a Parallax BASIC Stamp 2 appears elsewhere on this web site.
// DS1803_1.BS2 // // Illustrates how to control DS1803 Addressable Dual Potentiometer // // 16F84 DS1803 // // RB.1 (term 7) ------------------- SCL (term 9) ----- To Other // RB.0 (term 6) ------------------- SDA (term 10) ----- 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. In this // program A2, A1 and A0 are connected to ground. // // 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 a serial LCD on // RA.0. // // Note that in function ds1803_read_pots the settings are returned to // calling function using pointers. // // copyright Peter H. Anderson, Baltimore, MD, April, '99 #case #include <16f84.h> #include <string.h> #include <defs_f84.h> void ds1803_write_pot(int device, int pot, int setting); void ds1803_read_pots(int device, int *p_setting_0, int *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); // 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); #define TxData 0 // RA.0 for serial LCD #define SDA_PIN rb0 // RB.0 #define SCL_PIN rb1 // RB.1 #define SDA_DIR trisb0 #define SCL_DIR trisb1 void main(void) { int pot_setting_0, pot_setting_1; ds1803_write_pot(0, 0, 0x55); // dev 0, pot 0, setting 0x55 ds1803_write_pot(0, 1, 0x80); ds1803_read_pots(0, &pot_setting_0, &pot_setting_1); lcd_init(); lcd_hex_byte(pot_setting_0); lcd_char(' '); lcd_hex_byte(pot_setting_1); delay_ms(500); } void ds1803_write_pot(int device, int pot, int 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_ms(25); } void ds1803_read_pots(int device, int *p_setting_0, int *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, n; i2c_high_sda(); for (n=0; n<8; n++) { i2c_high_scl(); if (SDA_PIN) { i_byte = (i_byte << 1) | 0x01; // msbit first } else { i_byte = i_byte << 1; } i2c_low_scl(); } return(i_byte); } void i2c_out_byte(byte o_byte) { byte n; for(n=0; n<8; n++) { if(o_byte&0x80) { i2c_high_sda(); } else { i2c_low_sda(); } 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) { // bring SDA to high impedance SDA_DIR = 1; delay_10us(5); } void i2c_low_sda(void) { SDA_PIN = 0; SDA_DIR = 0; // output a hard logic zero delay_10us(5); } void i2c_high_scl(void) { SCL_DIR = 1; // high impedance delay_10us(5); } void i2c_low_scl(void) { SCL_PIN = 0; SCL_DIR = 0; delay_10us(5); } // delay routines 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); } // LCD routines 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); }