#51单片机#UART串口通信的初步认识

UART串口通信

UART,全称Universal Asynchronous Receiver/Transmitter,即通用异步收发器。

串口通信是单片机中最常用的一种技术,通常用于单片机和计算机之间以及单片机和单片机之间的通信。

UART的通信类型可分为两种,并行通信和串行通信。

并行通信:数据各个位同时传送,可实现以字节为单位来通信。缺点:通信线占用资源多,成本高。

串行通信:一次只传输一个字节的数据。

STC89C52有两个专门的UART通信引脚,P3.0(RXD)和P3.1(TXD),由它们组成的通信接口叫串行接口,简称串口。

下图体现了两个单片机相互收发信息的过程:
在这里插入图片描述

图中两单片机的GND互连,因为单片机之间的通信,要保证电源基准一致。

GND——单片机系统电源的参考地。

TXD——串行发送引脚。

RXD——串行接收引脚。

学习UART通信,要认识波特率。

波特率是发送二进制数据位的速率,习惯上用baud表示。发送一位二进制数据的持续时间=1/baud。

(UART串口的波特率常用值是300、600、1200、4800、9600、14400、19200、28800、38400、57600、115200等。)

在通信前,两个单片机需要明确约定好通信波特率。只有保持波特率一致,才能保证收发双方实现正常通信。

UART通信原则:低位先发,高位后发。

UART通信规定:当没有通信信号发生时,通信线路应保持高电平。发送数据之前,要先发一位0,标志数据起始位,数据发送完毕,要发送一位1,标志数据截止位。

下图位串口数据发送示意图:
在这里插入图片描述

改图表现了信号随着时间变化的对应关系,实际上是一个时域示意图。

比如:在单片机发送引脚上,左边的是先发送的,右边的是后发生的。数据位的切换时间即为1/波特率。

掌握时域的概念,有助于理解不同通信的时序图

为了更好的理解UART串口通信的原理,下面给出了一段IO口模拟UART串口通信的程序。

IO口模拟UART串行通信程序是一个简单的演示程序。使用烧录工具中的串口调试助手下发一个数据,待数据加1后,将自动返回。

串口调试助手的实质是利用计算机上的UART通信接口,发送数据给单片机或接收来自单片机的数据并显示在调试助手的界面上。(单片机通过USB与计算机相连,计算机中有USB转UART的芯片)

#include <reg52.h>

sbit PIN_RXD = P3^0;				//定义接收引脚
sbit PIN_TXD = P3^1;				//定义发送引脚

bit RxdOrTxd = 0;					//标志当前状态(发送或接收)
bit RxdEnd = 0;						//标志接收结束位
bit TxdEnd = 0;						//标志发送结束位
unsigned char RxdBuf = 0;			//接收缓冲器
unsigned char TxdBuf = 0;			//发送缓冲器

void ConfigUART(unsigned int baud);		//配置波特率
void StartTXD(unsigned char dat);		//开始发送数据
void StartRXD();						//开始接收数据

void main()
{
	EA = 1;				//中断使能总开关
	ConfigUART(9600);	//配置波特率位9600
	
	while(1)
	{
		while(PIN_RXD);		//等待接收引脚出现低电平,即起始位
		StartRXD();			//启动接收
		while(!RxdEnd);		//等待接收完成
		StartTXD(RxdBuf+1); //将接收到的数据+1后,发送回去
		while(!TxdEnd);		//等待发送完成
	}
}

void ConfigUART(unsigned int baud)
{
	TMOD &= 0XF0;					 //清零T0的控制位
	TMOD = 0X02;				     //设置T0为模式2
	TH0 = 256 - (11059200/12)/baud;  //计算T0重载值
}

void StartTXD(unsigned char dat)
{
	TxdBuf = dat;	//保存待发送数据到发送缓存器
	TL0 = TH0;		//T0计数初值为重载值
	ET0 = 1;		//使能T0中断
	TR0 = 1;		//启动T0
	PIN_TXD = 0;	//发送起始位
	TxdEnd = 0;		//清零发送结束标志
	RxdOrTxd = 1;	//设置当前状态为发送
}

void StartRXD()
{
	TL0 = 256 - ((256-TH0)>>1);		//启动时,将T0定时为1/2个波特率周期
	ET0 = 1;						//使能T0中断
	TR0 = 1;						//启动T0
	RxdEnd = 0;						//清零接收结束标志H7YHB 
	RxdOrTxd = 0;					//设置当前状态为接收	
}

void InterruptTimer0() interrupt 1
{
	static unsigned char cnt = 0;	//位接收或发送计数

	if(RxdOrTxd)
	{
		if(cnt <= 8)
		{
			PIN_TXD = TxdBuf & 0X01;
			TxdBuf >>= 1;
		}
		else if(cnt == 9)
		{
			PIN_TXD = 1;

		}
		else
		{
			cnt = 0;	//复位bit计数器
			TR0 = 0;	//关闭T0
			TxdEnd = 1; //标志发送结束
		}
	}
	else
	{
		if(cnt == 0)     	//处理起始位
		{
			if(!PIN_RXD) 	//起始位为0时,清零接收缓冲器,准备接收数据位
			{
				RxdBuf = 0;	
				cnt++;
			}
			else		   //起始位不为0,中止接收
			{
				TR0 = 0;   //关闭T0
			}
		}
		else if(cnt <= 8)
		{
			RxdBuf >>= 1;		//低位在前,所以将之前接收的位向有移
			if(PIN_RXD) 	    //接收脚为1时,缓冲器最高位置1
			{					
				RxdBuf |= 0X80;
			}
			cnt++;
		}
		else					 //停止位处理
		{
			cnt = 0;			 //复位bit计数器
			TR0 = 0;			 //关闭T0
			if(PIN_RXD)			 //若停止位为1,证明数据有效
			{
				RxdEnd = 1;		 //标志接收结束
			} 
		}
	}
}

可以观察到,接收函数启动时,定时为半个波特率周期。这是UART通信的一个小技巧。回头看看串口数据示意图,如果在数据位电平变化时读取数据,可能会因为时序误差或信号不稳定导致读错数据。需要找到非信号变动的位置读取电平数据。于是有了这个约定:选择信号中间位置读取电平状态,从而保证正确读出数据。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值