; Web-Monitored Thermostat
; Larry Pellach and Brian Silverstein
; Final Project
; EE 476 Monday Section Group 3
;=============================================
;,nolist
.include "c:\avrtool2\appnotes\8535def.inc"
;.include "c:\courses\ee476\8535def.inc
.list
;=============================================
;define registers
.def save =r1 ;save
location for the status resister
.def reload =r2 ;value
to set timer 0 to 1 Msec.
.def lcdstat =r3
.def timeout =r17 ;Timeout
value in mSec passed to subroutine
.def fan =r18
.def button =r19
.def thresh =r20
.def temp =r21 ;temporary
register
.def instuff =r22
.def RXparm =r23
.def temp2 =r24
.def itemp =r25
.def anaL =r26 ;frequency
high
.def anaH =r27 ;frequency
low
.equ lcdrs =PC6 ;LCD
rs pin connected to PC6
.equ lcdrw =PC5 ;LCD
r/w pin connected to PC5
.equ lcde =PC4 ;LCD
e pin connected to PC4
;=============================================
;EBC
;Initialization
.dseg
string: .byte 6
.cseg
.org $0000
rjmp RESET ;reset
entry vector
reti
reti
reti
reti
reti
rjmp T1CompA
reti
reti
rjmp TIMER
reti
reti
reti
reti
reti
reti
reti
;=============================================
RESET:
ldi Temp, LOW(RAMEND) ;setup stack pointer
out SPL, Temp
ldi Temp, HIGH(RAMEND)
out SPH, Temp
;set up
analog converter to read channel zero
ldi temp, 0
out ADMUX, temp
;set up the
PORTs
ser Temp ;set
PORTC to be
out DDRB,Temp ;all
OUTPUTS for fan output
ldi temp, 0x00
out PORTB, temp ;Initialize the fan to off
;set up the
PORTs
ser Temp ;set
PORTC to be
out DDRC,Temp ;all
OUTPUTS for LCD
ldi Temp, 0x7F ;Need Pin7 input for switch
out DDRD,Temp ;and
leave the rest outputs
;enable
timer0 overflow and timer1 compare match A
ldi Temp,0b00010001 ;0th pin is timer0
out TIMSK, Temp
;setup UART
-- RX, TX pins
ldi temp, 0b00011000
out UCR, temp
;set baud
rate to 9600
ldi temp, 25 ;9600 baud
out UBRR, temp
;set up
timer 0 for 1 mSec ticks
ldi temp, 3 ;prescale
timer by 64
out TCCR0, temp
ldi temp,256-62 ;preload timer since
mov reload, temp
out TCNT0, Reload ;62.5 x (64x.25) microSec = 1.0 mSec.
;and set
the compare time to 62500 ticks
ldi temp, 0xf4 ;set the match A register to
out OCR1AH, temp ;62500 since 62500*16microsec=1sec
ldi temp, 0x24 ;62500 = 0xf424
out OCR1AL, temp
ldi temp,0b00001011 ;prescale timer by 64 (one tick=16 microsec)
out TCCR1B, temp ;and clear-on-matchA
;initialize
registers
ldi AnaL, 0x00
ldi AnaH, 0x00
ldi thresh, 25
ldi button, 0
ldi temp, 0x00
ldi ZH, 0x00
ldi ZL, 0x00
ldi fan, 0x00
;Start the
clock ticking
sei ;enable all
interrupts
rcall lcdinit ;Initialize
LCD module
rcall lcdclr ;Clear
LCD screen
;Initialize
memory with initial threshold
ldi ZL, LOW(string)
ldi ZH, HIGH(string)
ldi temp, '0'
st Z, temp
;Store
initial threshold in memory
adiw ZL,1
ldi temp, '2'
st Z, temp
adiw ZL,1
ldi temp, '5'
st Z, temp
;Handshake
with web-server
;look for a
'g' for GO!
;Keep
looking for characters until a 'g' is found
;Then we
are assured that we are nSync with the web server
ldi temp, 0x80
rcall lcdcmd
ldi temp, 'W'
rcall lcdput
ldi temp, 'a'
rcall lcdput
ldi temp, 'i'
rcall lcdput
ldi temp, 't'
rcall lcdput
ldi temp, 'i'
rcall lcdput
ldi temp, 'n'
rcall lcdput
ldi temp, 'g'
rcall lcdput
ldi temp, '.'
rcall lcdcmd
ldi temp, 0xC0
rcall lcdcmd
ldi temp, '.'
rcall lcdput
ldi temp, '.'
rcall lcdput
synch:
rcall RXgetc
cpi RXparm, 'g'
brne synch
;We have
found our g and are nsync with the web/matlab interface
ldi temp, 0x00
;Main
program loop - executes tasks infinitely
main:
rcall Get_temperature
rcall Ana_to_LCD
rcall check_button
rcall Get_new_threshold
rcall Set_fan_status
rjmp main
;=============================================
;Get the temperature from the ADC and store it.
;Divide (shift) the temperature by 4 (2) to convert the
;10 bit input into the 8 bit temperature we are looking for.
Get_temperature:
in temp, ADCSR ;wait for A to D start
andi temp, 0b01000000;by checking if ADSC bit
is set
breq Get_temperature ;this bit is set by t1match interrupt
await: in temp, ADCSR ;wait for A to D done
andi temp, 0b01000000;by checking ADSC bit
brne await ;this
bit is cleared by the AtoD hardware
in AnaL, ADCL ;read the temperature
in AnaH, ADCH
lsr AnaH ;double
precision shift
ror AnaL ;right
twice
clc
lsr AnaH
ror AnaL
clc
ret
;=============================================
;Converts the hexadecimal temperature to ASCII characters
;for display on the LCD and output to the UART for
;Web display
Ana_to_LCD:
push AnaL
push AnaH
push temp
push temp2
push thresh
;Tell the
user this is the current temperature,
;and output
it
rcall lcdclr
ldi temp, 0x80
rcall lcdcmd
ldi temp, 'T'
rcall lcdput
ldi temp, 'e'
rcall lcdput
ldi temp, 'm'
rcall lcdput
ldi temp, 'p'
rcall lcdput
ldi temp, '='
rcall lcdput
;Send a 't'
for synchronization with the Matlab interface
;Then send
the three digits of the current temperature to
;the UART
and to the LCD
ldi temp, 0x00
ldi RXParm, 't'
rcall RXputc
hun1: ;hundreds
digit
ldi temp2, 0x64
sub AnaL, temp2
brmi hun2
inc temp
rjmp hun1
hun2:
subi temp, -'0'
mov RXparm, temp
rcall RXputc
ldi temp2, 0x64
add AnaL, temp2
cpi temp, '0'
breq dont_print
rcall lcdput
rjmp norm
dont_print:
ldi temp, 0x00
ldi temp, 0x87
rcall lcdcmd
ldi temp, 0xdF ; Degrees symbol
rcall lcdput
ldi temp, 0xC0
rcall lcdcmd
ldi temp, 'C' ; C for Celsius
rcall lcdput
ldi temp, 0x85
rcall lcdcmd
ldi temp, 0x00
rjmp tn1
norm:
ldi temp, 0xC0 ; Change to address 8
rcall lcdcmd
ldi temp, 0xdF ; Degrees symbol
rcall lcdput
ldi temp, 'C' ; C for Celsius
rcall lcdput
ldi temp, 0x86 ; Change to address 6
rcall lcdcmd
ldi temp, 0x00
tn1: ;tens
digit
sbiw AnaL, 10
brmi tn2
inc temp
rjmp tn1
tn2:
adiw AnaL, 10
subi temp, -'0'
mov RXparm, temp
rcall RXputc
rcall lcdput
mov temp, AnaL
subi temp, -'0'
mov RXparm, temp
rcall RXputc
rcall lcdput
ldi temp, 0xC3
rcall lcdcmd
ldi ZL, LOW(string)
ldi ZH, HIGH(string)
ld instuff, Z
cpi instuff, '0'
breq dont_printa
mov temp, instuff
rcall lcdput
dont_printa:
adiw ZL, 1
ld instuff, Z
mov temp, instuff
rcall lcdput
adiw ZL, 1
ld instuff, Z
mov temp, instuff
rcall lcdput
adiw ZL, 1
ldi temp, 0xdF ; Degrees symbol
rcall lcdput
ldi temp, 'C'
rcall lcdput
;Send fan
status and button status to UART
subi fan, -'0'
mov RXparm, fan
rcall RXputc
rcall check_button
subi button, -'0'
mov RXparm, button
rcall RXputc
pop thresh
pop temp2
pop temp
pop AnaH
pop AnaL
ret
;=============================================
;Checks the D7 button's state - should we signal
;a prompt to the UART to change the threshold
;temperature?
Check_button:
push temp
;input the
PIND status and check to see
;if D7 is 0
(pressed)
in temp, PIND
sbrs temp, 7
rjmp button_pressed
rjmp button_not_pressed
;Mark that the button was pressed
button_pressed:
ldi button, 0x01
rjmp leave_button_check
;Mark that the button was not pressed
button_not_pressed:
ldi button, 0x00
leave_button_check:
pop temp
ret
;=============================================
;Should we wait for the UART to send us the new threshold?
;If so, get each character, and convert the ASCII input to
;a hex value stored in register thresh.
Get_new_threshold:
push temp2
push temp
push ZL
push ZH
;was the
button pressed that last time we checked?
cpi button, 0x01
breq wait_for_threshold
rjmp dont_wait
wait_for_threshold:
;Set the Z
memory pointer to the correct address in RAM
ldi ZL, LOW(string)
ldi ZH, HIGH(string)
rcall
RXgetc ;Poll for first
char
st Z, RXparm
adiw ZL,1
rcall
RXgetc ;Poll for second
char
st Z, RXparm
adiw ZL,1
rcall
RXgetc ;Poll for third
char
st Z, RXparm
;Now take
the 3 chars from memory and create one hex threshold value
ldi ZL, LOW(string)
ldi ZH, HIGH(string)
ldi thresh, 0x00
hundred1:
ld instuff, Z
subi instuff, '0'
ldi temp, 0x00
hundred2:
cp instuff,temp
breq ten1
ldi temp2, 0x64
add thresh, temp2
inc temp
rjmp hundred2
ten1:
adiw ZL,1
ld instuff, Z
subi instuff, '0'
ldi temp, 0x00
ten2: cp instuff,temp
breq one
subi thresh, -10
inc temp
rjmp ten2
one:
adiw ZL,1
ld instuff, Z
subi instuff, '0'
add thresh, instuff
;Synchronize
with web server once again....
ldi RXparm, 'g'
rcall RXputc
dont_wait:
pop ZH
pop ZL
pop temp
pop temp2
ret
;=============================================
;Should the fan be on or off? Check to see if the current
threshold is above
;the threshold. If it is, turn the fan on! If it isnt, leave
it off.
Set_fan_status:
push temp
;Are we greater than or equal to the threshold temperature?
mov temp, thresh
subi temp, 1
cp temp, AnaL
brlo turn_fan_on
rjmp turn_fan_off
;Turn the fan on - we are equal to or past the threshold
turn_fan_on:
ldi fan, 0x01
ldi temp, 0x01
out PORTB, temp
rjmp leave_fan_section
;turn the fan off - we are no longer equal to or past the
threshold
turn_fan_off:
ldi fan, 0x00
ldi temp, 0x00
out PORTB, temp
leave_fan_section:
pop temp
ret
;=============================================
;LCD Managment Code
;================================================
; Clear
entire LCD and delay for a bit
lcdclr:
ldi temp,1 ;Clear
LCD command
rcall lcdcmd
ldi timeout,3 ;Delay 3 mS for clear command
rcall delay
ret
;================================================
; Initialize
LCD module
lcdinit:
push temp
ldi temp,0 ;Setup
port pins
out PORTC,temp ;Pull all pins low
ldi temp,0xff ;All pins are outputs
out DDRC,temp
ldi timeout,15 ;Wait at least 15 mS at power up
rcall delay
;LCD specs
call for 3 repetitions as follows:
;first rep
ldi temp,3 ;Function
set
out PORTC,temp ;to 8-bit mode
nop ;nop is data setup
time
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
ldi timeout,15 ;Wait at least 15 mS
rcall delay
;second rep
ldi temp,3 ;Function
set
out PORTC,temp
nop
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
ldi timeout,15 ;Wait at least 15 ms
rcall delay
;third rep
ldi temp,3 ;Function
set
out PORTC,temp
nop
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
ldi timeout,15 ;Wait at least 15 ms
rcall delay
;Now change
to 4-wire interface mode
ldi temp,2 ;Function
set, 4 wire databus
out PORTC,temp
nop
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
;Finally,
at this point,
;the normal
4 wire command routine (lcdcmd) can be used
ldi temp,0b00100000 ;Function set, 4 wire, 1 line, 5x7 font
rcall lcdcmd
ldi temp,0b00001100 ;Display on, no cursor, no blink
rcall lcdcmd
ldi temp,0b00000110 ;Address increment, no scrolling
rcall lcdcmd
pop temp
ret
;============================================
; Wait for
LCD to go unbusy
lcdwait:
ldi temp,0xF0 ;Make 4 data lines inputs
out DDRC,temp
sbi PORTC,lcdrw ;Set r/w pin to read
cbi PORTC,lcdrs ;Set register select to command
waitloop:
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
in lcdstat,PINC ;Read busy flag
;Read, and
ignore lower nibble
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
sbrc lcdstat,3 ;Loop
until done
rjmp waitloop
ret
;=============================================
; Send
command in temp to LCD
lcdcmd:
push temp ;Save
character
rcall lcdwait
ldi temp,0xFF ;Make all port D pins outputs
out DDRC,temp
pop temp ;Get
character back
push temp ;Save
another copy
swap temp ;Get
upper nibble
andi temp,0x0F ;Strip
off upper bits
out PORTC,temp ;Put on port
nop ;wait for data
setup time
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
pop temp ;Recall
character
andi temp,0x0F ;Strip
off upper bits
out PORTC,temp ;Put on port
nop
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
ret
;=============================================
; Send
character data in temp to LCD
lcdput:
push temp ;Save
character
rcall lcdwait
ldi temp,0xFF ;Make all port D pins outputs
out DDRC,temp
pop temp ;Get
character back
push temp ;Save
another copy
swap temp ;Get
upper nibble
andi temp,0x0F ;Strip
off upper bits
out PORTC,temp ;Put on port
sbi PORTC,lcdrs ;Register select set for data
nop
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
pop temp ;Recall
character
andi temp,0x0F ;Strip
off upper bits
out PORTC,temp ;Put on port
sbi PORTC,lcdrs ;Register select set for data
nop
sbi PORTC,lcde ;Toggle enable line
nop
cbi PORTC,lcde
ret
;UART Management Code
;=============================================
;Output 1 character
RXputc:
sbis USR, UDRE ;wait
until clear then send one char
rjmp RXputC
out UDR, RXparm
ret
;Input 1 character
RXgetc:
sbis USR, RXC ;wait
until ready then get one char
rjmp RXgetc
in RXparm, UDR
ret
;=============================================
; subroutine waits for time equal to value in
; register timeout
;the register 'timeout' should be loaded before the call
delay: tst timeout
brne delay
ret
;=============================================
;timer 0 overflow ISR
;Used for miscellaneous timing
;Every 1ms
TIMER:
in save, SREG ;save sreg state register
dec timeout
out SREG, save
reti
;=============================================
;timer 1 compare match ISR
;Enters every 1 second to switch the ADSC bit
T1CompA:
in save, SREG ;save cpu state
push temp
ldi itemp, 0b11000101 ;start A to D conversion
out ADCSR, itemp
pop temp
out SREG, save ;restore cpu state
reti
;=============================================