Full Version : Weiss & Avrunin Ultimate Alarm Clock (AVR ASM)
avr >>HOME & TIME & TEMPERATURE PROJECTS >>Weiss & Avrunin Ultimate Alarm Clock (AVR ASM)


Admin3- 04-18-2006
Our alarm clock features a large, bright time display, easily visible in the bedroom. It also features a loud, irritating alarm, sure to wake even the soundest of sleepers. By far the most innovative part of the alarm is the LCD display, which gives the date, alarm status, and status for setting the clock.

Link: http://instruct1.cit.cornell.edu/courses/e...joel/final.html

CODE

;Philip Weiss
;Joel Avrunin


.nolist  ;Suppress listing of include file
.include "8535def.inc";Define chip particulars.list
;***** register variables
.def save  =r1;saves the SREG in ISRs
.def reload =r2;timer 0 interval
.def lcdstat =r3;used with the lcd display setup
.def maybe  =r4;used in the button debounce routine
.def savSREG =r5;saves the SREG in an interrupt
.def thirtyms  =r6;thirty millisecond counter
.def butflag =r7;=1 if button was pressed
.def leap  =r8;used to check for a leap year
.def a1on  =r9;=1 if the alarm is set to turn on
.def ahour  =r10;hour the alarm will turn on
.def amin  =r11;minute the alarm will turn on
.def secflash =r12;used to blink the green LED every second
.def timetemp  =r14;temporary register used when outputting time
.def asciitemp =r15;temporary register used when outputting the date
.def temp  =r16;General use temp register
.def timeout =r17;Timeout value in mSec passed to subroutine
.def charcnt =r18;Char position on the display
.def seconds =r20;seconds on the clock
.def minutes =r21;minutes on the clock
.def  hours  =r22;hours on the clock
.def month  =r23;current month
.def date  =r24;current date
.def year  =r25;current year
.def  key      =r26;used in debounce routine
.def  press    =r27;button pressed out of debounce routine
.def state  =r28;current state in debounce routine
.def temp2  =r30;another temp
;***** Other equates
.equ lcdrs  =PD6;LCD rs pin connected to PD6
.equ lcdrw  =PD5;LCD r/w pin connected to PD5
.equ lcde  =PD4;LCD e pin connected to PD4
.equ down  =0b11100111; * (time down)
.equ up  =0b11101101; # (time up)
.equ set  =0b11101110; D (set)
.equ almset =0b11011110; C (set alarm)
.equ toga1  =0b01111110; A (turn on/off alarm)

.cseg

; Interrupt vectors

.org $0000
rjmp  RESET;reset entry vector
reti  
reti
reti
rjmp timer2;used for the real-time clock
reti
reti
reti
reti
rjmp timer0;interrupts every 1 millisecond
reti
reti
reti
reti
reti
reti
reti

keytbl: .db 0b11101110, 0b11101101, 0b11101011, 0b11100111
      .db 0b11011110, 0b11011101, 0b11011011, 0b11010111
      .db 0b10111110, 0b10111101, 0b10111011, 0b10110111
      .db 0b01111110, 0b01111101, 0b01111011, 0b01110111

sethourd: .db "---<Set Hour>---", 0x00, 0x00
setmind: .db  "--<Set Minute>--", 0x00, 0x00
setalarm: .db "--<Set  Alarm>--", 0x00
setdate: .db "---<Set Date>---", 0x00, 0x00

; Main program entry point on reset
RESET:  
ldi temp, LOW(RAMEND);setup stack pointer
out  SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp

ldi temp,0
out  TIMSK,temp

     ldi     Temp, 3        ;prescale timer0 by 64
     out     TCCR0, Temp
     ldi     temp,256-62  ;reload timer since
     out     TCNT0, temp  ;62.5 x (64x.25) microSec = 1.0 mSec.

;set up pin0(alarm buzzer) and pin1(blinking led) on portc to be an output
ldi temp,3
out DDRC,temp

;set up timer2
ldi temp,0b00001000;run asynchronously from cpu clock
out ASSR,temp
clr temp
out  TCNT2,temp
ldi temp,0b00000101;prescale by 128 to overflow every 1 second
out TCCR2,temp

waitlp:;wait until TC2 is updated
in temp,ASSR
andi temp, 0x07
cpi temp,0x07
breq waitlp

ldi temp,0b01000001;enable timer2 and timer0 overflow interrupt
out  TIMSK,temp


;set up port B
       ser     Temp          ;set PORTB to be
       out     DDRB,Temp      ;all outputs


sei;Enable interrupts

ldi timeout,255;Wait 255 mSec to let the 32.768KHz crystal settle
rcall delay

clr temp
mov thirtyms,temp
mov butflag,temp
;initialize system on reset
rcall   lcdinit;initialize the lcd
       rcall   lcdclr;clear the lcd
       clr     charcnt
ldi state,1
clr hours
clr minutes
clr seconds
clr temp
mov a1on,temp
mov secflash,temp
mov ahour,temp
mov amin,temp
ldi month,1
ldi date,1
ldi year,0
isettime:;display the set hour string
rcall lcdclr
clr     charcnt
       ldi     ZH, HIGH(sethourd<<1)
       ldi     ZL, LOW(sethourd<<1)

nextc:  lpm    ;r0            ;Get next character from flash
       tst     r0            ;See if at end of message
       breq    end1          ;If so, next message
       cpi     charcnt,8      ;addressing changes at char #8!
       brne    wrtit          ;at char 8, fix the addressing
       ldi     temp,0xC0      ;Set address to last 8 chars

rcall   lcdcmd

wrtit:  mov     temp,r0        ;Send it to the LCD
      rcall   lcdput
       adiw    ZL,1          ;Increment Z-pointer
       inc     charcnt        ;keep track of chars on display
       rjmp    nextc          ;Loop for more
end1:   clr     charcnt

ldi temp,1
mov butflag,temp
sethour:
ldi temp,0
cp butflag,temp
breq nopress4;see if button was pressed
ldi temp, 29
cp temp, thirtyms
brne sethour
rcall disptime;updates time on clock (called evert 30 msec)
rcall debounce;check for a button press
cpi state, 1;if the state != 1 go back to sethour
brne sethour
nopress4:
ldi temp,0
mov butflag,temp;clear butflag
ldi temp,29
cp      temp,thirtyms
       brne    d1
rcall disptime
       rcall   debounce
d1: cpi press,up;see if up key was pressed
       brne next0
ldi temp,1
mov butflag,temp;set butflag since key was pressed
inc hours  
cpi hours,24;hours should not equal 24
breq zhour  
rjmp   sethour;go to top and wait for another button
zhour: ldi hours,0;reset hours to zero if incremented past 23
rjmp sethour;go to top and wait for another button
next0: cpi press,down;see if down key was pressed
brne next1
ldi temp,1
mov butflag,temp;set butflag since key was pressed
dec hours
cpi hours,255;see if hours was decremented too much
breq mhour
rjmp sethour;go to top and wait for another button
mhour: ldi hours,23;set hours to 23 if decremented below 0
rjmp sethour;go to top and wait for another button
ldi hours,0
next1: cpi press,set
breq iisetmin;if the set button was pressed set the minutes
brne sethour

iisetmin:;display the set minutes prompt    
rcall lcdclr
clr     charcnt
       ldi     ZH, HIGH(setmind<<1)
       ldi     ZL, LOW(setmind<<1)

mnextc:  lpm    ;r0            ;Get next character from flash
       tst     r0            ;See if at end of message
       breq    mend1          ;If so, next message
       cpi     charcnt,8      ;addressing changes at char #8!
       brne    mwrtit          ;at char 8, fix the addressing
       ldi     temp,0xC0      ;Set address to last 8 chars

rcall   lcdcmd

mwrtit:  mov     temp,r0        ;Send it to the LCD
      rcall   lcdput
       adiw    ZL,1          ;Increment Z-pointer
       inc     charcnt        ;keep track of chars on display
       rjmp    mnextc          ;Loop for more
mend1:   clr     charcnt
ldi temp,1
mov butflag, temp
isetmin:
ldi temp,1
mov butflag,temp

setmin:
ldi temp,0
cp butflag,temp
breq nopress5
ldi temp, 29
cp temp, thirtyms
brne setmin
rcall disptime
rcall debounce
cpi state, 1
brne setmin
nopress5:
ldi temp,0
mov butflag,temp
ldi temp,29
cp      temp,thirtyms
       brne    d2
rcall disptime
       rcall   debounce
d2: cpi press,up
       brne next2
ldi temp,1
mov butflag,temp
inc minutes
cpi minutes,60;minutes should not equal 60
breq zmin
rjmp   setmin
zmin: ldi minutes,0;reset to zero if incremented past 59
rjmp setmin
next2: cpi press,down
brne next3
ldi temp,1
mov butflag,temp
dec minutes
cpi minutes,255
breq mmin
rjmp setmin
mmin: ldi minutes,59;set to 59 if decremented below zero
rjmp setmin
ldi minutes,0
next3: cpi press,set;if pressed, the time set is complete
breq timedone
brne setmin

timedone:;display the set date prompt
rcall lcdclr
clr     charcnt
       ldi     ZH, HIGH(setdate<<1)
       ldi     ZL, LOW(setdate<<1)

nextc2:  lpm    ;r0            ;Get next character from flash
       tst     r0            ;See if at end of message
       breq    end2          ;If so, next message
       cpi     charcnt,8      ;addressing changes at char #8!
       brne    wrtit2          ;at char 8, fix the addressing
       ldi     temp,0xC0      ;Set address to last 8 chars

rcall   lcdcmd

wrtit2:  mov     temp,r0        ;Send it to the LCD
      rcall   lcdput
       adiw    ZL,1          ;Increment Z-pointer
       inc     charcnt        ;keep track of chars on display
       rjmp    nextc2          ;Loop for more
end2:   clr     charcnt


isetmonth:
ldi temp,1
mov butflag, temp
setmonth:
ldi temp,0
cp butflag,temp
breq nopress1
ldi temp, 29
cp temp, thirtyms
brne setmonth
rcall disptime
rcall debounce
cpi state, 1
brne setmonth
nopress1:
ldi temp,0
mov butflag,temp
ldi temp,29
cp      temp,thirtyms
       brne    d3
rcall disptime
       rcall   debounce
d3: cpi press,up
       brne next4
ldi temp,1
mov butflag,temp
inc month
cpi month,13;month should not equal 13
breq zmonth
rcall asciidate;show the date display
rjmp   setmonth
zmonth: ldi month,1;reset months to 1 if incremented past 12
rcall asciidate;update the date display
rjmp setmonth
next4: cpi press,down
brne next5
ldi temp,1
mov butflag,temp
dec month
cpi month,0;month should not equal zero
breq mmonth
rcall asciidate
rjmp setmonth
mmonth: ldi month,12;set month to 12 if decremented below 1
rcall asciidate;update the date display
rjmp setmonth
ldi month,1
next5: cpi press,set
breq isetday;done with months, so set the date
brne setmonth

isetday:
ldi temp, 1
mov butflag, temp
rcall asciidate
setday:
ldi temp,0
cp butflag,temp
breq nopress2
ldi temp, 29
cp temp, thirtyms
brne setday
rcall disptime
rcall debounce
cpi state, 1
brne setday
nopress2:
ldi temp,0
mov butflag,temp
ldi temp,29
cp      temp,thirtyms
       brne    d4
rcall disptime
       rcall   debounce
d4: cpi press,up
       brne next6
ldi temp,1
mov butflag,temp
inc date
cpi date,32;no months have 32 days
breq zday
cpi date,31;if months incremented to 31 check if month
   ;has 31 days to see if it is valid
brne ck29
cpi month,4
breq zday
cpi month,6
breq zday
cpi month,9
breq zday
cpi month,11
breq zday
ck29: cpi date,29;needed to check February
brne norst
cpi month,2
breq zday
norst: rcall asciidate
rjmp   setday
zday: ldi date,1;set the day to 1 if incremented past max day
rcall asciidate
rjmp setday
next6: cpi press,down
brne next7
ldi temp,1
mov butflag,temp
dec date
cpi date,0
breq mday
rcall asciidate
rjmp setday
mday: cpi month,4;if decremented below one set to max day
   ;for given month
breq ld30
cpi month,6
breq ld30
cpi month,9
breq ld30
cpi month,11
breq ld30
cpi month,2
brne ld31
ldi date,28
rjmp dayp
ld31: ldi date,31
rjmp dayp
ld30: ldi date,30
dayp: rcall asciidate
rjmp setday
ldi date,1
next7: cpi press,set
breq isetyear;go to setting the year
rjmp setday
isetyear:
ldi temp,1
mov butflag, temp
setyear:
ldi temp,0
cp butflag,temp
breq nopress3
ldi temp, 29
cp temp, thirtyms
brne setyear
rcall disptime
rcall debounce
cpi state, 1
brne setyear
nopress3:
ldi temp,0
mov butflag,temp
ldi temp,29
cp      temp,thirtyms
       brne    d5
rcall disptime
       rcall   debounce
d5: cpi press,up
       brne next8
ldi temp,1
mov butflag,temp
inc year
cpi year,100;year can't be 100 since only hold last two digits
breq zyear
rcall asciidate
rjmp   setyear
zyear: ldi year,0;reset year to zero if incremented past 99
rcall asciidate
rjmp setyear
next8: cpi press,down
brne next9
ldi temp,1
mov butflag,temp
dec year
cpi year,255;check if year was decremented below zero
breq myear
rcall asciidate
rjmp setyear
myear: ldi year,99;set year to 99 if decremented below zero
rcall asciidate
rjmp setyear
ldi year,0
next9: cpi press,set
breq setdone;if set was pressed, jump to main program loop
rjmp setyear

setdone:
rcall asciidate;print the date
ldi temp, 1
mov butflag, temp
setdone1:
ldi temp,0
cp butflag,temp
breq nopress6
ldi temp, 29
cp temp, thirtyms
brne setdone1
rcall disptime;display the time
rcall debounce;run debounce routing
cpi state, 1
brne setdone1
nopress6:
ldi temp,0
mov butflag,temp
ldi temp,29
cp      temp,thirtyms
     brne    d6
rcall asciidate
rcall disptime
     rcall   debounce
d6: cpi press,set
brne noset
rjmp isettime  ;if set was pressed, set the clock again
noset: cpi press,almset;see if the alarm set button was pressed
brne noalmset
rcall alm1set;set the alarm
noalmset:
cpi press,toga1;check if the alarm on/off button was pressed
brne endpgm
ldi temp,1
eor a1on, temp;turn the alarm on/off
mov butflag,temp
endpgm:
rjmp setdone1;back to top of main loop
;***********************************
lcdclr:
      ldi     temp,1        ;Clear LCD command
      rcall   lcdcmd
       ldi     temp,3
      mov     timeout,temp      ;Delay 3 mS for clear command
      rcall   delay
      ret
;================================================
;       Initialize LCD module
lcdinit:
     ;cbi     PORTB,0        ;Turn on LED 0
      ldi     temp,0        ;Setup port pins
      out     PORTD,temp    ;Pull all pins low
      ldi     temp,0xff      ;All pins are outputs
      out     DDRD,temp
      ldi     temp,15
      mov     timeout,temp    ;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     PORTD,temp    ;to 8-bit mode
      nop                    ;nop is data setup time
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,lcde
      ldi     temp,15
      mov     timeout,temp    ;Wait at least 15 mS
      rcall   delay
     ;second rep
      ldi     temp,3        ;Function set
      out     PORTD,temp
      nop
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,lcde
      ldi     temp,15
      mov     timeout,temp    ;Wait at least 15 ms
      rcall   delay
     ;third rep
      ldi     temp,3        ;Function set
      out     PORTD,temp
      nop
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,lcde
      ldi     temp,15
      mov     timeout,temp    ;Wait at least 15 ms
      rcall   delay
     ;Now change to 4-wire interface mode
      ldi     temp,2        ;Function set, 4 wire databus
      out     PORTD,temp
      nop
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,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
     ;sbi     PORTB,0        ;Turn off LED 0
      ret
;============================================
;       Wait for LCD to go unbusy
lcdwait:
     ;cbi     PORTB,1        ;Turn on LED 1
      ldi     temp,0xF0      ;Make 4 data lines inputs
      out     DDRD,temp
      sbi     PORTD,lcdrw    ;Set r/w pin to read
      cbi     PORTD,lcdrs    ;Set register select to command
waitloop:
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,lcde
      in      lcdstat,PIND  ;Read busy flag
     ;Read, and ignore lower nibble
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,lcde
      sbrc    lcdstat,3      ;Loop until done
      rjmp    waitloop
     ;sbi     PORTB,1        ;Turn off LED 1
      ret
;=============================================
;       Send command in temp to LCD
lcdcmd:
      push    temp          ;Save character
      rcall   lcdwait
      ldi     temp,0xFF      ;Make all port D pins outputs
      out     DDRD,temp
      pop     temp          ;Get character back
      push    temp          ;Save another copy
      swap    temp          ;Get upper nibble
      andi    temp,0x0F      ;Strip off upper bits
      out     PORTD,temp    ;Put on port
      nop                    ;wait for data setup time
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,lcde
      pop     temp          ;Recall character
      andi    temp,0x0F      ;Strip off upper bits
      out     PORTD,temp    ;Put on port
      nop
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,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     DDRD,temp
      pop     temp          ;Get character back
      push    temp          ;Save another copy
      swap    temp          ;Get upper nibble
      andi    temp,0x0F      ;Strip off upper bits
      out     PORTD,temp    ;Put on port
      sbi     PORTD,lcdrs    ;Register select set for data
      nop
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,lcde
      pop     temp          ;Recall character
      andi    temp,0x0F      ;Strip off upper bits
      out     PORTD,temp    ;Put on port
      sbi     PORTD,lcdrs    ;Register select set for data
      nop
      sbi     PORTD,lcde    ;Toggle enable line
      nop
      cbi     PORTD,lcde
      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
;***************************************************************
;debounce state machine

debounce:
       cpi      state,1;jump to appropriate state
       breq    _key1
       cpi      state,2
       breq    _key2
       cpi      state,3
       breq    _key3
       cpi      state,4
       breq    _key4
_key1:
       rcall   kloop;get button
       cpi     key,0
       brne    _key1no;button pressed
                             ;_key1yes
       clr     press
       ret
_key1no:
       mov     maybe,key
       ldi     state,2;move to state 2
       ret
_key2:
       rcall   kloop
       cp      key,maybe
       brne    _key2no
                             ;_key2yes
       mov     press,key
       ldi     state,3;move to state 3
       ret
_key2no:
       ldi     state,1;mov to state 1
       ret
_key3:
       rcall   kloop
       cp      key,press
       brne    _key3no
                             ;_key3yes
       ret
_key3no:
       ldi     state,4;move to state 4
       ret
_key4:  rcall   kloop
       cp      key,press
       brne    _key4no
                             ;_key4yes
       ldi     state,3;go back to state 3
       ret
_key4no:
       clr     press          ;set press to 0
       ldi     state,1;to state 1
       ret
;***************************************************************
;keypad monitor

kloop:  ldi     temp, 0x0f    ;set lower four lines to output
      out     DDRA, temp
      ldi     temp, 0xf0    ;and turn on the pullups on the inputs
      out     PORTA, temp
      nop                    ;Need some time for the pullups to
      nop                    ;charge the port pins
      nop
      nop
      nop                    ;Need some time for the pullups to
      nop                    ;charge the port pins
nop                    
      nop
      nop
      nop                    
      nop
      in      temp, PINA    ;read the high nibble
      mov     key, temp    ;and store it (with zeros in the low nibble)

      ldi     temp, 0xf0    ;set upper four lines to outputs
      out     DDRA, temp
      ldi     temp, 0x0f    ;and turn on pullups on the inputs
      out     PORTA, temp
      nop                    ;As before wait for the pin to charge
      nop                      
      nop
      nop
      nop
      nop
nop                    
      nop
      nop
      nop                    
      nop
      in      temp, PINA    ;read the low nibble
      or      key, temp      ;combine to make key code
ret
;***************************************************************
timer2:;timer 2 interrupt (enters every 1 second)
in      savSREG, SREG
     push    temp
push ZL
push ZH

ldi temp,0b00000010
eor secflash,temp;reverse secflash for blinking the seconds led
inc  seconds;increment seconds since enters isr every second
cpi seconds, 60;if seconds==60 need to reset to 0 and increment minutes
brne nochange
clr seconds
inc minutes
cpi minutes, 60;if minutes== 60 need to reset to 0 and increment hours
brne nochange
clr minutes
inc hours
cpi hours, 24;if hours==24 need to reset to zero and increment days
brne nochange
clr hours
inc date
cpi date,32;if date==32 need to reset to 1 and increment month
brne cpdate31
inc month
ldi date,1
rjmp cpmonth13
cpdate31:;if date==31 see if that is max for month
cpi date,31
brne cpdate30
cpi month,4;April has 30 days, so increment month
breq incmonth
cpi month,6;June has 30 days, so increment month
breq incmonth
cpi month,9;September has 30 days, so increment month
breq incmonth
cpi month,11;November has 30 days, so increment month
brne cpmonth13
breq incmonth
incmonth:
inc month
ldi date,1
rjmp cpmonth13
cpdate30:  
cpi date,30
brne cpdate29
cpi month,2;this will always switch from February to March
brne cpmonth13
inc month
ldi date,1
rjmp cpmonth13
cpdate29:
cpi date,29;if date==29 see if leap year and increment month
 ;if month is February and not a leap year
brne cpmonth13
cpi month,2
brne cpmonth13
mov r31,year
chklp: cpi r31,0;see if year is divisible by 4
breq islp
cpi r31,4
breq islp
subi r31,4
cpi r31,99
brpl nolp
rjmp chklp
nolp: inc month
ldi date,1
islp:
cpmonth13:
cpi month,13;if month==13 reset to 1
brne nochange
ldi month,1
inc year;increment year is month==13
 
nochange:
mov temp, a1on
cpi temp,1;if alarm is set to turn on check the time
brne iendt2
cp ahour,hours;see if correct hour
brne endt2
cp amin,minutes;see if correct minute
brne endt2

cpi seconds,5;only go on for five seconds
brpl iendt2

ldi temp,0b00000011;will output to portc to turn on
;green led and sound alarm
mov secflash,temp
rjmp endt2
iendt2:;don't sound alarm and complement led
ldi temp,0b00000010
and secflash,temp
ldi temp,0b00000010
eor secflash,temp
eor secflash,temp
endt2:
out PORTC,secflash;output secflash to port to
   ;sound alarm(if needed) and light led (or not)
pop ZH
pop ZL
pop     temp
     out     SREG, savSREG
reti


;**************************************************************
;timer 0 ISR (timer-zero overflow)
;Enters every 1.0 mSec
timer0: in      savSREG, SREG
       push    temp
       push    ZL
       push    ZH
       dec     timeout
       ldi     temp,256-62
       out     TCNT0, temp    ; keeps clock ticking at 1 mSec
       ldi     temp,1
       add     thirtyms,temp
       ldi     temp,30  
       cp      thirtyms,temp;clear 30ms counter if it equals 30
       brne    t0end
       clr     thirtyms
t0end:
       pop     ZH
       pop     ZL
       pop     temp
       out     SREG, savSREG
       reti                  ;back to backgound tasks
;**************************************************************
asciidate:;put the date and alarm set information on led
rcall lcdclr
clr temp
ldi temp2,10
mov asciitemp,month
monthtens:  ;count the number of tens in the months and
 ;output that number to the lcd
cp asciitemp,temp2
breq nmonthtens
cp asciitemp,temp2
brlo Imonthones
nmonthtens: inc temp
sub asciitemp,temp2
rjmp monthtens
Imonthones: ldi temp2,0x30;convert digit to ascii character
add temp,temp2
rcall lcdput
clr temp
ldi temp2,1
monthones:  
cp asciitemp,temp2
breq nmonthones
cp asciitemp,temp2
brlo monthdoner
nmonthones: inc temp
sub asciitemp,temp2
rjmp monthones
monthdoner: ldi temp2,0x30;convert digit to ascii
add temp,temp2
rcall lcdput
clr temp
ldi temp,'/';put a slash in the date
rcall  lcdput
clr temp
ldi temp2,10
mov asciitemp,date
datetens:  ;get the number of tens in the date and put on the lcd
cp asciitemp,temp2
breq ndatetens
cp asciitemp,temp2
brlo Idateones
ndatetens: inc temp
sub asciitemp,temp2
rjmp datetens
Idateones: ldi temp2,0x30;convert to ascii
add temp,temp2
rcall lcdput
clr temp
ldi temp2,1
dateones:
cp asciitemp,temp2
breq ndateones
cp asciitemp,temp2
brlo datedoner
ndateones: inc temp
sub asciitemp,temp2
rjmp dateones
datedoner: ldi temp2,0x30;convert the ones digit to ascii
add temp,temp2
rcall lcdput
clr temp
ldi temp,'/'
rcall  lcdput
clr temp
ldi temp2,10
mov asciitemp,year
yeartens:;get the number of tens in the year and put on the lcd
cp asciitemp,temp2
breq nyeartens
cp asciitemp,temp2
brlo Iyearones
nyeartens: inc temp
sub asciitemp,temp2
rjmp yeartens
Iyearones: ldi temp2,0x30;convert to ascii
add temp,temp2
rcall lcdput
clr temp
ldi temp2,1
yearones:
cp asciitemp,temp2
breq nyearones
cp asciitemp,temp2
brlo yeardoner
nyearones: inc temp
sub asciitemp,temp2
rjmp yearones

yeardoner: ldi temp2,0x30;convert digit to ascii
add temp,temp2
rcall lcdput
clr temp
ldi temp,1
cp a1on,temp
brne a1noton;if the alarm is not set to go on then finished
ldi     temp,0xC0      ;Set address to last 8 chars
rcall   lcdcmd
ldi temp,' '
rcall lcdput
ldi temp,'*';if alarm is set output "*ALARM*"
rcall lcdput
ldi temp,'A'
rcall lcdput
ldi temp,'L'
rcall lcdput
ldi temp,'A'
rcall lcdput
ldi temp,'R'
rcall lcdput
ldi temp,'M'
rcall lcdput
ldi temp,'*'
rcall lcdput
ret
a1noton:
ret


disptime:;puts the time on the led display
clr temp
ldi temp2,10
mov timetemp,hours
hourtens:;calculate the number of tens in the hour
cp timetemp,temp2
breq nhourtens
cp timetemp,temp2
brlo Ihourones
nhourtens: inc temp
sub timetemp,temp2
rjmp hourtens
Ihourones:
ori temp,0b01110000;select first digit
out PORTB, temp;output to port
ldi timeout, 4
rcall delay
clr temp
ldi temp2,1
hourones:
cp timetemp,temp2
breq nhourones
cp timetemp,temp2
brlo hourdoner
nhourones: inc temp
sub timetemp,temp2
rjmp hourones
hourdoner:
ori temp, 0b10110000;select second digit and
out PORTB, temp;output to port
ldi timeout, 4
rcall delay
clr temp
clr temp
ldi temp2,10
mov timetemp,minutes
mintens:  ;calculate the number of tens in minutes
cp timetemp,temp2
breq nmintens
cp timetemp,temp2
brlo Iminones
nmintens: inc temp
sub timetemp,temp2
rjmp mintens
Iminones:
ori temp,0b11010000;select the third digit and
out PORTB, temp;output to the port
ldi timeout, 4
rcall delay
clr temp
ldi temp2,1
minones:
cp timetemp,temp2
breq nminones
cp timetemp,temp2
brlo mindoner
nminones: inc temp
sub timetemp,temp2
rjmp minones
mindoner:
ori temp, 0b11100000;select the fourth digit and
out PORTB, temp;output to the port
ldi timeout, 4
rcall delay
ret


a1disptime:  ;same as disptime, but outputs alarm time to led
clr temp
ldi temp2,10
mov timetemp,ahour
a1hourtens:
cp timetemp,temp2
breq a1nhourtens
cp timetemp,temp2
brlo a1Ihourones
a1nhourtens: inc temp
sub timetemp,temp2
rjmp a1hourtens
a1Ihourones:
ori temp,0b01110000
out PORTB, temp
ldi timeout, 4
rcall delay
clr temp
ldi temp2,1
a1hourones:
cp timetemp,temp2
breq a1nhourones
cp timetemp,temp2
brlo a1hourdoner
a1nhourones: inc temp
sub timetemp,temp2
rjmp a1hourones
a1hourdoner:
ori temp, 0b10110000
out PORTB, temp
ldi timeout, 4
rcall delay
clr temp
clr temp
ldi temp2,10
mov timetemp,amin
a1mintens:
cp timetemp,temp2
breq a1nmintens
cp timetemp,temp2
brlo a1Iminones
a1nmintens: inc temp
sub timetemp,temp2
rjmp a1mintens
a1Iminones:
ori temp,0b11010000
out PORTB, temp
ldi timeout, 4
rcall delay
clr temp
ldi temp2,1
a1minones:
cp timetemp,temp2
breq a1nminones
cp timetemp,temp2
brlo a1mindoner
a1nminones: inc temp
sub timetemp,temp2
rjmp a1minones
a1mindoner:
ori temp, 0b11100000
out PORTB, temp
ldi timeout, 4
rcall delay
ret

alm1set:  ;sets the time for the alarm
rcall lcdclr
a1isettime: clr     charcnt
       ldi     ZH, HIGH(setalarm<<1);output set alarm prompt
       ldi     ZL, LOW(setalarm<<1)

a1nextc:  lpm    ;r0            ;Get next character from flash
       tst     r0            ;See if at end of message
       breq    a1end1          ;If so, next message
       cpi     charcnt,8      ;addressing changes at char #8!
       brne    a1wrtit          ;at char 8, fix the addressing
       ldi     temp,0xC0      ;Set address to last 8 chars
rcall   lcdcmd
a1wrtit:  mov     temp,r0        ;Send it to the LCD
      rcall   lcdput
       adiw    ZL,1          ;Increment Z-pointer
       inc     charcnt        ;keep track of chars on display
       rjmp    a1nextc          ;Loop for more
a1end1:   clr     charcnt
ai1sethour:
ldi temp,0
mov ahour,temp
ldi temp,1
mov butflag, temp
a1sethour:    ;set the hour
ldi temp,0
cp butflag,temp
breq a1nopress4
ldi temp, 29
cp temp, thirtyms
brne a1sethour
rcall a1disptime
rcall debounce
cpi state, 1
brne a1sethour
a1nopress4:
ldi temp,0
mov butflag,temp
ldi temp,29
cp      temp,thirtyms
     brne    a1d1
rcall a1disptime
       rcall   debounce
a1d1: cpi press,up
     brne a1next0
ldi temp,1
mov butflag,temp
ldi temp,1
add ahour,temp
ldi temp,24  ;hour should not be 24
cp ahour,temp
breq a1zhour
rjmp   a1sethour
a1zhour: ldi temp,0;reset hour to zero if incremented past 23
mov ahour,temp
rjmp a1sethour
a1next0: cpi press,down
brne a1next1
ldi temp,1
mov butflag,temp
ldi temp,1
sub ahour,temp
ldi temp,255;ckeck if hour was decremented below 0
cp ahour,temp
breq a1mhour
rjmp a1sethour
a1mhour: ldi temp,23;set hour to 23 if decremented below 0
mov ahour,temp
rjmp a1sethour
clr temp
mov amin,temp
a1next1: cpi press,set
breq a1isetmin
brne a1sethour
a1isetmin:
clr temp
mov amin,temp
ldi temp,1
mov butflag, temp    
a1setmin:
ldi temp,0
cp butflag,temp
breq a1nopress5
ldi temp, 29
cp temp, thirtyms
brne a1setmin
rcall a1disptime
rcall debounce
cpi state, 1
brne a1setmin
a1nopress5:
ldi temp,0
mov butflag,temp
ldi temp,29
cp      temp,thirtyms
     brne    a1d2
rcall a1disptime
       rcall   debounce
a1d2: cpi press,up
       brne a1next2
ldi temp,1
mov butflag,temp
ldi temp,1
add amin,temp
ldi temp,60  ;minutes can't equal 60
cp amin,temp
breq a1zmin
rjmp   a1setmin

a1zmin: clr temp
mov amin,temp  ;clear minutes if incremented past 59
rjmp a1setmin
a1next2: cpi press,down
brne a1next3
ldi temp,1
mov butflag,temp
ldi temp,1
sub amin,temp
ldi temp,255  
cp amin,temp  ;check if minutes is below zero
breq a1mmin
rjmp a1setmin
a1mmin:
ldi temp,59
mov amin,temp  ;set minutes to 59 if decremented below 0
rjmp a1setmin
clr temp
mov amin,temp
a1next3: cpi press,set
breq a1done
brne a1setmin
a1done:
ldi temp,1
mov butflag,temp
mov a1on,temp
ret





Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.