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