; io.asm ; Doug Ricket ; 31 July 2001 ; Tests serial input output: ; IN: bytes received are displayed on the LCD ; OUT: key presses are sent out 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 org 0h ljmp main main: mov sp, #30h lcall serialinit acall lcd_init acall lcd_clear acall lcd_print db "IO Test Mode", 0h mainloop: acall checkinput acall sendoutput sjmp mainloop checkinput: jnb ri, checkinputdone acall getchr acall lcd_print_chr acall lcd_get_cursor_pos cjne a, #10h, notend1 ; wrap at ends mov a, #40h acall lcd_set_cursor_pos ret notend1: cjne a, #50h, notend2 mov a, #00h acall lcd_set_cursor_pos ret notend2: checkinputdone: ret sendoutput: acall check_key ; Did we get a key? jz sendoutputdone acall key_to_ascii ; # --> asci acall sndchr ; out the serial port sendoutputdone: ret ; KEYPAY PIN DEFINITIONS keyport equ p1 col1 equ p1.7 col2 equ p1.6 col3 equ p1.5 col4 equ p1.4 row1 equ p1.3 row2 equ p1.2 row3 equ p1.1 row4 equ p1.0 ; ************************* ; Function: check_key ; ; Checks for a key from a 4x4 matrix keypad ; Turns off each row, tests to see if any columns go off ; If so, a key is found, and the key number 1-16 is stored in A ; Otherwise, 0 is stored in A ; ************************* check_key: mov keyport, #0FFh ; ready for input clr row1 ; Row 1 mov a, #01h jnb col1, keyfound ; If col1 went low, then it connects to row1 mov a, #02h jnb col2, keyfound mov a, #03h jnb col3, keyfound mov a, #04h jnb col4, keyfound setb row1 clr row2 ; Row 2 mov a, #05h jnb col1, keyfound mov a, #06h jnb col2, keyfound mov a, #07h jnb col3, keyfound mov a, #08h jnb col4, keyfound setb row2 clr row3 ; Row 3 mov a, #09h jnb col1, keyfound mov a, #0Ah jnb col2, keyfound mov a, #0Bh jnb col3, keyfound mov a, #0Ch jnb col4, keyfound setb row3 clr row4 ; Row 4 mov a, #0Dh jnb col1, keyfound mov a, #0Eh jnb col2, keyfound mov a, #0Fh jnb col3, keyfound mov a, #10h jnb col4, keyfound setb row4 keynotfound: mov a, #00h ; zero = no key pressed ret keyfound: ; a holds 1-16 ret ; ************************ ; Function: key_to_ascii ; ; Takes a key index 1-16 in A ; Returns the ascii code corresponding to that key in A ; ************************ key_to_ascii: ; Convert key code to ascii char movc a, @a+pc ; Lookup from the following table ret db '1', '2', '3', 'A' db '4', '5', '6', 'B' db '7', '8', '9', 'C' db '*', '0', '#', 'D' ; ************************* ; wait_for_key_done ; ; Loops until no key is pressed ; ************************* wait_for_key_done: push acc ; don't disturb the value in A wait_for_key_done_loop: acall check_key jnz wait_for_key_done_loop pop acc ret ; ******************** ; get_key ; ; Waits for a key to be pressed, ; Gets the key into A, ; Waits for the key to be released ; ******************** get_key: acall check_key jz get_key ; key == 0 means no key, so try again acall wait_for_key_done ret ; ************** ; get_char ; ; Waits for key press and release ; Returns ascii character for key ; ************** get_char: acall get_key acall key_to_ascii 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 prthex ; this routine takes the contents of the acc and prints it out ; as a 2 digit ascii hex number. ;=============================================================== prthex: push acc acall binasc ; convert acc to ascii acall sndchr ; print first ascii hex digit mov a, r2 ; get second ascii hex digit acall sndchr ; print it pop acc ret ;=============================================================== ; 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 getchr ; this routine reads in a chr from the serial port and saves it ; in the accumulator. ;=============================================================== getchr: jnb ri, getchr ; wait till character received mov a, sbuf ; get character anl a, #7fh ; mask off 8th bit clr ri ; clear serial status bit ret getchrx: ; extended -- includes 8th bit jnb ri, getchr ; wait till character received mov a, sbuf ; get character ;*** anl a, #7fh ; mask off 8th bit clr ri ; clear serial status bit 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