UART (Universal Asynchronous Receiver/Transmitter) 通用异步收发器。
UART是用于控制计算机与串行设备的芯片。有一点要注意的是,它提供了RS-232C数据终端设备接口,这样计算机就可以和调制解调器或其它使用RS-232C接口的串行设备通信了。
RS232
COM口是PC(个人计算机)上,异步串行通信口的简写。由于历史原因,IBM的PC外部接口配置为RS232,成为实际上的PC界默认标准。所以,现在PC机的COM口均为RS232。
上图最右边的是串口接口,统称为RS232接口(封装DB9)
通信过程中实际只有两个管脚参与通信
2脚:电脑的输入RXD
3脚:电脑的输出TXD
5脚:接地
通过2,3脚就实现全双工(可同时收发)的串行异步通信
作为接口的一部分,UART还提供以下功能:将由计算机内部传送过来的并行数据转换为输出的串行数据流。将计算机外部来的串行数据转换为字节,供计算机内部使用并行数据的器件使用。在输出的串行数据流中加入奇偶校验位,并对从外部接收的数据流进行奇偶校验。在输出数据流中加入启停标记,并从接收数据流中删除启停标记。处理由键盘或鼠标发出的中断信号(键盘和鼠票也是串行设备)。可以处理计算机与外部串行设备的同步管理问题。有一些比较高档的UART还提供输入输出数据的缓冲区,现在比较新的UART是16550,它可以在计算机需要处理数据前在其缓冲区内存储16字节数据,而通常的UART是8250。现在如果您购买一个内置的调制解调器,此调制解调器内部通常就会有16550 UART。
UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用来与PC进行通信,包括与监控调试器和其它器件,如EEPROM通信。
UART通信
UART首先将接收到的并行数据转换成串行数据来传输。消息帧从一个低位起始位开始,后面是7个或8个数据位,一个可用的奇偶位和一个或几个高位停止位。接收器发现开始位时它就知道数据准备发送,并尝试与发送器时钟频率同步。如果选择了奇偶,UART就在数据位后面加上奇偶位。奇偶位可用来帮助错误校验。
在接收过程中,UART从消息帧中去掉起始位和结束位,对进来的字节进行奇偶校验,并将数据字节从串行转换成并行。UART也产生额外的信号来指示发送和接收的状态。例如,如果产生一个奇偶错误,UART就置位奇偶标志。
数据方向和通信速度
数据传输可以首先从最低有效位(LSB)开始。然而,有些UART允许灵活选择先发送最低有效位或最高有效位(MSB)。
微控制器中的UART传送数据的速度范围为每秒几百位到1.5Mb。例如,嵌入在ElanSC520微控制器中的高速UART通信的速度可以高达1.1152Mbps。UART波特率还受发送和接收线对距离(线长度)的影响。
目前,市场上有只支持异步通信和同时支持异步与同步通信的两种硬件可用于UART。前者就是UART名字本身的含义,在摩托罗拉微控制器中被称为串行通信接口(SCI);Microchip微控制器中的通用同步异步收发器(USART)和在富士通微控制器中的UART是后者的两个典型例子。
数据通信的基本方式可分为并行通信与串行通信两种:
Ø 并行通信:是指利用多条数据传输线将一个资料的各位同时传送。它的特点是传输速度快,适用于短距离通信,但要求通讯速率较高的应用场合。
Ø 串行通信:是指利用一条传输线将资料一位位地顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。
一、异步通信及其协议
异步通信以一个字符为传输单位,通信中两个字符间的时间间隔是不固定的,然而在同一个字符中的两个相邻位代码间的时间间隔是固定的。
通信协议(通信规程):是指通信双方约定的一些规则。在使用异步串口传送一个字符的信息时,对资料格式有如下约定:规定有空闲位、起始位、资料位、奇偶校验位、停止位。
异步通讯的时序,如图5-1。
其中各位的意义如下:
起始位:先发出一个逻辑”0”信号,表示传输字符的开始。
资料位:紧接着起始位之后。资料位的个数可以是4、5、6、7、8等,构成一个字符。通常采用ASCII码。从最低位开始传送,靠时钟定位。
奇偶校验位:资料位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验资料传送的正确性。
停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。
波特率:是衡量资料传送速率的指针。表示每秒钟传送的二进制位数。例如资料传送速率为120字符/秒,而每一个字符为10位,则其传送的波特率为10×120=1200字符/秒=1200波特。
注:异步通信是按字符传输的,接收设备在收到起始信号之后只要在一个字符的传输时间内能和发送设备保持同步就能正确接收。下一个字符起始位的到来又使同步重新校准(依靠检测起始位来实现发送与接收方的时钟自同步的)。
笼统的说明一下UART鲜明的特点:
异步:通信双方不需要时钟同步
两线制:只有Tx和Rx两根数据线(不需要Clock线)
波特率:通信双方需要事前约定好相同的波特率,他们有各自的时钟
RS232:是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。现在PC机的COM口均为RS232。所以实现UART通信就必须通过RS232的一个转化。(更多的直接理解成是一种电平转化,就是TTL电平与3.3V之间的转化),可以把RS232理解成一个UART通信协议的一部分,属于协议的物理层。
以上是uart发送的数据格式和基本特点。下面通过LCP2131中的UATR0和UART1来具体的介绍UART!
首先来介绍一下LPC2131中的UART的特性:
16字节收发FIFO
寄存器位置符合16C550工业标准
接收器的FIFO触发点可为1、4、8和14字节
内置波特率发生器
包含使能实现软件流控制的机制
结构:
UART接受模块:接受缓冲。
数据由UxRSR移位寄存器到UxRBR缓存寄存器(即FIFO)然后等待CPU读取接收
UART发送模块:发送保持。
数据由UxTHR保持寄存器(FIFO)到UxTSR移位寄存器,然后通过串口发送出去
波特率产生及控制模块:由波特率产生模块UxBRG和UxDLL、UxDLM寄存器组成
中断接口:包含中断使能寄存器UxIER和中断标识寄存器UxIIR组成
VPB接口:提供CPU或主机与UART之间的通信连接
关于UART接受数据的两种方式:查询和中断
查询:通过不断查询状态标志寄存器UxLSR的接受标志位来判断是否有数据,如果有数据则从UxRBR(FIFO)中取出数据
中断:FIFO的深度可以设置为1、4、8和14字节,当到达深度时,触发中断,在中断服务程序中去一次性读取数据。
心得:这些基层的东西必须要了解,前段时间在做关于FPGA的一个项目时读到一个问题,在NiosII环境下,关于底层的库函数的封装程度已经比较高了,它的UART的读取函数已经封装为fgetch()形式,但是问题是这个函数实现的有残缺,当没有数据来临时,这个函数就会“死等”,这和我们程序实现的思想是向冲突的,故而必须从底层入手,抛弃原来的函数,自己封装一个符合自己需要的取数据函数,基本思想是查询和中断相结合,程序直接读取底层寄存器的标志位,然后从寄存器FIFO中去读取数据,由于处理器实现的不通,可能其中需要屏蔽中断、改变工作模式等操作,这个实现的具体细节,需参考处理器的技术手册。
二、资料传送方式
根据资料传送方向的不同有以下三种方式。如图5-2所示。
单工方式 半双工方式 全双工方式
图5-2 资料传送方式
1. 单工方式:资料始终是从A设备发向B设备。
2. 半双工方式:资料能从A设备传送到B设备,也能从B设备传送到A设备。在任何时候资料都不能同时在两个方向上传送,即每次只能有一个设备发送,另一个设备接收。但是通讯双方依照一定的通讯协议来轮流地进行发送和接收。
3. 全双工方式:允许通信双方同时进行发送和接收。这时,A设备在发送的同时也可以接收,B设备亦同。全双工方式相当于把两个方向相反的单工方式组合在一起,因此它需要两条数据传输线。在计算机串行通讯中主要使用半双工和全双工方式。
三、串行接口标准
串行接口标准:指的是计算机或终端(资料终端设备DTE)的串行接口电路与调制解调器MODEM等(数据通信设备DCE)之间的连接标准。
RS-232C标准
RS-232C是一种标准接口,D型插座,采用25芯引脚或9芯引脚的连接器,如图所示。
微型计算机之间的串行通信就是按照RS-232C标准设计的接口电路实现的。如果使用一根电话线进行通信,那幺计算机和MODEM之间的联机就是根据RS-232C标准连接的。其连接及通信原理如图所示
RS232信号定义
RS-232C标准规定接口有25根联机。只有以下9个信号经常使用.
引脚和功能分别如下:
Ø (第2脚):TXD发送资料线,输出。发送资料到MODEM。
Ø (第3脚):RXD接收资料线,输入。接收资料到计算机或终端。
Ø (第4脚):请求发送,输出。计算机通过此引脚通知MODEM,要求发送资料。
Ø (第5脚):允许发送,输入。发出 作为对 的回答,计算机才可以进行发送资料。
Ø (第6脚):资料装置就绪(即MODEM准备好),输入。表示调制解调器可以使用,该信号有时直接接到电源上,这样当设备连通时即有效。
Ø (第8脚):CD载波检测(接收线信号测定器),输入。表示MODEM已与电话线路连接好。
如果通信线路是交换电话的一部分,则至少还需如下两个信号:
Ø (第22脚):RI振铃指示,输入。MODEM若接到交换台送来的振铃呼叫信号,就发出该信号来通知计算机或终端。
Ø (第20脚):资料终端就绪,输出。计算机收到RI信号以后,就发出 信号到MODEM作为回答,以控制它的转换设备,建立通信链路。
Ø (第7脚):GND信号地
逻辑电平
RS-232C标准采用EIA电平,规定:
“1”的逻辑电平在-3V~-15v之间;“0”的逻辑电平在+3V~+15V之间。
由于EIA电平与TTL电平完全不同,必须进行相应的电平转换,MCl488完成TTL电平到EIA电平的转换,MCl489完成EIA电平到ITL电平的转换。还有MAX232可以同时完成TTL->EIA和EIA->TTL的电平转换。
Uart工作原理:
数据通信方式为:并行通信与串行通信两种:
§并行通信:利用多条数据线将数据的各位同时传送。
它的特点是:传输速度快,是用于短距离通信;
§串行通信:利用一条数据线将数据一位位地顺序传送。
特点是通信线路简单,利用简单的线缆就实现通信,低成本,是用于远距离通信。
异步通信:
ª异步通信:以一个字符为传输单位,通过两个字符间的时间间隔是不固定的,然而同一字符中的两个相邻位之间的时间间隔是固定的。
ª通信协议:是指通信双方约定的一些规则。在异步通讯时,对数据格式有如下约定:规定有空闲位、起始位、资料位、奇偶校验位、停止位。
起始位:先发一个逻辑“0”信号,表示传输字符的开始;
数据位:紧接在起始位之后。数据位的个数可以是4、5、6、7、8等,从最低位开始传送,靠时钟定位。
奇偶校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或(奇校验),以此校验数据传送的正确性。
停止位:它是一个字符数据的结束标志。
空闲位:处于逻辑“1”状态,表示当前线路没有数据传送。
波特率:
是衡量数据传送率的指标:记录每秒中传送的二进制位数。例如:数据传送速率为120字符、每秒。而每一个字符为10位,则其传送的波特率为10*120=1200位/秒=1200波特率
UART基本原理
通用异步收发器,简称UART,即“Universal Asynchronous Receiver Transmitter”,它用来传输串行数据;
发送数据时:
CPU将并行数据写入UART,UART按照一定的格式在一根电线上串行发出;
接收数据时:
UART检测另一根电线上的信号,将串行数据放在缓冲区中,CPU可读取UART获得的这些数据。
UART驱动程序设计
UART初始化:1.发送数据;2.接收数据;
UART初始化:1.设置波特率; 2.设置数据传输格式;3.选择通道工作模式;
一.设置波特率:(UBRDIV)
在s3c2440中,通过UBRDIV(p352)寄存器可以设定UART的波特率。Uart0、Uart1、Uart2分别对应UBRDIV0,UBRDIV1、UBRDIV2
到底UBRDIV寄存器中的值与波特率有何关系?
UBRDIV=(int)(UART clock / (buad rate *16))-1
(UART clock:PCLK or FCLK/ n or UEXTCLK)
如波特率为115200bps,UART时钟为40MHZ
UBRDIV =(int) (40MHZ /(115200*16))-1
二.设置数据传输格式(ULCON)
在s3c2440中,通过ULCON(page341),可以设置传输格式(有多少个数据位、是否使用校验位、是奇校验还是偶校验,有多少个停止位、是否使用流量控制)
Uart0、Uart1、Uart2分别对应ULCON0、ULCON1、ULCON2.
三.设置通道工作模式(UCON)
在s3c2440中,通过UCON(page342),可以设置UART通道的工作模式,(中断模式、查询模式、或DMA模式)
Uart0、Uart1、Uart2分别对应UCON0、UCON1、UCON2.
这三步都属于初始化:初始化完成之后à发送或/接收数据
发送数据:
将要发送的数据写UTXHn, UART会将保存到缓冲区中,并自动发出去。
UTXH0、UTXH1、UTXH2
接收数据:
当UART收到数据时(UTRSTATn寄存器bit[0]被置1),CPU读取URXHn寄存器,即可获得数据。
URXH0、URXH1、URXH2寄存器中读取数据
Main.c
#define GLOBAL_CLK 1
#include
#include
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "mmu.h"
#include "profile.h"
#include "memtest.h"
static void cal_cpu_bus_clk(void);
void Set_Clk(void);
/*************************************************
Function name: delay
Parameter : times
Description :延时函数
Return : void
Argument : void
Autor & date : Daniel
**************************************************/
void delay(int times)
{
int i,j;
for(i=0;i>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3); //set the register--rMPLLCON
ChangeClockDivider(key, 12); //the result of rCLKDIVN [0:1:0:1] 3-0 bit
cal_cpu_bus_clk(); //HCLK=100M PCLK=50M
}
/*************************************************
Function name: cal_cpu_bus_clk
Parameter : void
Description : 设置PCLK\HCLK\FCLK的频率
Return : void
Argument : void
Autor & date : Daniel
**************************************************/
static void cal_cpu_bus_clk(void)
{
static U32 cpu_freq;
static U32 UPLL;
U32 val;
U8 m, p, s;
val = rMPLLCON;
m = (val>>12)&0xff;
p = (val>>4)&0x3f;
s = val&3;
//(m+8)*FIN*2不要超出32位数!
FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<>1)&3;
p = val&1;
val = rCAMDIVN;
s = val>>8;
switch (m) {
case 0:
HCLK = FCLK;
break;
case 1:
HCLK = FCLK>>1;
break;
case 2:
if(s&2)
HCLK = FCLK>>3;
else
HCLK = FCLK>>2;
break;
case 3:
if(s&1)
HCLK = FCLK/6;
else
HCLK = FCLK/3;
break;
}
if(p)
PCLK = HCLK>>1;
else
PCLK = HCLK;
if(s&0x10)
cpu_freq = HCLK;
else
cpu_freq = FCLK;
val = rUPLLCON;
m = (val>>12)&0xff;
p = (val>>4)&0x3f;
s = val&3;
UPLL = ((m+8)*FIN)/((p+2)*(1<>1):UPLL;
}
2440lib.c
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include
#include
#include
#include
#include
static int whichUart=0;
void Port_Init0(void) //IO端口初始化
{
//*** PORT H GROUP
//Ports : GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1 GPH0 //Signal : CLKOUT1 CLKOUT0 UCLK nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0
//Binary : 10 , 10 10 , 11 11 , 10 10 , 10 10 , 10 10
rGPHCON = 0x00faaa;
rGPHUP = 0x7ff; // The pull up function is disabled GPH[10:0]
}
void Uart_Init(int pclk,int baud)
{
int i;
if(pclk == 0)
pclk = PCLK;
rUFCON0 = 0x0; //UART channel 0 FIFO control register, FIFO disable
rUMCON0 = 0x0; //UART chaneel 0 MODEM control register, AFC disable(AFC:流量控制)
//UART0
rULCON0 = 0x3; //Line control register : Normal,No parity,1 stop,8 bits
// [10] [9] [8] [7] [6] [5] [4] [3:2] [1:0]
// Clock Sel, Tx Int, Rx Int, Rx Time Out, Rx err, Loop-back, Send break, Transmit Mode, Receive Mode
// 0 1 0 , 0 1 0 0 , 01 01
// PCLK Level Pulse Disable Generate Normal Normal Interrupt or Polling
rUCON0 = 0x245; // Control register
rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 ); //Baud rate divisior register 0
for(i=0;i<100;i++);
}
//===================================================================
void Uart_Select(int ch)
{
whichUart = ch;
}
//=====================================================================
void Uart_SendByte(int data)
{
if(whichUart==0)
{
if(data=='\n')
{
while(!(rUTRSTAT0 & 0x2));
// Delay(1); //because the slow response of hyper_terminal
WrUTXH0('\r');
}
while(!(rUTRSTAT0 & 0x2)); //不为换行符时,Wait until THR is empty.
// Delay(1);
WrUTXH0(data);//往寄存器写数据
}
else if(whichUart==1)
{
if(data=='\n')
{
while(!(rUTRSTAT1 & 0x2));
//Delay(1); //because the slow response of hyper_terminal
rUTXH1 = '\r';
}
while(!(rUTRSTAT1 & 0x2)); //Wait until THR is empty.
//Delay(1);
rUTXH1 = data;
}
else if(whichUart==2)
{
if(data=='\n')
{
while(!(rUTRSTAT2 & 0x2));
//Delay(1); //because the slow response of hyper_terminal
rUTXH2 = '\r';
}
while(!(rUTRSTAT2 & 0x2)); //Wait until THR is empty.
//Delay(1);
rUTXH2 = data;
}
}
//====================================================================
void Uart_SendString(char *pt)
{
while(*pt)
Uart_SendByte(*pt++);
}
//=====================================================================
//If you don't use vsprintf(), the code size is reduced very much.
void Uart_Printf(char *fmt,...)
{
va_list ap;
char string[256];
va_start(ap,fmt);//va_start、 va_end成对出现,ap指向fmt之后的参数
vsprintf(string,fmt,ap);//把ap之后的参数拷贝进string
Uart_SendString(string);
va_end(ap);
}
中断方式,串口发送: