; clock2.asm ; Doug Ricket ; 28 June 2001 ; Adjustable clock RS equ p3.7 ; Pin 4 RW equ p3.6 ; Pin 5 EN equ p3.5 ; Pin 6 LCDATA equ p2 ; Pins 7-14 BUSY equ p2.7 ; Pin 14 pauseH equ 70h ; Memory locations for pause delays, high pauseM equ 71h ; medium, pauseL equ 72h ; and low timeTicks equ 73h ; 1/256th second timeSec equ 74h ; Memory locations for storing time timeMin equ 75h timeHour equ 76h newtime equ 0h ; BIT address org 0h ljmp main org 002Bh T2ISR: push acc inc timeTicks mov a, timeTicks jnz t2isr_done ; on overflow, increment seconds acall clock_inc setb newtime t2isr_done: pop acc clr TF2 clr EXF2 reti main: mov sp, #30h lcall serialinit lcall print db "Clock", 0ah, 0dh, 0h acall clock_init acall lcd_init acall lcd_clear acall lcd_goto_line2 acall lcd_print db "Time: ", 0h mainloop: acall update_time sjmp mainloop update_time: jnb newtime, update_time_done clr newtime acall lcd_get_cursor_pos ; save old position push acc ;mov a, #48h ;acall lcd_set_cursor_pos ; move to display region acall clock_print ; print pop acc acall lcd_set_cursor_pos ; restore cursor pos update_time_done: ret ; ************* TIME ************* clock_init: mov timeSec, #0h mov timeMin, #0h mov timeHour, #0h mov timeTicks, #0h ; 7200 (1c20) gives 1/256th second mov t2con, #00h mov RCAP2H, #0E3h ; 65536 - 7200 mov RCAP2L, #0E0h mov th2, #0E3h mov tl2, #0E0h setb TR2 ; start timer setb EA ; enable interrupts setb IE.5 ; ET2: enable timer 2 interrupt ret clock_inc: push acc mov a, #60 ; 60 seconds, minutes inc timeSec cjne a, timeSec, time_inc_done ; 60 seconds ; have to roll over to minutes: mov timeSec, #0h inc timeMin cjne a, timeMin, time_inc_done ; loop at 60 minutes mov timeMin, #0h inc timeHour mov a, #24 ; Wrap after 24 hours cjne a, timeHour, time_inc_done mov timeHour, #0h time_inc_done: pop acc ret clock_print: mov a, timeHour acall lcd_print_dec mov a, #':' acall lcd_print_chr mov a, timeMin acall lcd_print_dec mov a, #':' acall lcd_print_chr mov a, timeSec acall lcd_print_dec ret lcd_print_dec: ; prints a 2-digit # in ascii push acc push b mov b, #0Ah ; /div 10 div ab acall lcd_print_digit ; print 10s mov a, b acall lcd_print_digit ; print 1s (remainder) pop b pop acc ret lcd_print_digit: push acc add a, #30h ; convert to decimal acall lcd_print_chr pop acc ret ; ********* LCD High Level Commands ******** lcd_init: setb EN ; wait > 30 ms mov pauseH, #005h mov pauseM, #0E0h mov pauseL, #001h acall pause mov LCDATA, #38h ; 8-bit bus, 2 lines, 5x7 chars acall lcd_command_byte ; wait > 39 us mov pauseH, #05h mov pauseM, #01h mov pauseL, #50h acall pause mov LCDATA, #0Ch ; Display on, Cursor off. Blink off. acall lcd_command_byte ; wait > 39 us mov pauseH, #05h mov pauseM, #01h mov pauseL, #50h acall pause acall lcd_clear ; wait > 1.53 ms mov pauseH, #05h mov pauseM, #0Dh mov pauseL, #01h acall pause mov LCDATA, #06h ; Cursor auto-advance acall lcd_command_byte ret pause: ; #1c2000 ticks = 1 sec loop1: loop2: loop3: djnz pauseL, loop3 djnz pauseM, loop2 djnz pauseH, loop1 ret lcd_goto_line1: push acc mov a, #00h ; GOTO 0,0 acall lcd_set_cursor_pos pop acc ret lcd_goto_line2: push acc mov a, #40h ; GOTO 1,0 acall lcd_set_cursor_pos pop acc ret lcd_set_cursor_pos: push acc add a, #80h mov LCDATA, a acall lcd_command_byte pop acc lcall crlf ret lcd_clear: mov LCDATA, #01h ; Clear display acall lcd_command_byte ret lcd_print_chr: mov LCDATA, a lcall sndchr acall lcd_data_byte ret lcd_print_hex: push acc acall binasc ; convert acc to ascii acall lcd_print_chr ; print first ascii hex digit mov a, r2 ; get second ascii hex digit acall lcd_print_chr ; print it pop acc ret lcd_get_cursor_pos: acall lcd_read_status mov a, LCDATA anl a, #7Fh ; mask off the busy bit ret lcd_print: pop dph ; put return address in dptr pop dpl lcdprtstr: clr a ; set offset = 0 movc a, @a+dptr ; get chr from code memory cjne a, #0h, lcdmchrok ; if termination chr, then return sjmp lcdprtdone lcdmchrok: acall lcd_print_chr ; send character inc dptr ; point at next character sjmp lcdprtstr ; loop till end of string lcdprtdone: mov a, #1h ; point to instruction after string jmp @a+dptr ; return ; **************************** ; LCD Write Commands ; **************************** lcd_data_byte: setb RS ; RS high for data byte clr RW ; RW low for write mode mov pauseH, #01h mov pauseM, #01h mov pauseL, #20h acall pause clr EN nop setb EN nop acall lcd_wait_busy ret lcd_command_byte: clr RS ; RS low for command byte clr RW ; RW low for write mode clr EN mov pauseH, #01h mov pauseM, #01h mov pauseL, #70h acall pause nop setb EN acall lcd_wait_busy ret lcd_wait_busy: acall lcd_read_status lcd_wait_loop: jb BUSY, lcd_wait_loop ret lcd_read_status: clr RS ; read status setb RW ; read operation mov LCDATA, #0FFh ; prepare port for input clr EN nop setb EN nop ret ; *********************** PRINTING *********************** ;=============================================================== ; subroutine binasc ; binasc takes the contents of the accumulator and converts it ; into two ascii hex numbers. the result is returned in the ; accumulator and r2. ;=============================================================== binasc: mov r2, a ; save in r2 anl a, #0fh ; convert least sig digit. add a, #0f6h ; adjust it jnc noadj1 ; if a-f then readjust add a, #07h noadj1: add a, #3ah ; make ascii xch a, r2 ; put result in reg 2 swap a ; convert most sig digit anl a, #0fh ; look at least sig half of acc add a, #0f6h ; adjust it jnc noadj2 ; if a-f then re-adjust add a, #07h noadj2: add a, #3ah ; make ascii ret ; *************************************************************** ; ****** SERIAL COMMANDS ************ ; *************************************************************** serialinit: ; set up serial port with a 11.0592 MHz crystal, ; use timer 1 for 9600 baud serial communications (19200 for RD2) mov tmod, #20h ; set timer 1 for auto reload - mode 2 mov tcon, #41h ; run counter 1 and set edge trig ints mov th1, #0fdh ; set 9600 baud with xtal=11.059mhz mov scon, #50h ; set serial control reg for 8 bit data ; and mode 1 ret ;=============================================================== ; subroutine sndchr ; this routine takes the chr in the acc and sends it out the ; serial port. ;=============================================================== sndchr: clr scon.1 ; clear the tx buffer full flag. mov sbuf,a ; put chr in sbuf txloop: jnb scon.1, txloop ; wait till chr is sent ret ;=============================================================== ; subroutine print ; print takes the string immediately following the call and ; sends it out the serial port. the string must be terminated ; with a null. this routine will ret to the instruction ; immediately following the string. ;=============================================================== print: pop dph ; put return address in dptr pop dpl prtstr: clr a ; set offset = 0 movc a, @a+dptr ; get chr from code memory cjne a, #0h, mchrok ; if termination chr, then return sjmp prtdone mchrok: acall sndchr ; send character inc dptr ; point at next character sjmp prtstr ; loop till end of string prtdone: mov a, #1h ; point to instruction after string jmp @a+dptr ; return ;=============================================================== ; subroutine crlf ; crlf sends a carriage return line feed out the serial port ;=============================================================== crlf: push acc mov a, #0ah ; print lf acall sndchr pop acc cret: push acc mov a, #0dh ; print cr acall sndchr pop acc ret