AVR Assembler Source Blog

Ремонт частотных преобразователей AVR Assembler Source Blog: Clock_LCD_alarm_melody

Sunday, October 6, 2013

Clock_LCD_alarm_melody

Модернизация оборудования
                              ; *********************************************
                              ; * Digital AVR clock with an ATmega16        *
                              ; * (C)2010 by info (at) avr-asm-tutorial.net *
                              ; *********************************************
                              
.nolist
.include "m16def.inc"
.list
                              
                              ; ===================================================
                              ;      D e b u g g i n g   p a r a m e t e r s
                              ; ===================================================
                              ;   dbg = 0: debugging disabled, normal program execution
                              ;   dbg = 1: light first display
                              ;   dbg = 2: light second display
                              ;   dbg = 3: light third display
                              ;   dbg = 4: light fouth display
                              ;   dbg = 5: display seconds on alarm-minute position
                              ;   dbg = 6: display ADC results in hex on alarm display
                              
.equ dbg=0

                              ; ===================================================
                              ;                H a r d w a r e
                              ; ===================================================
                              ;  Processor type: ATmega16
                              ;               _________
                              ;             /          |
                              ;  Key red --|PB0    ADC0|-- Pot input
                              ;  Key blk --|PB1    ADC1|-- Fototransistor input
                              ;  Key wht --|PB2        |--
                              ;  Speaker --|OC0        |--
                              ;          --|        PA4|-- 1 Digit Anode Driver
                              ; ISP MOSI --|MOSI    PA5|-- 2
                              ;     MISO --|MISO    PA6|-- 3
                              ;      SCK --|SCK     PA7|-- 4
                              ;    RESET --|RESET  AREF|-- +5V
                              ;      VCC --|VCC     GND|-- GND
                              ;      GND --|GND    AVCC|-- +5V
                              ;    Xtal2 --|XTAL2   PC7|-- Large LED points
                              ;    Xtal1 --|XTAL1   PC6|-- g Large
                              ;  Small a --|PD0     PC5|-- f seven
                              ;  seven b --|PD1     PC4|-- e segm.
                              ;  segm. c --|PD2     PC3|-- d displ.
                              ;  displ.d --|PD3     PC2|-- c cath.
                              ;  cath. e --|PD4     PC1|-- b
                              ;        f --|PD5     PC0|-- a
                              ;        g --|PD6     PD7|-- Small LED points
                              ;            |___________
            
                              ; ===================================================
                              ;   D e s c r i p t i o n   h o w   i t   w o r k s
                              ; ===================================================
 
                              ; a) Displays and display modes
                              ;    The upper, large 7-segment displays show the time,
                              ;    the lower, small 7-segment displays show the alarm
                              ;    time. The larger double-dot LEDs of the upper display
                              ;    blink in second intervals. The smaller double-dot
                              ;    LEDs of the lower display blink, if the alarm is
                              ;    armed, and are always on, if the alarm is disarmed.
                              ; b) Display multiplexing
                              ;    The diplay uses Counter/Timer 1 in CTC mode to
                              ;    interrupt every 5 ms after reaching its top value.
                              ;    The 4 displays are refreshed in 20 ms, yielding a
                              ;    refresh frequency of 50 cs/s.
                              ;    The display is first switched off, the pointer
                              ;    to the displayed digit is advanced and digit infos
                              ;    in SRAM are written to the Ports C (large display
                              ;    for the time) and D (small display for the alarm
                              ;    time), the appropriate anode driver port bit on
                              ;    the upper nibble of Port A is set active (=0).
                              ; c) Display dimming
                              ;    Display dimming uses the TC1 in CTC mode and Compare
                              ;    Match B interrupt to disable the anode drivers. The
                              ;    compare match value is calculated from the ADC value
                              ;    that results from the fototransistor: the less light
                              ;    is on the transistor the higher its collector voltage
                              ;    and the higher its ADC value and the higher the com-
                              ;    pare match B value. Note that this is a non-linear
                              ;    function.
                              ; d) Time counting
                              ;    The time counting uses TC1 in CTC mode and the
                              ;    Compare Match A interrupt to downcount a counter
                              ;    from 200 to zero. If zero is reached, a flag is set
                              ;    and the 5-ms-counter is restarted.
                              ;    Outside the interrupt service routine, the time is
                              ;    advanced by one second, updating the time after 60
                              ;    seconds. If the alarm is armed, the time is compared
                              ;    with the alarm time and an alarm is triggered when
                              ;    time = alarm time.
                              ; e) Keys
                              ;    The keys are read every time an interrupt wake up
                              ;    took place. Active keys are recognised after 15 ms
                              ;    and stored. The respective action is executed after
                              ;    all keys are inactive for at least 15 ms.
                              ;    The following table gives key reactions in different
                              ;    operation modes.
                              ;    Mode          Key    Action
                              ;    ----------------------------------------------------
                              ;    Normal        Black  Toggle armed bit
                              ;                  Red    Enter time setting mode
                              ;                  White  Enter alarm time setting mode
                              ;    Time Setting  Black  Skip time setting mode
                              ;                  Red    Set time (hour or minute)
                              ;    Alarm Setting Black  Skip alarm time setting mode
                              ;                  White  Set alarm time (hour or minute)
                              ;    Armed         Black  Disable armed
                              ;                  Red    Advance alarm time by snooze
                              ;    Alarmed       Black  Disable alarm and reset alarm
                              ;                         time
                              ;                  Red    Disable alarm and advance alarm
                              ;                         time by snooze
                              ; f) AD conversion
                              ;    The ADC runs with a prescaler of 128, measures two
                              ;    channels and is controlled via interrupt.
                              ;    The analogue voltages of the potentiometer (channel
                              ;    ADC0) and of the collector of the fototransistor
                              ;    (channel ADC1) are measured, the left-adjusted upper
                              ;    result byte is added to a 16-bit sum. If 256 measure-
                              ;    ments per channel took place, the MSB of the 16-bit-
                              ;    result is handed to a routine outside the interrupt
                              ;    service routine. The channel results are used to
                              ;    Ch0: if in time or alarm setting mode, converted to
                              ;         hours or minutes and displayed
                              ;    Ch1: convert to compare match B values to set the dim
                              ;         time and reduce the brightness in a dark
                              ;         environment.
                              ; g) Alarm noise
                              ;    TC0 provides a programmable AF generator by setting
                              ;    the timer in CTC mode and toggling the output pin OC0
                              ;    on compare match. The TC0 runs with a prescaler of 8,
                              ;    providing audio signals between 600 (OCR0=255) and
                              ;    9600 (OCR0=16) cs/s.
                              ;    An interrupt on reaching CTC top plays a melody
                              ;    located in the EEPROM space by reading the CTC value
                              ;    and the duration of the tone. After reaching the table 
                              ;    end, the timer and OC0 output toggling is disabled.

                              ; ===================================================
                              ;               C o n s t a n t s
                              ; ===================================================

.equ clock=2457600            ; Xtal frequency
.equ cSnooze=5                ; snooze alarm time duration
.equ cPauseLong=$4000         ; long pause for melody repeat

                              ; ===================================================
                              ;               R e g i s t e r s
                              ; ===================================================

                              ; R0 used for LPM to flash and for calculations
                              ; R1 used for calculations
                              ; free R2..R8
.def rFChk=R9                 ; check for adjusting dimm
.def rAdcC=R10                ; ADC counter
.def rAdcFL=R11               ; ADC result adder fototransistor, low byte
.def rAdcFH=R12               ; ADC result adder fototransistor, high byte
.def rAdcPL=R13               ; Adc result adder potentiometer, low byte
.def rAdcPH=R14               ; Adc result adder potentiometer, high byte
.def rSreg=R15                ; SREG temp inside ints
.def rmp=R16                  ; multipurpose outside ints
.def rimp=R17                 ; multipurpose inside ints
.def rFlag=R18                ; flag register
.equ bArmed=0                 ; Alarm is enabled
.equ bAlarm=1                 ; Alarm is active
.equ bSetC=2                  ; Set clock
.equ bSetCm=3                 ; Set clock minutes
.equ bSetA=4                  ; Set alarm
.equ bSetAm=5                 ; Set alarm minutes
.equ bSec=6                   ; next second reached
.equ bAdc=7                   ; new ADC result ready
.def rC5ms=R19                ; 5ms counter to seconds
.def rDCnt=R20                ; Display counter anode driver
.def rKey=R21                 ; key code storage, last active key
.def rEep=R23                 ; EEPROM read address
.def rDurL=R24                ; Duration time counter LSB
.def rDurH=R25                ; Duration time counter MSB
                              ; R27:R26 used for pointing outside ints
                              ; R29:R28 used as display pointer inside ints
                              ; R31:R30 used for pointing outside ints

                              ; ===================================================
                              ;           S R A M   l o c a t i o n s
                              ; ===================================================

.DSEG
.ORG Sram_Start

sTime:

       .byte 4                ; four digit bytes for the large display

sAlarm:

       .byte 4                ; four digit bytes for the small display

sCs:

       .byte 1                ; clock seconds

sCm:

       .byte 1                ; clock minutes

sCh:

       .byte 1                ; clock hours

sSm:

       .byte 1                ; set alarm minutes

sSh:

       .byte 1                ; set alarm hours

sAm:

       .byte 1                ; alarm minutes

sAh:

       .byte 1                ; alarm hours

sAdcP:

       .byte 1                ; Adc result pot

sAdcF:

       .byte 1                ; Adc result fototransistor

sKey:

       .byte 1                ; pressed key

sKeyC:

       .byte 1                ; counter for pressed key

sKeyS:

       .byte 1                ; selected key


                              ; ===================================================
                              ;                  T i m i n g s
                              ; ===================================================

                              ; ADC:
                              ; - MUX channel 0 measures pot, MUX channel 1 measures fototransistor
                              ; - runs at divider = 128
                              ; - is interrupt driven
                              ; - result is left adjust, only the upper 8 bits are used
                              ; - on int, the upper 8 bits of the result are added to a 16-bit-sum
                              ; - after 256 results, the upper 8 bits of the sum are copied
                              ; - when running, one conversion requires 13 ADC clock cycles
                              ; - f = 2457600 / 128 / 13 / 256 = 5.77 cs/s = 173.3 ms

                              ; ===================================================
                              ;      R e s e t   a n d   I n t   v e c t o r s 
                              ; ===================================================

.cseg
.org $0000
 rjmp start                   ; Reset vector
 nop
 reti                         ; INT0
 nop
 reti                         ; INT1
 nop
 reti                         ; TC2COMP
 nop
 reti                         ; TC2OVF
 nop
 rjmp TC1Capt                 ; TC1CAPT
 nop
 rjmp TC1CompA                ; TC1COMPA
 nop
 rjmp TC1CompB                ; TC1COMPB
 nop
 reti                         ; TC1OVF
 nop
 reti                         ; TC0OVF
 nop
 reti                         ; SPI, STC
 nop
 reti                         ; USART RXC
 nop
 reti                         ; USART UDRE
 nop
 reti                         ; USART TXC
 nop
 rjmp AdcInt                  ; ADC
 nop
 reti                         ; EERDY
 nop
 reti                         ; ANACOMP
 nop
 reti                         ; TWI
 nop
 reti                         ; INT2
 nop
 rjmp Tc0Comp                 ; TC0COMP
 nop
 reti                         ; SPM RDY
 nop

                              ; ===================================================
                              ; I n t e r r u p t   S e r v i c e   R o u t i n e s
                              ; ===================================================

                              ; TC1 ICR period end, display next digit

TC1Capt:

       in rsreg,SREG          ; save SREG
       ldi rimp,0xF0          ; clear all digit drivers
       out PORTA,rimp
       in rKey,PINB           ; read key values
       ori rDCnt,0x08         ; set bit 3
       lsl rDCnt              ; shift display counter left
       brcc TC1Capt1          ; end of cycle
       adiw YL,1              ; next digit
       ld rimp,Y              ; read next display digit
       out PORTC,rimp         ; write to port
       ldd rimp,Y+4           ; read display digit alarm
       out PORTD,rimp         ; write to port
       out PORTA,rDCnt        ; set active driver
       out SREG,rsreg         ; restore SREG
       reti

TC1Capt1:

       ldi YH,HIGH(sTime)     ; restart pointer
       ldi YL,LOW(sTime)
       ld rimp,Y              ; read first digit
       out PORTC,rimp         ; write to port
       ldd rimp,Y+4           ; read first digit alarm time
       out PORTD,rimp         ; write to port
       ldi rDCnt,0xE0         ; display starting with bit 4 = 0
       out PORTA,rDCnt
       out SREG,rsreg         ; restore SREG
       reti

                              ; TC1 Comp A reached

TC1CompA:

       in rsreg,SREG          ; save SREG
       dec rC5ms              ; count down for seconds
       brne TC1CompA1         ; not zero
       sbr rFlag,1<<bSec      ; set flag
       ldi rC5ms,200          ; start new

TC1CompA1:

       out SREG,rSreg         ; restore SREG
       reti

                              ; TC1 Comp B reached

TC1CompB:

       ldi rimp,0xF0          ; switch anode drivers off
       out PORTA,rimp
       reti

                              ; ADC ready interrupt

AdcInt:

       in rsreg,SREG          ; save SREG
       in rimp,ADMUX          ; low or high byte?
       sbrc rimp,MUX0
       rjmp AdcInt1
       in rimp,ADCH           ; read MSB ADC result
       add rAdcPL,rimp        ; add to result
       ldi rimp,0             ; add high byte
       adc rAdcPH,rimp        
       ldi rimp,(1<<ADLAR)|(1<<MUX0)  ; set channel 1                       
       out ADMUX,rimp         
       ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0) ; start conversion
       out ADCSRA,rimp
       out SREG,rsreg         ; restore SREG
       reti

AdcInt1:

       in rimp,ADCH           ; read MSB ADC result
       add rAdcFL,rimp        ; add to result
       ldi rimp,0             ; add high byte
       adc rAdcFH,rimp
       dec rAdcC              ; dec counter
       brne AdcInt2           ; not zero
       sts sAdcP,rAdcPH       ; copy result pot
       sts sAdcF,rAdcFH       ; copy result fototransistor
       clr rAdcPL             ; clear adders
       clr rAdcPH
       clr rAdcFL
       clr rAdcFH
       sbr rFlag,1<<bAdc      ; set ADC flag

AdcInt2:

       ldi rimp,1<<ADLAR      ; set channel 0
       out ADMUX,rimp
       ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0) ; start conversion
       out ADCSRA,rimp
       out SREG,rsreg         ; restore SREG
       reti

                              ; TC0 compare match interrupt

Tc0Comp:

       in rSreg,SREG          ; save SREG
       tst rDurL              ; duration zero?
       brne Tc0Comp0          ; no
       tst rDurH              ; MSB zero?
       breq Tc0CompR          ; yes, skip

Tc0Comp0:

       sbiw rDurL,1           ; decrease duration counter
       brne Tc0CompR          ; not zero, go on
       inc rEep               ; increase EEPROM address
       mov rimp,rEep          ; copy EEPROM read adress
       lsl rimp               ; multiply by 2
       out EEARL,rimp
       ldi rimp,0             ; upper byte
       adc rimp,rimp
       out EEARH,rimp
       ldi rimp,1<<EERE       ; read enable EEPROM
       out EECR,rimp
       in rimp,EEDR           ; read first byte
       tst rimp ; check for 0
       brne Tc0Comp01
       dec rimp
       out OCR0,rimp          ; write to CTC
       ldi rimp,(1<<WGM01)|(1<<COM01)|(1<<CS01) ; clear COM output
       out TCCR0,rimp         ; set mode and COM
       rjmp Tc0Comp2

Tc0Comp01:

       out OCR0,rimp          ; write to CTC
       ldi rimp,(1<<WGM01)|(1<<COM00)|(1<<CS01) ; toggle COM output
       out TCCR0,rimp         ; set mode and COM

Tc0Comp2:

       in rimp,EEARL          ; read lower address
       inc rimp               ; increase address
       out EEARL,rimp         ; set LSB address
       ldi rimp,1<<EERE       ; read enable
       out EECR,rimp          ; to control register
       in rDurH,EEDR          ; read duration
       clr rDurL
       tst rDurH              ; check end of melody
       brne Tc0Comp3          ; no, go on
       ldi rimp,(1<<WGM01)|(1<<COM01)|(1<<CS01) ; clear COM output
       out TCCR0,rimp         ; set mode and COM
       ldi rimp,0xFF          ; long time
       ldi rDurH,High(cPauseLong) ; long duration
       ldi rDurL,Low(cPauseLong)
       ldi rEep,0xFF          ; restart melody after pause
       rjmp Tc0CompR

Tc0Comp3:

       lsr rDurH
       ror rDurL
       lsr rDurH
       ror rDurL
       lsr rDurH
       ror rDurL
       lsr rDurH
       ror rDurL
       lsr rDurH
       ror rDurL

Tc0CompR:

       out SREG,rSreg         ; restore SREG
       reti

                              ; ===================================================
                              ;        M a i n   p r o g r a m   i n i t
                              ; ===================================================

Start:
                              ; init stack
       ldi rmp,HIGH(RAMEND)   ; init the MSB of the stack pointer
       out SPH,rmp
       ldi rmp,LOW(RAMEND)    ; init the LSB of the stack pointer
       out SPL,rmp
                              ; init ports
       ldi rmp,0xFF           ; set Ports C and D to be outputs and off
       out DDRC,rmp 
       out DDRD,rmp
                              ; out PORTC,rmp
                              ; out PORTD,rmp
       ldi rmp,0xF0           ; set port A upper four bits to be outputs and off
       out DDRA,rmp
       ldi rmp,0xE0
       out PORTA,rmp
       ldi rmp,0x00
       out PORTC,rmp
       out PORTD,rmp
                              ; test display
        .if dbg==1
       ldi rmp,0xE0
       out PORTA,rmp

ex1:  

       rjmp ex1
        .endif
        .if dbg==2
       ldi rmp,0xD0
       out PORTA,rmp

ex2: 

       rjmp ex2
        .endif
        .if dbg==3
       ldi rmp,0xB0
       out PORTA,rmp

ex3: 

       rjmp ex3
        .endif
        .if dbg==4
       ldi rmp,0x70
       out PORTA,rmp
ex4: 

       rjmp ex4
.endif
                              ; end of test
        ldi rmp,0x08          ; set port B bits 0..2 to be input, 3 to output
        out DDRB,rmp
        ldi rmp,0x07          ; set pull-ups on key inputs active
        ut PORTB,rmp
                              ; init display drivers, set all displays to 0
        ldi YH,HIGH(sCs)      ; point to time info start
        ldi YL,LOW(sCs)
        clr R0
        ldi rmp,7             ; clear time in SRAM

Start1:

        st Y+,R0
        dec rmp
        brne Start1
        rcall UpDateTime      ; set up time display
        rcall UpDateAlarm     ; set up alarm display
        out PORTC,rmp         ; display ports
        out PORTD,rmp
        ldi rDCnt,0x70        ; set last display to driver
        ldi YH,HIGH(sTime+3)  ; point to display start
        ldi YL,LOW(sTime+3)
        clr rFlag             ; set flags to zero
        clr rmp               ; disable watchdog
        out WDTCR,rmp
                              ; init ADC
        ldi rmp,1<<ADLAR      ; Left adjust result, channel 0, external VREF
        out ADMUX,rmp
        clr rmp               ; set SROR
        out SFIOR,rmp
        ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0) ; enable ADC
        out ADCSRA,rmp  
        ldi rmp,1             ; set dimm checking on first ADC cycle
        mov rFChk,rmp
                              ; init timer 0
        clr rDurL             ; set duration zero to block timer
        clr rDurH
        ldi rmp,175           ; set compare value to 175 (880 cs/s)
        out OCR0,rmp
        ldi rmp,(1<<WGM01)|(1<<COM00) ; stop alarm timer
        out TCCR0,rmp         ; set mode and COM
                              ; init timer 1 as clock and digit driver
.equ divider=(5*clock+500)/1000 ; 5 ms time int
        ldi rmp,HIGH(divider) ; set compare match ICR1
        out ICR1H,rmp
        di rmp,LOW(divider)
        out ICR1L,rmp
        ldi rmp,HIGH(divider/2) ; set compare match A as 5-ms-int
        out OCR1AH,rmp
        ldi rmp,LOW(divider/2)
        out OCR1AL,rmp
        ldi rmp,HIGH(divider-2) ; set compare match B as dim int
        out OCR1BH,rmp
        ldi rmp,LOW(divider-2)
        out OCR1BL,rmp
        clr rmp               ; clear WGM11 and WGM10
        out TCCR1A,rmp
        ldi rmp,(1<<WGM13)|(1<<WGM12)|(1<<CS10) ; ICR-CTC, div = 1
        out TCCR1B,rmp
                              ; enable timer interrupts
        ldi rmp,(1<<OCIE1A)|(1<<OCIE1B)|(1<<TICIE1)|(1<<OCIE0) ; ICR1-,COMP1-,TC0 int enable
        out TIMSK,rmp
                              ; set sleep mode
        ldi rmp,1<<SE         ; set sleep enable and sleep mode 0
        out MCUCR,rmp
                              ; enable interrupts
        sei
                              ; ===================================================
                              ;        M a i n   p r o g r a m   l o o p
                              ; ===================================================
Loop:
        sleep                 ; go to sleep
        nop                   ; dummy after wakeup

        rcall keys            ; check keys after every wakeup
                              ; Check for flags that have been set
        sbrc rFlag,bSec       ; jump over if second flag not set
        rcall Second
        sbrc rFlag,bAdc       ; jump over if no new ADC conversion results
        rcall AdcNew
        rjmp Loop

                              ; ===================================================
                              ;            C h e c k   k e y s
                              ; ===================================================

.equ cKeyRed = 0x06
.equ cKeyBlack = 0x05
.equ cKeyWhite = 0x03

keys:
        andi rKey,0x07        ; isolate keys
        lds rmp,sKey          ; read stored key value
        cp rmp,rKey           ; compare key value
        breq key1             ; eqal key
                              ; key different from last key, store new, clear counter
        sts sKey,rKey         ; store key
        ldi rmp,0             ; clear count
        sts sKeyC,rmp
        ret

key1:                         ; key equals last key

        lds rmp,sKeyC         ; read key count
        inc rmp               ; increase key count
        sts sKeyC,rmp         ; store
        cpi rmp,3             ; three identical key codes
        breq key2             ; identical
        brcs key1a
        ldi rmp,5
        sts sKeyC,rmp

key1a:

        ret

key2:                         ; key valid

        lds rmp,sKey          ; read key code
        cpi rmp,0x07          ; key unpressed?
        breq key3             ; yes
        sts sKeyS,rmp         ; store selected key
        ret

key3:

        lds rmp,sKeyS         ; read selected key
        ldi ZL,0
        sts sKeyS,ZL
        tst rmp
        brne key4
        ret

key4:                         ; conditional jumps according to flags
        sbrc rFlag,bAlarm     ; currently alarm?
        rjmp keyAlarm         ; react to key during alarm
        sbrc rFlag,bArmed     ; currently armed?
        rjmp keyArmed         ; react to key during armed
        sbrc rFlag,bSetC      ; currently on setting clock?
        rjmp keySetC          ; react to key during clock setting
        sbrc rFlag,bSetA      ; currently on setting alarm time?
        rjmp keySetA          ; react to key during alarm time setting
                              ; normal mode, treat as new key
        cpi rmp,cKeyRed       ; red key?
        brne key5             ; no
        sbr rFlag,1<<bSetC    ; set flag
        ret

key5:

        cpi rmp,cKeyWhite     ; white key?
        brne key6             ; no
        sbr rFlag,1<<bSetA    ; set flag
        ret

key6:

        cpi rmp,cKeyBlack     ; black key?
        brne key7
        ldi rmp,1<<bArmed     ; toggle armed flag
        eor rFlag,rmp
        ret

key7:

        ret

keySetC:                      ; keys during set C

        cpi rmp,cKeyBlack     ; black key pressed = skip
        brne keySetC1
        cbr rFlag,(1<<bSetC)|(1<<bSetCM) ; clear flags
        rjmp UpDateTime

keySetC1:

        cpi rmp,cKeyRed       ; red key pressed
        brne keySetC3         ; no
                              ; red key pressed
        sbrs rFlag,bSetCm     ; set clock minutes?
        rjmp keySetC2         ; no, set hours
                              ; set minutes
        clr rmp               ; clear seconds
        sts sCs,rmp
        lds rmp,sAdcP
        ldi ZL,60
        mul rmp,ZL
        sts sCm,R1
        cbr rFlag,(1<<bSetC)|(1<<bSetCm) ; clear flags
        rjmp UpDateTime

keySetC2:                     ; set hours

        lds rmp,sAdcP
        ldi ZL,24
        mul rmp,ZL
        sts sCh,R1
        clr rmp ; clear seconds
        sts sCs,rmp
        sbr rFlag,(1<<bSetC)|(1<<bSetCm) ; set minute flag
        ret

keySetC3:                     ; illegal key

        ret

keySetA:                      ; keys during set A

        cpi rmp,cKeyBlack     ; black key pressed = skip
        brne keySetA1         ; no
        cbr rFlag,(1<<bSetA)|(1<<bSetAm) ; clear flags
        rjmp UpDateAlarm

keySetA1:

        cpi rmp,cKeyWhite     ; white key pressed?
        brne keySetA3         ; no
                              ; white key pressed
        sbrs rFlag,bSetAm     ; set alarm minutes?
        rjmp keySetA2         ; no, set hours
                              ; set minutes
        lds rmp,sAdcP         ; read pot value
        ldi ZL,60
        mul ZL,rmp
        sts sAm,R1            ; set alarm time
        sts sSm,R1            ; set Set alarm time
        cbr rFlag,(1<<bSetA)|(1<<bSetAm) ; clear set alarm flags
        sbr rFlag,1<<bArmed   ; set armed flag
        rjmp UpDateAlarm

keySetA2:                     ; set hours

        lds rmp,sAdcP
        ldi ZL,24
        mul ZL,rmp
        sts sAh,R1            ; set alarm time
        sts sSh,R1            ; set Set alarm time
        sbr rFlag,1<<bSetAm   ; set minutes flag
        ret

keySetA3:

        ret

keyAlarm:                     ; key during alarm

        cpi rmp,cKeyRed       ; red key pressed?
        brne keyAlarm1
                              ; red key during alarm: snooze function
keyAlarmSnooze:

        lds rmp,sAm           ; read alarm minutes
        subi rmp,-cSnooze     ; add snooze time
        sts sAm,rmp           ; and store
        cpi rmp,60            ; above or equal 60 minutes?
        brcs keyAlarmOff      ; no, go on
        subi rmp,60           ; subtract 60 minutes
        sts sAm,rmp           ; and store
        lds rmp,sAh           ; read hours
        inc rmp               ; next hour
        sts sAh,rmp           ; and store
        cpi rmp,24            ; greater than or equal 24
        brcs keyAlarmOff      ; no, go on
        clr rmp               ; restart hours
        sts sAh,rmp           ; and store

keyAlarmOff:

        cbr rFlag,1<<bAlarm   ; clear alarm flag
        ldi rmp,(1<<WGM01)|(1<<COM00) ; stop alarm timer
        out TCCR0,rmp         ; set mode and COM
        cbi PORTB,3           ; clear OC0 port bit
        rjmp UpDateAlarm  

keyAlarm1:

        cpi rmp,cKeyBlack     ; black key pressed?
        brne keyAlarm2        ; no
                              ; black key during alarm: set alarm and armed off
        lds rmp,sSm           ; read set alarm minutes
        sts sAm,rmp           ; write to alarm minutes
        lds rmp,sSh           ; read alarm minutes
        sts sAh,rmp           ; write to alarm minutes
        cbr rFlag,1<<bArmed   ; clear armed flag
        rjmp keyAlarmOff

keyAlarm2:
                              ; any other key: do nothing
        ret

keyArmed:                     ; key during armed

        cpi rmp,cKeyBlack     ; black key pressed
        brne keyArmed1        ; not pressed
                              ; black key during armed
        cbr rFlag,1<<bArmed   ; set armed off
        lds rmp,sSm           ; read set alarm minutes
        sts sAm,rmp           ; write to alarm minutes
        lds rmp,sSh           ; read alarm minutes
        sts sAh,rmp           ; write to alarm minutes
        rjmp UpDateAlarm

keyArmed1:

        cpi rmp,cKeyRed       ; red key during armed
        brne keyArmed2        ; not pressed
                              ; red key during armed: increase alarm time
        rjmp keyAlarmSnooze   ; increase alarm time

keyArmed2:
                              ; any other key: ignore
        ret
            
                              ; ===================================================
                              ;         A   s e c o n d   i s   o v e r
                              ; ===================================================

Second:

        cbr rFlag,1<<bSec     ; clear second flag
        lds rmp,sCs           ; read second
        inc rmp               ; next second
        sts sCs,rmp           ; store seconds
        .if dbg == 5
        rcall dispsec
        .endif
        cpi rmp,60            ; next minute?
        brcs Second1          ; no, not yet
        clr rmp               ; clear seconds
        sts sCs,rmp           ; store zero
        lds rmp,sCm           ; read minutes
        inc rmp               ; next minute
        sts sCm,rmp           ; store minutes
        cpi rmp,60            ; next hour?
        brne UpdateTime
        clr rmp               ; clear minutes
        sts sCm,rmp           ; store minutes
        lds rmp,sCh           ; read hours
        inc rmp               ; next hour
        sts sCh,rmp           ; store hours
        cpi rmp,24            ; next day?
        brne UpdateTime
        clr rmp               ; clear hours
        sts sCh,rmp
        rjmp UpdateTime

Second1:                      ; blink time points

        sbrc rFlag,bSetC
        rjmp Second4
        ror rmp               ; lowest bit to carry
        lds rmp,sTime         ; load first displayed digit
        brcs Second2          ; low bit = 1
        sbr rmp,1<<7          ; clear led
        rjmp Second3

Second2:

        cbr rmp,1<<7          ; set led

Second3:
        sts sTime,rmp         ; to first displayed digit
                              ; blink alarm points
Second4:

        sbrs rFlag,bArmed     ; if not armed return
        ret
        lsl rmp               ; bit 7 to carry
        lds rmp,sAlarm        ; read alarm position
        brcs Second5
        andi rmp,0x7F         ; clear bit 7
        rjmp Second6

Second5:

        sbr rmp,1<<7          ; set bit 7

Second6:

        sts sAlarm,rmp        ; store alarm byte
        ret

dispsec:

        lds rmp,sCs
        ldi XH,High(sAlarm+2)
        ldi XL,Low(sAlarm+2)
        rcall To7Seg
        lds rmp,sCs
        ret
                              ; ===================================================
                              ;          U p d a t e   d i s p l a y
                              ; ===================================================
                              ;
                              ; Update displayed alarm time
                       
UpDateAlarm:

        ldi XH,High(sAlarm)
        ldi XL,Low(sAlarm)
        lds rmp,sAh
        rcall To7Seg
        lds rmp,sAm
        rjmp To7Seg

                              ; Updates the time displayed

UpdateTime:

        sbrc rFlag,bArmed     ; if armed, compare alarm time
        rcall CheckAlarm      ; check alarm time
        sbrc rFlag,bSetC      ; if Set Clock active, skip
        ret
        ldi XH,High(sTime)    ; point to time
        ldi XL,LOW(sTime)
        lds rmp,sCh           ; read hours
        rcall To7Seg
        lds rmp,sCm           ; read minutes

To7Seg:

        clr R0                ; R0 is counter

To7Seg1:

        subi rmp,10
        brcs To7Seg2
        inc R0
        rjmp To7Seg1

To7Seg2:

        subi rmp,-10
        ldi ZH,HIGH(2*Tab7Seg); load table
        ldi ZL,LOW(2*Tab7Seg)
        add ZL,R0
        brcc To7Seg3
        inc ZH

To7Seg3:

        lpm
        st X+,R0
        ldi ZH,HIGH(2*Tab7Seg); load table
        ldi ZL,LOW(2*Tab7Seg)
        add ZL,rmp
        brcc To7Seg4
        inc ZH

To7Seg4:

        lpm
        st X+,R0
        ret
                              ; Conversion table decimal to 7-segment
Tab7Seg:

.db 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10
                              ; hex values
.db 0x08,0x03,0x27,0x21,0x06,0x0E

                              ; ===================================================
                              ;  C h e c k   a l a r m   t i m e    r e a c h e d
                              ; ===================================================

CheckAlarm:

        lds R0,sCh            ; read clock hours
        lds rmp,sAh           ; read alarm hours
        cp R0,rmp             ; equal?
        brne CheckAlarmRet
        lds R0,sCm            ; read clock minutes
        lds rmp,sAm           ; read alarm minutes
        cp R0,rmp             ; equal?
        brne CheckAlarmRet
        sbr rFlag,1<<bAlarm   ; set Alarm flag
        ser rEep              ; address to end of EEPROM
        ldi rDurL,1           ; start at new address in int cycle
        clr rDurH
        ldi rmp,(1<<WGM01)|(1<<COM01)|(1<<CS01) ; start alarm timer
        out TCCR0,rmp         ; set mode and COM and prescale = 8

CheckAlarmRet:

        ret

                              ; ===================================================
                              ;   N e w   A d c   r e s u l t   p r o v i d e d
                              ; ===================================================

AdcNew:

        cbr rFlag,1<<bAdc     ; clear ADC flag
        .if dbg == 6
        rcall dispadc
        .endif
        dec rFChk             ; check dim adjust?
        brne AdcNew2          ; don't adjust
        ldi rmp,0x10          ; set down counter
        mov rFChk,rmp
        lds rmp,sAdcF         ; read fototransistor value
        cpi rmp,0xFF          ; dark?
        brcs AdcNew1          ; no
        ldi rmp,HIGH(divider/2); set half time
        out OCR1BH,rmp
        ldi rmp,LOW(divider/2)
        out OCR1BL,rmp
        rjmp AdcNew2

AdcNew1:

        ldi rmp,HIGH(divider-30); set full time
        out OCR1BH,rmp
        ldi rmp,LOW(divider-30)
        out OCR1BL,rmp

AdcNew2:

        lds rmp,sAdcP         ; read pot value
        sbrs rFlag,bSetC      ; C setting?
        rjmp AdcNew4          ; no C
                              ; set C
        sbrs rFlag,bSetCm     ; minutes setting?
        rjmp AdcNew3
                              ; display minutes from pot setting
        ldi XH,High(sTime+2)  ; set pointer
        ldi XL,Low(sTime+2)
        ldi ZL,60             ; 60 minutes
        rjmp Mult             ; muliply and display

AdcNew3:                      ; display hours setting

        ldi XH,High(sTime)    ; set pointer
        ldi XL,Low(sTime)
        ldi ZL,24             ; multiply by 24
        rjmp Mult             ; multiply and display

AdcNew4:

        sbrs rFlag,bSetA      ; A setting ?
        ret                   ; no
        sbrs rFlag,bSetAm     ; minutes?
        rjmp AdcNew5          ; no
        ldi XH,High(sAlarm+2) ; set pointer
        ldi XL,Low(sAlarm+2)
        ldi ZL,60
        rjmp Mult             ; multiply and display

AdcNew5:

        ldi XH,High(sAlarm)   ; set pointer
        ldi XL,Low(sAlarm)
        ldi ZL,24
        rjmp Mult

                              ; Multiply and display

Mult:

        mul ZL,rmp
        mov rmp,R1
        rjmp To7Seg

                              ; ===================================================
                              ;  D e b u g :   D i s p l a y   a d c   r e s u l t
                              ; ===================================================

dispadc:

       ldi XH,HIGH(sAlarm)
       ldi XL,LOW(sAlarm)
       lds rmp,sAdcP
       rcall dispadc1
       lds rmp,sAdcF

dispadc1:

       push rmp
       swap rmp
       rcall dispadc2
       pop rmp

dispadc2:

       andi rmp,0x0F
       ldi ZH,HIGH(2*Tab7Seg)
       ldi ZL,LOW(2*Tab7Seg)
       add ZL,rmp
       brcc dispadc3
       inc ZH

dispadc3:

       lpm
       st X+,R0
       ret

                              ; ===================================================
                              ;      C o p y r i g h t   i n f o r m a t i o n
                              ; ===================================================
                              ;
.db "C(2)10 0ybh tt:p//ww.wva-rsa-mutotirlan.te"
                              ;
                              ; ===================================================
                              ;         M e l o d y   i n   E E P R O M
                              ; ===================================================

.eseg
.org $0000

.equ cPa = 10                 ; pause duration
.equ cD = 9216                ; tone duration constant

                              ; Frequency table
.equ cf2e = 659
.equ cf2f = 698
.equ cf2g = 784
.equ cf2a = 880
.equ cf2h = 988
.equ cf3c = 1047
.equ cf3d = 1175
.equ cf3e = 1319
.equ cf3f = 1397
.equ cf3g = 1568
.equ cf3a = 1760
.equ cf3h = 1976
.equ cf4c = 2093
.equ cf4d = 2349
.equ cf4e = 2637
.equ cf4f = 2794
.equ cf4g = 3136
.equ cf4a = 3520
.equ cf4h = 3951
.equ cf5c = 4186
                              ; CTC table for these frequencies
.equ cc2e = clock/16/cf2e
.equ cc2f = clock/16/cf2f
.equ cc2g = clock/16/cf2g
.equ cc2a = clock/16/cf2a
.equ cc2h = clock/16/cf2h
.equ cc3c = clock/16/cf3c
.equ cc3d = clock/16/cf3d
.equ cc3e = clock/16/cf3e
.equ cc3f = clock/16/cf3f
.equ cc3g = clock/16/cf3g
.equ cc3a = clock/16/cf3a
.equ cc3h = clock/16/cf3h
.equ cc4c = clock/16/cf4c
.equ cc4d = clock/16/cf4d
.equ cc4e = clock/16/cf4e
.equ cc4f = clock/16/cf4f
.equ cc4g = clock/16/cf4g
.equ cc4a = clock/16/cf4a
.equ cc4h = clock/16/cf4h
.equ cc5c = clock/16/cf5c
                              ; tone duration constants
.equ cd2e = cd/cc2e
.equ cd2f = cd/cc2f
.equ cd2g = cd/cc2g
.equ cd2a = cd/cc2a
.equ cd2h = cd/cc2h
.equ cd3c = cd/cc3c
.equ cd3d = cd/cc3d
.equ cd3e = cd/cc3e
.equ cd3f = cd/cc3f
.equ cd3g = cd/cc3g
.equ cd3a = cd/cc3a
.equ cd3h = cd/cc3h
.equ cd4c = cd/cc4c
.equ cd4d = cd/cc4d
.equ cd4e = cd/cc4e
.equ cd4f = cd/cc4f
.equ cd4g = cd/cc4g
.equ cd4a = cd/cc4a
.equ cd4h = cd/cc4h
.equ cd5c = cd/cc5c
                              ; melody
                              ; 4g  4g  4f   3a
                              ; 4e  4d 4d
                              ; 4c  3h  4c   4f
                              ; 4f 4g-4f
                              ; table
.db cc3g,cd3g,cc3g,cd3g,cc3f,cd3f,cc2a,cd2a
.db cc3e,cd3e,cc3d,cd3d,cc3d,cd3d
.db cc3c,cd3c,cc2h,cd2h,cc3c,cd3c,cc3f,cd3f
.db cc3f,cd3f,cc3g,cd3g,cc3f,cd3f
                              ; end of table
.db 0,0

                              ; End of source code

No comments:

Post a Comment