(周振安)8031单片机内都包含有一个全双工串行通信接口。利用该口可以同时发送和接收数据,实现双机或多机通信。本讲将着重介绍8031串行口工作原理及单片机与单片机、单片机与IBM-PC系统机之间的通信实验。
8031单片机串行口简介
8031单片机片内RAM(见1990年12期《无线电》)中有一个串行数据缓冲器SBUF,地址为99H,它用来暂存要接收或发送的数据。它实际上对应着两个寄存器:发送寄存器和接收寄存器。发送寄存器只能写入而不能读出,接收寄存器只能读出而不能写入。所以通过读、写指令可以很方便地访问这两个地址相同的专用寄存器,而不致混乱。
1.串行口的控制寄存器SCON(片内RAM的98H单元)
利用指令写入特定的控制字可以实现对串行口工作方式的控制。SCON可以直接字节寻址,也可以直接位寻址,其各位定义如下:
7D 6D 5D 4D 3D 2D 1D 0D
SMO SM1 SM2 REN TB8 RB8 TI RI
SM0、SM1为串行口工作方式选择位,定义见下表:

其中,波特率是指串行口每秒所发送或接收数据的位数。SM2:当串行口工作于方式2或方式3时,此位有其特定含义;当工作于方式0或方式1时,此位置0。REN为允许接收位,当REN为1时,允许接收;当REN为0时,禁止接收。TB8是发送数据位8,当串行口工作于方式2或方式3时,该位是要发送数据的第9位。在许多通信协议中,该位定义为奇偶校验位,或作为所发送信息的特征位,用来表示是地址帧还是数据帧。 RB8为接收数据位8,当串行口工作于方式2或方式3时,与TB8有相似的意义。在方式1中,若SM2为0,则RB8是已接收的停止位。TI是发送中断标志。当一帧信息发送完毕,由硬件自动置1,申请中断。当CPU响应中断后,首先由指令清除TI,然后发送下一帧信息。RI是接收中断标志,当接收完一帧信息后,由硬件自动置1,申请中断,请求CPU取走数据,并用指令清除RI。
2.工作方式简介:
1)方式0:在方式0状态下,串行口用作同步移位寄存器,其波特率是固定的(fosc/12),即波特率为晶振频率的1/12。数据由RXD(0P3)端输入、输出,同步移位时钟由TXD(1P3)端输出,发送、接收的均是8位数据,且低位在先,高位在后。利用方式0可以很方便地将串行口变成并行口使用。
2)方式1:在方式1中,串行口为8位异步通信接口,每帧信息为10位,其中有一位为起始位(低电平0)、8位数据位(低位在先)、一位停止位(1)。TXD为发送端,RXD为接收端,波特率可变,它取决于定时器1的溢出速率。
方式1发送和接收过程见图1时序图所示。在发送过程中,见图1(a),CPU每执行一条写入SBUF指令(MOV SBUF,A)使启动串行口发送;当发送完一帧信息时,发送中断标志位TI自动置1。在接收过程中,见图1(b),当允许接收标志让REN置1后,接收器便以波特率的16倍速率不断采样RXD端电平;当采样到1至0跳变时(起始位到来)便启动接收器接收8位数据。当接收到第10位的停止位(1)后,将停止位送RB8,8位数据进入接收缓冲寄存器SBUF,同时置位中断标志RI。实际上,在接收每一位数据过程中,将每一位的接收时间等分成16个计数状态,并在第7、8、9三个计数状态时采样接收端RXD,即每一位数据被采样三次,至少两次采样值相同才被确认。

3)方式2和方式3:方式2和方式3发送或接收的每一帧信息均由11位组成,一个起站位(0)、8个数据位(低位在先),一个可定义位(即第9位数据位)和一个停止位(1)。二者区别在于,方式2中波特率不变,方式3中波特率可变。过两种方式的接收和发送过程与方式1的相似。
3.波特率的设定
方式0和方式2中,波特率都是固定不变的;方式1和方式3中,波特率可变,这时波特率由定时器1的溢出速率决定:
(SMOD)
波特率=(定时器1的溢出速率)/32/2
其中SMOD是专用寄存器PCON(87H)的第7位,在此用来使波特率加倍,SMOD位不能位寻址,但可用字节操作指令进行置1或清0操作。
当定时器1工作在自动装载方式(方式2)时,TL1作计数用,TH1内放自动装载的值(计数初值),则溢出速率为:溢出速率=\(\frac{fosc/12}{256-(TH1)}\)。例如,当晶振频率fosc=6MHz,定时器1工作在方式2(自动装载方式),若要求波特率为1200位/秒,则TH1中应装入的定时初值计算如下:
(SMOD)
(SMOD)
(TH1)= 256-\(\frac{fosc*2}{32*12*波特率}\)=256-13.02*2
当(SMOD)=0时,(TH1)=242.98≈243=F3H,当(SMOD)=1时,(TH1)=229.96≈230=E6H。SMOD的取值可以任选,以误差最小为宜。例如,本例中取(SMOD)=0。
8031之间的双机通信实验
1.实验硬件:
本实验利用TD-I型机和TDII型机进行相互通信。当两个机器相距在1米以内时,可按图2将它们之间的有关连线直接相连,以实现全双工通信。

2.软件编写要点:
约定TD-Ⅰ型机发送,TD-Ⅱ型机接收,晶振频率均为6MHz,波特率为1200位/秒,串行口均工作在方式1,定时器1工作在方式2,计数初值取(TH1)=F3H。
发送程序编写要点(详见程序1):
1)设置一个待发送数据的数据存储区,首地址为0150H,存储区块长为80H。
2)串行口及定时器1进行初始化。
3)设置地址指针:
(3FH)←40H;设置接收端数据存放地址4000H的
(3EH)←00H;地址指针3FH、3EH
(3DH)←01H;设置发送端数据存放地址0150H的
(3CH)←50H;地址指针3DH、3CH
(3BH)←80H;块长指针3BH
4)呼叫信号为FFH,应答信号为00H。当应答成功后,先发送数据存放地址和长度。
5)数据发送采用中断方式。
接收程序编写要点(详见程序2):
1)串行口及定时器1初始化。
2)应答成功后等待接收。
3)地址与数据的接收均采用查询方式。
4)接收完毕,显示“good”。
3.实验步骤:
1)将TD-Ⅰ型机与TD-Ⅱ型机按图2连接。
2)通电后,将发送程序输入到TD-Ⅰ型机,控收程序输入到TD-Ⅱ型机。仔细检查,确认无误。
3)运行时,先运行TD-Ⅱ的接收程序,后运行TD-Ⅰ的发送程序。若TD-Ⅱ显示“good”,则通信成功,否则停止运行,仔细检查程序机器码。
4)通信成功后,按TD-Ⅱ的MON键使之停机,检查以4000H为首地址的80H个单元内容,看是否与发送端数据相一致。
5)改变波特率(两机要一致),例如都改为110(或者4800),对应的TH1初值为72H(或者FDH),再运行。
8031单片机与IBM-PC系统机的通信实验
1.实验硬件:
单片机与PC机通信时,必须要加电平转换电路。最典型的电平转换电路有1488、1489集成电路。图3是TD-Ⅰ型机(TD-Ⅱ型机)与PC机通信的接口电路图。对于拥有TD-Ⅲ型机的读者,由于该机已接有1488、1489芯片,实验时可参考图3右半部分1488、1489与PC机连线方法。实验时请注意,1488芯片需按+12V、-12V电源,无论采用那种机型,都别忘记加上这组电源。

2.实验软件:
本实验用TD-Ⅲ型机作为发送机,IBM-PC机作为接收机,本实验的发送程序与前一实验中的发送程序稍有差别:待发送的数据首先须变换成ASCII码才能发送;每发送完一个数据后,再送一个回车符的ASCII码(ODH)。
接收程序用高级语言Turbo BASIC编写,它在完成以下功能:按一定格式打开串行口,设置串行口数据的长度;建立一个数据文件,将接收的数据装入该文件。
发送、接收程序清单见程序3、程序4。
3.实验步骤:
1)按图3连接线路,加上+5V电源(±12V先不要加)。
2)输入发送程序到TD-Ⅲ型机中。
3)用Turbo BASIC编译系统启动IBM-PC机,输入接收程序,并在A驱动器中插入数据软盘。
4)先运行发送程序,再运行接收程序。A驱动器指示灯亮表示正在往A盘中写入数据,指示灯熄灭后表示通信结束,用“AIt+X”键退回到操作系统。
5)检查数据文件:键入“TYPEA:Z”并回车,屏幕显示00~98共100个两位十进制数。这里需要补充说明的是,有了数据文件,可利用高级语言对它进行进一步处理,因此本实验很有实际意义。如果手头没有Turbo BASIC编译系统,可改用其它系统软件,接收程序中的一些语句要作相应修改。
夿
程序1:发送程序(I型机通过);
1: ORG 0000H
2:0000 020040; LJMP MAIN
3: ORG 0023H
4:0023 020100; LJMP TRINT
5: ORG 0040H
6:D040 00 ; MAIN:NOP
7:0041 900150; MOV DPTR,#0150H,
写数据块内容
8:0044 7A80; MOV R2,#80H
9:0046 7400; MOV A,#00H
10:0048 F0; LOOPO: MOVX @DPTR,A
11:0049 04; INC A
12:004A A3; INC DPTR
13:004B DAFB; DJNZ R2,LOOPo
14:004D 758920; MOV TMOD,#20H;
T1,初始化
15:0050 758DF3; MOV TH1,#OF3H
16:0053 758BF3; MOV TL1, #OF3H
17:0056 D2AF; SETB EA
18:0058 D28E; SETB TR1
19:005A C2AC ; CLR ES
20:005C 753F40; MOV 3FH,#40H;
接收端数据块地址→3FH、3EH
21:005F 753E00; MOV 3EH,#00H
22:0062 753D01; MOV 3DH,#01H;
发送端数据块地址→3DH、3CH
23:0065 753C50; MOV 3CH,#50H
24:0068 753B80; MOV 3BH,#80H
块长→3BH
25:006B 759850; MOV SCON,#50H;
串行口初始化
26:006E 7599BB;START: MOV SBUF,#OBBH;
发送呼叫信号(BBH)
27:0071 3099FD;WAIT1: JNB TI, WAIT1
28:0074 0299; CLR TI
29:0076 3098FD;WAIT2: JNB R1, WAIT2;
等待接收回答信号(00H)
30:0079 C298; CLR RI
31:007B E599; MOV A, SBUF
32:007D 70EF ; JNZ START;
若未接收到回答信号,则继续呼叫
33:007F 853F99; MOV SBUF 3FH;发送地址
34:0082 3099FD;WAIT3: JNB TI,WAIT 3
35:0085 C299; CLR TI
36:0087 853E99; MOV SBUF,3EH
37:008A 3099FD;WAIT4: JNB TI,WAIT4
38:008D C299; CLR TI
39:008F 853B99; MOV SBUF,3BH;发送块长
40:0092 D2AC; SETB ES
41:0094 80FE; LOOP: SJMP LOOP;开中断(数据发送用中断方式)
42: ORG 0100H
43:0100 C299; TRINT: CLR TI
44:0102 C083; PUSH DPH
45:0104 C082; PUSH DPL
46: 0106 COEO; PUSH ACC
47:0108 853D83; MOV DPH, 3DH;
取数据地址
48:010B 853C82; MOV DPL,3CH
49:010E EO; MOVX A,@DPTR;
取待发送数据
50:010F F599 ; MOV SBUF,A;发送
51:0111 153B; DEC 3BH
52:0113 AA3B; MOV R2,3BH
53:0115 BA0002; CJNE R2,#00H,TRIN1;
发送完毕?
54:0118 8004; SJMP STOP
55:01lA 053C; TRIN1: INC 3 CH;未完,继续下一
字节
56:0llC 8004; SJMP RETUNE
57:0l1E C2AC; STOP: CLR ES
58:0120 C28E; CLR TR1
59: 0122 DOEO; RETUNE: POP ACC
60:0124 D082; POP DPL
61:0126 D083; POP DPH
62:0128 32; RETI
63:END
程序2:接收程序(II型机上通过):
1: ORG 3A00H
200 023AA40; LJMP RECE
3: ORG 3A23H
4:3A23 023A80; LJMP REINT
5: ORG 3A40 H
6: 3A40 758920;RECE: MOV TMOD,#20H;
T1k串行口初始化
7:3A43 758DF3; MOV TH1,#OF3H
8:3A46 758BF3; MOV TL1,#OF3H
9:3A49 D28E; SETB TR1
10:3A4B D2AF; SETB EA
11:3A4D C2AC; CLR ES
12:3A4F 759850; MOV SCON,#50H
13:3A52 3098FD;WAIT1: JNB RI,WAIT1;
等待接收标志
14:3A55 C298; CLR RI
15:3A57 E599: MOV A,SBUF
16:3A59 64BB; XRL A,#0BBH;
是呼叫信号(BBH)
17:3A5B 70F5; JNZ WAIT1
18:3A5D 759900; MOV SNUF,#00H;
发应答信号(00H)
19:3A60 3099FD:WAIT2: JNB TI,WAIT2
20:3A63 C299; CLR TI
21:3A65 3098FD;WAIT3: JNB RI,WAIT3;
接收地址高八位→3FH
22:3A68 C298 ; CLR RI
23:3A6A E599 ; MOV A,SBUF
24:3A6C F53F; MOV 3FH,A
25:3A6E 3098FD;WAIT4: JNB RI,WAIT4;
接收地址低8位→3EH
26:3A71 C298; CLR RI
27:3A73 E599; MOV A,SBUF
28:3A75 F53E; MOV 3EH A
29:3A77 3098FD;WAIT5: JNB RI,WAIT5;
接收数据块长度→3BH
30:3A7A C298; CLR RI
31:3A7C E599; MOV A, SBUF
32:3A7E F53B; MOV 3BH,A
33:3A80 3098FD;REINT: JNB RI, REINT;接收数据
34:3A83 C298; CLR RI
35:3A85 E599; MOV A, SBUF
36:3A87 853F83; MOV DPH, 3FH;
取数据存放地址
37:3A8A 853E82; MOV DPL, 3EH
38:3A8D FO ; MOVX @DPTR
39:3A8E 053E; INC 3EH;修正地址
40:3A90 153B; DEC 3BH
41:3A92 AA3B; MOV R2,3BH
42:3A94 BA00E9; CJNE R2, #00H,REINT;
接数完毕?
43:3A97 90381E; MOV DPTR,#381EH;
显示9000
44:3A9A 7410 ; MOV A,#10H
45:3A9C F0; MOVX @DPTR,A
46:3A9D A3 ; INC DPTR
47:3A9E F0; MOVX @DPTR,A
48:3A9F 7413 ; MOV A,#13H
49:3AA1 A3; INC DPTR
50:3AA2 F0; MOVX @DPTR,A
5l:3AA3 7412; MOV A,#12H
52:3AA5 A3; INC DPTR
53:3AA6 F0; MOVX @DPTR,A
54:3AA7 A3; INC DPTR
55:3AA8 F0; MOVX @DPTR,A
56:3AA9 740D ; MOV A,#0DH
57:3AAB A3; INC DPDR
58:3AAC F0; MOVX @DPTR,A
59:3AAD123AB3;LEDI: LCALL DIS
60:3AB0 023AAD; LIMP LEDI
61:3AB3 22; DIS: RET
62 : END
程序3(TD-Ⅲ发送程序):
ORG A000H
A000 909000; MOV DPTR,#9000H;在以9000H为首地址的连续100个单元
A003 7400 ; MOV A,#00H
A005 7A64 ; MOV R2,#64h
内存入0~100数据的BCD码
A007 F0 ;DAT:MOVX @DPTR
A008 2401 ; ADD A,#01H
A00A D4 ; DA A
A00B A3 ; INC DPTR
A00C DAF9 ; DJNZ R2,DAT
A00E 758920; MOV TMOD,#20H
定时器1初始化
A011 758DF3: MOV TH1,#OF3H
A014 758BF3; MOV TL1,#OF3H
A017 C2AF ; CLR EA
A019 D28E ; SETB TRl;启动定时器1
A01B 909000; MOV DPTR,#9000H;
DPTR指向数据源地址
A01E 759850 ; MOV SCON,#50H;
串行口初始化
A021 3098FD;T1: JNB RI, T1;等待发送
A024 C298 ; CLR RI
A026 E0 ;T2: MOVX A,@DPTR ;取数据
A027 F5F0 ; MOV B,A
A029 54FO ; ANL A,#OFOH;先发送高半字节
A02B C4 ; SWAP A
A02C 2430 ; ADD A,#30H;变成ASCll码
A02E F599 ; MOV SBUF,A ;发送
A030 3099FD;T3: JNB T1,T3
A033 C299 ; CLR TI;等待发送结束
A035 E5FO ; MOV A B;取低半字节发送
A037 540F ; ANL A,#OFH
A039 2430 ; ADD A,#30H
A03B F599 ; MOV SBUF,A
A03D 3099FD; T4: JNB TI, T4
A040 C299 ; CLR TI
A042 740D ; MOV A,#ODH;发送回本符
A044 F599 ; MOV SBUF
A046 3099FD;T5: JNB TI,T5
A049 C299 ; CLR TI
A04B A3 ; INC DPTR;取下一字节数据
A04C A882 ; MOV RO, DPL
A04E B864D5; CJNE RO, #64H, T2;
判100字节发送完毕否?
A051 75790F; MOV 79H, #0FH;
发送结束,显示器最低
A064 75780F; MOV 78H, #OFH
A057 12045O; LCALL DIS;二位显示“FF”
A05A 80FE ;T6: SJMP T6
程序4 (IBM-PC接收程序):
10 open“coml:1200,n,8,1,rs,cs,ds,cd:lf as#1;打
开串行口,并初始化
20 ¥coml 4096;设置串行口数据缓冲区长度
30 open“a: z”for output as#2;在a盘打开一个名为
z的数据文件
40 print#1,n;通知对方发送
50 close#2
60 for i=1to 200
70 oped“a: z”for append as#2;将串行口接收到的数
据存到z文件中
80 input #1, a¥
85 a=val(a¥)
90 print#2, usins“####”; a;每个数据占4位
100 close# 2
110 next i
120 close #1;传送结束,关闭串行口
130 end