★7.3.5 单片机与微机的串行通信
1 单片机与PC的串行多机通信
主从式通信系统:一主机+多从机;每个从机都被赋予唯一的地址。一般还要预留1~2个“广播地址”。主机与各从机之间能实现双向通信,而各从机之间不能直接通信,只能通过主机才能沟通。
图7-25 多机通信系统示意图(1)
(1)单片机与PC多机通信原理
串行接口控制寄存器SCON中的SM2为多机通信接口控制位,串行接口以方式2或3接收时,若SM2=1,表示置多机通信功能位,这时出现两种可能情况。多机通信系统示意图如图7-25所示。①接收到的第9位数据RB8为1时,数据才装入SBUF,并置位RI=1,向CPU发中断请求;②接收到的第9位数据RB8为0时,则不产生中断,信息抛弃。
各从机初始化:MOV SCON,#0B0H;或#0F0H
主机发送信息:其中第9位数据TB8作为区分地址/数据的标识。TB8=1表示地址,TB8=0表示数据。例如,主机发送地址帧信息02H,02H是从机2的地址。多机通信系统示意图如图7-26所示。
图7-26 多机通信系统示意图(2)
各从机响应中断,在中断程序中判断接收到的地址与本机是否相符,相符则SM2=0,不符则保持SM2=1不变。发送的数据帧,因RB8=0,只有SM2=0的从机可接收,进入中断处理。多机通信系统示意图如图7-27所示。
(2)多机通信关键
主机第1次发出的地址信息要能被所有的从机响应,而第2次的数据信息只能被n#从机所响应——多机通信控制位SM2对接收中断请求的管理功能。
图7-27 多机通信系统示意图(3)
例7-6:设一主机与多台从机进行通信,通信各方的晶振频率为11.0592MHz,波特率发生器采用定时器2实现。
解:假定各从机地址号分别为01、02、03,主机循环选定各从机进行通信。发送前,在P2口显示所呼叫的从机机号,主机发送的数据包格式为:从机以中断方式接收主机发送的首字节,然后在中断服务程序里用查询方式接收数据包的后续字节。收到完整数据包后,判别数据包里的从机机号与本机机号是否匹配,并校验和是否正确。若两条件均成立,则回送应答信息0xA0与本机机号之和,同时将本机机号送P2口显示,表示主机正在与该从机通信;若两条件不同时成立,则将0xFF送P2口显示,表示本机空闲。主机收到应答后,在P2口显示应答信息。
初始化:串行接口工作在方式3,允许接收,则SCON=0xF0。T2CON格式如下所示:
T2作为波特率发生器,则T2CON=00110100B=0x34。
可得T2计数初值:波特率为9600bit/s,则(RCAP2H,RCAP2L)为0FFDCH。
2 PC与单片机的点对点通信设计
(1)硬件接口电路
在功能比较复杂的控制系统和数据采集系统中,一般常用PC作为主机,单片机作为从机,如图7-28所示。单片机通过串行接口与PC的串行接口相连,将采集到的数据传送至PC,再在PC上进行数据处理。由于单片机的输入/输出是TTL电平,而PC配置的都是RS-232标准串行接口。由于两者的电平不匹配,必须将单片机输出的TTL电平转换为RS-232电平。
图7-28 PC与单片机的点对点通信
(2)PC与多个单片机的串行通信接口程序设计
在工控系统(尤其是多点现场工控系统)设计实践中,单片机与PC组合构成分布式测控系统是一个重要的发展方向。PC与单片机间的通信采用主从方式,PC为主机,单片机为从机,由PC确定与哪个单片机进行通信,如图7-29所示。
图7-29 PC与多个单片机的串行通信接口
例7-7:甲机键盘输入,波特率为1200bit/s,乙机LED数码管显示输出,接发双机数据分别完成双机串行通信。
解:(1)甲机程序(键盘输入、发送,接收乙机发来数据)
ORG 0000H
SJMP STAR
ORG 0030H
STAR:MOV SCON,#50H;设置串行接口方式1,允许接收
MOV TMOD,#20H;设计定时器1工作方式2
MOV PCON,#0H;波特率不加倍
MOV TH1,#0E6H;12MHz晶振频率,波特率1200bit/s
MOV TL1,#0E6H
SETB TR1;启动定时器1
CLR ES;禁止串行接口中断
MOV SP,#5FH;设置堆栈指针
MOV P2,#0H;数码管显示“8”,P1.0~P1.3为列,P1.4~P1.7为行
KEYS:MOV R0,#4;键盘扫描和数码管显示子程序
MOV R1,#11101111B;行扫描,从0行开始扫描
MOV R2,#11111111B;(R2)=0FFH,假设未按键
SNEXT:MOV A,R1;送出行扫描码
MOV P1,A
MOV A,P1;读键状态
ORL A,#0F0H
CJNE A,#0FFH,KEYIN;判断是否按键
MOV A,R1;未按键盘继续扫描下一行
RL A;修改行扫描数
MOV R1,A;保存行键扫描数
DJNZ R0,SNEXT;4行未扫描完,循环
LJMP KEYS;循环查键
KEYIN:MOV R2,A;键盘状态保存在R2
ACALL DLY;除按键抖动并等待按键弹起
NOPEN:MOV A,P1;读入键盘状态
ORL A,#0F0H
CJNE A,#0FFH,NOPEN;键未弹起,转NOPEN等待弹起
LCALL DLY;延时消键弹起抖动
LCALL KEYV;将扫描码转成按键码
MOV SBUF,A;发送
JNB TI,$;等待一帧发送完毕
CLR TI;清发送中断标志
CLR RI;清接收中断标志
ACALL DLY;调用延时
MOV A,SBUF;接收乙机的数据
JNB RI,$;等待接收完一帧数据
CLR RI ;清接收中断标志
LCALL SEG7;乙机的数据转成显示码
CPL A;取反为共阳段码
MOV P2,A;显示按键值
LJMP KEYS;重新扫描按键
DLY:MOV R7,#30;延时15ms(12MHz晶振频率时)
MOV R6,#0
S1:DJNZ R6,$
DJNZ R7,S1
RET;延时子程序返回,求键值子程序KEYV,P1.0~P1.3为列,P1.4~P1.7为行
KEYV:MOV B,#0;(B)=按键码,预设为0
MOV A,R2;判断目前是哪一列?
C1:RRC A
JNC C2;按键在当前列,转C2
INC B;按键不在本列,(B)+4,因为每一列按键码相差4
INC B
INC B
INC B
LJMP C1;返回继续判断按键在哪一列
C2:MOV A,R1;(A)=(R1),行扫描码
RR A;右移4位,将高4位移到低4位,以便后续的判断
RR A
RR A
RR A
C3:RRC A;判断哪一行被按下
JNC C4;在当前行,转C4
INC B;非当前行,键值+1(每一行每个按键差1)
LJMP C3
C4:MOV A,B;(A)=(B)按键码给A
RET;键值判断子程序返回
SEG7:INC A;将键值转换为共阴显示码
MOVC A,@A+PC
RET
DB 03FH,06H,5BH,4FH,66H,6DH,7DH,07H;共阴数码管显示0~7
DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H,03FH;共阴数码管显示8~F,0
END;程序结束
(2)乙机程序(接收由甲机发来的数据并显示在数码管上,加1后再发送到甲机)
ORG 0000H
SJMP STAR
ORG 0023H
LJMP LOOP;通信中断服务程序入口
ORG 30H
STAR:MOV R7,#50H
MOV SP,#5FH;设置堆栈指针
MOV P2,#0H;开始,显示“8”
MOV SCON,#50H;设置串行接口方式,REN=1允许接收
MOV TMOD,#20H;定时器1方式2
MOV PCON,#0H;波特率不加倍
MOV TL1,#0E6H;晶振频率12MHz时的初装值
MOV TH1,#0E6H
SETB TR1;启动定时器1
SETB EA;中断总允许
SETB ES;开串行中断
SJMP $
LOOP:LCALL S_R
LCALL S_T
RETI
S_T:CLR TI;清发送中断标志
MOV SBUF,10H
JNB TI,$
CLR TI
RET
S_R:MOV A,SBUF;接收数据
JNB RI,$;等待接收完一帧数据
CLR RI;清接收中断标志
MOV 10H,A
INC 10H;将接收到的数据加1后再回发到甲机
ACALL SEG7;调显示子程序
CPL A
MOV P2,A
RET
SEG7:INC A
MOVC A,@A+PC
RET
DB 03FH,06H,5BH,4FH,66H,6DH,7DH,07H;共阴数码管显示0~7
DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H;共阴数码管显示8~F
END;程序结束