📄 serialio.asm
字号:
;Serial I/O routines using the 8051's built-in UART.;Almost all of these should use CIN and COUT, so they;could pretty easily be adapted to other devices which;could have similar single character I/O routines,;including the 8051's UART using interrupts and buffers;in memory.;Much of this code appears in PAULMON1... see the;PAULMON1.EQU file for an example of how to use some;of these routines. ;timer reload calculation ; baud_const = 256 - (crystal / (12 * 16 * baud)) .equ baud_const, 252 ;19200 baud w/ 15 MHz;.equ baud_const, 243 ;4800 baud w/ 12 MHz;---------------------------------------------------------;; ;; Subroutines for serial I/O ;; ;;---------------------------------------------------------;cin: jnb ri, cin clr ri mov a, sbuf retcout: jnb ti, cout clr ti mov sbuf, a retnewline:push acc mov a, #13 acall cout mov a, #10 acall cout pop acc ret ;get 2 digit hex number from serial port ; c = set if ESC pressed, clear otherwise ; psw.5 = set if return w/ no input, clear otherwiseghex:ghex8: clr psw.5ghex8c: acall cin ;get first digit acall upper cjne a, #27, ghex8fghex8d: setb c clr a retghex8f: cjne a, #13, ghex8h setb psw.5 clr c clr a retghex8h: mov r2, a acall asc2hex jc ghex8c xch a, r2 ;r2 will hold hex value of 1st digit acall coutghex8j: acall cin ;get second digit acall upper cjne a, #27, ghex8k sjmp ghex8dghex8k: cjne a, #13, ghex8m mov a, r2 clr c retghex8m: cjne a, #8, ghex8pghex8n: acall cout sjmp ghex8cghex8p: cjne a, #21, ghex8q sjmp ghex8nghex8q: mov r3, a acall asc2hex jc ghex8j xch a, r3 acall cout mov a, r2 swap a orl a, r3 clr c ret ;carry set if esc pressed ;psw.5 set if return pressed w/ no inputghex16: mov r2, #0 ;start out with 0 mov r3, #0 mov r4, #4 ;number of digits left clr psw.5ghex16c: acall cin acall upper cjne a, #27, ghex16d setb c ;handle esc key clr a mov dph, a mov dpl, a retghex16d:cjne a, #8, ghex16f sjmp ghex16kghex16f:cjne a, #127, ghex16g ;handle backspaceghex16k:cjne r4, #4, ghex16e ;have they entered anything yet? sjmp ghex16cghex16e:acall cout acall ghex16y inc r4 sjmp ghex16cghex16g:cjne a, #13, ghex16i ;return key mov dph, r3 mov dpl, r2 cjne r4, #4, ghex16h clr a mov dph, a mov dpl, a setb psw.5ghex16h:clr c retghex16i:mov r5, a ;keep copy of original keystroke acall asc2hex jc ghex16c xch a, r5 lcall cout mov a, r5 push acc acall ghex16x pop acc add a, r2 mov r2, a clr a addc a, r3 mov r3, a djnz r4, ghex16c clr c mov dpl, r2 mov dph, r3 retghex16x: ;multiply r3-r2 by 16 (shift left by 4) mov a, r3 swap a anl a, #11110000b mov r3, a mov a, r2 swap a anl a, #00001111b orl a, r3 mov r3, a mov a, r2 swap a anl a, #11110000b mov r2, a retghex16y: ;divide r3-r2 by 16 (shift right by 4) mov a, r2 swap a anl a, #00001111b mov r2, a mov a, r3 swap a anl a, #11110000b orl a, r2 mov r2, a mov a, r3 swap a anl a, #00001111b mov r3, a retasc2hex: ;carry set if invalid input clr c push b subb a,#'0' mov b,a subb a,#10 jc a2h1 mov a,b subb a,#7 mov b,aa2h1: mov a,b clr c anl a,#11110000b ;just in case jz a2h2 setb ca2h2: mov a,b pop b retphex:phex8: push acc swap a anl a, #15 add a, #246 jnc phex_b add a, #7phex_b: add a, #58 acall cout pop accphex1: push acc anl a, #15 add a, #246 jnc phex_c add a, #7phex_c: add a, #58 acall cout pop acc retPHEX16: PUSH ACC MOV A,DPH ACALL PHEX MOV A,DPL ACALL PHEX POP ACC RETPSTR: ;print string @DPTR PUSH ACCPSTR1: CLR A MOVC A,@A+DPTR JZ PSTR2 mov c, acc.7 anl a, #01111111b acall cout Jc pstr2 inc dptr SJMP PSTR1 PSTR2: POP ACC RET ;first we initialize all the registers we can, setting up;for serial communication.poweron: mov sp, #0x30 clr psw.3 ;set for register bank 0 (init needs it) clr psw.4 orl PCON,#10000000b ; set double baud rate MOV TMOD,#00010001b MOV SCON,#01010000b ; Set Serial for mode 1 & ; Enable reception ORL TCON,#01010010b ; Start timer 1 both timer mov a, #baud_const mov th1, a setb ti ;ti is normally set in this program clr ri ;ri is normally cleared ;jump to main program from here...pint8u: ;prints the unsigned 8 bit value in Acc in base 10 push b push acc sjmp pint8bpint8: ;prints the signed 8 bit value in Acc in base 10 push b push acc jnb acc.7, pint8b mov a, #'-' lcall cout pop acc push acc cpl a add a, #1pint8b: mov b, #100 div ab setb f0 jz pint8c clr f0 add a, #'0' lcall coutpint8c: mov a, b mov b, #10 div ab jnb f0, pint8d jz pint8epint8d: add a, #'0' lcall coutpint8e: mov a, b add a, #'0' lcall cout pop acc pop b ret ;print 16 bit unsigned integer in DPTR, using base 10.pint16u: ;warning, destroys r2, r3, r4, r5, psw.5 push acc mov a, r0 push acc clr psw.5 mov r2, dpl mov r3, dphpint16a:mov r4, #16 ;ten-thousands digit mov r5, #39 acall pint16x jz pint16b add a, #'0' lcall cout setb psw.5pint16b:mov r4, #232 ;thousands digit mov r5, #3 acall pint16x jnz pint16c jnb psw.5, pint16dpint16c:add a, #'0' lcall cout setb psw.5pint16d:mov r4, #100 ;hundreds digit mov r5, #0 acall pint16x jnz pint16e jnb psw.5, pint16fpint16e:add a, #'0' lcall cout setb psw.5pint16f:mov a, r2 ;tens digit mov r3, b mov b, #10 div ab jnz pint16g jnb psw.5, pint16hpint16g:add a, #'0' lcall coutpint16h:mov a, b ;and finally the ones digit mov b, r3 add a, #'0' lcall cout pop acc mov r0, a pop acc ret;ok, it's a cpu hog and a nasty way to divide, but this code;requires only 21 bytes! Divides r2-r3 by r4-r5 and leaves;quotient in r2-r3 and returns remainder in acc. If Intel;had made a proper divide, then this would be much easier.pint16x:mov r0, #0pint16y:inc r0 clr c mov a, r2 subb a, r4 mov r2, a mov a, r3 subb a, r5 mov r3, a jnc pint16y dec r0 mov a, r2 add a, r4 mov r2, a mov a, r3 addc a, r5 mov r3, a mov a, r0 retupper: ;converts the ascii code in Acc to uppercase, if it is lowercase push acc clr c subb a, #97 jc upper2 ;is it a lowercase character subb a, #26 jnc upper2 pop acc add a, #224 ;convert to uppercase retupper2: pop acc ;don't change anything retpbin: mov r0, #8pbin2: rlc a mov f0, c push acc mov a, #'0' addc a, #0 lcall cout pop acc mov c, f0 djnz r0, pbin2 rlc a retlenstr: mov r0, #0 ;returns length of a string in r0 push acclenstr1:clr a movc a,@a+dptr jz lenstr2 mov c,acc.7 inc r0 Jc lenstr2 inc dptr sjmp lenstr1 lenstr2:pop acc ret .equ str_buf, 0x20 ;16 byte buffer.equ max_str_len, 19getstr: ;get a string and store in an internal ram buffer ; str_buf = beginning of the buffer ; max_str_len = max number of char to receive ; (buffer must be one larger for null termination) mov r0, #str_bufgstrz: mov @r0, #0 ;fill buffer with zeros inc r0 cjne r0, #(str_buf+max_str_len+1), gstrz mov r0, #str_bufgstr_in:lcall cin lcall isascii jnc gstr_ctrl cjne r0, #(str_buf+max_str_len), gstradd sjmp gstr_ingstradd:lcall cout mov @r0, a inc r0 sjmp gstr_ingstr_ctrl: cjne a, #13, gstrc2 ;carriage return clr a mov @r0, a retgstrc2: cjne a, #8, gstrc3 ;backspacegstrbk: cjne r0, #str_buf, gstrbk2 sjmp gstr_ingstrbk2:mov a, #8 lcall cout mov a, #' ' lcall cout mov a, #8 lcall cout dec r0 sjmp gstr_ingstrc3: cjne a, #127, gstrc4 ;delete sjmp gstrbkgstrc4: sjmp gstr_in ;ignore all otherspstrbuf: ;print the string in the internal ram buffer mov r0, #str_bufpstrbuf2: mov a, @r0 jz pstrbuf3 lcall cout inc r0 sjmp pstrbuf2pstrbuf3: ret ;get unsigned integer input to accgint8u: mov r0, #0 ;r0 holds sum so far mov r1, #0 ;r1 counts number of charactersgi8_in: lcall cin mov r2, a ;r2 is temp holding space for input char clr c subb a, #'0' jc gi8_ctrl subb a, #10 jnc gi8_ctrl mov a, r0 mov b, #10 mul ab xch a, b jnz gi8_in mov a, r2 clr c subb a, #'0' add a, b jc gi8_in mov r0, a mov a, r2 lcall cout inc r1 sjmp gi8_ingi8_ctrl: mov a, r2 cjne a, #13, gi8c2 mov a, r0 retgi8c2: cjne a, #8, gi8c3gi8bk: cjne r1, #0, gi8bk2 sjmp gi8_ingi8bk2: mov a, #8 lcall cout mov a, #' ' lcall cout mov a, #8 lcall cout mov a, r0 mov b, #10 div ab mov r0, a sjmp gi8_ingi8c3: cjne a, #127, gi8c4 sjmp gi8bkgi8c4: sjmp gi8_inisascii: ;is acc an ascii char, c=1 if yes, c=0 if no push acc cjne a, #0x7F, isasc2 sjmp isasc_noisasc2: anl a, #10000000b jnz isasc_no pop acc push acc anl a, #11100000b jz isasc_no setb c pop acc retisasc_no: clr c pop acc ret
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -