; *************************************************************** ; * 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 http://www.avr-asm-tutorial.net * ; * Created: 16.2.2002, Last change: 2802.2002 * ; *************************************************************** ; .NOLIST .INCLUDE "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-Storage for Date and Time ; ; 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 "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 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 ;