串行口通信

工作原理

pk42

波特率发生器由定时器1产生。

发送接收用的是一个寄存器

RXD 接外设的 TXD、TXD 接外设的RXD

TI 发送标志位 TI=1 发送完成 TI=0 允许发送(需要手动清0)

RI 接收标志位 RI=1 接收完成 RI=0 允许接收(需要手动清0)

串行口控制寄存器SCON

SCON D7 D6 D5 D4 D3 D2 D1 D0
98H SM0 SM1 SM2 REN TB8 RB8 TI RI

SM0、SM1:串行口工作方式选择位

SM0 SM1 方式 功能 波特率
0 0 0 移位寄存器方式 f/12
0 1 1 8位异步通信方式 可变
1 0 2 8位异步通信方式 f/32或f/64
1 1 3 9位异步通信方式 可变

SM2:多机通信控制位

REN : REN=1 允许接收 ; REN=0 禁止接收

TB8 : 发送数据第9位

RB8 : 接收数据第9位

TI : 发送中断标志位

RI : 接收中断标志位

电源控制寄存器PCON

PCON D7 D6 D5 D4 D3 D2 D1 D0
87H SMOD

当SMOD 为1时,波特率加倍

八位异步通信方式

RXD 接外设的 TXD、TXD 接外设的RXD

TXD:发送数据端 RXD:接收数据段

数据格式

1位起始位(0),SUBD 的8位数据位(低位在前高位在后)和一位停止位(1)

波特率计算

波特率(只能由T1产生,所以要回到定时计数器,且为8位可重载的方式产生)

波特率:2SMOD *(T1的溢出率)/ 32

T1的溢出率 = f / (12*(256-初值)) 256为八位的,所以是2^8=256.

T1的初值=256 - [f * 2SMOD / ( 12 * 波特率 *32 )]

12MHz = 12000000

有小数,误差很多 = 256 - [ 12000000 * 20 / 12 / ( 12 * 9600 * 32 )]

11.0592MHz = 11059200

是整数,所以保证通信不会出错 256 - [ 11059200 * 20 / 12 / ( 12 * 9600 * 32 )] = 3

(1)发送

条件:TI = 0

结果: 发送完毕,TI 置 1 TI 不会自动清0,需要手动清0

(2) 接收

条件:RI = 0 , REN(SCON.4) 置 1

结果: 8位的数据存入缓存器SBUF中,同时,RI 置 1 ,向CPU申请中断

串行口初始化编程

1.串行口控制寄存器SCON位的确定。

  • 根据工作方式确定SM0,SM1 位。
  • 方式2,3确定SM2位
  • 如果接收端,则允许接收 使得 REN=1
  • 方式2,3发送数据,则发送数据的第9位写入TB8中

2.设置波特率

波特率(只能由T1产生,所以要回到定时计数器,且为8位可重载的方式产生)

程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include"reg51.h"

unsigned char recdat=0,flag=0;

void initscon()
{
SCON=0x50; //串口通信:0101 0000 串行口控制寄存器SCON位的确定
TMOD=0x20; //串口通信:0010 0000 设置波特率,只能由T1产生,回到定时计数器,8位可重载的方式产生
TH1=256-3;
TL1=256-3;
ES=1; //中断:串行口中断的允许位
EA=1; //中断:开启总中断
TR1=1; //定时器:设置定时计数器1启动
}

void senddat()
{
SBUF=recdat; //发送接收的数据
while(!TI); //判断是否发送完成,完成TI置1
TI=0;
}

void main()
{
initscon();
while(1)
{
if(flag==1)
{
senddat();
flag=0;
}
}
}

void scon_isr() interrupt 4
{
recdat=SBUF;//读取数据
RI=0; //清0标志位,继续接收
flag=1; //表示接收完成
}