PIC16C505 - Frost Alarm using a DS18S20
// FRST_ALM.C (PIC16C505), CCS PCB
//
// Frost Alarm.
//
// Continually measures temperature using a Dallas DS18S20. If the temperature
// is negative (degrees C) or if T_C < T_threshold then a Sonalert on PORTC2
// is pulsed five times.
//
// The alarm threshold temperature T_thresh is measured using the RC configuration
// shown below. If the time required for the capacitor to discharge to a logic zero
// exceeds nominally 65 ms as might be the case if the potentiometer is not present
// the T_thresold is 2 degrees C. Otherwise, the RC time is mapped into T_threshold
// values in the range of 0 to 14 degrees C and 30 degrees C. The 30 degrees C is
// provided for testing of the sonalert alarm.
//
// The program continually loops, displaying the values of T_threshold and T_C on a
// serial LCD or PC COM port at 9600, inverted.
//
// PIC16C505
// PORTC1 (term 9) --- 330 ----- --------
// | |
// 1.0 uFd 10K Pot
// | |
// | 10K Resistor
// | |
// GRD GRD
// +5VDC
// |
// 4.7K
// |
// PORTB0 (term 13) ---------------- DS18S20
// PORTC0 (term 10) ---------------- To Serial LCD or PC COM Port
//
//
// PORTC2 (term 8) ----------------- Sonalert ---- GRD
//
// GRD ---- \---------- PORTB3 (term 4) See Text.
//
// copyright, Peter H. Anderson, Elmore, VT, July, '01
#case
#device PIC16C505 *=8
#include <defs_505.h>
#include <delay.h>
#include <ser_505.h>
#define TRUE !0
#define FALSE 0
#define TxData 0 // use PORTC0
#define INV // send inverted RS232
#define _1W_PIN 0
byte meas_threshold(void);
byte meas_temperature(void);
void alarm(void);
// 1-wire prototypes
void w1_init(void);
int w1_in_byte(void);
void w1_out_byte(byte d);
void w1_strong_pull_up(void);
void main(void)
{
byte T_C, T_threshold, minus_flag;
DIRB = 0x3f;
DIRC = 0x3f;
while(1)
{
ser_init();
// measure the alarm threshold
T_threshold = meas_threshold();
ser_dec_byte(T_threshold, 2);
ser_new_line();
T_C = meas_temperature();
if (T_C & 0x80) // if negative
{
minus_flag = TRUE;
T_C = (~T_C) + 1;
ser_char('-');
}
else
{
minus_flag = FALSE;
}
if (T_C > 9)
{
ser_dec_byte(T_C, 2);
}
else
{
ser_dec_byte(T_C, 1);
}
if ((minus_flag) || (T_C < T_threshold))
{
alarm();
}
else
{
delay_ms(1000);
}
}
}
void alarm(void) // pulse sonalert five times
{
byte n;
portc2 = 0;
dirc2 = 0;
#asm
MOVF DIRC, W
TRIS PORTC
#endasm
for (n=0; n<5; n++)
{
portc2 = 1;
delay_ms(100);
portc2 = 0;
delay_ms(100);
}
}
byte meas_threshold(void)
{
byte count_hi, count_lo, tmr0_old, tmr0_new, T_thresh;
t0cs = 0; // fosc / 4 is clock source
psa = 0; // prescale assigned to WDT
ps2 = 0; // 1:1 prescale
ps1 = 0;
ps0 = 0;
#asm
MOVF OPTIONS, W
OPTION
#endasm
dirc1 = 0; // output
#asm
MOVF DIRC, W
TRIS PORTC
#endasm
portc1 = 1; // charge capacitor
delay_ms(10);
count_hi = 0;
count_lo = 0;
tmr0_old = 0x00;
TMR0 = 0x00;
#asm
BSF DIRC, 1
MOVF DIRC, W
TRIS PORTC
#endasm
while(1) // wait for cap to discharge
{
tmr0_new = TMR0;
if ((tmr0_new < 0x80) && (tmr0_old >= 0x80)) // there was a roll over
{
++count_hi;
if (count_hi == 0) // no zero crossing with 65 ms
{
return(2);
}
}
if (!portc1) // if capacitor discharged below zero corssing
{
count_lo = tmr0_new;
break;
}
tmr0_old = tmr0_new;
}
if (count_hi < 24)
{
count_hi = 24;
}
else if (count_hi > 48)
{
count_hi = 48;
}
else if (count_hi > 40)
{
return(30); // this is to test the alarm
}
else
{
return(count_hi - 24); // in the range of 0 to 16 degrees C
}
}
byte meas_temperature(void)
{
byte T_C, sign;
w1_init();
w1_out_byte(0xcc); // skip ROM
w1_out_byte(0x44); // perform temperature conversion
w1_strong_pull_up();
w1_init();
w1_out_byte(0xcc); // skip ROM
w1_out_byte(0xbe); // read the result
T_C = w1_in_byte();
sign = w1_in_byte();
if (sign) // if negative, change to pos for divide by two
{
T_C = ~T_C + 1;
}
T_C = T_C / 2;
if (sign) // negative
{
T_C = ~T_C + 1;
}
return(T_C);
}
// The following are standard 1-Wire routines.
void w1_init(void)
{
#asm
BSF DIRB, _1W_PIN // high impedance
MOVF DIRB, W
TRIS PORTB
BCF PORTB, _1W_PIN // bring DQ low for 500 usecs
BCF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
#endasm
delay_10us(50);
#asm
BSF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
#endasm
delay_10us(50);
}
byte w1_in_byte(void)
{
byte n, i_byte, temp;
for (n=0; n<8; n++)
{
#asm
BCF PORTB, _1W_PIN // wink low and read
BCF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
BSF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
CLRWDT
NOP
NOP
NOP
NOP
#endasm
temp = PORTB; // now read
if (temp & (0x01 << _1W_PIN))
{
i_byte=(i_byte>>1) | 0x80; // least sig bit first
}
else
{
i_byte=i_byte >> 1;
}
delay_10us(6);
}
return(i_byte);
}
void w1_out_byte(byte d)
{
byte n;
for(n=0; n<8; n++)
{
if (d&0x01)
{
#asm
BCF PORTB, _1W_PIN // wink low and high and wait 60 usecs
BCF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
BSF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
#endasm
delay_10us(6);
}
else
{
#asm
BCF PORTB, _1W_PIN // bring low, 60 usecs and bring high
BCF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
#endasm
delay_10us(6);
#asm
BSF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
#endasm
}
d=d>>1;
} // end of for
}
void w1_strong_pull_up(void) // bring DQ to strong +5VDC
{
#asm
BSF PORTB, _1W_PIN // output a hard logic one
BCF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
#endasm
delay_ms(750);
#asm
BSF DIRB, _1W_PIN
MOVF DIRB, W
TRIS PORTB
#endasm
}
#include <delay.c>
#include <ser_505.c>