串行式传输每次传输一个位,数据传输的速度表面上不怎么快,但连接两个系统之间,只要两条传输线即可,适合长距离的通信。实际上,目前串行端口传输速率已比并行端口输出传输速率快。
实际中考虑使用并行式传输还是串行式传输要根据数据量与环境而定。若要将8051系统的数据传至另一8051系统,则可以使用串行式数据传输。
最典型的串行式数据传输接口是RS232C,例如个人计算机的COM1、COM2接口就是属于RS232接口。
在串行式数据传输里有单工及双工之分:
类型 | 说明 |
---|---|
单工 | 一条线只能有一种用途,例如输出线就只能将数据传出,输入线就只能将数据传入。 |
双工 | 一条线有两种用途,可传入数据么也可传出数据。 |
若系统上只有一条线,且在同一时刻中不是进行传入数据就传出数据,则称之为“半双工”。
若在系统上有两条传输线,这两条传输线可同时进行数据输入与传出,则称之为“全双工”。
通常以每秒传输多少位(bit per second,简称bit/s)表示串行式数据传输的速率,又称为比特率(baud rate)。
通常,微控制器里的数据处理属于并行式处理。对8051而言,一次处理一个字节,也就是8个位,不管怎样,串行式数据与并行式数据之间的转换是无法避免的。
在8051里,若要把8位的并行数据传出去,只要把数据放入并行寄存器(SBUF)即可,8051就会帮我们把这些数据一个位一个位送出去。
接收串行数据也是一样,8051会把外面传入的数据,一个位一个位放入SBUF,当SBUF存满后,产生中断,即为并行数据,再将SBUF里的8位数据移做他用。
不论是接收还是发送,很明显SBUF扮演了关键性的角色,在8051中接收用的SBUF与传送用的SBUF虽然都叫做SBUF,但是它们分别是两个不同的8位寄存器。
8051提供一个全双工的万用异步串行端口(Universal Asynchronous Receiver-Transmitter,简称UART),这个串行端口有4种工作模式(mode),使用不同工作模式其比特率各有不同,说明如下:
mode 0:
mode0工作模式是一固定比特率的位移式数据传输,其比特率为8051系统时钟脉冲的1/12,即OSC/12。若在时钟脉冲为12MHz,则其比特率为1M bit/s。
在此模式下,不管是接收还是发送,CPU的RxD引脚(P3.0)连接串行数据线,TxD引脚(P3.1)连接位移脉冲线。执行数据接收时,由TxD引脚送出位移脉冲,而由RxD引脚收下串行数据,如下图:
执行数据传送时,也是依据TxD引脚所送出的位移脉冲,由RxD引脚发送串行数据:
mode 1:
mode 1工作模式是以可变的比特率进行串行数据的传输,其比特率可由Timer 1来控制(若是8052还可以使用Timer 2控制比特率)。在此模式下,8051的RxD引脚连接数据源的TxD引脚,8051的TxD引脚连接目的地的RxD引脚。
在mode 1下,每个数据是由10位组成,包括起始位(start bit)、8个位的数据以及停止位(stop bit),其中第一个位就是低电平的起始位,紧接着是8位数据的bit0(LSB),bit7(MSB)之后是高电平的停止位,如下图:
mode 2:
mode 2工作模式是以OSC/32或OSC/64的比特率进行串行数据的传输,而其线路的连接,也是8051的RxD引脚连接数据源的TxD引脚,8051的TxD引脚连接目的地的RxD引脚。在mode 2下,每笔数据是由11位组成,包括起始位(start bit)、8个位的数据、奇偶位(parity bit)以及停止位(stop bit),其中第一个位就是低电平的起始位,紧接着是8位数据的bit0(即LSB),而bit7之后的是奇偶位,最后则是高电平的停止位:
当进行数据传出时,第9个位TB8(即SCON寄存器的TB8)为奇偶位,可取自程序状态字组寄存器PSW中的P位,以达到奇偶校验的目的。当收到数据时,第9个位将直接移入SCON寄存器中RB8,而不必管停止位。
mode3:
mode3工作模式是以可变的比特率进行串行数据的传输,其比特率可由Timer 1来控制(若是8052则还可使用Timer 2控制比特率)。除此之外,mode 3与 mode 2几乎完全一样。
SBUF是8位的寄存器,只用于8051的串行通信。通过TxD导线传输的字节数据,必须存放在SBUF寄存器中。同样,SBUF保存了8051的RxD引脚接收到的数据,SBUF与其他8051的寄存器一样可以被访问。
SCON寄存器是8位的寄存器,用于编程起始位、停止位、数据帧的数据位或其他内容。以下描述了SCON寄存器的不同位。
SM2是SCON寄存器的D5位,该位使得8051具有多重处理能力,这已超出了本章的讨论范围。应用中,我们使SM2=0,因为无需使用多重处理能力的8051。
本位为多重处理器通信启用位:
mode 0时,Sm2=0;
mode 1时,若SM2=1,且收到有效的停止位,则RI=1(产生RI中断),否则RI=0;
mode 2或 mode 3时,若Sm2=1,且收到的第9位为1,则RI=1(产生RI中断),若第9位为1,则RI=0
REN(接收使能)位是SCON寄存器的D4位。
REN位也称为SCON.4,因为SCON是位可寻址寄存器。当REN位置高时,允许8051接收RxD引脚上的数据。所以,若想让8051既发送数据又传输数据,REN就必须设置为1.REN=0,表示接收器禁止接收。
REN=1或REN=0分别由指令“SETBSCON.4”和指令“CLRSCON.4”实现。注意,这些指令使用了寄存器SCON的位可寻址特性。该位能屏蔽任何串行数据的接收块,是SCON寄存器中很重要的位。
本位为串行接收启用位,说明:
REN=1,开始接收;
REN=0,停止接收;
RB8(接收位8)是SCON寄存器的D2位。
串行模式1中,当接收到8位数据后,该位就得到停止位的复制。该位(与TB8的情况一样)几乎不再使用。在几乎所有的应用中,RB8=0。与TB8一样,RB8也用于串行模式2和模式3。
mode 2或mode 3传送数据时,本位为第9传输位,可用软件来设定或清除。
mode 2或mode 3接收数据时,本位为第9个接收位;
mode 1时,若SM2=0,则本位为停止位;
mode 0时,本位无作用。
TI(发送中断)是SCON寄存器的D1位,它是SCON寄存器中非常重要的位。
当8051完成8位字符发送后,TI标志被置位,表示已经准备好传送另一个字节,TI位在停止位开始置位。这将在给出数据传输程序时详细讨论该位。
本位为中断标识位,当中断结束时,本位并不会恢复为0,必须由软件清除。
mode 1、mode 2或mode 3时,若完成传送停止位,则本位自动设定为1,并产生TI中断。
mode 0时,若完成传送第8位,则本位自动设定为1,并产生TI中断。
RI(接收中断)是SCON寄存器的D0位,它是SCON寄存器中另一个非常重要的标志位。
当8051通过RxD接收到数据后,它就将起始位和停止位去掉得到字节,并将字节放入SBUF寄存器中,然后置位RI标志表示字节已接收,应该在丢失之前拿出。RI是在停止位中间置位,随后分析它在串行数据接收程序中的应用。
本位为接收中断标志位,当中断结束时,本位并不会恢复为0,必须由软件置0。
mode 1、mode2或mode 3时,若完成接收到停止位,则本位自动设定为1,并产生RI中断。
mode 0时,若完成接收第8位,则本位自动设定为1,并产生RI中断。
8051串行口的比特率设定方式有如下几种:
一、在mode 0下,比特率固定为OSC/12,不需要进行设定!完全是依照系统的时钟脉冲而定,不是软件所能改变的。
二、在mode 2下,其比特率可为OSC/32或OSC/64,
其中SMOD为PCON寄存器中的bit 7:
若将SMOD设定为0,则设定采用的比特率OSC/64;
若将SMOD设定为1,则设定采用的比特率OSC/32。
其重点在于配置TMOD寄存器和SCON寄存器,在改为c语言的重点同样如此
TOMD寄存器配置为0010 0000,为使用定时器1,模式2
配置TH1来调整波特率
配置SCOM为0101 0000,SM0=0,SM1=1,串行模式1,8位数据,1位停止位,1位起始位。
运行Rx接收数据。
之后运行不断将A放入SBUF寄存器
C语言的代码如下:
#include
void main(void)
{
TMOD=0x20;
TH1=0xFD;
SCON=0x50; //重点在配置这仨寄存器
TR1=1;
while(1)
{
SBUF='A';
while(TI==0);
TI=0;
}
}
分别设置a,b机的代码:
#include
sbit key=P1^6;
void init(); //初始化函数
void init()
{
TMOD=0x20;//定时器1,8位自动重载
TH1=0xfd;//波特率9600
SCON=0x50;
TR1=1; //定时器开启
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
//_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void printname()
{
unsigned char j=0;
unsigned char name[]="yujiang_2138010006";
for(j=0;j<24;j++)
{
SBUF=name[j];
while(TI==0);
TI=0;
}
}
void main()
{
unsigned char i=0;
init();
printname();
P2=0;
key=1;
while(1)
{
if(key==0)
{break;}
}
while(1)
{
while(key==0);
P2=i;
SBUF=i++;
while(!TI);
TI=0;
Delay500ms();
}
}
#include
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
//_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void init();
void init()
{
TMOD=0x20; //定时器1 模式2
TH1=0xfd; //9600波特率
SCON=0x50;//串行模式1,8位数据,1位停止位
TR1=1; //开启定时器
}
void main()
{
init();
while(1)
{
if(RI==1)
{
while(RI==0);
P2=~SBUF;
Delay500ms();
RI=0;
}
}
}