// DS18B20_1.C - Sourceboost C // // copyright, P H Anderson, July 6, '09 #include <system.h> #include <icd2.h> #include <string.h> #include <stdio.h> #pragma DATA 0x2007, 0x28e4 #pragma DATA 0x2008, 0x3eff #pragma CLOCK_FREQ 4000000 #define NEGATIVE 1 #define POSITIVE 0 #define TRUE !0 #define FALSE 0 typedef unsigned char byte; // 1-wire prototypes byte _1w_init(void); byte _1w_read_bit(void); void _1w_write_bit(byte d); byte _1w_in_byte(void); void _1w_out_byte(byte d, byte strong); void _1w_pin_hi(void); void _1w_pin_low(void); byte calc_crc(byte *buff, byte num_vals); void print_str(char *s); void print_float(byte sign_bit, byte whole, byte fract); void asynch_setup(void); rom byte _0_mask[8] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f}; rom byte _1_mask[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; byte channel; void main() { unsigned int T_reading; int Tc_100; byte a, n, whole, fract,sign_bit, crc, d[9]; char s[25]; osccon = 0x61; anselh = 0x00; // turn off highest six A/Ds trisb = 0xff; portb = 0x00; asynch_setup(); while(1) { channel = 1; // globally defined to avoid having to pass // to every function _1w_init(); _1w_out_byte(0xcc, 0); // skip ROM _1w_out_byte(0x44, 1); // perform temperature meas // followed by strong pullup delay_s(1); _1w_init(); _1w_out_byte(0xcc, 0); // skip ROM _1w_out_byte(0xbe, 0); // send temperature data for (n=0; n<9; n++) { d[n] = _1w_in_byte(); } crc = calc_crc(d, 9); // check CRC if (crc != 0) // failure { strcpy(s, "-88.88?n"); print_str(s); } else { T_reading = d[1]; // high byte T_reading = (T_reading << 8) | d[0]; // a[0] is low byte if (T_reading & 0x8000) { sign_bit = NEGATIVE; T_reading = (T_reading ^ 0xffff) + 1; // 2s comp } else { sign_bit = POSITIVE; } Tc_100 = (6 * T_reading) + (T_reading / 4); // multiple by 6.25 whole = Tc_100 / 100; fract = Tc_100 % 100; print_float(sign_bit, whole, fract); } delay_s(2); } } byte calc_crc(byte *buff, byte num_vals) // see http://www.phanderson.com/PIC for an explanation { byte shift_reg=0, data_bit, sr_lsb, fb_bit, i, j, sum=0; for (i=0; i<num_vals; i++) { sum = sum + buff[i]; } if (sum == 0) { return(1); } 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); } void asynch_setup(void) { // for UART, see Manual pages beginning at page 151 trisc.7 = 1; trisc.6 = 1; // TX rcsta.SPEN = 1; // enable serial port txsta.TXEN = 1; // enable transmitter txsta.SYNC = 0; // asynchronous txsta.BRGH = 1; spbrg = 25; // 9600 baud at 4.0 MHz } void print_float(byte sign_bit, byte whole, byte fract) { char s[20]; if (sign_bit == NEGATIVE) { strcpy(s, "-"); print_str(s); } sprintf(s, "%u", whole); print_str(s); strcpy(s, "."); print_str(s); sprintf(s, "%02u", fract); print_str(s); strcpy(s, "?n"); print_str(s); } void print_str(char *s) { while(*s != '\0') { txreg = *s; while(txsta.TRMT == 0) { } ++s; } } // The following are standard 1-Wire routines. byte _1w_init(void) { int n = 500; asm { CLRWDT } _1w_pin_hi(); _1w_pin_low(); delay_10us(50); _1w_pin_hi(); while(--n) { if (((portb >> channel) &0x01) == 0) { delay_10us(50); return(TRUE); } } delay_10us(50); return(FALSE); } byte _1w_read_bit(void) { byte temp, _0, _1, n; n = 3; // possibly adjust this _0 = _0_mask[channel]; _1 = _1_mask[channel]; portb &= _0; // bring bit to zero trisb &= _0; // output asm { NOP NOP } trisb |= _1; // back to one while(--n) ; // loop delay temp = portb; // read state 10 usec later delay_10us(6); return((temp >> channel)&0x01); } void _1w_write_bit(byte d) { byte temp, a, _0, _1; _0 = _0_mask[channel]; _1 = _1_mask[channel]; if (d&0x01) // wink low and then back to high Z { portb &= _0; trisb &= _0; asm { NOP NOP NOP NOP NOP } // asm delay_2us(2); trisb |= _1; delay_10us(6); } else // bring low for 60 usecs { portb &= _0; trisb &= _0; delay_10us(6); trisb |= _1; } } byte _1w_in_byte(void) // read a byte from DS18B20 { byte n, i_byte = 0x00, b; for (n=0; n<8; n++) { b = _1w_read_bit(); if (b & 0x01) { 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(byte d, byte strong) // output a byte to DS1820 { byte a, b, n, _0, _1; _0 = _0_mask[channel]; _1 = _1_mask[channel]; for(n=0; n<8; n++) { _1w_write_bit(d&0x01); d=d>>1; } if (strong) { porttb |= _1; trisb &= _0; delay_s(1); trisb |= _1; portb &= _0; } } void _1w_pin_hi(void) // high Z { byte _1 = _1_mask[channel]; trisb |= _1; } void _1w_pin_low(void) // hard logic zero { byte _0; _0 = _0_mask[channel]; portb &= _0; trisb &= _0; }