该文章部分参考http://blog.csdn.net/yx_l128125/article/details/7703653
一、uart原理简介
数据通信方式为:并行通信与串行通信两种:
§并行通信:利用多条数据线将数据的各位同时传送。
它的特点是:传输速度快,是用于短距离通信;
§串行通信:利用一条数据线将数据一位位地顺序传送。
特点是通信线路简单,利用简单的线缆就实现通信,低成本,是用于远距离通信。
异步通信:
ª异步通信:以一个字符为传输单位,通过两个字符间的时间间隔是不固定的,然而同一字符中的两个相邻位之间的时间间隔是固定的。
ª通信协议:是指通信双方约定的一些规则。在异步通讯时,对数据格式有如下约定:规定有空闲位、起始位、资料位、奇偶校验位、停止位。
起始位:先发一个逻辑“0”信号,表示传输字符的开始;
数据位:紧接在起始位之后。数据位的个数可以是4、5、6、7、8等,从最低位开始传送,靠时钟定位。
奇偶校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或(奇校验),以此校验数据传送的正确性。
停止位:它是一个字符数据的结束标志。
空闲位:处于逻辑“1”状态,表示当前线路没有数据传送。
UART:Universal Asynchronous Receiver/Transmitter(通用异步收发送器),用来传输串行数据,发送数据时,CPU将并行数据写入UART,UART按照一定格式在TxD线上串行发出;接收数据时,UART检测到RxD线上的信号,将串行收集放到缓冲区中,CPU即可读取UART获得的这些数据。
UART最精简的连线形式只有3根线,TXD用于发送,RXD用于接收,GND用于提供参考电平。UART之间以帧作为数据传输单位,帧由具有完整意义的若干位组成,它包含开始位、数据位、校验位和停止位。发送数据之前,互相通信的UART之间要约定好数据传输速率(波特率的倒数)、数据的传输格式(多少个数据位、是否使用校验位、奇校验还是偶校验、多少个停止位)。
二、s3c2440 uart特性
S3C2440的通用异步收发器(UART)配有3个独立异步串行I/O(SIO)端口,每个都可以通过产生中断或DMA请求(及查询)来进行CPU和UART之间的数据传输。如下图所示:每个UART包含一个波特率发生器、发送器、接收器和一个控制单元。
波特率发生器可以由PCLK、FCLK/n或UEXTCLK(外部输入时钟)时钟驱动。UART通过使用系统时钟可以支持最115.2Kbps的比特率。如果是使用外部器件提供UEXTCLK的UART,则UART可以运行在更高的速度。发送器和接收器各包含一个64字节的FIFO和数据移位器。
发送数据:1、将外设总线的数据写入到发送缓冲区(缓冲区由控制单元中UFCONn控制寄存器设置:FIFO模式或非FIFO模式)
2、将发送缓冲区数据复制到8bit的发送移位器中。若非FIFO模式,操作一次即可;而FIFO模式根据存储深度决定。
3、波特率发生器提供将数据从发送数据引脚(TXDn)移出的移位时钟。
接收数据同发送数据相似。从接收数据引脚(RXDn)移入收到的数据,接着从移位器复制到FIFO。
波特率发生器
每个UART的波特率发生器为发送器和接收器提供串行时钟,波特率发生器的时钟源可以选择S3C2440A的内部时钟系统或者UEXTCLK。波特率时钟是通过16和由UART波特率分频寄存器(UBRDIVn)指定的16位分频系数来分频源时钟(PCLK,FCLK/n或者UEXTCLK)产生的,UBRDIVn由下列表达式确定:
UBRDIVn=(int)(UART时钟/(波特率*16))-1
UART时钟:PCLK,FCLK/n或者UEXTCLK,例如,如果波特率为115200bps并且UART时钟为25MHz,则UBRDIVn为:
UBRDIVn=(int)(25000000/(115200*16))-1=(int)(13.5)-1(取最接近的整数)=14-1=13
三、s3c2440 uart应用
我用的开发板是天祥的TX2440,电路连接如图所示:
介绍发送和接收操作之前,先介绍几个重要的寄存器
UBRDIVn寄存器:设置波特率,UART的时钟源有两种选择:PCLK、UEXTCLK、FCLK/n,其中n的值通过UCON0-UCON2联合设置
ULCONn寄存器:设置传输格式
UCONn寄存器:它用于选择UART时钟源、设置UART中断方式
UFCONn寄存器:用于设置是否使用FIFO,设置各FIFO的触发阙值,即发送FIFO中有多少个数据时产生中断、接收FIFO中有多少个数据时产生中断。并可以通过设置UFCONn寄存器来复位各个FIFO。读取UFSTATn寄存器可以知道各个FIFO是否已经满,其中有多少个数据。
UMCONn寄存器:用于流量控制
UTRSTATn寄存器:表明数据是否已经发送完毕、是否已经接收到数据UERSTATn寄存器,用来表示各种错误是否发生
UTXHn寄存器,CPU将数据写入这个寄存器,UART即会将它保存到缓冲区中,并自动发送出去
URXHn寄存器,当UART接收到数据时,CPU读取这个寄存器,即可获得数据。
对于S3C2440,使用UART之前,首选需要对2440的UART模块进行初始化,
1、uart对应IO端口设置
2、传输帧格式设置(如数据位、停止位、基偶校验位等)
3、传输协议设置(是否FIFO,中断等)
4、波特率生成设置/*1、uart对应IO端口设置*/ rGPHCON = rGPHCON & (~(0xffff)); //UART0: RXD0<==>GPH3 TXD0<==>GPH2 rGPHCON = rGPHCON | (0xaaa0) ; //设置GPH端口为UART口,详情见S3C2440手册输入输出端口 rGPHUP = 0x0; //使能上拉功能 /*2、传输帧格式设置*/ rULCON0=0x03; //不采用红外线传输模式,无奇偶校验位,1个停止位,8个数据位 /*3、传输协议设置*/ rUFCON0=0x00; // 不使用FIFO rUMCON0=0x00; //不使用自动流控制 rUCON0=0x245; //发送中断为电平方式,接收中断为边沿方式,禁止超时中断,允许产生错误状态中断,禁止回送模式,禁止中止 //信号,传输模式为中断请求模式,接收模式也为中断请求模式。 /*4、波特率生成设置*/ rUBRDIV0=( (int)(pclk/16/baud+0.5) -1 ); //根据波特率计算UBRDIV0的值
四、uart程序
//=========================================================================
// 工程名称: UART.mcp
// 文件名称: main.c
// 功能描述: 通过超级终端完成PC和S3C2440的数据传输,利用超级终端输入需要发送的字符,回车后,字符会再发送回来显示。
// 1、通过串口0、1发送和接收单个字节
// 2、通过串口0、1发送和接收字符串
// 组成文件: main.c 2440lib.c 2440init.s 2440slib.s
// 头文件: 2440addr.h def.h option.h 2440lib.h 2440slib.h
// 程序分析:
// 硬件连接: 用串口线将开发板和PC机串口相连
// 维护记录: 2011年4月7日
//
//
//=========================================================================
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "option.h"
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
//====================================================
// 函数定义区
//====================================================
extern void Delay(int time);
void myUart_Select(int ch);
void myUart_Init(int whichuart, int baud);
void myUart_SendByte(char ch);
char myUart_ReceiveByte(void);
void myUart_Send (char *str);
void myUart_receive(char *string);
void myUart_Printf(char *fmt,...);
extern unsigned int PCLK;
static int UartNum=0;
char *string;
//====================================================
// 语法格式:int Main(void)
// 功能描述: 发送并接收字符串,测试UART通信
// 入口参数: 字符串指针
// 出口参数: 无
//======================================================================
int Main(void)
{
SetSysFclk(FCLK_400M);//FCLK_400M=((92<<12)|(1<<4)|1),MPLL=2*(92+8)*12M/((1+2)*2)=400M
//电源工作模式默认NORMAL,FCLK=MPLL
ChangeClockDivider(2, 1);//设置FCLK HCLK PCLK 分频比1:8:16
CalcBusClk();//启动总线
myUart_Select(0);//UART的端口选择,0--选择UART0,1--选择UART1 (只可以选择UART0和UART1)
myUart_Init(0,115200);
while(1)
{
Delay(500);
//myUart_Printf("Please Input a string:\n");
myUart_Send("Please Input a string:\n");//myUart_Printf与myUart_Send功能相同。
myUart_receive(string);
//myUart_Printf("hailin\n");
//myUart_SendByte(0x35);
Delay(500);
myUart_Send(string);
myUart_Send("\n");
}
}
void myUart_Select(int ch)//UART的端口选择,UartNum定义成全局变量
{
UartNum = ch;
}
//====================================================
// 语法格式:void myUart_Init(int whichuart, int baud)
// 功能描述: 对Uart进行初始化,以所需要的波特率为输入参数
// 入口参数: UART端口号 波特率
// 出口参数: 无
//======================================================================
void myUart_Init(int pclk, int baud)
{
if (pclk == 0)
pclk = PCLK;
if(UartNum == 0) //判断是否使用UART0
{
/*1、uart对应IO端口设置*/
rGPHCON = rGPHCON & (~(0xffff)); //UART0: RXD0<==>GPH3 TXD0<==>GPH2
rGPHCON = rGPHCON | (0xaaa0) ; //设置GPH端口为UART口,详情见S3C2440手册输入输出端口
rGPHUP = 0x0; //使能上拉功能
/*2、传输帧格式设置*/
rULCON0=0x03; //不采用红外线传输模式,无奇偶校验位,1个停止位,8个数据位
/*3、传输协议设置*/
rUFCON0=0x00; // 不使用FIFO
rUMCON0=0x00; //不使用自动流控制
rUCON0=0x245; //发送中断为电平方式,接收中断为边沿方式,禁止超时中断,允许产生错误状态中断,禁止回送模式,禁止中止
//信号,传输模式为中断请求模式,接收模式也为中断请求模式。
/*4、波特率生成设置*/
rUBRDIV0=( (int)(pclk/16/baud+0.5) -1 ); //根据波特率计算UBRDIV0的值,通过加上0.5,提高精度。
Delay(10);
}
else if(UartNum == 1)
{
rGPHCON = rGPHCON & (~(0xffff)) ; //UART1: RXD1<==>GPH5 TXD1<==>GPH4
rGPHCON = rGPHCON | (0xaaa0) ; //设置GPH端口为UART口
rGPHUP = 0x0; // 使能上拉功能
rULCON1=0x3;
rUFCON1=0x0;
rUMCON1=0x0;
rUCON1=0x245;
rUBRDIV1=( (int)(pclk/16./baud+0.5) -1 );
Delay(10);
}
}
//====================================================
// 语法格式:void myUart_SendByte(char ch)
// 功能描述: 发送字节数据
// 入口参数: 发送的字节数据
// 出口参数: 无
//====================================================================
void myUart_SendByte(char ch)
{
if (UartNum ==0)
{
if(ch=='\n')//判断发送的字符是不是'\n'(换行)
{
while(!(rUTRSTAT0 & 0x2)); //等待,直到发送缓冲区为空
// Delay(10); //超级中断的响应速度较慢
WrUTXH0('\r'); //发送回车符
}
//如果发送的字符不是'\n'(换行)
while(!(rUTRSTAT0 & 0x2)); //等待,直到发送缓冲区为空
// Delay(10);
WrUTXH0(ch); //发送字符
}
else //使用UART1
{
if(ch=='\n')//判断发送的字符是不是'\n'(换行)
{
while(!(rUTRSTAT1 & 0x2)); //等待,直到发送缓冲区为空
// Delay(10); //等待
rUTXH1='\r';
}
while(!(rUTRSTAT1 & 0x2)); //Wait until THR is empty.
// Delay(10);
WrUTXH1(ch);
}
}
//====================================================
// 语法格式:char myUart_ReceiveByte(void)
// 功能描述: 接收字节数据
// 入口参数: 无
// 出口参数: 接收的字节数据
//====================================================================
char myUart_ReceiveByte(void)
{
if(UartNum==0)
{
while(!(rUTRSTAT0 & 0x1)); //判断接收缓冲区是否有有效数据,有数据时UTRSTAT0.1=1
//等待接收数据
return RdURXH0();
}
else if(UartNum==1)
{
while(!(rUTRSTAT1 & 0x1)); //等待接收数据
return RdURXH1();
}
return 0;
}
//====================================================
// 语法格式:void myUart_Send (char *str)
// 功能描述: 发送字符串
// 入口参数: 字符串指针
// 出口参数: 无
//====================================================================
void myUart_Send (char *str)
{
myUart_Init(0,115200);//每次发送字符串时,都初始化串口UART
while (*str)//发送字符串,直到字符串的结束符‘0’(对应ASCII的0,即空操作),停止发送字符
myUart_SendByte(*str++);//*str++ 1、先发送指针*str指向字符
// 2、指针str=str+1,指向下个字符
}
//====================================================
// 语法格式:void myUart_receive(char *string)
// 功能描述: 接收字符串
// 入口参数: 字符串指针
// 出口参数: 无
//===================================================================
void myUart_receive(char *string)
{
char *string2 ;
char c;
string2 = string;
myUart_Init(0,115200);
while((c = myUart_ReceiveByte())!='\r')//'\r'--回车,当有回车按下,表示字符串输入结束
{
if(c=='\b')//'\b'--退格,当有TAB键按下,在SecureCRT显示退格
{
if( (int)string2 < (int)string )
{
printf("\b \b");
string--;
}
}
else
{
*string++ = c;
myUart_SendByte(c);
}
}
*string='\0';
myUart_SendByte('\n');
}
void myUart_Printf(char *fmt,...)
{
va_list ap;
char string[256];
va_start(ap,fmt);
vsprintf(string,fmt,ap);
myUart_Send(string);
va_end(ap);
}
原计划:通过逻辑分析仪监测2440与PC机的uart通信,但是uart采用RS232模式,只支持点对点,不支持一对多。所以无法实现监测。目前通过监测2440的TXD对应的RS232发送端,了解数据发送过程。
在main()执行下面程
myUart_Printf("hailin\n");
myUart_SendByte(0x35);
利用逻辑分析仪查看2440的TXR端 的波形如下:(监测到发送端与程序一致。)
通道0设置如下:
五、uart传输分析
uart传输格式:1起始位 +8位数据位+1位停止位。RS232逻辑是负逻辑,即+12V为逻辑0,-12V为逻辑1;而2440的uart逻辑是正逻辑。而下图是2440的TXD端经过max3232芯片转换为RS232负逻辑,即显示逻辑0实质是2440发送的逻辑1。
2440发送0x68(即h)数据,发送顺序:以字节形式先LSB发送后MSB发送。发送数据0001,0110 。