Uart工作原理:
可编程发送数据帧。由1 个起始位、5 至8 位数据位、1 个可选奇偶校验位以及1 至2 个停止位组成,是由行
控制寄存器(ULCONn)指定。发送器也可以产生单帧发送期间强制串行输出为逻辑0 状态的断点状态。此模块在
完成发送当前发送字后发送断点信号。在发出断点信号后,其不断发送数据到Tx FIFO(非FIFO 模式情况下Tx
保持寄存器)中。
数据接收
与发送类似,接收数据帧也是可编程的。由1 个起始位、5 至8 位数据位、1 个可选奇偶校验位以及1 至2 个
停止位组成,是由行控制寄存器(ULCONn)指定。接收器能够检测出溢出(overrun)错误、奇偶校验错误、帧
错误和断点状态,每个都可以设置一个错误标志。
– 溢出错误表明新数据在读出旧数据前覆盖了旧数据。
– 奇偶校验错误表明接收器检测出一个非预期奇偶校验字段。
– 帧错误表明接收到的数据没有有效的结束位。
– 断点状态表明RxDn 的输入保持为逻辑0 状态的时间长于单帧传输时间。
当其在3 字时间期间(此间隔在字宽位的设置随后)并且在FIFO 模式中Rx FIFO 为非空时不接收任何数据时
发生接收超时状态。
每个UART 的波特率发生器为发送器和接受器提供串行时钟。波特率发生器的源时钟可以选择S3C2440A 的
内部系统时钟或UEXTCLK。换句话说,分频由设置UCONn 的时钟选项选择。波特率时钟是通过16 和由UART
波特率分频寄存器(UBRDIVn)指定的16 位分频系数来分频源时钟(PCLK,FCLK/n 或UEXTCLK)产生的。
UBRDIVn 由下列表达式决定:
UBRDIVn = (int)( UART 时钟 / ( 波特率 × 16) ) - 1
(UART 时钟:PCLK,FCLK/n 或UEXTCLK)
当然,UBRDIVn 应该是从1 至(216-1),只有在使用小于PCLK 的UEXTCLK 时设置为0(旁路模式)。
例如,如果波特率为115200 bps 并且UART 时钟为40 MHz,则UBRDIVn 为:
UBRDIVn = (int)(40000000 / (115200 x 16) ) - 1
= (int)(21.7) - 1 [取最接近的整数]
= 22 - 1 = 21
该寄存器的位6决定是否使用红外模式,位5、位4和位3决定校验方式,位2决定停止位长度,位1和位0决定每帧的数据位数。具体如下:
ULCONn[7]
ULCONn[6]
ULCONn[5:3]
ULCONn[2]
ULCONn[1:0]
UART控制寄存器UCONn
该寄存器决定UART的各种模式。
UCONn[10]
UCONn[9]
CONn[8]
UCONn[7]
UCONn[6}
UCONn[5]
UCONn[4]
UCONn[3:2]
UCONn[1:0]
UART FIFO控制寄存器UFCONn
UFCONn[7:6]
UFCONn[5:4]
UFCONn[3]
UFCONn[2]
UFCONn[1]
UFCONn[0]
UART MODEM控制寄存器UMCONn
UMCONn[7:5]
UMCONn[4]
UMCONn[3]
UMCONn[0]
发送寄存器UTXH和接收寄存器URXH
这两个寄存器存放发送和接收的数据,当然只有1字节(8位数据)。需要注意的是,在发生溢出错误时,接收的数据必须被读出来,否则会引发下次溢出错误。
发送和接收状态寄存器UTRSTATn
UTRSTATn发送和接收状态寄存器包括 UTRSTAT0, UTRSTAT1 and UTRSTAT2
UTRSTATn 寄存器各位定义:
UTRSTATn [2]
1=发送器空
UTRSTATn [1] 发送缓冲器空标志
0 =不空;
1 = 空。
UTRSTATn [0] 接收缓冲器有接收数据标志
0 =空;
1 = 接收缓冲器有数据。
{
int i;
int Scom=0;
Set_Clk(); //uart涉及到外设总线 bus频率
//收发寄存器IO初始化
rGPHCON = 0xa0; //TXD[0]输出 RXD[0]接收
rGPHUP = 0x7ff; //禁止上拉电阻
beep_init();
Uart_Init(0,115200);
Uart_Select(Scom);
for(i=0;i<10;i++)
Uart_Printf("\n hello \n");
}
{
int i;
if(pclk == 0)
pclk = PCLK;
rUFCON0 = 0x0; //不使用FIFO
rUMCON0 = 0x0; //不连接外部调制解调器
rULCON0 = 0x3; //行控制 正常 无校验 一个停止位 8位数据
[10] [9] [8] [7] [6] [5] [4] [3:2] [1:0]
时钟频率, 发送触发, 接收触发, 接收超时中断,接收错误中断, 回环模式, 发出断点信号, 发送模式, 接收模式
0 1 0 , 0 1 0 0 , 01 01
PCLK 电平 脉冲 禁止 产生 正常 正常 中断或查询 中断或查询
rUCON0 = 0x245; //控制寄存器
rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 ); //波特率
// 写成16./baud的话就变成浮点型和整形做运算,结果是浮点型,小数部分被保留。
//+0.5以后,原变量小数部分>=0.5的时候进位,达到四舍五入的效果
for(i=0;i<100;i++); //这个是为了使设定稳定下来
}
{ //(多个可变参数组成一个列表,后面有专门的指针指向他)
va_list ap; //初始化指向可变参数列表的指针 宏定义在stdarg.h中
char string[256];
va_start(ap,fmt); //将第一个可变参数的地址付给ap,即ap指向可变参数列表的开始
vsprintf(string,fmt,ap);//将参数fmt、ap指向的可变参数一起转换成格式化字符串,
//放string数组中,其作用同 sprintf(),只是参数类型不同
Uart_SendString(string); //把格式化字符串从开发板串口送出去
va_end(ap); //ap付值为0,没什么实际用处,主要是为程序健壮性
}
(1)格式化字符串 printf(“%d\n”,x);
printf把printf(“%d\n”,x)翻译成电脑认识的字符
(2)vsprintf(char *string, char *format, va_list param);类似printf
从第二个参数开始与printf是一样的,只是sprintf是输出到指定数组中,printf是输出到屏幕
(一个标准输出文件),因而sprintf多了char *string这参数。
(3)[转]va_start va_arg va_end 的使用和原理
stdarg.h中查到如下宏定义:
typedef int *va_list[1];//va_list 变量类型定义
#define va_start(ap, parmN) (void)(*(ap) = __va_start(parmN))
#define va_arg(ap, type) __va_arg(*(ap), type)//取可变参数的内容
#define va_end(ap) ((void)(*(ap) = 0))
◎用法:
func( Type para1, Type para2, Type para3, ... )
{
/****** Step 1 ******/
va_list ap;
va_start( ap, para3 ); //一定要“...”之前的那个参数
/****** Step 2 ******/
//此时ap指向第一个可变参数
//调用va_arg取得里面的值
Type xx = va_arg( ap, Type );
//Type一定要相同,如:
//char *p = va_arg( ap, char *);
//int i = va_arg( ap, int );
//如果有多个参数继续调用va_arg,ap会自动变化(一般是自增)
/****** Step 3 ******/
va_end(ap); //For robust!
}
{
while(*pt)
Uart_SendByte(*pt++); 从第一个字符开始依次发送
}
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)); //等待,直到发送状态寄存器显示为空
//Delay(1);
WrUTXH0(data); //把数据写入发送寄存器
}
}