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