; 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

;=============================================