本章目标:

了解UART原理;
掌握S3C2410/S3C2440中UART的使用

11.1 UART原理及UART内部使用方法

11.1.1 UART原理说明

    UART用于传输串行数据:
    发送数据时,CPU将并行数据写入UART,UART按照一定的格式在一根电线上串行发出;
    接收数据时,UART检测另一根电线上的信号,将串行收集放在缓冲区中,CPU即可读取
UART获得这些数据。
    UART之间以全双工方式传输数据,最精简的连接方式只有3根线:TxD、RxD、Gnd。
    UART使用标准的TTL/CMOS逻辑电平(0~5V、0~3.3V、0~2.5V或0~1.8V)来表示数据,
高电平表示1,低电平表示0.为了增强数据抗干扰能力、提高传输长度,通常将TTL/CMOS
逻辑电平转换为RS-232逻辑电平,3~12V表示0,-3~-12V表示1。

11.1.2 S3C2410/S3C2440 UART的特性

    S3C2410/S3C2440中UART功能类似,有3个独立的通道,每个通道都可以工作于中断
或DMA模式。即UART可以发出中断或DMA请求以便在UART、CPU间传输数据。
    UART由波特率发生器、发送器、接收器和控制逻辑组成。
    使用系统时钟时,S3C2410的UART波特率可以达到230.4Kbit/s,S3C2440则可以达到
115.2Kbit/s;如果使用UEXTCLK引脚提供的外部时钟,则可以达到更高的波特率。波特率
可以通过编程进行控制。
    S3C2410 UART的每个通道都有16字节的发送FIFO和16字节的接收FIFO,S3C2440 UART
的FIFO深度为64。
    S3C2410/S3C2440 UART的每个通道支持的停止位有1、2位,数据位有5、6、7或8位,
支持校验功能,另外还有红外发送/接收功能。

11.1.3 S3C2410/S3C2440 UART的使用

    在使用UART之前需要设置波特率、传输格式(多少数据位、是否使用校验位、是奇校验
还是偶校验、有多少停止位、是否使用流量控制);对于S3C2410/S3C2440,还要选择所涉及
管脚为UART功能、选择UART通道的工作模式为中断模式或DMA模式。设置好之后,向某个寄存器
中写入数据即可发送,读取某个寄存器即可得到接收到的数据。可以通过查询状态寄存器或
设置中断来获知数据是否已经发送完毕、是否已经接收到数据。
    针对上述过程,下面一一说明。
1.将所涉及的UART通道管脚设为UART功能
2.UBRDIVn寄存器(UART BAUD RATE DIVISOR):设置波特率
    S3C2410 UART 的时钟源有两种选择:PCLK、UEXTCLK;S3C2440 UART的时钟源有
三种选择:PCLK、UEXTCLK、FCLK/n,其中n的值通过UCON0~UCON2联合设置。
    根据给定的波特率、所选择的时钟源的频率,可以通过如下公式计算UBRDIVn寄
存器(n为0~2,对应3个UART通道)的值。
    UBRDIVn = (int)(UART clock / (buad rate * 16)) - 1
    上面计算出来的UBRDIVn寄存器不一定是整数,只要其误差在1.87%之内即可。误
差计算公式如下:
    tUPCLK = (UBRDIVn + 1) * 16 * 1Frame/(UART clock)    //实际的UART时钟
    tUEXACT = 1Frame / baud-rate                  //理论的UART时钟
    UART error = (tUPCLK - tUEXACT) / tUEXACT * 100%     //误差
3.ULCONn寄存器(n:0~2)(UART LINE CONTROL):设置传输格式
4.UCONn寄存器(UART CONTROL)
    UCONn寄存器用于选择UART时钟源、设置UART中断方式等。由于S3C2410的UART
只有两个时钟源,S3C2440有3个时钟源,所以在选择和设置时钟源时有所不同。
    S3C2410的UCONn寄存器格式如下表11.2所示。
    S3C2440的UCONn寄存器在UART时钟的选择方面与S3C2410有所不同,从位[10]往上
的位含义不一样,并且原来的位[4]用于徐娜则是否发出“break”信号,这些位的含义
如表11.3所示。

    UCON0、UCON1、UCON2这三个寄存器的位[15:12]一起用来确定n的值,它们的意义如下。
    (1)UCON2[15]:“FCLK/n”使能位。
    它等于0时,禁止使用“FCLK/n”作为UART时钟源;等于1时,可以用作UART时钟源。
    (2)n的值设置。
    UCON0[15:12]、UCON1[15:12]、UCON2[14:12]三者用于设置n的值,当其中一个被射程非
0时,其他两个必须为0.
    ① n的值处于7~21处时,UART时钟 = FCLK/(divider + 6),divider 为UCON0[15:12]的值,大于0。 
    ② n的值处于22~36时,UART时钟 = FCLK/(divider + 21),divider为UCON1[15:12]的值,大于0。
    ③ n的值处于37~43时,UART时钟 = FCLK/(divider + 36),divider为UCON2[14:12]的值,大于0.
    ④ UCON0[15:12]、UCON1[15:12]、UCON2[14:12]都等于0时,UART时钟:FCLK/44。
5.UFCONn寄存器(UART FIFO CONTROL)、UFSTATn寄存器(UART FIFO STATUS)
    UFCONn寄存器用于设置是否使用FIFO,设置个FIFO的触发值。并可以通过设置UFCONn
寄存器来复位个寄存器。
    读取UFSTATn寄存器可以知道各个FIFO是否已经满、其中有多少个数据。
    不使用FIFO时,可以认为FIFO的深度为1,使用FIFO时,S3C2410的FIFO深度为16,
S3C2440的FIFO深度为64.这两类寄存器各位的含义请参考数据手册,后面的实例部分没有
使用FIFO。
6.UMCONn寄存器(UART MODEM CONTROL)、UMSTATn寄存器(UART MODEM STATUS)
    这两类寄存器用于流控,这里不介绍。
7.UTRSTATn寄存器(UART TX/RX STATUS)
    UTRSTATn寄存器用于表明数据是否已经发送完毕、是否已经接收到数据,格式如表11.4
所示。缓冲区起始就是图11.3中的FIFO,只不过不使用FIFO功能时可以认为其深度为1。

8.UERSTATn寄存器(UART ERROR STATUS)
    用于表示各种错误是否发生,位[0]~位[3]为1时分别表示溢出错误、校验错误、帧错误、
检测到“break”信号。读取这个寄存器时,它会自动清零。
    注意:接收数据时,如果使用FIFO,则UART内部会使用一个“错误FIFO”来表明接收FIFO
中哪个数据在接收过程中发生了错误。CPU只有在读出这个错误的数据时,才会察觉到发生了错
误。要想清除“错误FIFO”,则必须读出错误的数据,并读出UERSTATn寄存器。
9.UTXHn寄存器(UART TRANSMIT BUFFER REGISTER)
    CPU将数据写入这个寄存器,UART即将它保存到缓冲区中,并自动发送出去。
10.URXHn寄存器(UART RECEIVE BUFFER REGISTER)
    当UART接收到数据时,CPU读取这个寄存器,即可获得数据。

11.2 UART 操作实例

11.2.1 代码详解

    本实例代码在/work/hardware/uart目录下。目的是在串口上输入一个字符,单板收到后将
它的ASCII值加1后,从串口输出。
    首先设置MPLL提高系统时钟,令PCLK为50MHz,UART将选择PCLK作为时钟源。将代码复制到
SDRAM之后,调用main函数。这些代码与第10章相似。重点在于main函数对UART0的初始化、收发
数据,这由3个函数实现:usat0_init、getc和putc,它们在serial.c文件中。
1.UART初始化
    uart0_init函数代码如下:
  1. #define PCLK 50000000 //init.c中的clock_init函数设置PCLK为50MHz
  2. #define UART_CLK PCLK //UART0的时钟源设为PCLK
  3. #define UART_BAUD_RATE 115200
  4. #define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)
  5.  
  6. /*
  7. *初始化UART0
  8. *115200, 8N1, 无流控
  9. */
  10. void uart0_init(void)
  11. {
  12. GPHCON |= 0xa0; //GPH2、GPH3用作TXD0、RXD0
  13. GPHUP = 0x0c; //GPH2、GPH3内部上拉
  14.  
  15. ULCON0 = 0x03; //波特率:115200,8N1
  16. UCON0 = 0x05; //查询方式,UART时钟源为PCLK
  17. UFCON0 = 0x00; //不使用FIFO
  18. UMCON0 = 0x00; //不使用流控
  19. UBRDIV0 = UART_BRD; //波特率:115200
  20. }

serial.c->uart0_init()

2.发送字符的函数
    本实例不使用FIFO,发送字符前,先判断上一个字符是否已经发送出去。如果没有,
则不断查询UTRSTAT0寄存器的位[2],当它为1时表示已经发送完毕。于是,即可向UTXH0寄
存器中写入要发送的字符。代码如下(宏TXD0READY被定义为“(1 << 2)”):
  1. /*
  2. *发送一个字符
  3. */
  4. void putc(unaigned char c)
  5. {
  6. /*等待,直到发送缓冲区中的数据已经全部发送出去*/
  7. while(!(UTRSTAT0 & TXD0READY));
  8.  
  9. /*向UTXH0寄存器中写数据,UART自动将其发送出去*/
  10. UTXH0 = c;
  11. }

serial.c->putc()

3.接收字符的函数
    试图读取数据前,先查询UTRSTAT0寄存器的位[1],当它为1时,表示接收缓冲区中有数据。
于是,即可读取URXH0得到数据。代码如下(宏RXD0READY被定义为“(1)”):
  1. /*
  2. *接收字符
  3. */
  4. unsigned char getc(void)
  5. {
  6. /*等待,知道接收缓冲区中有数据*/
  7. while(!(UTRSTAT0 & RXD0READY));
  8.  
  9. /*直接读取URXH0寄存器,即可获得接收到的数据*/
  10. return URXH0;
  11. }

serial.c->getc()

4.主函数
    初始化完UART0之后,不断地读取串口数据,并判断它是否是数据或字符。如果是的话,
将它加1后从串口输出。代码如下:
  1. #include "serial.h"
  2.  
  3. int main()
  4. {
  5. unsigned char c;
  6. uart0_init(); //波特率:115200,8N1
  7.  
  8. while()
  9. {
  10. //从串口接收数据后,判断其是否为数字或字母,若是则加1后输出
  11. c = getc();
  12. if(isDigit(c) || (isLetter(c)))
  13. putc(c+);
  14. }
  15.  
  16. return ;
  17. }

main.c

11.2.2 实例测试

1.PC上的串口工具推荐
    Windows下推荐使用SecureCRT工具,Linux下推荐使用kermit。
    下面介绍在Linux下安装、使用kermit的方法。
    确保Linux能上网,然后使用下面命令安装,会安装一个kermit命令。
  1. $ sudo apt-get install ckermit
    在使用kermit之前,先建立一个配置文件,在/home/book(假设用户名为book)目录下创
建名为.kermrc的文件,内容如下:
  1. set line /dev/ttyS0
  2. set speed
  3. set carrier-watch off
  4. set handshake none
  5. set flow-control none
  6. robust
  7. set file type bin
  8. set file name lit
  9. set rec pack
  10. set send pack
  11. set window

配置kermrc

    然后,运行“$ sudo kermit -c”命令即可开启串口:要关闭串口,可以先输入
“Ctrl+\”,然后按住“C”键,最后输入“exit”后回车。
2. 测试方法
    首先使用串口线将开发板的COM0和PC的串口连接,打开PC上的串口工具并设置其波
特率为115200、8N1。
    然后,在uart目录下运行make命令生成可执行文件uart.bin,将它烧入NAND Flash
中运行。
    最后,在PC上串口工具中输入数字或字母,可以看到输出另一个字符(加了1):如果
输入其他字符,则无输出。
    /work/hardware/stdio目录下的程序在串口0上实现printf、scanf等函数,它使用
scanf、sscanf和printf等函数从串口接收一个十进制数字序列,然后将它转换为十六进制
输出。步骤与UART实例相似,读者可自行操作。
附:代码:
链接: https://pan.baidu.com/s/1kV24a9L 密码: tfab

JZ2440 裸机驱动 第11章 通用异步收发器UART的更多相关文章

  1. JZ2440 裸机驱动 第13章 LCD控制器(1)

    本章目标  了解LCD显示器的接口及时序: 掌握S3C2410/S3C2440 LCD控制器的使用方法: 了解帧缓冲区的概念,掌握如何设置帧缓冲区来显示图像: 13.1 LCD和LCD控制器 13.1 ...

  2. JZ2440 裸机驱动 第12章 I2C接口

    本章目标: 了解I2C总线协议: 掌握S3C2410/S3C2440中I2C接口的使用方法: 12.1 I2C总线协议及硬件介绍 12.1.1 I2C总线协议 1 I2C总线的概念 2 I2C总线的信 ...

  3. JZ2440 裸机驱动 第9章 中断体系结构

    本章目标:     了解ARM体系CPU的7种工作模式     了解S3C2410/S3C2440中断体系结构     掌握S3C2410/S3C2440的中断服务程序的编写方法 9.1 S3C241 ...

  4. JZ2440 裸机驱动 第7章 内存管理单元MMU

    本章目标:     了解虚拟地址和物理地址的关系:     掌握如何通过设置MMU来控制虚拟地址到物理地址的转化:     了解MMU的内存访问权限机制:     了解TLB.Cache.Write ...

  5. JZ2440 裸机驱动 第6章 存储控制器

    本章目标:     了解S3C2410/S3C2440地址空间的布局     掌握如何通过总线形式访问扩展的外设,比如内存.NOR Flash.网卡等 ························ ...

  6. JZ2440 裸机驱动 第5章 GPIO接口

    本章目标:     掌握嵌入式开发的步骤:编程.编译.烧写程序.运行     通过GPIO的操作了解软件如何控制硬件 5.1 GPIO硬件介绍     S3C2440A有130个多功能输入/输出口引脚 ...

  7. JZ2440 裸机驱动 第14章 ADC和触摸屏接口

    本章目标:     了解S3C2410/S3C2440和触摸屏的结构:     了解电阻触摸屏的工作原理和等效电路图:     了解S3C2410/S3C2440触摸屏控制器的多种工作模式:     ...

  8. JZ2440 裸机驱动 第10章 系统时钟和定时器

    本章目标      了解S3C2410/S3C2440的时钟体系结构     掌握通过设置MPLL改变系统时钟的方法     掌握在不同的频率下设置存储控制器的方法     掌握PWM定时器的用法   ...

  9. JZ2440 裸机驱动 第8章 NAND Flash控制器

    本章目标  了解NAND Flash 芯片的接口 掌握通过NAND Flash控制器访问NAND Flash的方法 8.1 NAND Flash介绍和NAND Flash控制器使用     NAND ...

随机推荐

  1. iOS系统版本与机型的对应关系

    1.手机系统版本:10.3 NSString* phoneVersion = [[UIDevice currentDevice] systemVersion]; 2.手机类型:iPhone 6 NSS ...

  2. noip2007-4

    首先预处理f[i][j]表示i到j的路径 然后枚举i,j,如果f[i][j]<=s,那么 寻找最大的k,计算路径距离 计算最短的 代码: #include<bits/stdc++.h> ...

  3. Mysql Innodb 表碎片整理

    一.为什么会产生碎片 简单的说,删除数据必然会在数据文件中造成不连续的空白空间,而当插入数据时,这些空白空间则会被利用起来.于是造成了数据的存储位置不连续,以及物理存储顺序与理论上的排序顺序不同,这种 ...

  4. 字符串 date 转标准 yyyyMMdd 格式

    学习转换成数字相加的思想 public static int ToDateInt(string dateStr)        {            if (string.IsNullOrEmpt ...

  5. (转载)SAPI 包含sphelper.h编译错误解决方案

    [转]SAPI 包含sphelper.h编译错误解决方案 在使用Microsoft Speech SDK 5.1开发语音识别程序时,包含了头文件“sphelper.h”和库文件“sapi.lib”.编 ...

  6. iOS plist文件的读写

    原帖:http://blog.csdn.net/totogo2010/article/details/7634185 在做iOS开发时,经常用到到plist文件,  那plist文件是什么呢? 它全名 ...

  7. CSS 网格布局学习

    转自:https://blog.jirengu.com/?p=990 CSS网格布局(又名“网格”)是一个二维的基于网格的布局系统,其目的只在于完全改变我们设计基于网格的用户界面的方式. CSS一直用 ...

  8. OO面向对象 课程总结

    测试与正确性论证的效果差差异 测试和正确性论证都是对程序进行可靠性的验证. 测试: IEEE提出了对软件测试的定义:使用人工或者自动的手段来运行或测定某个系统的过程,其目的在于检验它是否满足规定的需求 ...

  9. PDB调试模块

    这里主要是一些对于调试常用的命令:1.直接通过命令端输入进行调试 以pdb调试模式运行(主要用这个) python3 -m pdb file.py 2.在代码中导入pdb模块 import pdb 功 ...

  10. 数据库备份-SQL Server 维护计划

    SQL Server 维护计划(数据库备份)   公司的项目都需要定期备份,程序备份关掉iis站点复制文件就可以了,难受的地方就是数据库的备份了.服务器上装的大都是英文版,一看见英文,操作都变得小心翼 ...