Overview
In routine 1820_1.C a temperature measurement is made on RB.0, RB.1, RB.2 and RB.3. For each measurement, all nine bytes are stored in array buff and displayed on the serial LCD.
Note that on terminals other than RB.0, the temperature (the first two bytes) is falsely reported as zero. This suggest a problem with the strong pullup routine where a hard logic one is maintained on DQ for 250 ms. However, I don't see the problem. If you find it, please let me know.
In routine 1820_2.C the 8-byte ROM address of the DS1820 is fetched and saved to the 16F84's EEPROM and displayed on the LCD display. The ROM address is then fetched and the DS1820 is addressed (match ROM), a temperature measurement is performed and the nine bytes are displayed on the LCD
In routine 1820_3.C, a temperature measurement (Skip ROM) is performed and the nine bytes are displayed. A cyclic redundancy check is then performed on the nine bytes and the result is displayed. Note that the CRC should be 0x00. More discussion of the CRC algorithm appears on my main PIC page.
// 1820_1.C, CCS - PCM (PIC16F84) // // Illustrates an implementation of Dallas 1-wire interface. // // Configuration. DS1820 on RB.0, RB.1, RB.2 and RB.3. Note a 4.7K // pullup to +5V is required. DS1820s configured in parasite power mode. // That is, VCC connected to ground. // // Reads and displays nine bytes from each device in turn and displays // the result on serial LCD connected to RA.0. // // Bug. Temperature (first two bytes) is zero on RB.1, RB.2 and RB.3 // // copyright, Peter H. Anderson, Baltimore, MD, April, '99 #include <16f84.h> #include <string.h> #include <defs_f84.h> #define MAX_SENSORS 4 // 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); #define TxData 0 // output to serial LCD void main(void) { int buff[9], sensor, n; for (sensor=0; sensor<MAX_SENSORS; sensor++) { _1w_init(sensor); _1w_out_byte(0xcc, sensor); // skip ROM _1w_out_byte(0x44, sensor); // perform temperature conversion _1w_strong_pull_up(sensor); _1w_init(sensor); _1w_out_byte(0xcc, sensor); // skip ROM _1w_out_byte(0xbe, sensor); // read the result for (n=0; n<9; n++) { buff[n]=_1w_in_byte(sensor); } lcd_init(); lcd_hex_byte(sensor); // display the sensor number lcd_new_line(); for (n=0; n<4; n++) // display 4 bytes { lcd_hex_byte(buff[n]); lcd_char(' '); } lcd_new_line(); for (n=4; n<9; n++) // displays the other 5 bytes { lcd_hex_byte(buff[n]); lcd_char(' '); } lcd_new_line(); delay_ms(1000); } } // 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) // bring DQ to strong +5VDC { PORTB = 0x01 << sensor; TRISB = 0xff & (~(0x01 << sensor)); delay_ms(250); TRISB = 0xff; } // 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 } 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); }
// Program 1820_2.C // // Reads 64-bit address from DS1820, saves to the 16F84's EEPROM // and displays it on serial LCD. // // Uses 64-bit address to perform temperature measurement. Data is // is displayed on serial LCD // // // 16F84 DS1820 // PortB.0 (term 6) ------------------------------ DQ (term 2) // // PORTA, Bit 0 (terminal 17) ------ TX ----------> to RX on Serial LCD // // // copyright, Peter H. Anderson, Baltimore, MD, Apr, 99 #case #include <16f84.h> #include <string.h> #include <defs_f84.h> void display_lcd(int *d, int num_vals); void get_16f84_eeprom(int adr, int *d, int num_vals); void put_16f84_eeprom(int adr, int *d, int num_vals); void write_16f84_eeprom(int adr, int d); int read_16f84_eeprom(int adr); void ds1820_read_rom(int *d, int sensor); void make_temperature_meas(int *adr, int *d, int sensor); // 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); #define TxData 0 void main(void) { int dev_adr[8], t_dat[9]; // temporary storage lcd_init(); ds1820_read_rom(dev_adr, 0); // read serial number from DS1820 display_lcd(dev_adr, 8); // display the result on LCD put_16f84_eeprom(0x00, dev_adr, 8); // save to eeprom, beginning at adr 0x00, 8 bytes // now fetch the serial number, address and perform a temperature // measurment get_16f84_eeprom(0x00, dev_adr, 8); // fetch from 16F84, 8 bytes and return in array d make_temperature_meas(dev_adr, t_dat, 0); display_lcd(t_dat, 9); // display the 9 byte result #asm DONE: clrwdt GOTO DONE #endasm } void display_lcd(int *d, int num_vals) { int n; for (n=0; n<num_vals; n++) { if ((n%4==0) && (n!=0)) { lcd_new_line(); } lcd_hex_byte(d[n]); lcd_char(' '); } lcd_new_line(); } void put_16f84_eeprom(int adr, int *d, int num_vals) { int n; for(n=0; n<num_vals; n++, adr++) { write_16f84_eeprom(adr, d[n]); } } void get_16f84_eeprom(int adr, int *d, int num_vals) { int n; for(n=0; n<num_vals; n++, adr++) { d[n]=read_16f84_eeprom(adr); } } void write_16f84_eeprom(int adr, int d) { EEADR = adr; EEDATA = d; wren = 1; EECON2 = 0x55; // protection sequence EECON2 = 0xaa; wr = 1; // begin programming sequence delay_ms(20); wren = 0; // disable write enable } int read_16f84_eeprom(int adr) { EEADR=adr; rd=1; // set the read bit return(EEDATA); } void ds1820_read_rom(int *d, int sensor) { int n; _1w_init(sensor); _1w_out_byte(0x33, sensor); for(n=0; n<8; n++) { d[n]=_1w_in_byte(sensor); } } void make_temperature_meas(int *adr, int *d, int sensor) { int n; _1w_init(sensor); _1w_out_byte(0x55, sensor); // match ROM for(n=0; n<8; n++) // followed by the 8-byte ROM address { _1w_out_byte(adr[n], sensor); } _1w_out_byte(0x44, sensor); // start temperature conversion _1w_strong_pull_up(sensor); _1w_init(sensor); _1w_out_byte(0x55, sensor); // match ROM for(n=0; n<8; n++) // followed by the 8-byte ROM address { _1w_out_byte(adr[n], sensor); } _1w_out_byte(0xbe, sensor); for(n=0; n<9; n++) { d[n]=_1w_in_byte(sensor); } } // 1-Wire, delay and LCD routines are the same as 1820_1.C
// 1820_3.C // // Cyclic redudancy check (CRC). // // Makes measurement and displays the nine values on serial LCD. // Then calculates CRC and displays. // // copyright, Peter H. Anderson, Baltimore, MD, Apr, '99 #case #include <16f84.h> #include <string.h> #include <defs_f84.h> int calc_crc(int *buff, int num_vals); // 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); // 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 void main(void) { int buff[9], sensor=0, crc, n; _1w_init(sensor); _1w_out_byte(0xcc, sensor); // skip ROM _1w_out_byte(0x44, sensor); // perform temperature conversion _1w_strong_pull_up(sensor); _1w_init(sensor); _1w_out_byte(0xcc, sensor); // skip ROM _1w_out_byte(0xbe, sensor); for (n=0; n<9; n++) { buff[n]=_1w_in_byte(sensor); } lcd_init(); for (n=0; n<4; n++) { lcd_hex_byte(buff[n]); lcd_char(' '); } lcd_new_line(); for (n=4; n<9; n++) { lcd_hex_byte(buff[n]); lcd_char(' '); } lcd_new_line(); crc = calc_crc(buff, 9); lcd_hex_byte(crc); lcd_new_line(); delay_ms(500); } int calc_crc(int *buff, int num_vals) { int 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); } // 1_Wire, delay and LCD routines are the same as in 1820_1.c