Site hosted by Angelfire.com: Build your free website today!

'****************************************************************
'* Name : RTC876_Rev30.BAS *
'* Author : Rebecca Martin *
'* Notice : Copyright (c) 2006 *
'* : All Rights Reserved *
'* Date : 5/17/2007 *
'* Version : 3.0.0 *
'* Notes : PicBasic Pro program that demonstrates the use *
'* : of the Timer 1 interrupt for a real-time clock. *
'* : An external 32.768kHz Xtal on RC0 & RC1 is the *
'* : clock for Timer1. *
'* : Ver. 2.0 leaves Ports RC.6 and RC.7 open to *
'* : implement UART and serial comm via a MAX232. *
'* : V. 2.0 shifts LCD Data Port from RC.4-RC.7 *
'* : to RB.0-RB.3, shifts LCD Anode from RB.2 to RC.5, *
'* : and Triac Driver from RB.1 to RC.4. *
'* : RA.1 now configured to use as ADC for heat sink *
'* : temperature sensing. *
'* : Ver. 3.0 changes the ADC reference to *
'* : differential to raise the upper temp measurement *
'* : limit to 123F.
'****************************************************************
High PORTC.4 ' Start with triac off before doing anything!
high PORTC.5 ' Backlight ON.
DEFINE OSC 4 ' 4 Mhz xtal

' Set port for LCD
DEFINE LCD_DREG PORTB ' Define PIC port used for LCD Data lines
DEFINE LCD_DBIT 0 ' Define first pin of portB connected to LCD DB4
DEFINE LCD_RSREG PORTC ' Define PIC port used for RS line of LCD
DEFINE LCD_RSBIT 2 ' Define Portb pin used for RS connection
DEFINE LCD_EREG PORTC ' Define PIC prot used for E line of LCD
DEFINE LCD_EBIT 3 ' Define PortB pin used for E connection
DEFINE LCD_BITS 4 ' Define the 4 bit communication mode to LCD
DEFINE LCD_LINES 1 ' Define using a 1 line LCD
DEFINE LCD_COMMANDUS 2000 ' Define delay between sending LCD commands
DEFINE LCD_DATAUS 50 ' Define delay time between data sent.

' Define ADCIN parameters
Define ADC_BITS 10 ' Set number of bits in result
Define ADC_CLOCK 3 ' Set clock source (3=rc)
Define ADC_SAMPLEUS 50 ' Set sampling time in uS

' Define Assembly Language interrupt handler
DEFINE INTHAND myint ' Define interrupt handler

' Establish special variables for assembly interrupts
wsave VAR BYTE $20 system ' W storage in bank0
wsave1 VAR BYTE $a0 system ' W storage in bank1
wsave2 VAR BYTE $120 system ' W storage in bank2
wsave3 VAR BYTE $1a0 system ' W storage in bank3
ssave VAR BYTE bank0 system ' Status register save
psave VAR BYTE bank0 system ' PCLATH register save
TICK VAR BYTE bank0 ' make sure variables are in bank 0 if they
' are to be used in the interrupt handler 
PRELOADH var byte bank0 ' high byte value for timer preload
PRELOADL var byte bank0 ' low byte value for timer preload

' Establish Program variables
seconds VAR BYTE ' Elapsed seconds
minutes VAR byte ' Elapsed minutes
hour var byte ' Elapsed hours, 12 hour format
h24 var byte ' hours in 24 h format
ampm var bit ' true (1) when PM
adval var word ' A-D conversion result
Tin var word ' Temperature reading
Tind var word ' Decimal part of Temp reading
av var word ' # of temperature samples to average
SetTemp var word ' Trigger temp to turn fan or heater on.
ST var word
SetTempD var word
HeatCool var byte '0 for cooling mode, 1 for heating, 2 for OFF
Hysteresis var byte 'Temp. hysteresis loop variable 0.5°F to 4°F (5 to 40)
BackLED var bit '1 = ON, 0 = OFF. Bit RC.5 drives the lamp.
HST var word 'Heat Sink Temperature
HSTd var word 'decimal part of HST

' Preset Program Variables 
seconds = 59 ' Preset time to 12:00:00 Midnight
minutes = 59
hour = 11
h24 = 23
settemp = 720 ' Preset temp to 72.0°F
heatcool = 2 ' startup in OFF mode
Hysteresis = 5 ' +/-0.5°F hysteresis loop
backled = 1 ' Backlight ON at startup 

' Preset Assembly variables
PRELOADH = $80 ' Preset timer1h to 80 hex (nom. value f/ 32768Hz Xtal
preloadl = $00 ' Added because my crystal is a bit fast...

T1CON = $0F ' Turn on Timer1, prescaler = 1, External 32.768Khz
INTCON = $C0 ' Enable global interrupts, peripheral interrupts
PIE1 = $01 ' Enable TMR1 overflow interrupt

GoTo init ' jump over the interrupt handler and subroutines

'******************** Assembly language interrupt handler ********************
Asm ; Tell PicBasic Pro Assembly Commands follow
myint 
; Uncomment the following if the device has less than 2k of code space
;movwf wsave ; Save W
;swapf STATUS, W ; Swap STATUS to W (swap avoids changing STATUS)
;clrf STATUS ; Clear STATUS
;movwf ssave ; Save swapped STATUS
;movf PCLATH, W ; Move PCLATH to W
;movwf psave ; Save PCLATH

; Set the high register of Timer1 to cause an interrupt every
; 32768 counts (65536-32768 = 32768 or $8000). 
movf _PRELOADH,W ; Preload Timer1 High Byte for 1 second overflow
movwf TMR1H ; Set TMR1H to 80h
movf _PRELOADL,W ; Preload Timer1 Low Byte for slow Xtal
movwf TMR1L ; Set TMR1L to 00h
incf _TICK,F ; Increment TICK count (number of overflows)
bcf PIR1, 0 ; Clear interrupt flag 

movf psave, W ; restore the state of everything
movwf PCLATH
swapf ssave, W
movwf STATUS
swapf wsave, F
swapf wsave, W
retfie ; Return from interrupt
EndAsm ' End of assembly code

' ***********************
get_time: 'Subroutine to update the hours, minutes and seconds variables
' Read the timer1 overflows as TICK and then add to the seconds 
' variable. Increment Minutes and Hours as necessary. 
PIE1 = 0 ' Mask the interrupt while we're messing with TICK
seconds = seconds + tick ' Add the accumulated seconds
tick = 0 ' Retain the left-over ticks
PIE1 = $01 ' Interrupt on again
minutes = minutes + (seconds / 60) ' Add the accumulated minutes
seconds = seconds // 60 ' Retain the left-over seconds
hour = hour + (minutes/60) 'Add the accumulated hours
h24 = h24 + (minutes/60) '24 hour to set ampm flag
minutes = minutes//60 ' Retain the left -over minutes
if hour > 12 then
HOUR = HOUR - 12 '12 HOUR FORMAT
endif
If h24 = 24 then
h24 = 0 : ampm = 0
endif
If h24 > 11 then
ampm = 1
endif
Return ' Return to the main program

get_temp: ' Subroutine to average 50 temp samples and set triac accordingly
adval = 0: Tin = 0: tind = 0
for av = 1 to 50 '
ADCIN 0, adval: Tin = Tin + adval ' take 50 samples and average them
next av '
Tin = Tin / 50
if heatcool = 2 then high PORTC.4 ' OFF mode.
If tin <= settemp - Hysteresis and heatcool = 1 then low PORTC.4 
'Turn on the heater active low
if tin >= settemp + Hysteresis and heatcool = 1 then high PORTC.4
'Turn off the heater w/hysteresis 
If tin >= settemp + Hysteresis and heatcool = 0 then low PORTC.4 
'Turn on the Fan
if tin <= settemp - Hysteresis and heatcool = 0 then high PORTC.4 
'Turn off the fan w/hysteresis
Tind = Tin: Tin = Tin / 10 ' get the decimal remainder of the temperature
Return ' Return to the main program

set_BackLED: 'turn backlight on/off
gosub Check_RB5 'debounce key
while PORTB.5 = 1
if PORTB.4 = 0 then backled = not backled
if backled then 
high PORTC.5 ' Backlight ON 
else
low PORTC.5 ' Backlight OFF
endif
if backled = 0 then lcdout $fe, 1, "Backlight OFF "
If backled = 1 then lcdout $fe, 1, "Backlight ON "
pause 333 
Wend

' following code is for engineering measurements
' comment out for production model
gosub Check_RB5 'debounce key
while PORTB.5 = 1 ' Measure the heat sink temperature
adval = 0: hst = 0: hstd = 0
for av = 0 to 50
adcin 1, adval: HST = HST + adval
next av
hst = hst/50: hstd = hst: hst = hst/10
Lcdout $fe, $80, "Heat Sink: ",dec HST, ".", dec1 HSTd, $df
pause 333
Wend
' end of engineering mode code block

return

set_All: ' Subroutine to set all modes
' Subroutine to set functional mode (heat or cool).
gosub Check_RB4 'debounce key
while PORTB.4 = 1
if PORTB.5 = 0 then heatcool = heatcool + 1 ' Toggle mode.
if heatcool > 2 then heatcool = 0
if heatcool = 0 then lcdout $fe, 1, "Mode: COOL "
If heatcool = 1 then lcdout $fe, 1, "Mode: HEAT "
if heatcool = 2 then lcdout $fe, 1, "Mode: OFF " 
pause 333 
Wend
if heatcool = 1 then 
settemp = 720 ' default temp for heat ON = 72°F
else
if heatcool = 0 then settemp = 750 ' default for cooling = 75°F
endif
gosub Check_RB4 'debounce key
' Subroutine to set temperature threshold.
while PORTB.4 = 1
if PORTB.5 = 0 then settemp = settemp + 5 'Increment setpoint 0.5°F
If settemp > 850 then settemp = 550 'allowed range is 55°F to 85°F
settempd = settemp
St = settemp / 10
lcdout $fe, 1, "Set Temp: ", dec2 st, ".", dec1 settempd, $df, "F"
pause 333 
Wend
gosub Check_RB4 'debounce key
' Subroutine to set the time of day.
while PORTB.4 = 1
if PORTB.5 = 0 then hour = hour + 1: h24 = h24 + 1 'Increment the hour
If hour > 12 then hour = 1 ' 12 hour format
if h24 > 23 Then 
h24 = 0: ampm = 0
endif
if h24 > 11 then ampm = 1
lcdout $fe, 1, "Set Hour:", dec2 hour, ":", dec2 minutes
if ampm = 0 then lcdout "AM"
if ampm = 1 then lcdout "PM"
pause 333 
Wend
gosub Check_RB4 'debounce key
while PORTB.4 = 1
if PORTB.5 = 0 then minutes = minutes + 1 'Increment minutes
If minutes > 59 then minutes = 0 ' 
lcdout $fe, 1, "Set Mins:", dec2 hour, ":", dec2 minutes
if ampm = 0 then lcdout "AM"
if ampm = 1 then lcdout "PM"
pause 333 
Wend
Return

Check_RB4:
while PORTB.4 = 0 'debounce the key (Sw0)
pause 12
wend
return

Check_RB5:
while PORTB.5 = 0 'debounce the key (Sw1)
pause 12
wend
return 


init: 
' **************************************************************
' Begin program code here. The time will be updated when you *
' call the get_time routine. *
' **************************************************************
TRISA = %11111111 ' Set PORTA to all input
TRISC.4 = 0 ' Port C.4 (output) turns the triac on (low) and off
TRISC.5 = 0 ' Port C.5 (output) turns the LED Backlight on
TRISB.4 = 1 ' Sw0 input (active low) on port B.4 
TRISB.5 = 1 ' Sw1 input (active low) on port B.5
ADCON1 = %10001011 ' Set PORTA as ADC inputs with A.3 as Vref+ input,
' A.2 as Vref- and r. justify result.

high PORTC.5 ' Backlight ON at boot to show logo

LCDOut $fe, 1, "RebCor,Inc. 2007" ' Clear LCD
pause 2000

main: 'Main Program Loop

GoSub get_time ' Update minutes and seconds
gosub get_temp ' update the temp and set/clear the triac
if PORTB.4 = 0 then gosub set_All
if PORTB.5 = 0 then gosub set_BackLED

'**** Display the temperature and time ******
Lcdout $fe, $80, dec Tin, ".", dec1 Tind, $df , " " 
if hour > 9 then 
lcdout $fe, $86, DEC2 hour, ":", DEC2 minutes , ":", DEC2 seconds
else 'blank time lead zero
lcdout $fe, $86, " ", DEC1 hour, ":", DEC2 minutes , ":", DEC2 seconds
endif
if ampm = 0 then 
lcdout $fe, $80 + 14, "AM"
else
lcdout $fe, $80 + 14, "PM"
endif 
pause 333 'loop 3 times per second
GoTo main ' Repeat main loop

End

BACK