Pfad: Home =>
AVR-Overview =>
2-Line-LCD on STK500 => demo clock
; ***************************************************************
; * Clock with a 2-line-LCD for STK500 using Timer/Counter1 *
; * Connect the LCD over a 4-bit-data cable to the Port A *
; * Bit0=E, Bit1=RS, Bit4..7:D4..D7 *
; * Includes the LCD basic routines in Lcd4IncE.asm *
; * Adjusted to the board's clock of 3.685 MHz (STK500) *
; * (C)2002 by info!at!avr-asm-tutorial.net *
; * Created: 16.2.2002, Last change: 28.02.2002 *
; ***************************************************************
;
.NOLIST
.INCLUDE "C:\avrtools\appnotes\8515def.inc"
.LIST
;
; Timing-Scheme to create the 1-second-clock
;
;3.685.000Hz--> 460.625Hz --> 67 Hz --> 1 Hz
;
;+---------+ +----------+ +----------+ +--------+
;|CPU-Clock| |TC1-Divid.| |TC1-Compa-| |Register|
;|3,685 Mcs|-->|Prescaler |-->|re Match A|-->| rdiv1s |--> 1 s
;|7,37Mcs/2| |Divid. /8 | | /6875 | | /67 |
;+---------+ +----------+ +----------+ +--------+
;
; Constants
;
.EQU ftakt = 3685000 ; Frequency STK500 internal clock
.EQU cdivtc1 = 6875 ; Dibvider for TC1
.EQU cdiv1s = 67 ; Divider for 1 s
;
; Active Ports for LCD-Output
;
.EQU pLcdPort=PORTA ; LCD connected to PORT A
.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
; +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
; | Day | |Month| | Year| | Hour| |Minut| |Secnd|
; | Z E | | Z E | | Z E | | Z E | | Z E | | Z E |
; +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
.DSEG
.ORG $0060 ; Data segment begins at $0060
ramdt:
.BYTE 6 ; dd mm yy hh mm ss, reserve packed BCD
;
; Code starts here
;
.CSEG
.ORG $0000
;
; Reset- and Interrupt-Vectors
;
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 ; save status
inc rdiv1s ; Divider by 67, inc by one
out SREG,rint ; restore status register
reti
;
; ******** End of the Interrupt Service Routines *******
;
; ******** Some subroutines *********
;
; Include LCD-4-Bit-Routines
;
.NOLIST
.INCLUDE "Lcd4Inc.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 0x28,0x02,0x02,0x14,0x05,0x00 ; Packed date/time
;
; 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 ; Display null-terminated string
ldi rmp,'.' ; Separator for date
mov R0,rmp
ldi ZH,HIGH(ramdt) ; Point to date
ldi ZL,LOW(ramdt)
rcall disp3 ; Display three packed BCDs
;
; Display time on LCD
;
disptime:
ldi rmp,0x40 ; LCD Cursor to start of line 2
ldi ZH,HIGH(2*timet) ; Display Time-Text
ldi ZL,LOW(2*timet)
rcall Lcd4ZTxt ; Display null-terminated string
ldi rmp,':' ; Separator for time
mov R0,rmp
ldi ZH,HIGH(ramdt+3) ; Point to time
ldi ZL,LOW(ramdt+3)
rcall disp3 ; Display three packed BCDs
lds rmp,ramdt+5 ; Read seconds
com rmp ; Invert
out PORTB,rmp ; und display on the LEDs
ret ; Fertig
;
; Strings, null-terminated, for date and time on LCD
;
datet:
.DB "Date: ",0x00,0x00
timet:
.DB "Time: ",0x00,0x00
;
; Display three packed BCDs starting at Z on the LCD
; Separator (: or .) in R0
;
disp3:
ld rmp,Z+ ; Read packed BCD 1
rcall Lcd4PBcd ; Display packed BCD
mov rmp,R0 ; Display separator
rcall Lcd4Chr
ld rmp,Z+ ; Read next packed BCD
rcall Lcd4PBcd
mov rmp,R0 ; Display separator
rcall Lcd4Chr
ld rmp,Z ; Read third packed BCD
rjmp Lcd4PBcd
;
; **************** End of the subroutines ****************
;
; ***************** Main loop starts here ****************
;
; Main program starts here
;
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 to output, for the LEDs
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 ; sleep until int at clock
nop ; wake-up
cpi rdiv1s,cdiv1s ; 67 reached?
brcs loop ; not yet
clr rdiv1s ; New start, second has ended
ldi rmp,0x06 ; Add Packed BCD Seconds
mov R0,rmp ; Constant, needed for packed BCD
clr R2 ; Start value for overflow to upper digits
ldi rmp,0x60 ; overflow at 60 seconds
ldi ZH,HIGH(ramdt+5) ; point to SRAM-adress seconds
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
;
; End of the program
;
©2002 by http://www.avr-asm-tutorial.net