【蓝桥杯】串口通信详解附双串口代码

目录


IAP15F2K61S2单片机拥有两个全双工串口通信接口(串口1和串口2)

1、串口相关寄存器

【蓝桥杯】串口通信详解附双串口代码
每个串口都有2个数据缓冲器、一个移位寄存器、一个串行控制器和一个波特率发生器

1.1数据缓冲器SBUF

这是两个物理上独立的接收、发送缓冲器,可同时发送、接收数据。
发送缓冲器只写不能读,接收缓冲器只读不能写。因此两个缓冲器共用一个地址码
从STC15F2K60S2这个头文件的190行和192行可以看出串行口1SBUF地址是99H,串行口2S2UBF地址是9BH。

1.2串行口(工作方式)控制寄存器SCON

【蓝桥杯】串口通信详解附双串口代码
IAP15F2K61S2 单片机的串行口有 4 种工作方式。
(1)SM0、SM1控制工作方式
【蓝桥杯】串口通信详解附双串口代码
方式0:同步串行通信
方式1:异步串行通信8位,串行口1波特率取决于定时器T1,串行口1波特率取决于定时器T2,波特率都可变
方式2:异步串行通信9位(多一个奇偶检验位、或地址帧/数据帧标识位),波特率取决于内部晶振,波特率不可变
方式3:异步串行通信9位(多一个奇偶检验位、或地址帧/数据帧标识位),串行口1波特率取决于定时器T1,串行口1波特率取决于定时器T2,波特率可变
(2)SM2多机通信控制位,用来控制是否激活RI
①当串口以方式2或方式3接收时:
如果SM2 = 1,则只有当接收到的第9位数据(RB8)为“1”时,才使RI置“1”,产生中断请求,并将接收到的前8位数据送入SBUF。当接收到的第9位数据(RB8)为“0”时,不使RI置“1”,并将接收到的前8位数据丢弃。
当SM2 = 0时,则不论第9位数据是“1”还是“0”,都将前8位数据送入SBUF中,并使RI置“1”,产生中断请求。
②方式0、方式1时,SM2 = 0。
(3)TB8—发送的第9位数据
在多机通信中用来表示主机发送的是地址帧还是数据帧,TB8=1为地址帧,TB8=0为数据帧。
双机串行通信时,为奇偶校验位。
(4)RB8—接收的第9位数据
方式0,不使用RB8。
方式1中,RB8是接收到的停止位。
方式2和方式3,RB8存放接收到的第9位数据。作为地址帧/数据帧标识位、或奇偶校验位。
(5)REN—允许串行接收位。
由软件置“1”或清“0”。
REN=1,允许串行口接收数据。
REN=0,禁止串行口接收数据。
(6)TI—发送中断标志位
TI =1,表示一帧数据发送结束。TI状态可供软件查询,也可申请中断。CPU响应中断后,在中断服务程序中向SBUF写入要发送的下一帧数据。
方式0,串行发送的第8位数据结束时TI由硬件置“1”,
在其他方式中,串行口发送停止位的开始时置TI 为“1”。
TI必须由软件清“0”
(7)RI—接收中断标志位
RI=1,表示一帧数据接收完毕,并申请中断,要求CPU从接收SBUF取走数据。该位的状态也可供软件查询。
方式0时,接收完第8位数据时,RI由硬件置“1”。
在其他工作方式中,串行接收到停止位时,该位置“1”。

RI必须由软件清“0”。

1.3特殊功能寄存器PCON

【蓝桥杯】串口通信详解附双串口代码
PCON中仅最高位SMOD与串口有关:SMOD:波特率倍增位。
方式0时(同步),此位未采用,即波特率的速度不受SMOD影响。
方式1、2、3时,SMOD=1时的波特率比SMOD=0时的波特率速度提高一倍。所以称SMOD位为波特率倍增位。

2、波特率

异步通信没有时钟线的约束,通信双方都有自己的通信频率(波特率),且双方的波特率要相同。
波特率的设置 (fosc:frequency oscillate晶振频率)

方式0的波特率 = fosc/12

方式2的波特率 =(2SMOD/64*fosc

方式1的波特率 =(2SMOD/32)*(T溢出率)

方式3的波特率 =(2SMOD/32)*(T溢出率)
一般我们使用定时器作为波特率的发生器,进行串口通信,如果两个串口同时使用,那么我们需要准备两个波特率发生器
串行口1使用定时器1作为波特率发生器
串行口2使用定时器2作为波特率发生器
下面进行串口通信波特率可变的函数编写(两个串口全部使用)
串口2的S2CON 的8个位没有在头文件定义,要自己定义

#include <STC15F2K60S2.H>
#include <stdio.h>
#define S2RI  0x01              
#define S2TI  0x02              
#define S2RB8 0x04             
#define S2TB8 0x08             
#define S2_S0 0x01
//定义接收数组
unsigned char Buffer1[5]={0};//串口1接收数组
unsigned char Buffer2[5]={0};//串口2接收数组
unsigned char buf[12]={0}; //发送数组
unsigned char i=0,j=0;
void Uart1Init(void)		//9600bps@12.000MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0xC7;		//设定定时初值
	TH1 = 0xFE;		//设定定时初值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
	EA=1;
    ES=1;
}
void Uart2Init(void)		//9600bps@12.000MHz
{
	S2CON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x04;		//定时器2时钟为Fosc,即1T
	T2L = 0xC7;		//设定定时初值
	T2H = 0xFE;		//设定定时初值
	AUXR |= 0x10;		//启动定时器2
}
//串口1字符串发送
void Uart_Sendstring(unsigned char *pucStr) 
{ 
 while(*pucStr != '\0') 
 { 
	 SBUF = *pucStr; 
	 while(TI == 0); 
	 TI = 0; 
	 pucStr++; 
 } 
}
//主函数
void  main()
{
	Uart1Init();
	Uart2Init();
	sprintf  (buf,"%u","lianglujun");
	while(1)
	{
	  
	}
}

//中断接收函数
void UART1receive() interrupt 4
{
	 if(RI)
	 { 
		  Buffer1[i]=SBUF;
		  RI=0;
	 }
	
	 SBUF=Buffer1[i]; 	//TI =1,表示一帧数据发送结束。TI状态可供软件查询,也可申请中断
	 while(!TI)	;
	 TI=0;
	 i++;
	 if(i>=5){
	 	i=0;
	 }
}
//中断函数
void UART2receive() interrupt 8	using 2
{
    //接收标记,S2RI=1,表示一帧数据接收完毕,并申请中断
	//因为头文件对串口2缺少定义,这里采用一些位操作
	 if(S2CON &S2RI)
	 { 
		  Buffer2[j]=S2BUF;
		  S2CON &= ~S2RI;
	 }
	
	 S2BUF=Buffer2[j];//发送数据
	 while(!S2CON & S2TI);
	 S2CON &= ~S2TI;
	 j++;
	 if(j>=5){
	 	j=0;
	 }
}		 
上一篇:[2101] Tokens-to-Token ViT: Training Vision Transformers from Scratch on ImageNet


下一篇:外星人 Alienware x15 R2 评测