51单片机的UART应用

串行通信方式:将数据字节分成一位一位的行驶在一条传输线上进行传输,如图:

异步串行通讯方式:异步串行通信数据格式一般为字符格式,一个字符一个字符(即一帧)地传输,每个字符一位一位的传输,各个位是以固定的时间(即波特率)传送的,并且传输一个字符时,总是以“起始位”开始,以“停止位”结束,字符间的间隙没有固定的间隔要求。每一个字符的前面都有一位起始位(低电平),字符本身由5-7位数据位组成,接着字符后面是一位校验位(也可以没有校验位),最后一位或一位半或两位停止位,停止位后面是不定长的空闲位。其一帧字符信息由4部分组成:起始位、数据位、奇偶检验位、停止位。停止位和空闲位都规定为高电平,这样就保证了起始位开始处有一个下跳沿。

通讯的发送和接收设备使用各自的时钟控制数据的发送和接收,为使双方收发协调,要求发送和接收的时钟尽可能一致(即波特率要一致),所以收发设备都要保持一致的协议配置,波特率、停止位、数据位、校验位等。如图:

帧格式:

波特率:波特率即数据传速率,表示每秒传送二进制代码的位数,它的单位是b/s。波特率对于CPU与外界的通信是很重要的,假设数据传送的速率是120字符/s,而每个字符格式包含10个代码位(一个起始位,一个中止位、8位数据位D0-D7),这是传送的波特率为:10bit/字符*120字符/s = 1200 b/s。波特率即为1200 b/s。每一位的时间即为1/1200。

串行口结构:51单片机串行口是一个可编程全双工的通信接口,具有Uart(通用异步收发器)的全部功能,能同时进行数据的发送与接收,也可作为同步一位寄存器使用。其主要由两个独立的串行数据缓冲寄存器SBUF (一个发送,一个接收)和发送控制器、接收控制器,输入移位寄存器及若干控制门电路。如图:

上图中有两个物理上独立的接收、发送缓冲器SBUF,它们占用同一地址99H,可同时发送、接收数据。发送缓冲器只能写入,不能读出;接收缓冲器只能读出,不能写入。

上图中可以看出,接收器是双缓冲结构,在前一个字节被从接收缓冲器SBUF读出之前,第二个字节即开始接收(串行输入至移位寄存器),但是,在第二个字节接收完毕而前一个字节CPU未读取时,会丢失前一个字节。

串行口的发送和接收都是以特殊功能寄存器SBUF的名义进行读、写的。当向SBUF发送“写”命令时(SBUF = num,假设num是我已经定义好的一个变量),即是向发送缓冲器SBUF装载并开始由TXD引脚向外发送一帧数据,发送完后发送中断标志位TI则自动置1。

在满足串行口接收中断标志位RI = 0的条件下,置允许接收位REN = 1,就会接收一帧数据进入移位寄存器,并装载到接收SBUF中,同时使RI = 1,当发读SBUF命令时(num = SBUF),便由接收缓冲器SBUF取出信息通过89c51内部总线送CPU。

对于发送缓冲器,因为发送时CPU是主动的,不会产生重叠错误,一般不需要用双缓冲结构来保持最大传送速率。

串口方式1:10位数据异步通讯口,1起始,8数据,1停止,TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。其传输波特率可变,对51而言,波特率有定时器1的溢出率而决定,一般而言,在单片基于单片机,单片机与计算机,计算机与计算机串口通讯时,基本都市选择方式1,所以此种方式必须掌握

串口方式1的编程实现:

方式1数据输出时序图如下:

当数据被写入SBUF寄存器后,单片机自动开始从起始位发送数据,发送到停止位的开始时,由内部硬件将TI置1,向CPU申请中断,接下来可在中断服务程序中进行相关处理。

接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器的最左边,
控制电路进行最后一次移位,当RI=0且SM2=0(或结收到的停止位为1)时,
将接受到的9位数据前8位数据装入接收SBUF,第九位(停止位)进入RB8,并置RI=1,向CPU申请中断,

 串行口控制字及控制寄存器

SCON:

SM0、SM1工作方式控制位

SM2:多机通信控制位,1-允许、0-不允许;主要用于方式2和方式3。

REN:串行接收允许位(相当于串行接收的开关,在串行通信接收控制过程中,如果满足RI = 0和REN = 1的条件,就允许接收。)。1-允许、0-不允许

TB8:发送数据第九位

RB8:接收数据第九位

TI:发送中断标志位,在一帧数据发送完时被置位。在串行发送到停止位的开始时由硬件置位,可用软件查询。它同时也申请中断。TI置位意味着向CPU提供“发送缓冲器SBUF已空”的信息,CPU可以准备发送下一帧数据。串行口发送中断被响应后,TI不会自动清0,必须软件清0.

RI:接收中断标志位,接收中断标志,在接收到一帧数据后由硬件置位。当RI = 1时,申请中断,表示一帧数据接收结束,并已装入接收SBUF中,要求CPU取走数据,CPU响应中断,取走数据。RI位也必须由软件来清0。

串行发送中断标志TI和接收中断标志RI是同一个中断源,CPU事先不知道是发送中断TI还是接收中断RI产生的中断请求,所以,在全双工通信时,必须由软件来判别。复位时SCON所有位都清0.

小结: 
此处意在理解串口传输的几个要点: 
①串口数据由TX和RX(发送和接收)两根数据线组成。 
②串口数据在51单片机内,是由SBUF寄存器来存储的,且每次只能存储一位(即一个字节)。 
③串口数据发送过程:读SBUF,将一位数据从TX传送出去,同时发送完毕TI置1。 
④串口数据接收过程:写SBUF,将一位数据从RX接收进来,同时接收完毕RI置1。 
⑤虽然从程序上看都是SBUF,但实际上内部读操作和写操作是针对不同的寄存器操作的。 
⑥无论是单片机内部串口间传输、与外部串口传输,数据均可先存入存储区(如数组,flash等),然后逐位传输。

串口数据接收举例:

串口数据接收与发送都应该做成一个完整的数据包,包括包头、数据长度、数据位、校验位等;

接收一包数据不能只考虑接收一包正确的数据,还应考虑如果收到错误的数据、不完整的数据等该怎么处理,如下:

/******************************************************************************************************************
*@brief: 串口接收中断函数
*@param: 
*@return: 
*@descriptions: 数据收到包头0xA5开始接收指定长度的数据
*               1、有数据但没有包头0xA5,则丢弃不接收
*               2、数据有包头0xA5,但数据大于指定长度,则只接收指定的长度,多余的丢弃
*               3、数据有包头0xA5,但数据小于指定长度或50ms内没有收到完整的数据包,则不做处理
*               4、正常收到一包数据,但立即又收到一包正常的数据包,则后一包数据丢弃
********************************************************************************************************************/
uint8 UartFlagRxE = 0;  /*一包数据接收完成*/  
uint8 UartRxIndex = 0;
uint8 UartRxHead =0;
uint8 UartFlagRxErr =0; /*数据出错标志位,0表示没有错;1表示数据出错*/  
uint8 UartFlagRxRrrCount =0; /*数据出错计数,收到错误数据,50ms后重新开始*/
xdata uint8 UartRxPackage[UART_RX_BUFF_LEN];
xdata uint8 UartTxPackage[UART_TX_BUFF_LEN]; 
void uart_interrupt()  interrupt 4
{
	 if(RI ==1)  /*接收完一个字节,RI就被硬件置一,需软件清零*/
	 {
		  RI =0;   /*清中断准备接收下一字节*/
		  if(UartFlagRxE == 0)  /*解决注释中第4个问题,当UartRxPackage处理完后,UartFlagRxE会置零,才可以接收新的数据*/
			{
				if(UartRxHead ==0)  
				{
					if(SBUF0 == 0xA5) /*检测到包头*/
					{					 
						 UartRxHead =1;       /*置一,下一个字节就在下一段程序保存*/
						 UartRxIndex = 0;	    /*数组指针从0开始缓存*/
						 UartRxPackage[UartRxIndex++] =SBUF0;	/*保存包头*/ 
					}
				}
				else
				{
					UartRxPackage[UartRxIndex++] =SBUF0; /*保存剩余的数据*/ 				
					if(UartRxIndex >= UART_RX_PACK_LEN)  /*一包数据接收完成*/
					{
						UartRxHead = 0;		      /*接收完一包数据,从0开始重新接收*/ 	           
						UartFlagRxE =1;   /*接收完一包数据*/
						UartFlagRxErr = 0;
					}
					else    /*收到包头开始计时50ms内没有收到完整的数据包,视为数据错误,清零重新开始;UartRxHead变量要置零*/      
					{
					  UartFlagRxErr = 1;
						UartFlagRxRrrCount = 0;/*可在定时器中计时*/
					}
				}	
		  }			
 	 }
}

可能会遇到的问题:

  • 初始化后,发送一串初始化信息,如“UartSendString("uart_init");”,串口助手接收的是“art_init”,‘u’没有接收到;可能是串口初始化时TI被置一了(TI = 1;),应该TI被置零的(TI= 0)。

使用UART作为数据传输需要注意:

  • 发送方的数据封装;接收方的数据解析
  • 收到错误数据该怎么处理;
  • 收到数据比正常一包数据要大,该怎么处理;
  • 收到一包数据,包头正确,后面数据不完整,该怎么处理;

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值