; *************************************************************** ; * Uhr mit 2-Zeilen-LCD-Anzeige für STK500 mit Timer/Counter 1 * ; * Anschluss der LCD über 4-Bit-Kabel an Port des STK500 * ; * Bit0=E, Bit1=RS, Bit4..7:D4..D7 * ; * Benötigt die LCD-Basisroutinen Lcd4Inc.asm * ; * Eingestellt auf Taktfrequenz 3,685 MHz des STK500 * ; * (C)2002 by info@avr-asm-tutorial.net * ; * Erstellt: 16.2.2002, Letzte Änderung: 17.2.2002 * ; *************************************************************** ; .NOLIST .INCLUDE "C:\avrtools\appnotes\8515def.inc" .LIST ; ; Timing-Schema zur Erzeugung des 1-Sekunden-Taktes ; ;3.685.000Hz--> 460.625Hz --> 67 Hz --> 1 Hz ; ;+---------+ +----------+ +----------+ +--------+ ;|CPU-Takt | |TC1-Teiler| |TC1-Compa-| |Register| ;|3,685 MHz|-->|Prescaler |-->|re Match A|-->| rdiv1s |--> 1 s ;|7,37MHz/2| |Teiler /8 | | /6875 | | /67 | ;+---------+ +----------+ +----------+ +--------+ ; ; Konstanten ; .EQU ftakt = 3685000 ; Frequenz STK500 interner Takt .EQU cdivtc1 = 6875 ; Teiler für TC1 .EQU cdiv1s = 67 ; Teiler für 1 s ; ; Aktive Ports für LCD-Ausgabe ; .EQU pLcdPort=PORTA ; LCD an PORT A angeschlossen .EQU pLcdDdr=DDRA ; Datenrichtungsregister LCD-Port ; ; Benutzte Register ; .DEF rint= R15 ; Interrupt temp register .DEF rmp = R16 ; Multi-Purpose Register .DEF rdiv1s = R17 ; Teiler durch 67 ; ; Datensegment ; ; SRAM-Speicher für Datum und Uhrzeit ; ; Packed BCD: Z=Bit7..4, E=Bit3..0 ; ; $0060 +1 +2 +3 +4 +5 ; +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ ; | Tag | |Monat| | Jahr| |Stund| |Minut| |Sekun| ; | Z E | | Z E | | Z E | | Z E | | Z E | | Z E | ; +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ ; .DSEG .ORG $0060 ; Datensegment beginnt bei $0060 ramdt: .BYTE 6 ; dd mm yy hh mm ss, packed BCD reservieren ; ; Code beginnt hier ; .CSEG .ORG $0000 ; ; Reset- und Interrupt-Vektoren ; rjmp Start ; Reset-vector reti ; External Interrupt Request 0 reti ; External Interrupt Request 1 reti ; Timer/Counter1 Capture event rjmp TCmp1A ; Timer/Counter1 Compare match A reti ; Timer/Counter1 Compare match B reti ; Timer/Counter1 Overflow reti ; Timer/Counter0 Overflow reti ; SPI Serial Transfer complete reti ; Uart Rx char available reti ; Uart Tx data register empty reti ; Uart Tx complete reti ; Analog comparator ; ; ************** Interrupt service routines ******** ; ; ; Timer/Counter 1, Compare match A interrupt ; TCmp1A: in rint,SREG ; Status-Register retten inc rdiv1s ; Teiler durch 67 erhöhen out SREG,rint ; Status vor Int wieder herstellen reti ; ; **************** Ende der Interrupt Service Routinen ********* ; ; **************** Verschiedene Unterprogramme ************* ; ; LCD-4-Bit-Routinen einbinden ; .NOLIST .INCLUDE "Lcd4IncE.asm" .LIST ; ; Init date-time default ; initdt: ldi ZH,HIGH(2*initdtt) ; Set date/time to default ldi ZL,LOW(2*initdtt) ldi XH,HIGH(ramdt) ldi XL,LOW(ramdt) ldi rmp,6 initdt1: lpm st X+,R0 adiw ZL,1 dec rmp brne initdt1 ret initdtt: ; Default date and time table .DB 0x17,0x02,0x02,0x14,0x05,0x00 ; ; Add 1 to BCD number that Z points to ; R0 must be 0x06, R1 is used temporarily, R2 is restart ; value, rmp is maximum value for overflow ; return with carry set if no overflow occurs ; inct: ld R1,Z ; Read Packed BCD to R1 sec ; Set carry adc R1,R0 ; add 06 and carry brhs inct1 ; If half carry: don't sub 06 sub R1,R0 ; no half carry inct1: cp R1,rmp ; max value reached? brcs inct2 ; no overflow mov R1,R2 ; set to restart value inct2: st Z,R1 ; Write to RAM ret ; and return ; ; Display date on LCD ; dispdate: clr rmp ; Set LCD home position ldi ZH,HIGH(2*datet) ; display Date-Text ldi ZL,LOW(2*datet) rcall Lcd4ZTxt ; Gib nullterminierten Text aus ldi rmp,'.' ; Separator für Datum mov R0,rmp ldi ZH,HIGH(ramdt) ; Zeige auf Datum ldi ZL,LOW(ramdt) rcall disp3 ; Gib drei PBCD-Zahlen mit Separator aus ; ; Display time on LCD ; disptime: ldi rmp,0x40 ; LCD Cursor Beginn 2. Zeile ldi ZH,HIGH(2*timet) ; Display Time-Text ldi ZL,LOW(2*timet) rcall Lcd4ZTxt ; Gib nullterminierten String aus ldi rmp,':' ; Separator für Zeit mov R0,rmp ldi ZH,HIGH(ramdt+3) ; Zeige auf Zeit ldi ZL,LOW(ramdt+3) rcall disp3 ; Gib die nächsten drei PBCD aus lds rmp,ramdt+5 ; Lese Sekunden com rmp ; Invertiere out PORTB,rmp ; und gib auf LEDs aus ret ; Fertig ; ; Text, nullterminiert, für Datum und Zeit auf LCD ; datet: .DB "Date: ",0x00,0x00 timet: .DB "Time: ",0x00,0x00 ; ; Gib die drei PBCD ab Z auf die LCD aus ; Separator (: oder .) in R0 ; disp3: ld rmp,Z+ ; Lese Zahl rcall Lcd4PBcd ; Gib Packed BCD aus mov rmp,R0 ; Gib Separator aus rcall Lcd4Chr ld rmp,Z+ ; Lese nächste Zahl rcall Lcd4PBcd mov rmp,R0 ; Gib Separator aus rcall Lcd4Chr ld rmp,Z ; Lese dritte Zahl rjmp Lcd4PBcd ; ; **************** Ende der Unterprogramme ********************* ; ; ******************** Hauptprogram **************************** ; ; Hauptprogramm beginnt hier ; Start: ldi rmp,HIGH(RAMEND) ; Initiate stack pointer out SPH,rmp ldi rmp,LOW(RAMEND) out SPL,rmp ldi rmp,0b00100000 ; Sleep Mode Idle out MCUCR,rmp ser rmp ; Port B auf Ausgang out DDRB,rmp rcall Lcd4Init ; Init LCD output rcall initdt ; Init date and time default rcall dispdate ; Default date/time to LCD clr rmp out TCNT1H,rmp ; High Byte TC1 clear out TCNT1L,rmp ; Low Byte TC1 clear ldi rmp,HIGH(cdivtc1) ; Compare Match, MSB first out OCR1AH,rmp ldi rmp,LOW(cdivtc1) ; Compare Match A, LSB last out OCR1AL,rmp ldi rmp,0b01000000 ; Toggle Output A on Comp Match out TCCR1A,rmp ldi rmp,0b00001010 ; Clear on Comp Match A, Div 8 out TCCR1B,rmp ; Start Timer ldi rmp,0b01000000 ; TC1 CompA Int Enable out TIMSK,rmp sei loop: sleep ; Schlafenlegen nop ; Aufwachen cpi rdiv1s,cdiv1s ; 67 erreicht? brcs loop ; not nicht clr rdiv1s ; Neustart, Sekunde zu Ende ldi rmp,0x06 ; Addiere Packed BCD Sekunden mov R0,rmp ; Konstante wird für Packed BCD benötigt clr R2 ; Startwert für Überlauf auf höherwertige Zahl ldi rmp,0x60 ; Überlaufwert für Sekunden ldi ZH,HIGH(ramdt+5) ; Auf SRAM-Adresse der Sekunden ldi ZL,LOW(ramdt+5) rcall inct ; inc seconds brcs tok ; Time is ok sbiw ZL,1 ; set pointer to minutes rcall inct ; inc minutes brcs tok ; time is ok ldi rmp,0x24 ; maximum value for hours sbiw ZL,1 ; Point to hours rcall inct ; inc hours brcs tok ; time is ok inc R2 ; Set Day/Month default to 1 ldi ZH,HIGH(ramdt+1) ; Point to month ldi ZL,LOW(ramdt+1) ld rmp,Z ; Read month cpi rmp,0x02 ; February? brne nonfeb ; Not February adiw ZL,1 ; Point to year ld rmp,Z ; Read year tst rmp ; Year=00? breq m28 ; February 2000 is 28 days only andi rmp,0x10 ; Tens of Years=odd? ld rmp,Z ; Read year again brne yodd ; Tens of years odd andi rmp,0x03 ; lower nibble year=0,4,8? brne m28 ; February has 28 days m29: ldi rmp,0x30 ; February has 29 days rjmp mok ; month is ok yodd: andi rmp,0x03 ; Tens of years are odd cpi rmp,0x02 ; Lower nibble year=2 or 6? breq m29 ; Yes, February has 29 days m28: ldi rmp,0x29 ; February has 28 days rjmp mok nonfeb: cpi rmp,0x07 ; Month > June? brcs monthok ; No, don't inc dec rmp ; back one month monthok: andi rmp,0x01 ; Odd month? brne m31 ; Month has 31 days ldi rmp,0x31 ; Month has 30 days rjmp mok m31: ldi rmp,0x32 ; Month has 31 days mok: ldi ZH,HIGH(ramdt) ; Point to day ldi ZL,LOW(ramdt) rcall inct ; add 1 day brcs dok ; Date is ok adiw ZL,1 ; Point to month ldi rmp,0x13 ; Max monthes rcall inct ; next month brcs dok ; Date is ok adiw ZL,1 ; Point to year clr R2 ; Default year=00 rcall inct ; Next year ; ; Refresh date on LCD ; dok: rcall dispdate ; Display date ; ; Refresh time on LCD ; tok: rcall disptime ; Display time rjmp loop ; ; Ende des Programmes ;