四、通用异步收发器UARN
原文地址 http://blog.csdn.net/woshidahuaidan2011/article/details/51137047
by jaosn Email: woshidahuaidan2011@hotmail.com
UART(Universal AsynchronousReceiver/Transmitter。通用异步接收/发送装置)用于异步通信。能够实现全双工发送和接收。
2440有三个UART:UART0。UART1。UART2其结构图例如以下所看到的:
通过上图能够看到UART包括baud-rate generator波特率发生器,transmitter发送器,receiver 接收器and a control unit控制单元。
在UART使用FIFO模式的时候,当中发送器和接收器分别有一个大小为64字节的发送缓存器寄存器和接收缓存寄存器FIFO(先进先出),通过上图还能够看到。假如不使用FIFO模式,接收器分别使用的发送保存寄存器和接收保存寄存器。还能够看到,图中波特率产生器会受到时钟源的影响,UART可有三个时钟源以供选择,分别为PCLK,FCLK/n还有外部时钟UEXTCLK。
对于波特率产生器,首先要提到UBRDIVn(n为0,1,2以下雷同)。能够通过该寄存器设置波特率,设置的公式例如以下:
UBRDIVn=(int)(UARTclock / (buad ratex 16) ) –1
当中UART clock正如上面说的,能够选择PCLK, FCLK/n or UEXTCLK
UBRDIVn能够取值为0到2^16-1,在旁路模式下(bypass mode),该寄存器能够设置为0,该寄存器图为:
此寄存器不用多说明。直接填写数字就能够。
如果要设置的波特率为115200。UART的时钟UART clock为40M的话,那么:
UBRDIVn =(int)(40000000 / (115200 x 16) ) -1
= (int)(21.7) -1 [round to the nearestwhole number]
=22 -1 = 21
能够看到。上面的计算取整之后将会出现误差,这里的误差同意范围为1.87%,误差计算方式为:
tUPCLK = (UBRDIVn + 1)x 16 x 1Frame / PCLK tUPCLK: 实际UART Clock
tUEXACT = 1Frame / baud-rate tUEXACT: 理想UART Clock
UART error = (tUPCLK – tUEXACT) / tUEXACTx 100%
当中1Frame = start bit + data bit + parity bit + stop bit. 開始位+数据位奇偶校验位+停止位
这里的帧能够绘图表示:
start bit(1位) | data bit(5-8位) | parity bit(1位) | stop bit(1或2位) | ||||||||||
|
|
|
|
至于一帧数据究竟是怎么设置的,能够使用ULCONn寄存器。以ULCON0为例:
ULCON0【1:0】设置数据位的格式。能够设置成5到8位
ULCON0【2】设置停止位。1位或者两位停止位
ULCON0【5:3】设置校验模式。0xx表示无校验
100表示奇校验
101表示偶校验
101表示发送数据强制设置为1。接受数据检測是否为1
101表示发送数据强制设置为0,接受数据检測是否为0
ULCON0【6】设置模式,0表示正常模式。1表示红外模式
通过ULCONn设置帧的传输格式是最基本设置,设置完帧格式后就能够设置UART时钟源和一些模式设置。这个设计的寄存器为UCONn:
这里。UCONn主要是设置一写发送或者接收数据模式、中断触发形式和UART的时钟选择设置。看一下每一位详细含义:
UCONn【1:0】选择怎样接收缓存器读取数据 00表示禁止接收数据
01表示中断接收或者查询法接收
10表示DMA0请求(UART0独有)
DMA3请求(UART2独有) 11表示DMA1请求(UART1独有)
UCONn【3:2】选择怎样发送缓存器发送数据 00表示禁止发送数据
01表示中断发送或者查询法发送
10表示DMA0请求(UART0独有)
DMA3请求(UART2独有) 11表示DMA1请求(UART1独有)
UCONn【4】 设置此位,UART会在一帧的时间内发送一个break信号,发送完之后改位自己主动清除。
UCONn【5】 自循环模式,这样的模式仅用于測试,该位设置为1能够,在内部,RX和TX会连接起来。
UCONn【6】设置接收错误状态接收使能,此位设置为1时。当发生比方帧错误,溢出错误时将产生中断。
UCONn【7】当使用UART的FIFO的时,此位设置为1时,当接收超时时,会触发中断。
UCONn【8】接收中断设置。设置为1表示电平触发。设置为0表示脉冲触发。在FIFO模式时。当FIFO的值达到设置的阈值会触发中断。在非FIFO模式时。有一个数据便触发中断。
UCONn【9】发送中断设置,设置为1表示电平触发,设置为0表示脉冲触发,在FIFO模式时,当FIFO的值达到设置的阈值会触发中断,在非FIFO模式时,有一个数据便触发中断。
UCONn【11:10】UART时钟选择: 00/10 PCLK 01外部时钟UEXTCLK 11 FCLK/n
UCONn【15:12】选择FCLK/n模式的时候,用来确定n的具体数值。以下具体介绍一下:
n的值要受到UCON0【15:12】、UCON1【15:12】和UCON2【14:12】共同决定的,且当当中的一个设置为非0时,其余两个必须设置为0,当中要注意的是:
UCON2[15]起到决定性因素。是FCLK/n的使能位。
n的值设置方式为:
当n的范围为7到21时,UART时钟=FCLK/( UCON0【15:12】的设定值+6)
当n的范围为22到36时,UART时钟=FCLK/(UCON1【15:12】的设定值+21)
当n的范围为37到43时,UART时钟=FCLK/(UCON2【14:12】的设定值+36)
通过阅读上面的寄存器的含义结合自己实际的需求就能够完毕其模式的选择即使时钟的配置,刚才有有提到UART发送和接收都能够使用一款缓冲区FIFO,这里介绍一下UART的FIFO。控制FIFO的寄存器UFCONn:
这里仍以UFCON0为例:
UFCON0【0】FIFO使能位。决定是否使用FIFO
UFCON0【1】接收FIFO复位位,设置为1,将自己主动清除接收FIFO的内容
UFCON0【2】发送FIFO复位位,设置为1。将自己主动清除发送FIFO的内容
UFCON0【5:4】接收FIFO触发阈值设定
UFCON0【7:6】发送FIFO触发阈值设定
UART的FIFO整体来说比較简单,结合前面所解说的帧格式,时钟,基本就设置的差点儿相同了,通过上面的基本设置就能够使用UART,可是,2440为了是数据在传输的过程中尽量避免数据的丢失。也有有关自己主动流控制AFC(Auto Flow Control)的寄存器UMCONn,介绍该寄存器之前。须要对流控制做有关的说明:
数据在两个串口之间传输时,经常会出现丢失数据的现象,或者两台计算机的处理速度不同,如台式机与单片机之间的通讯,接收端数据缓冲区已满。则此时继续发送来的数据就会丢失。如今我们在网络上通过MODEM进行传输数据,这个问题就尤为突出。
流控制能解决问题。当接收端数据处理只是来时,就发出“不再接收”的信号,发送端就停止发送。直到收到“能够继续发送”的信号再发送数据。因此流控制能够控制传输数据的进程,防止数据的丢失。
PC机中经常使用的两种流控制是硬件流控制(包含RTS/CTS、DTR/CTS等)和软件流控制XON/XOFF(继续/停止)
对于硬件流控制经常使用的有RTS/CTS流控制和DTR/DSR(数据终端就绪/数据设置就绪)流控制。硬件流控制必须将相应的电缆线连上,用RTS/CTS(请求发送/清除发送)流控制时,应将通讯两端的RTS、CTS线相应相连。数据终端设备(如计算机)使用RTS来起始调制解调器或其他数据通讯设备的数据流。而数据通讯设备(如调制解调器)则用CTS来起动和暂停来自计算机的数据流。这样的硬件握手方式的过程为:我们在编程时依据接收端缓冲区大小设置一个高位标志(可为缓冲区大小的75%)和一个低位标志(可为缓冲区大小的25%),当缓冲区内数据量达到高位时。我们在接收端将CTS线置低电平(送逻辑0),当发送端的程序检測到CTS为低后,就停止发送数据,直到接收端缓冲区的数据量低于低位而将CTS置高电平。RTS则用来标明接收设备有没有准备好接收数据。经常使用的流控制还有还有DTR/DSR(数据终端就绪/数据设置就绪)。
我们在此不再详述。
因为电缆线的限制,我们在普通的控制通讯中一般不用硬件流控制,而用软件流控制。一般通过XON/XOFF来实现软件流控制。经常用法是:当接收端的输入缓冲区内数据量超过设定的高位时,就向数据发送端发出XOFF字符(十进制的19或Control-S。设备编程说明书应该有具体阐述),发送端收到XOFF字符后就马上停止发送数据;当接收端的输入缓冲区内数据量低于设定的低位时,就向数据发送端发出XON字符(十进制的17或Control-Q),发送端收到XON字符后就马上開始发送数据。一般能够从设备配套源程序中找到发送的是什么字符。 当软件里用了流控制时,应做具体的说明,怎样接线,怎样应用。应该注意,若传输的是二进制数据,标志字符也有可能在数据流中出现而引起误操作。这是软件流控制的缺陷,而硬件流控制不会有这个问题。
接下来看下2440自己主动流控制有关的寄存器UMCONn:
通过以下的凝视能够注意到仅仅有UART0和UART1拥有AFC功能,以下对寄存器的位做出简要说明
UMCONn【0】:设置为1使能nRTS(请求发送),可是假如使能使能AFC功能,该位是无效的,该位的值是2440自己主动设置的
UMCONn【1:3】:保留位,必须为0
UMCONn【1】:AFC使能位,设置为1使能AFC
UMCONn【5:7】:保留位,必须为0
与之相应的状态寄存器是UMSTATn。主要是读取一些请求发送的状态信息,这里不再具体说明,具体查阅手冊。
设置部分已经介绍完成,通过上面的设置,就可以完整的完成通信。
可是当数据发送或者接收的时候,用户往往想知道是否发送完成。或者已经发送了多少还差多少能够发送完成等,也不比方在接收数据的时候,用户要知道已经接收到了多少数据,是否已经接收完成或者还差多少才干够接收完成。所以我们还须要几个状态寄存器来了解UART的执行状态:
UTSTATn寄存器用于表明收发的一些状态,是一些仅仅读寄存器:
UTSTATn【0】收到数据该位自己主动置1。当使用FIFO。应该配合查询检測UFSTAT寄存器
UTSTATn【1】当发送缓冲区没有数据时该位置1,当使用FIFO,应该配合查询检測UFSTAT寄存器
UTSTATn【2】当发送缓存器没有数据且最后一个数据发送完成的时候该为置1.
刚才有提到UFSTATn寄存器,看下下他的作用:
UFSTATn寄存器是使用FIFO须要注意的:
UFSTATn【5:0】接收FIFO缓存器的数据的数目
UFSTATn【6】当接收FIFO缓存器的满了之后该位自己主动为置1
UFSTATn【13:8】发送FIFO缓存器的数据的数目
UFSTATn【14】当发送FIFO缓存器的满了之后该位自己主动为置
另一个错误状态寄存器UERSTATn须要须要注意:
UERSTATn【0】在接受数据时。发生溢出错误是该位置1
UERSTATn【1】在接受数据时,有校验错误则置1
UERSTATn【2】在接受数据时。有帧错误则置1
UERSTATn【3】在接受数据时。到BREAK信号的时候则置1
注意,当读取该寄存器时,UERSTATn寄存器将自己主动清零。
寄存器UFSTATn和寄存器UERSTATn就像一个显示器一样,通过这两个显示器。你能够知道UART的收发数据状态及其FIFO的状态。
到如今为止。有关UART的原理及其寄存器已经介绍完成。一切设置完成后就可接收或者发送数据了,接收和发送比較简单,仅仅须要向着UTXHn 和URXHn写入数据或者读取数据就能够(都是以byte为单位):
UTXHn:将要发送的数据发到此寄存器,UART会把数据放到发送缓冲区,自己主动发送出去。数值0到255
URXHn :从该寄存器读取数据,数值0到255
如今对串口接收实例进行总结:
1、 设置相关的引脚为UART功能的引脚 能够通过GPnCON寄存器来设置。普通情况下要使能上拉电阻功能以使port稳定。通过GPnUP设置上拉使能
2、 设置UART的数据帧格式 可通过ULCONn来设置
3、 设置UART的时钟源,及其发送接收方式 可通过UCONn来设置
4、 对于有关FIFO的设置 通过UFCONn来设置
5、 设置是否使用自己主动流控 可通过UMCONn来设置
6、 设置UART的波特率 UBRDIVn
给出一个初始化的样例:
voiduart0_init(void)
void uart0_init(void) //初始化函数
{
//1、设置相关的引脚为UART功能的引脚能够通过GPnCON寄存器来设置,普通情况下要使能上拉电阻功能以使port稳定,通过GPnUP设置上拉使能
// TXD0=GPH2 RXD0=GPH3
rGPHCON &=~(3<<4);
rGPHCON|=(2<<4); //TXD0
rGPHCON&=~(3<<6);
rGPHCON|=(2<<6); //TXD0
rGPHUP &=~(3<<2);//使能上拉
//2、设置UART的数据帧格式可通过ULCONn来设置
//8个数据位1位停止位无校验位正常模式
rULCON0 |= 0x03 ;
//3、设置UART的时钟源,及其发送接收方式 可通过UCONn来设置
rUCON0 |=(1|(1<<2));//设置查询或者中断接收,查询或者中断发送,时钟源为PCLK其余採用默认值
//4、对于有关FIFO的设置通过UFCONn来设置
rUFCON0 &=~1;//不使用FIFO
//5、设置是否使用自己主动流控可通过UMCONn来设置
rUMCON0 &=~(1<<4);//不使用AFC
//6、设置UART的波特率 UBRDIVn
rUBRDIV0=(int)( PCLK_DATA /( BUAD_RATE * 16) )-1;//PCLK=50m 波特率115200
}
void send_c(unsigned char c) //发送一个字符函数
{
/* 等待,直到发送缓冲区中的数据已经所有发送出去 */
while(!(rUTRSTAT0 & (1<<2)));
/* 向UTXH0寄存器中写入数据。UART即自己主动将它发送出去 */
rUTXH0 = c;
}
unsigned char get_c(void) //接收函数
{
/* 等待。直到接收缓冲区中的有数据 */
while(!(rUTRSTAT0 & 1));
/* 直接读取URXH0寄存器,就可以获得接收到的数据 */
returnrURXH0;
}
參考:http://blog.csdn.net/g1036583997/article/details/12717297