; ********************************************* ; * 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<