uart

  http://www.360doc.com/content/11/1022/09/7906690_158136472.shtml

 

Uart工作原理:

数据通信方式为:并行通信与串行通信两种:
§并行通信:利用多条数据线将数据的各位同时传送。
它的特点是:传输速度快,是用于短距离通信;
§串行通信:利用一条数据线将数据一位位地顺序传送。
特点是通信线路简单,利用简单的线缆就实现通信,低成本,是用于远距离通信。
 
异步通信:
ª异步通信:以一个字符为传输单位,通过两个字符间的时间间隔是不固定的,然而同一字符中的两个相邻位之间的时间间隔是固定的。
ª通信协议:是指通信双方约定的一些规则。在异步通讯时,对数据格式有如下约定:规定有空闲位、起始位、资料位、奇偶校验位、停止位。

 

 

 

 

一.设置波特率:(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寄存器中读取数据

 

 

数据发送
可编程发送数据帧。由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
UART行控制寄存器:

该寄存器的位6决定是否使用红外模式,位5、位4和位3决定校验方式,位2决定停止位长度,位1和位0决定每帧的数据位数。具体如下:

ULCONn[7]     保留;

ULCONn[6]     红外线模式,0:正常模式;1:红外线模式;

ULCONn[5:3]  校验模式,0xx:无校验;100:奇校验;101:偶校验;

ULCONn[2]     停止位,0:一个停止位;1:二个停止位;

ULCONn[1:0]  数据位,00:5位;01:6位;10:7位;11:8位。

UART控制寄存器UCONn

该寄存器决定UART的各种模式。

UCONn[10]    1:ULK做波特率发生器;0:PLK做波特率发生器。

UCONn[9]     1:Tx中断电平触发;0:Tx中断脉冲触发。

CONn[8]     1:Rx中断电平触发;0:Rx中断脉冲触发。

UCONn[7]     1:接收超时中断允许;0:接收超时中断禁止。

UCONn[6}     1:产生接收错误中断;0:不产生接收错误中断。

UCONn[5]     l:发送直接传给接收方式(loopback);0:正常模式。

UCONn[4]     1:发送间断信号;0:正常模式发送。

UCONn[3:2]    发送模式选择:

             00:禁止发送;

             01:中断或查询模式;

             10:DMA0请求(UART0 ) , DMA3请求(UART2);

             11:DMAl请求(UART1)。

UCONn[1:0]  接收模式选择。

             00:禁止接收;

             01:中断或查询模式;

             10 : DMA0请求UART0,DMA2请求UART2;

             11:DMAl请求UART1。

UART FIFO控制寄存器UFCONn

UFCONn[7:6]

     00:Tx FIFO寄存器中有0字节就触发中断;

     01:Tx FIFO寄存器中有4字节就触发中断;

     10:Tx FIFO寄存器中有8字节就触发中断;

     11:Tx FIFO寄存器中有12字节就触发中断。

UFCONn[5:4]

     00:Rx FIFO寄存器中有4字节就触发中断;

     01:Rx FIFO寄存器中有8字节就触发中断;

     10:Rx FIFO寄存器中有12字节就触发中断;

     11:Rx FIFO寄存器中有16字节就触发中断。

UFCONn[3]  保留。

UFCONn[2]  1: FIFO复位清零Tx FIFO;0 : FIFO复位不清零TxFIFO。

UFCONn[1]  1:  FIFO复位清零Rx FIFO;0:F1FO复位不清零RxFIFO。

UFCONn[0]  1:允许FIFO功能;0:禁止FIFO功能。

UART MODEM控制寄存器UMCONn

UMCONn[7:5]  保留,必须全为0。

UMCONn[4]    1:允许使用AFC模式;0:禁止使用AFC模式。

UMCONn[3]    保留,必须全为0。

UMCONn[0]    1:激活rRTS;0:不激活rRTS。

发送寄存器UTXH和接收寄存器URXH

这两个寄存器存放发送和接收的数据,当然只有1字节(8位数据)。需要注意的是,在发生溢出错误时,接收的数据必须被读出来,否则会引发下次溢出错误。

发送和接收状态寄存器UTRSTATn

UTRSTATn发送和接收状态寄存器包括 UTRSTAT0, UTRSTAT1 and UTRSTAT2

UTRSTATn 寄存器各位定义:

UTRSTATn [2]

1=发送器空

UTRSTATn [1] 发送缓冲器空标志

0 =不空;

1 = 空。

UTRSTATn [0] 接收缓冲器有接收数据标志

0 =空;

1 = 接收缓冲器有数据。 

void Main( void)
{    
     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 ");
}

 

 

void Uart_Init( int pclk, int baud)
{
     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++);    // 这个是为了使设定稳定下来

} 

 

void Uart_Printf( char *fmt,...)   // ...表示 可变参数 ,不限定个数和类型
{                                 // (多个可变参数 组成一个列表 ,后面有专门的指针指向他)
    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 * stringchar *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!

} 

 

void Uart_SendString( char *pt)
{
     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);  // 把数据写入发送寄存器
    }

} 

转载于:https://www.cnblogs.com/liuchengchuxiao/p/4179538.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值