; ********************************************* ; * Digitale AVR Uhr mit einem 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 ; =================================================== ; dbg = 0: Debugging aus, normale Programmausfuehrung ; dbg = 1: Erstes Display an ; dbg = 2: Zweites Display an ; dbg = 3: Drittes Display an ; dbg = 4: Viertes Display an ; dbg = 5: Sekundenanzeige auf der Minutenposition der Weckzeit ; dbg = 6: Zeige die ADC-Werte in Hex auf dem Weckzeit-Display an ; .equ dbg = 0 ; ; =================================================== ; H a r d w a r e ; =================================================== ; Processortyp: ATmega16 ; _________ ; / | ; Taste rt --|PB0 ADC0|-- Potentiometereingang ; Taste sw --|PB1 ADC1|-- Fototransistoreingang ; Taste ws --|PB2 |-- ; Lautspr. --|OC0 |-- ; --| PA4|-- 1 Digit Anodentreiber ; 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 ; Quarz 2 --|XTAL2 PC7|-- Grosser LED Doppelpunkt ; Quarz 1 --|XTAL1 PC6|-- g Grosse ; Kleine a --|PD0 PC5|-- f Sieben- ; Sieben b --|PD1 PC4|-- e Segment- ; Segm. c --|PD2 PC3|-- d Anzeige ; Anzeiged --|PD3 PC2|-- c Kathoden ; Kath. e --|PD4 PC1|-- b ; f --|PD5 PC0|-- a ; g --|PD6 PD7|-- Kleiner LED Doppelpunkt ; |___________ ; ; =================================================== ; B e s c h r e i b u n g d e r F u n k t i o n ; =================================================== ; ; a) Anzeigen und Anzeigenmodi ; Die obere, grosse Siebensegmentanzeige zeigt die Zeit ; an, die untere kleine zeigt die Weckzeit an. ; Der grosse Doppelpunkt in der oberen Anzeige blinkt ; in Sekundenintervallen. Der kleinere Doppelpunkt ; zeigt an, ob der Weckalarm aktiviert ist. Sind diese ; LEED dauernd an, ist der Weckalarm ausgeschaltet. ; b) Anzeigenmultiplex ; Die Anzeige verwendet Zaehler/Zeitgeber 1 im CTC- ; Modus, um alle 5 ms eine Unterbrechung auszuloesen. ; Die vier Anzeigen werden alle 20 ms erneuert, was ; zu einer Multiplexfrequenz von 50 Hz fuehrt. ; Die Anzeige wird zuerst ausgeschaltet, der Zeiger ; auf die angezeigte Ziffer wird erhoeht und das ; Byte an der Ziffernposition wird an Port C (grosse ; Zeitanzeige) bzw. D (kleine Weckalarmanzeige) kopiert. ; Dann wird das Portbit fuer den richtigen Anodentreiber ; im oberen Nibble von Port A aktiviert (=0). ; c) Anzeige dimmen ; Das Abblenden der Anzeige verwendet den Zaehler/Zeitgeber ; 1 im CTC-Modus und die Unterbrechung bei Compare Match B ; und schaltet die Anodentreiber alle fruehzeitig aus. Der ; Wert fuer den Compare Match B wird aus dem ADC-Wert des ; Fototransistors ermittelt: je weniger Licht am Foto- ; transistor ankommt, desto hoeher ist seine Kollektor- ; spannung, desto groesser ist der ADC-Wert und der ; Wert von Compare Match B. Beachte, dass dies nicht-linear ; ist (es gibt nur zwei Helligkeitsstufen). ; d) Zeitbestimmung ; Die Zeit wird vom Zaehler/Zeitgeber 1 und der Compare ; Match A Unterbrechung gesteuert. Die Unterbrechung ; zaehlt einen Zaehler von 200 auf Null abwaerts. Wenn ; Null erreicht wird, wird eine Flagge gesetzt und der ; 5-ms-Zaehler neu gestartet. ; Ausserhalb der Unterbrechungsroutine wird die Zeit ; um eine Sekunde erhoeht, beim Erreichen von 60 wird ; die Zeit um eine Minute erhoeht. Wenn das Wecken akti- ; viert ist, wird die Zeit mit der Weckzeit verglichen ; und bei Gleichheit die Alarmierung aktiviert. ; e) Tasten ; Die Tasten werden im Anschluss an jede Unterbrechung ; gelesen. Eine gedrueckte Taste wird nach drei ; Unterbrechungen erkannt und gespeichert. Die entsprechende ; Aktion wird ausgefuehrt wenn fuer mindestens 15 ms keine ; der Tasten mehr gedrueckt ist. ; Die folgende Tabelle zeigt die ausgefuehrten Aktionen in ; den verschiedenen Betriebszustaenden: ; Modus Taste Aktion ; ---------------------------------------------------------- ; Normal Schwarz Ein-/Ausschalten Wecken ; Rot Beginne Einstellung der Zeit ; Weiss Beginne Einstellung der Weckzeit ; Zeiteinstellung Schwarz Beende Zeiteinstellung vorzeitig ; Rot Stelle Zeit (Stunden oder Minuten) ; Weckeinstellung Schwarz Beende Weckzeiteinstellung vorzeitig ; Weiss Stelle Weckzeit (Stunden oder Minuten) ; Alarmierung an Schwarz Stelle Alarmierung aus ; Rot Stelle Alarmzeit um 5 Minuten spaeter ; Alarmiert Schwarz Alarm aus und Weckzeit auf Original ; Rot Alarm aus und Weckzeit um 5 Minuten spaeter ; f) AD-Wandlung ; Der AD-Wandler laeuft mit einem Vorteiler von 128, misst zwei ; Kanaele und wird mittels Unterbrechung bedient. ; Die Analogspannungen am Potentiometer (Kanal ADC0) und am ; Kollektor des Fototransistors (Kanal ADC1) werden gemessen, ; die oberen acht Byte des linksbuendigen Ergebnisses eingelesen ; und zu einer 16-Bit-Summe addiert. Wenn 256 Messungen pro ; Kanal addiert sind, werden die oberen 8 Bit der Summe an ; eine Routine ausserhalb der Unterbrechungsroutine uebergeben. ; Dies wird verwendet um bei ; Kanal 0: falls Zeit- oder Weckzeiteinstellung aktiv sind, ; wird das Ergebnis in Stunden bzw. Minuten umgerechnet und ; auf der jeweiligen Stunden-/Minutenposition ausgegeben. ; Kanal 1: in laengeren Abstaenden wird daraus der Compare ; Match B Wert zu bestimmen und zu setzen (Dim-Funktion). ; Messfrequenz: f = 2457600 / 128 / 13 / 256 / 2 = 2,88 Hz ; (beide Kanaele) ; g) Wecken ueber Melodie ; Der Zaehler/Zeitgeber 0 wird als programmierbarer Tongenerator ; betrieben, so dass er im CTC-Modus bei aktiviertem Ausgabeport ; (Umpolung bei Compare Match) Melodien spielen kann. Der TC0 ; wird mit einem Vorteiler von 8 betrieben, so dass NF zwischen ; 600 (OCR0=255) und 9600 (OCR=16) Hz erzeugt werden kann. ; Wenn der oberste CTC-Wert erreicht wird, wird die naechste Note ; und die naechste Spieldauer des Tons aus dem EEPROM gelesen. ; Ist der letzte Tabellenwert gespielt, wird TC0 stillgelegt ; und der OC0-Ausgang abgeschaltet. ; ; =================================================== ; K o n s t a n t e n ; =================================================== ; .equ clock = 2457600 ; Quarzfrequenz .equ cSnooze = 5 ; Zeit in Minuten fuer Schlummern .equ cPauseLong = $4000 ; lange Pause fuer Melodiewiederholung ; ; =================================================== ; R e g i s t e r ; =================================================== ; ; verwendet mit LPM fuer Lesen aus dem Flash und fuer Berechnungen ; verwendet fuer Berechnungen ; frei R2..R8 .def rFChk = R9 ; Zaehler fuer Dimm-Funktion .def rAdcC = R10 ; ADC Zaehler .def rAdcFL = R11 ; LSB ADC-Summe Fototransistor .def rAdcFH = R12 ; dto., MSB .def rAdcPL = R13 ; LSB ADC-Summe Potentiometer .def rAdcPH = R14 ; dto., MSB .def rSreg = R15 ; SREG temporaer innerhalb Unterbrechung .def rmp = R16 ; Vielzweckregister ausserhalb Unterbrechungen .def rimp = R17 ; Vielzweckregister innerhalb Unterbrechungen .def rFlag = R18 ; Flaggenregister .equ bArmed = 0 ; Alarm ist aktiviert .equ bAlarm = 1 ; Alarm ist ausgeloest .equ bSetC = 2 ; Stelle Uhrzeit .equ bSetCm = 3 ; Stelle Uhrzeit Minuten .equ bSetA = 4 ; Stelle Weckzeit .equ bSetAm = 5 ; Stelle Weckzeit Minuten .equ bSec = 6 ; Naechste Sekunde erreicht .equ bAdc = 7 ; Neues ADC-Ergebnis fertig .def rC5ms = R19 ; 5 ms Zaehler fuer Sekunde .def rDCnt = R20 ; Anzeige Anodentreiber .def rKey = R21 ; Tastenspeicher letzte aktive Taste .def rEep = R23 ; EEPROM-Leseadresse .def rDurL = R24 ; LSB Zaehler fuer Dauer Toene .def rDurH = R25 ; dto., MSB ; R27:R26 verwendet als Zeiger ausserhalb Unterbrechung ; R29:R28 verwendet als Zeiger fuer Anzeigenmultiplex innerhalb Unterbrechung ; R31:R30 verwendet als Zeiger ausserhalb Unterbrechung ; ; =================================================== ; S R A M A d r e s s e n ; =================================================== ; .DSEG .ORG Sram_Start sTime: .byte 4 ; vier Ziffern fuer die grosse Anzeige sAlarm: .byte 4 ; vier Ziffern fuer die kleine Anzeige sCs: .byte 1 ; Uhrzeit Sekunden sCm: .byte 1 ; Uhrzeit Minuten sCh: .byte 1 ; Uhrzeit Stunden sSm: .byte 1 ; Eingestellte Weckzeit Minuten sSh: .byte 1 ; Eingestellte Weckzeit Stunden sAm: .byte 1 ; Aktuelle Weckzeit Minuten sAh: .byte 1 ; Aktuelle Weckzeit Stunden sAdcP: .byte 1 ; Adc Ergebnis Potentiometer sAdcF: .byte 1 ; Adc Ergebnis Fototransistor sKey: .byte 1 ; gedrueckte Taste sKeyC: .byte 1 ; Zaehler fuer Tastendruecke sKeyS: .byte 1 ; letzte aktive Taste ; ; =================================================== ; R e s e t u n d I n t - V e k t o r e n ; =================================================== ; .cseg .org $0000 rjmp start ; Reset Vektor 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 n ; =================================================== ; ; TC1: ICR Periodenende, zeige naechste Ziffer an ; TC1Capt: in rsreg,SREG ; rette SREG ldi rimp,0xF0 ; Zifferntreiber aus out PORTA,rimp in rKey,PINB ; lese Tasten ori rDCnt,0x08 ; Setze Bit 3 Anodenregister lsl rDCnt ; Schiebe Anodenregister links brcc TC1Capt1 ; Wenn 0, dann Zyklusende adiw YL,1 ; naechste Ziffer ld rimp,Y ; Lese naechste Ziffer Uhrzeit out PORTC,rimp ; Schreibe auf Port ldd rimp,Y+4 ; Lese naechste Ziffer Weckzeit out PORTD,rimp ; Schreibe auf Port out PORTA,rDCnt ; Setze aktiven Anodentreiber out SREG,rsreg ; stelle SREG wieder her reti TC1Capt1: ldi YH,HIGH(sTime) ; Neustart Zeiger auf Ziffer ldi YL,LOW(sTime) ld rimp,Y ; Lese erste Ziffer Uhrzeit out PORTC,rimp ; Schreibe auf Port ldd rimp,Y+4 ; Lese erste Ziffer Weckzeit out PORTD,rimp ; Schreibe auf Port ldi rDCnt,0xE0 ; Starte Anodentreiberport mit Bit 4 = 0 out PORTA,rDCnt ; an Anodentreiber out SREG,rsreg ; stelle SREG wieder her reti ; ; TC1 Comp A erreicht ; TC1CompA: in rsreg,SREG ; Rette SREG dec rC5ms ; Zaehle 5-ms-Zaehler herunter brne TC1CompA1 ; Nicht Null sbr rFlag,1<