11-串口通信的基本原理与应用

发布时间 2023-10-08 23:15:13作者: 夏日清凉~

串行通信概述

  • 微控制器与外部设备的数据通信,根据连线结构传送方式的不同,可以分为两种:并行通信串行通信

并行通信:指数据的各位同时发生或接收,每个数据位使用一条导线。

串行通信:指数据一位接一位地顺序发送或接收

  • 串行通信有SPI、IIC、UART等多种,最常见最通用的就是指UART,大多数情况下,串口通信指的就是UART

  • 串口通信的制式有:单工、半双工、全双工三种。

​ RS385总线式半双工的通信制式

串口通信的主要方式有两种:同步异步

同步串口通信:需要使用同一个时钟,以数据块为单元传送数据。

异步串口通信:每个设备都有自己的时钟信号,通信中双方的波特率要保持一致,以字符为单元进行数据帧传送,依次传送一个帧。

关于波特率计算

  • 波特率:串口每秒钟传输的位数
  • 在波特率的介绍之前需要先提到一个寄存器

SCON : 串行控制寄存器 (可位寻址)

SFR name Address bit B7 B6 B5 B4 B3 B2 B1 B0
SCON 98H name SM0/FE SM1 SM2 REN TB8 RB8 TI RI

SM0/FE:当PCON寄存器中的SMOD0/PCON.6位为1时,该位用于帧错误检测。当检测到一个无效停止位时,通过UART接收器设置该位。它必须由软件清零.当PCON寄存器中的SMOD0/PCON.6位为0时,该位和SM1一起指定串行通信的工作

方式,如下表所示。

其中SM0、SM1按下列组合确定串行口1的工作方式:

SM0 SM1 工作方式 功能说明 波特率
0 0 方式0 同步移位串行方式:移位寄存器 当UART_M0x6 = 0时,波特率是SYSclk/12,
当UART_M0x6 = 1时,波特率是SYSclk / 2
0 1 方式1 8位UART,波特率可变 串行口1用定时器1作为其波特率发生器且定时器1工作于模式0(16位自动重装载模式)或串行口用定时器2作为其波特率发生器时,
波特率=(定时器T1的溢出率和定时器T2的溢出率 )/4
注意:此时波特率与SMOD无关。
当串行口1用定时器1作为其波特率发生器且定时器1工作于模式2(8位自动重装模式)时,
波特率=( 2SMOD/32 )×(定时器1的溢出率)
1 0 方式2 9位UART ( 2SMOD / 64) x SYSclk系统工作时钟频率
1 1 方式3 9位UART,波特率可变 当串行口1用定时器1作为其波特率发生器且定时器1工作于模式0(16位自动重装载模式)或串行口用定时器2作为其波特率发生器时,
波特率=(定时器1的溢出率或定时器2的溢出率)/4
注意:此时波特率与SMOD无关 当串行口1用定时器1作为其波特率发生器且定时器1工作于模式2(8位自动重装模式)时 波特率=( 2SMOD/32 )×(定时器1的溢出率)
当定时器1工作于模式0(16位自动重装载模式)且AUXR.6/T1x12 = 0时,
		定时器1的溢出率 = SYSclk/12/( 65536 - [RL_TH1,RL_TL1]) ;
当定时器1工作于模式0(16位自动重装载模式)且AUXR.6/T1x12 = 1时,
		 定时器1的溢出率 = SYSclk / (65536 - [RL_TH1,RL_TL1]) 
当定时器1工作于模式2(8位自动重装模式)且T1x12 = 0时,
		定时器1的溢出率 = SYSclk/12/( 256 - TH1);
当定时器1工作于模式2(8位自动重装模式)且T1x12 = 1时,
		 定时器1的溢出率 = SYSclk / ( 256 - TH1) 
当AUXR.2/T2x12 = 0时, 定时器T2的溢出率 = SYSclk / 12/ ( 65536 - [RL_TH2,RL_TL2] );
当AUXR.2/T2x12 = 1时, 定时器T2的溢出率 = SYSclk / ( 65536 - [RL_TH2,RL_TL2] );

SM2:允许方式2或方式3多机通信控制位。

​ 在方式2或方式3时,如果SM2位为1且REN位为1,则接收机处于地址帧筛选状态。此时

​ 可以利用接收到的第9位(即RB8)来筛选地址帧:若RB8=1,说明该帧是地址帧,地址信

​ 息可以进入SBUF,并使RI为1,进而在中断服务程序中再进行地址号比较;若RB8=0,

​ 说明该帧不是地址帧,应丢掉且保持RI=0。在方式2或方式3中,如果SM2位为0且REN位

​ 为1,接收收机处于地址帧筛选被禁止状态。不论收到的RB8为0或1,均可使接收到的

​ 信息进入SBUF,并使RI=1,此时RB8通常为校验位.

​ 方式1和方式0是非多机通信方式,在这两种方式时,要设置SM2 应为0。

REN:允许/禁止串行接收控制位。由软件置位REN,即REN=1为允许串行接收状态,可启动

​ 串行接收器RxD,开始接收信息。软件复位REN,即REN=0,则禁止接收。

TB8: 在方式2或方式3,它为要发送的第9位数据,按需要由软件置位或清0。例如,可用作数

​ 据的校验位或多机通信中表示地址帧/数据帧的标志位。在方式0和方式1中,该位不用.

RB8: 在方式2或方式3,是接收到的第9位数据,作为奇偶校验位或地址帧/数据帧的标志位。

​ 方式0中不用RB8(置SM2=0). 方式1中也不用RB8(置SM2=0, RB8是接收到的停止位)。

TI: 发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,

​ 即TI=1,向主机请求中断,响应中断后TI必须用软件清零,即TI=0。在其他方式中,

​ 则在停止位开始发送时由内部硬件置位,即TI=1,响应中断后TI必须用软件清零。

RI: 接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI=1,

​ 向主机请求中断,响应中断后RI必须用软件清零,即RI=0。在其他方式中,串行接收

​ 到停止位的中间时刻由内部硬件置位,即RI=1,向CPU发中断申请,响应中断后RI必须

​ 由软件清零。

但是我们通常使用定时器1的工作模式2 (8位自动重装)来产生波特率,TL1作为脉冲计数寄存器,TH1作为自动重装寄存器,当计数到最大值溢出时,TH1会自动重装到TL1中

UART口的数据发送与接收

2. 串行口数据缓冲寄存器SBUF

STC15系列单片机的串行口1缓冲寄存器(SBUF)的地址是99H,实际是2个缓冲器,写SBUF

的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个

不同的寄存器,1个是只写寄存器,1个是只读寄存器。

串行通道内设有数据寄存器。在所有的串行通信方式中,在写入SBUF信号(MOV SBUF,A)

的控制下,把数据装入相同的9位移位寄存器,前面8位为数据字节,其最低位为移位寄存器的

输出位。根据不同的工作方式会自动将“1”或TB8的值装入移位寄存器的第9位,并进行发送.

串行通道的接收寄存器是一个输入移位寄存器。在方式0时它的字长为8位,其他方式时为

9位。当一帧接收完毕,移位寄存器中的数据字节装入串行数据缓冲器SBUF中,其第9位则装入

SCON寄存器中的RB8位。

如果由于SM2使得已接收到的数据无效时,RB8和SBUF中内容不变.由于接收通道内设有输入移位寄存器和SBUF缓冲器,从而能使一帧接收完将数据由移位

寄存器装入SBUF后,可立即开始接收下一帧信息,主机应在该帧接收结束前从SBUF缓冲器中

将数据取走,否则前一帧数据将丢失。SBUF以并行方式送往内部数据总线

也就是说串行口有两个缓冲寄存器都叫SBUF,一个是发送寄存器,一个是接收寄存器,这两个寄存器在物理结构上是独立的,但是他们的地址都是相同的
当是9位UART的时候,前八位是数据字节,后一位是移位寄存器的输出位,
在方式2或方式3时,如果SM2位为1且REN位为1,则接收机处于地址帧筛选状态。此时可以利用接收到的第9位(即RB8)来筛选地址帧
  • 这个重叠的地址靠读/写指令区分:

​ 串行发送时,CPU向SBUF写入数据,此时99H表示发送缓存SBUF

​ 串口接收时,CPU向SBUF读出数据,此时99H表示接收缓冲SBUF

  • 数据发送,把数据丢进SBUF后,内核会自动将数据发送出去,内容发生完成后,会将TI标志位置1

发送数据程序:SBUF= 数据/变量 如:SBUF= 0X58;

  • 数据接收:内核从串口接收到一个完整的数据后,会将RI标志位置1,用户用SBUF直接读取即可

接收数据程序:变量 = SBUF; 如:dat = SBUF

对于异步8位UART并且允许接收:SCON = 0X50;

对于IAP15F2K61S2单片机,你还要对辅助寄存器AUXR(0x8e) 进行设置

这边先了解下辅助寄存器AUXR:

3. 辅助寄存器AUXR

辅助寄存器AUXR的格式及各位含义如下:

AUXR : 辅助寄存器 (不可位寻址)

SFR name Address B7 B6 B5 B4 B3 B2 B1 B0
AUXR 8EH T0x12 T1x12 UART_M0x6 T2R T2_C/\(\overline{T}\) T2x12 EXTRAM S1ST2

T0x12: 定时器0速度控制位

​ 0, 定时器0是传统8051速度,12分频;

​ 1, 定时器0的速度是传统8051的12倍,不分频

T1x12: 定时器1速度控制位

​ 0, 定时器1是传统8051速度,12分频;

​ 1, 定时器1的速度是传统8051的12倍,不分频

如果UART1/串口1用T1作为波特率发生器,则由T1x12决定UART1/串口是12T还是1T

UART_M0x6: 串口模式0的通信速度设置位。

​ 0, 串口1模式0的速度是传统8051单片机串口的速度,12分频;

​ 1, 串口1模式0的速度是传统8051单片机串口速度的6倍,2分频

T2R: 定时器2允许控制位

​ 0, 不允许定时器2运行;

​ 1, 允许定时器2运行

T2_C/T: 控制定时器2用作定时器或计数器。

​ 0, 用作定时器(对内部系统时钟进行计数);

​ 1, 用作计数器(对引脚T2/P3.1的外部脉冲进行计数)

T2x12: 定时器2速度控制位

​ 0, 定时器2是传统8051速度,12分频;

​ 1, 定时器2的速度是传统8051的12倍,不分频

如果串口1或串口2用T2作为波特率发生器,则由T2x12决定串口1或串口2是12T还是1T.

EXTRAM: 内部/外部RAM存取控制位

​ 0, 允许使用逻辑上在片外、物理上在片内的扩展RAM;

​ 1, 禁止使用逻辑上在片外、物理上在片内的扩展RAM

S1ST2: 串口1(UART1)选择定时器2作波特率发生器的控制位

​ 0, 选择定时器1作为串口1(UART1)的波特率发生器;

​ 1, 选择定时器2作为串口1(UART1)的波特率发生器,此时定时器1得到释放,可以作为

独立定时器使用

串口1可以选择定时器1做波特率发生器,也可以选择定时器2作为波特率发生器。当设置AUXR寄存器中的S1ST2位(串行口波特率选择位)为1时,串行口1选择定时器2作为波特率发生器,此时定时器1可以释放出来作为定时器/计数器/时钟输出使用.对于STC15系列单片机,串口2只能使用定时器2作为波特率发生器,不能够选择其他定时器作为其波特率发生器;而串口1默认选择定时器2作为其波特率发生器,也可以选择定时器1作为其波特率发生器;串口3默认选择定时器2作为其波特率发生器,也可以选择定时器3作为其波特率发生器;串口4默认选择定时器2作为其波特率发生器,也可以选择定时器4作为其波特率发生器。

20231008160625

#include <REGX52.H>
sfr AUXR = 0x8E;

unsigned char urdat;

void _74HC138(unsigned char n) {
	switch(n) {
		case 4: P2=(P2&0x1f) | 0x80;
		break;
		case 5: P2=(P2&0x1f) | 0xa0;
		break;
		case 6: P2=(P2&0x1f) | 0xc0;
		break;
		case 7: P2=(P2&0x1f) | 0xe0;
		break;
	}
}

void SytemInit(void) {
	_74HC138(5);
	P0 = 0X00;
	_74HC138(4);
	P0 = 0xFF;

}

void UART_Init(void) {
	// 设置定时器1
	TMOD = 0x20;
	AUXR = 0x00;
	// 串口方式1,允许串行口接收控制位
	SCON = 0x50;
	// 9600  
	// 波特率=( 2^SMOD/32 )×(定时器1的溢出率)
	// 由于此时产生的是方式1的波特率,所以溢出率为
	// 溢出率: fosc/12 * (1/(2^8)-TH1);
	TH1 = 0xf9;
	TL1 = 0xf9;
	
	// 打开定时器1
	TR1 = 1;
	// 开启中断
	ES = 1;
	EA = 1;

}


void SendByte(unsigned char dat) {
	SBUF = dat;    // 将数据放到自动重装寄存器中
	while(TI == 0); //当TI 不等于1 的时候,就给TI清零 
		TI = 0;
}

void SendString(unsigned char *str) {
	while(*str != '\0') 
		SendByte(*str++); 
	

}



void main(void) {
	SytemInit();
	UART_Init();
	
	
	
	
	while(1);
	
}



void UART_Rountine (void) interrupt 4 {
	
	
	if(RI == 1) {
		// 接收内容
		urdat = SBUF;
		RI = 0;
		_74HC138(4);
		P0 = urdat;
		// 发送内容
		SendByte(urdat+1);
		
		
		
		
		
		
		
	}
	

}