【嵌入式-单片机】AURT串口通信详解

2023-12-13 18:41:17

最近学习串口通信确实有点复杂,设计到定时器/计数器、中断、通信模式等,我花了3天时间,终于理解了2个小时的视频内容。。。。但好在理解了。下面来看看单片机中的AURT串口通信部分。
如果看详解,直接跳到串口模式图开始看。

基础介绍

在这里插入图片描述

硬件电路

在这里插入图片描述

电平标准

在这里插入图片描述

UART串口通信模式

在这里插入图片描述

串口参数及时序图

在这里插入图片描述

串口模式图

在这里插入图片描述

建议开两个流量器窗口,跟着配置看。
第一步:配置串口、定时器、中断

  1. 配置SCON串口工作模式及PCON中的SMOD波特率加倍
  2. 配置TMOD定时器/计数器8位重装载模式,此时需要配置TL1和TH1,及定时器的低8位TL1定时器初值和高8位TH1重装值。按道理讲应该一样。
  3. 配置禁止定时器中断(ET1=0; 我测试了1和0都没关系。。)。设置TR1=1,允许开始计数。
  4. 允许串口中断和所有中断ES=1;及EA=1;

第二步:单片机通过串口发送信息
1 将数据写入SBUF
2. 检测TI请求发送中断标志位,当标志位由非中断状态0变为中断状态1时,将TI重置为0

第三步:通过串口向单片机发送消息

  1. 这里是在中断中收到串口数据,直接编写中断服务函数,处理数据即可
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"

void UART_Init();
void UART_SendByte(unsigned char byte);


/**
	目的:
		在串口中向电脑发送数据
	原理:
		查看串口模式图中所示,数据总线上接有两个独立的串口数据缓存寄存器,物理上是两个独立的寄存器,占用相同的地址。
		写入的是发送寄存器,读操作时,读出的是接受寄存器。
		在发送数据时,数据写入到SBUF中,数据流过控制门,由波特率相关元件控制传输速率。
		T1溢出率指的是
	
		采用STC89C52单片机的UART串口,使用模式1(8位UART,波特率可变(常用))向电脑发送数据
		电脑端采用STC-ISP程序中的串口工具,接受单片机传输的数据即可。
	步骤:
		
*/

void main()
{
	unsigned char Sec;
	UART_Init();
	
	while(1) {
		// UART_SendByte(Sec);
		// Sec++;
		// Delay(1000);
		
	}
}

/**
*	@brief	串口消息发送
*	@param	1字节
*	@retval	无
*/
void UART_SendByte(unsigned char byte)
{
	// 发送数据到SBUF, 由硬件控制发送. 这里如果SBUF在左边,表示数据送入SBUF,向外发送数据;SBUF在右边,表示从SBUF读取数据。
	SBUF = byte;
	/*
		通过不停检测TI == 0, 来判断硬件是否已经将TI置为1,即发送请求中断,如果跳出while循环,表示TI=1,此时,将TI重新设置为0(我理解发送请求中断处理结束)即可。
		当向外部串口写入数据时, 在发送数据结束时, 硬件会将TI自动置位为1,表示请求中断, 需要手动设置TI = 0;
	*/
	while(TI == 0);
	TI = 0;
}

// 串口初始化
void UART_Init()
{
	// 配置串口
	/*
		配置SCON串行控制寄存器(可位寻址).
		B7		B6	B5	B4	B3	B2	B1	B0
		SM0/FE	SM1	SM2	REN	TB8	RB8	TI	RI
		0		1	0	0	0	0	0	0
		当PCON寄存器中的SMOD0/PCON.6位为1, 即SMOD0为1, 代表该位用于错误检测. 为0时, 和SM1一起指定串行通信的工作方式
		SM0和SM1用于确定串口工作方式. 直接查手册即可.
		REN: 允许/禁止串行接受控制位. REN=1, 表示允许串行接受状态, 可启动串行接收器RxD,开始接受信息. 软件复位REN, 即REN=0,则禁止接受。
		T1: 发送中断请求标志位. 数据发送结束后, 会向主机请求中断, 硬件自动将T1置位为T1=1;请求中断, 然后由软件复位TF=0;即该帧数据发送完毕.
		RI: 接收中断请求标志位. 类似T1, 只是发送换成了接收
		这里配置为0x40, 即0100 0000, 意思如下:
		SM0 SM1分别为01:即串口工作方式使用01工作方式即方式1,8位UART,波特率可变。波特率=(2^SMOD/32)*(定时器1的溢出率)。
		REN=0:禁止接收串行数据.
		TB8、RB8分别为00:不考虑这两个. 具体可以参考文档. 其实文档中说的RB8在方式1时, 若SM2=0,则RB8时接收到的停止位。
		T1=0:即初始化时不向主机请求中断。这个通常在定时时间到了以后,由硬件置1,即向主机请求中断,而响应中断以后(即检测到TI从0到1以后while(TI==0);,要自己手动将TI复位,即TI=0;)
	*/
	SCON = 0x50;
	
	
	// PCON = 10 其他位不变
	/*
		配置PCON电源控制寄存器(不可位寻址).
		B7		B6		B5	B4	B3	B2	B1	B0
		SMOD	SMOD0	-	POF	GF1	GF0	PD	IDL
	
		SMOD:	波特率选择位. 当SMOD=1时, 则使串行通信方式1、2、3的波特率加倍;SMOD=0时各工作方式的波特率不加倍。
		SMOD0:	帧错误检测有效控制位。SMOD0=1时,SCON寄存器中的SM0/FE位用于FE(帧错误检测)功能;SMOD0=0时,SCON
				寄存器中SM0/FE位用于SM0功能,并和SM1一起指定串口的工作方式。
		
		SMOD=1:波特率加倍;
		SMOD0=0:配合SCON中的SM1一起指定串口工作方式。注意,这里SMOD0似乎默认就是0,文档中说复位时SMOD0=0;
		其他位不予改变, 由于是不可位寻址, 需要使用位运算处理
		PCON = PCON | 1000 0000;即其他位不变,仅设置SMOD=1
		PCON = PCON | 0x80;
	*/
	PCON = PCON | 0x80;
	

	// 配置定时器/计数器工作模式寄存器. 因为使用到了波特率发生器, 即T1定时器/计数器
	/*
		TMOD各位描述如下:
		7		6		5	4	3		2		1	0
		GATE	C/T拔	M1	M0	GATE	C/T拔	M1	M0
		0		0		1	0	低四位不变即可.
		
		GATE:控制定时器,置1时只有在外部中断(INT1拔或者INT0拔)脚为高及(TR1或TR0)控制位置1时才可打开定时器/计数器0或定时器/计数器1
			  也就是GATE为1且控制位为1同时生效才能打开定时器/计数器,详情查看图。当GATE=0时,只需要TR0或者TR1一个位就能打开定时器/计数器。
		C/T拔:高电平为C,即计数器;低电平为T拔,即定时器;
		M1、M0:用于定时器/计数器模式选中,共4种模式:
		00:13位定时器/计数器
		01:16位定时器/计数器. TL1、TH1全用
		10:8位自动重装载定时器,当TL1溢出时,TH1自动将自己的初始值装入TL1。
		11:定时器/计数器1此时无效。(停止计数)
		
		由此:使用GATE=0仅需TR0或者TR1就能打开定时器就可;C/T拔使用定时器T拔即可;选择8位重装载模式,因为16位定时器/计数器要求在中断中手动
		重置TH1和TL1,比较耗费时间,因此采用10模式,即8位自动重装载模式;
		
	*/
	// 配置TMOD. 0010 0000
	// 低位不变, 高位清零
	TMOD = TMOD & 0x0F;
	// 低位不变, 高位设为0010
	TMOD = TMOD | 0x20;
	
	/*
		配置TMOD为8位自动重装载后要配置TL1和TH1的初始值,并且应该是一样的初值~
		这里设置TL1和TH1为0xF3的原因是:
			0xF3=243=256-13
			也就是13us(13微秒)溢出一次,前面已经讲过12MHZ的晶振在12T模式下,每隔1us(1微秒)记一次数,这里相当于
			每隔13微秒计数器/定时器溢出一次,
			1/13us=0.07692307MHz	// 相当于频率为0.07692307MHz
			0.07692307MHZ/16=0.0048076923MHZ≈4807.69Hz	// 经过16分频以后,频率变为4807Hz. 这里SMOD=1,波特率加倍了。
			因此波特率使用4800Hz,误差率在7.69/4800≈0.0016025641, 即误差0.16%
			
			如果使用SMOD=0,即不对波特率加倍的情况下,0.07692307MHZ/2/16=0.002403846MHZ≈2403.846Hz
			
			因此如果给定波特率为BAUD=4800Hz,1/(256 - TL1)/2^SMOD/16*10^6=BAUD; 10^6/(256-TL1)/2^SMOD/16=BAUD; 256-TL1 = 10^6/2^SMOD/16/BAUD; TL1 = 256 - [10^6/2^SMOD/16/BAUD];
			结论:TL1 = 256 - [10^6/2^SMOD/16/BAUD];
	*/
	// 设定定时器初值
	TL1 = 0xF3;
	// 设定定时器重装值
	TH1 = 0xF3;

	/*
		这里ET1=0表示禁止定时器1中断。这里其实禁止不禁止似乎没关系.
	*/
	// 禁止定时器1中断
	ET1 = 0;
	
	/*
		配置定时器/计数器控制寄存器TCON
		在配置TMOD时已经说明,在GATE=0时,仅需TR1或者TR0定时器1或者定时器0的运行控制位位1即代表允许开始技术~
	*/
	TR1 = 1;
	
	// 允许所有Enable All中断
	EA = 1;
	// 允许串口中断
	ES = 1;
}

/**
*	@brief	UART串口中断服务函数
*	@param	无
*	@retval	无
*/
void UART_Routine() interrupt 4
{
	if(TI == 1)
	{
		// 发送请求中断
		// P2_7 = ~P2_7;
	}
	
	if(RI == 1)
	{
		// 接收请求中断
		// P2_7 = ~P2_7;
		UART_SendByte(SBUF);
		P2 = SBUF;
		RI = 0;
		// LCD_ShowNum(1, 1, P2_7, 2);
	}
}

文章来源:https://blog.csdn.net/qq_34291570/article/details/134900898
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。