Pfad:
Home =>
AVR-Übersicht =>
4-Bit-LCD am STK500 => Quellcode Uhr
(This page in English:
)
; ***************************************************************
; * 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!at!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
;
©2002 by http://www.avr-asm-tutorial.net