// 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;
}