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

最近学习串口通信确实有点复杂,设计到定时器/计数器、中断、通信模式等,我花了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

  1. 检测TI请求发送中断标志位,当标志位由非中断状态0变为中断状态1时,将TI重置为0

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

  1. 这里是在中断中收到串口数据,直接编写中断服务函数,处理数据即可
c 复制代码
#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);
	}
}
相关推荐
电子科技圈12 分钟前
Arm电机控制开发工具哪家强?
arm开发·单片机·嵌入式硬件·设计模式·软件构建
JasmineX-127 分钟前
下位机直接控制57步进电机匀速转动
stm32·单片机·嵌入式硬件
聆思科技AI芯片1 小时前
【AI硬件开发上手教程】怎么使用AI编程实现小聆AI语音控制舵机
人工智能·嵌入式硬件·开源·ai编程·智能硬件
abc light1 小时前
ARM 裸机开发(6)——时钟树与定时器
arm开发·单片机·fpga开发
吠品11 小时前
智谱开源 ZCode 之后,真正的考试才开始
单片机·嵌入式硬件·1024程序员节
Chery114012 小时前
高速ADC与精密DAC怎么选?DP9230D与DP8532D应用解析
嵌入式硬件·物联网·射频工程
小李不想当小白15 小时前
SPI通信外设与W25Q64 (硬件SPI)(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
LCG米15 小时前
STM32驱动W5500以太网模块实测:TCP吞吐瓶颈定位、TX指针回绕陷阱与断线重连保活落地
stm32·单片机·嵌入式硬件·tcp/ip
尼喃17 小时前
662K/65Z5三脚稳压芯片规格书—PW6566B33/B30引脚功能
嵌入式硬件
创界工坊工作室17 小时前
63-基于STC89C52霍尔传感器的智能化电能表设计
stm32·单片机·嵌入式硬件·51单片机·proteus