zoukankan      html  css  js  c++  java
  • s3c2440串口详解

    一、UART原理说明

    通用异步收发器简称UART(Universal Asynchronous Receiver/Transmitter),它用来传输串行数据:发送数据时,CPU将并行数据写入UART,UART按照一定的格式在一根电线上串行发出;接收数据时,UART检测另一根电线上的信号,将串行数据收集放在缓冲区中,CPU就可以读取UART获得这些数据。串口之间以全双工方式传输数据,最精简的连线只有三根线:TxD用于发送数据,RxD用于接收数据,Gnd用于给双方提供参考电平,连线如下图:


    UART使用标准的TTL/CMOS逻辑电平(0-5V、0-3.3V、0-2.5V、0-1.8V)来表示数据,高电平表示1,低电平表示0。为了增强数据的抗干扰能力、提高传输长度,通常将TTL/CMOS逻辑电平转换为RS232逻辑电平,3-12V表示0,-3--12V表示1。

    TxD、RxD数据线以‘位’为最小单位传输数据。帧由具体完整意义的、不可分割的若干位组成,它包含开始位、数据位、校验位、停止位。发送数据之前UART之间要约定好数据的传输速率(每位所占用的时间,其倒数称为波特率)、数据的传输格式(有多少数据位、是否使用校验位、是奇校验还是偶校验,有多少个停止位)。

    数据传输如下图:


    (1)、平时数据线处于“空闲”状态(1状态)
    (2)、当要发送数据时,UART改变TxD数据线的状态(变为0状态)并维持1位的时间,这样接收方检测到开始位后,再等待1.5位的时间就开始一位一位地检测数据线的状态得到所传输的数据。
    (3)、UART一帧中可以有5、6、7、8位数据,发送方一位一位地改变数据线的状态将它们发送出去,首先发送最低位。
    (4)、如果使用校验功能,UART在发送完数据后,还要发送1个校验位。有两种校验法:奇校验、偶校验(数据位连同校验位中,“1”的数目是奇数还是偶数)。

    (5)、最后,发送停止位,数据线恢复到“空闲”状态。停止位的长度有3种:1位、1.5位、2位。

    二、S3C2440 UART的特性
    s3c2440中UART,有三个独立的通道,每个通道都可以工作于中断模式或DMA模式,即UART可以发出中断或DMA请求以便在UART、CPU间传输数据。UART由波特率发生器、发送器、接收器和控制逻辑组成。

    使用系统时钟时,s3c2440可以达到115.2Kbit/s;s3c2440UART的FIFO深度为64字节。发送数据时,CPU先将数据写入发送FIFO中,然后UART会自动将FIFO中的数据复制到“发送移位器”中,发送移位器将数据一位一位地发送到TxD数据线上(根据设定的格式,插入开始位、校验位、停止位)。接收数据时,“接收移位器”将RxD数据线上的数据一位一位接收进来,然后复制到接收FIFO,CPU即可从中读取数据。

    UART结构图


    三、s3c2440UART的使用

    在使用UART之前需要设置波特率、传输格式(有多少个数据位、是否使用校验位、是奇校验还是偶校验、有多少个停止位、是否使用流量控制);对于s3c2440还要设置相应的管脚位UART功能、选择UART通道工作模式为中断模式还是DMA模式,设置好后,往某个寄存器写入数据即可发送,读取某个寄存器即可得到接收到的数据。可以查询状态寄存器或设置中断来获知数据是否已经发送完毕、是否已经接收完毕。

    具体操作方法:

    1、将所涉及的UART通道管脚设为UART功能
    比如UART0,GPH2、GPH3分别用作TxD0、RxD0,要使用串口通道0时,先设置GPHCON寄存器将GPH2、GPH3引脚功能设置为TxD0、RxD0。
    2、UBRDIVn寄存器:设置波特率
    s3c2440UART的时钟源有三种选择:FLCK/n(n值通过UCON0-UCON2联合设置)、UEXTCLK、PCLK。
    根据给定的波特率、所选择的的时钟源的频率。可以通过以下公式计算UBRDIVn寄存器(n为0-2)的值,
    给出了计算公式、例子及误差计算

    3、ULCONn寄存器:设置传输格式


    4、UCONn寄存器:串口控制寄存器

    UCONn寄存器用来选择UART时钟源、设置UART中断方式等。



    n的值有UCON0、UCON1、UCON2这3个寄存器的[15:12]一起来确定。

    5、UFCONn寄存器、UFSTATn寄存器
    UFCONn寄存器用于设置是否使用FIFO,设置各FIFO的触发阈值,即发送FIFO中有多少个数据时产生中断、接收FIFO中有多少个数据时产生中断。并可以通过设置这个寄存器来复位各个FIFO。
    读取USTATn寄存器可以知道各个FIFO是否已满、其中有多少个数据。
    不适用FIFO时可以认为FIFO深度为1,使用FIFO时s3c2440FIFO深度64。
    6、UMOCONn寄存器、UMSTATn寄存器
    这两类寄存器用于流量控制。
    7、UTRSTATn寄存器
    这个寄存器用来表示数据是否已经发送完毕、是否接收完毕。
    8、UERSTATn寄存器
    用来表示各种错误是否发生。
    9、UTXHn寄存器
    CPU将数据写入这个寄存器,UART就会将它保存到缓冲区中,并自动发送出去
    10、URXHn寄存器
    当UART接收到数据,CPU读取这个寄存器,就可以获取数据。

    四、UART使用程序

    serial.h

    void uart0_init(void);
    void putc(unsigned char c);
    unsigned char getc(void);
    int isDigit(unsigned char c);
    int isLetter(unsigned char c);
    

    serial.c

    #include "s3c24xx.h"
    #include "serial.h"
    
    #define TXD0READY   (1<<2)
    #define RXD0READY   (1)
    
    #define PCLK            50000000    // init.c中的clock_init函数设置PCLK为50MHz
    #define UART_CLK        PCLK        //  UART0的时钟源设为PCLK
    #define UART_BAUD_RATE  115200      // 波特率
    #define UART_BRD        ((UART_CLK  / (UART_BAUD_RATE * 16)) - 1)
    
    /*
     * 初始化UART0
     * 115200,8N1,无流控
     */
    void uart0_init(void)
    {
        GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
        GPHUP   = 0x0c;     // GPH2,GPH3内部上拉
    
        ULCON0  = 0x03;     // 8N1(8个数据位,无较验,1个停止位)
        UCON0   = 0x05;     // 查询方式,UART时钟源为PCLK
        UFCON0  = 0x00;     // 不使用FIFO
        UMCON0  = 0x00;     // 不使用流控
        UBRDIV0 = UART_BRD; // 波特率为115200
    }
    
    /*
     * 发送一个字符
     */
    void putc(unsigned char c)
    {
        /* 等待,直到发送缓冲区中的数据已经全部发送出去 */
        while (!(UTRSTAT0 & TXD0READY));
        
        /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
        UTXH0 = c;
    }
    
    /*
     * 接收字符
     */
    unsigned char getc(void)
    {
        /* 等待,直到接收缓冲区中的有数据 */
        while (!(UTRSTAT0 & RXD0READY));
        
        /* 直接读取URXH0寄存器,即可获得接收到的数据 */
        return URXH0;
    }
    
    /*
     * 判断一个字符是否数字
     */
    int isDigit(unsigned char c)
    {
        if (c >= '0' && c <= '9')
            return 1;
        else
            return 0;       
    }
    
    /*
     * 判断一个字符是否英文字母
     */
    int isLetter(unsigned char c)
    {
        if (c >= 'a' && c <= 'z')
            return 1;
        else if (c >= 'A' && c <= 'Z')
            return 1;       
        else
            return 0;
    }
    


  • 相关阅读:
    手游渠道分成的那些坑来等你跳
    [手游新项目历程]-43-sql关键字解决
    一些相似词的区别
    程序员之间的“笑料”
    程序员之间的“笑料”
    2014游戏圈员工跳槽必看
    2014游戏圈员工跳槽必看
    游戏应该怎么做-美术
    游戏应该怎么做-美术
    [手游新项目历程]-44-gdb
  • 原文地址:https://www.cnblogs.com/Ye-Jason/p/7374724.html
Copyright © 2011-2022 走看看