S5PV210串口
串口设置之输入输出字符
S5PV210 UART相关说明
        通用异步收发器简称UART,即UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTER,它用来传输串行数据。发送数据时,CPU将并行数据写入UART,UART按照一定的格式在一根电线上串行发出;接收数据时,UART检测另一根电线的信号,将串行收集在缓冲区中,CPU即可读取UART获得这些数据。
        在S5PV210中,UART提供了4对独立的异步串口I/O端口,有4个独立的通道,每个通道可以工作于DMA模式或者中断模式。其中,通道0有256byte的的发送FIFO和256byte的接收FIFO,通道1有64byte的的发送FIFO和64byte的接收FIFO,而通道2和3只有16byte的的发送FIFO和16byte的接收FIFO。 
S5PV210的uart结构图如下:

S5PV210的uart结构图
UART使用标准的TTL/CMCOS逻辑电平来表示数据,为了增强数据抗干扰能力和提高传输长度,通常将TTL/CMOS逻辑电平转换为RS-232逻辑电平,查看原理图可知Mini210S使用的是MAX3232SOP芯片,使用的是TX0和DX0:

搜索“XuTXD0”,可知:

通过设置UART相关寄存器,我们就可以驱动UART工作,达到发送和接收字符的目的。
程序例子:(完整代码见链接)
/*main.c*/
int main() 
{
 char c;
 uart_init(); // 初始化串口
 while (1)
{
 c = getc (); // 接收一个字符c
 putc(c+1); // 发送字符c+1
 }
 return 0; 
} 
在main函数中,先会调用uart_init()初始化UART,然后使用getc接收PC发过来的字符,再调用putc()将该字符+1回复给PC。
/*uart.c*/
void uart_init()
{
// 1 配置引脚用于RX/TX功能 
GPA0CON = 0x22222222; 
GPA1CON = 0x2222; 
// 2 设置数据格式等 
UFCON0 = 0x1; // 使能FIFO 
UMCON0 = 0x0; // 无流控 
ULCON0 = 0x3; // 数据位:8, 无校验, 停止位: 1
UCON0 = 0x5; // 时钟:PCLK,禁止中断,使能UART发送、接收 // 3 设置波特率
UBRDIV0 = UART_UBRDIV_VAL; // 35 
UDIVSLOT0 = UART_UDIVSLOT_VAL; // 0x1 
} 
上述代码共有3个步骤,下面我们来一一讲解每一个步骤:
第一步 配置引脚用于RX/TX功能
参考UART引脚连接图,我们需要设置GPA0CON和GPA1CON寄存器使GPA0和GPA1引脚用于UART功能。

GPA0CON寄存器图

GPA1CON寄存器图
第二步 设置数据格式等
<1> ULCON0用来设置数据格式,见下图

Word Length = 11,8bit的数据; 
Number of Stop Bit = 0,1bit的停止位; 
Parity Mode = 000,无校验; 
Infrared Mode =0,使用普通模式;
所以ULCON0=0x3
<2> 9UCON0是UART的配置寄存器,见下图


Receive Mode = 01 ,使用中断模式或者轮询模式; 
Transmit Mode = 01,使用中断模式或者轮询模式; 
Send Break Signal = 0,普通传输; 
Loop-back Mode = 0,不使用回环方式; 
我们采用轮询的方式接受和发送数据,不使用中断,所以bit[6-9]均为0; 
Clock Selection = 0,使用PCLK作为UART的工作时钟; 
我们不使用DMA,所以bit[16]和bit[20]均为0;
所以UCON0 = 0x5
<3> UFCON0和UMCON0
这两个寄存器比较简单,UFCON0用来使能FIFO,UMCON0用来设置无流控。
第三步 设置波特率
波特率即每秒传输的数据位数,涉及两个寄存器:UBRDIV0和UDIVSLOT0


波特率设置相关公式:UBRDIVn + (num of 1's in UDIVSLOTn)/16 = (PCLK / (bps x 16)) −1 
其中,由Maximum Operating Frequency for Each Sub-block图可知,UART工作于PSYS下,所以PCLK即PCLK_PSYS = 66.5MHz,我们的波特率bps设置为115200,所以
(66.5MHz/(115200 x 16)) – 1 = 35.08 = UBRDIVn + (num of 1's in UDIVSLOTn)/16,所以我们设置UBRDIV0=35,UDIVSLOT0=0x1 
getc()和putc()的代码如下: 
// 接收一个字符 
char getc(void) 
{
 while ((UFSTAT0 & 0xff) == 0); // 如果RX FIFO空,等待
 return URXH0; // 取数据 
} 
// 发送一个字符 
void putc(char c) 
{
 while (UFSTAT0 & (1<<24)); // 如果TX FIFO满,等待
 UTXH0 = c; // 写数据 
}

UART数据发送寄存器

UART数据接收寄存器

发送/接收状态寄存器
通过读UTRSTAT0 发送/接收状态寄存器,当Receive buffer data ready= 1时说明接收到数据,读URXH0寄存器可以得到8bit的数据;当Transmitter empty = 1时说明可以发送数据,写8bit的数据到UTXH0。
移植printf和scanf功能
第一节 移植的途径
对于如何移植printf和scanf,我们有许多选择:
1) 移植linux的printk功能,版本越新越难移植,但是功能也越强大;
2) 移植uboot的printf和scanf功能,实际uboot也是从linux内核中移植而来的;
3) 完全自己编写,但是功能比较弱;
在保证整个裸机其他代码部分没有任何问题,且编译器也没有任何问题的情况下,上述三种方法都是可行的。下面我们只是直接利用网友从linux中移植好的printk,为我们的裸机代码增加上该部分功能。
第二节 移植步骤
第一步 解压printf.rar到uart_stdio目录,解压成功后会多出include 和lib两个目录,其中include放的是相关头文件,lib放的是printf和scanf相关的代码。
第二步 修改uart_stdio目录下的makefile,将lib目录下的代码编译链接成lib.a,然后将lib.a编译进bin中,具体修改见源码。
第三步 编写main函数进行测试。
第三节 程序相关讲解
完整代码见目录uart_stdio,与前一章的代码相比,BL1目录的代码没有任何变化,BL2目录的代码多了include和lib目录以及main.c的内容被修改了。
1. /lib/printf.c
<1> printf的定义如下:
int printf(const char *fmt, ...) 
{ 
    int i; 
    int len; 
    va_list args; // va_list 即 char *    
    va_start(args, fmt); 
    len = vsprintf(g_PCOutBuf,fmt,args);// 内部使用了va_arg()
    va_end(args); 
    for (i = 0; i < strlen(g_PCOutBuf); i++) 
    { 
        putc(g_PCOutBuf[i]); 
    } 
    return len; 
}
<2> printf函数是个变参函数,什么是变参函数:
可变参数函数的原型声明为type VAFunction(type arg1, type arg2, … ); 参数可以分为两部分:个数确定的固定参数和个数可变 的可选参数。函数至少需要一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,声明时用"..."表示。固定参数和可选参数公同构成一个函数的参数列表。
<3> printf函数涉及了3个十分重要的宏:
宏1: #define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
宏2: #define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
宏3: #define va_end(ap) (void) 0
在这些宏中,va 就是 variable argument(可变参数)的意思; 
ap:是指向可变参数表的指针; 
A:指可变参数表的前一个固定参数; 
T:可变参数的类型。 
va_list 也是一个宏,其定义为 typedef char * va_list,实质上是一char型指针。
<4> 三个宏的作用:
1) va_start 宏 作用:
根据v取得可变参数表的首指针并赋值给ap,方法:最后一个固定参数A的地址 + 第一个变参对A的偏移地址,然后赋值给 ap,这样 ap 就是可变参数表的首地址。 举例:
如果有变参函数的声明是 void va_test(char a, char b,char c, …),则它的固定参数依次是 a,b,c,最后一个固定参数 为 c,因此就是 va_start(ap, c)。
2) va_arg 宏 作用:
指取出当前 ap 所指的可变参数并将 ap 指针指向下一可变参数。
3) va_end 宏 作用:
结束可变参数的获取。va_end ( list )实际上被定义为空,没有任何真实对应的代码,用于代码对称,与 va_start 对应。
<5> 得到可变参数个数的三种办法:
1) 函数的第一个参数,指定后续的参数个数,如 func(int num,...);
2) 根据隐含参数,判断参数个数,如 printf 系列的,通过字符串中%的个数判断;
3) 特殊情况下(如参数都是不大于 0xFFFF 的 int),可以一直向低处访问堆栈,直到返回地址。
有了上述知识我们就可以看懂printf()函数的内容了,首先va_start(args, fmt);会将可变参数的首地址保存在args中,然后调用vsprintf(g_PCOutBuf,fmt,args)进行处理,在vsprintf()中,会调用va_arg()逐个的取出变参,然后进行解析。如果是普通字符则无须转换,直接保存在g_PCOutBuf;如果是字符串,则从可变参数表中拿到指向字符串的指针,将字符串的内容拷贝到g_PCOutBuf;如果是数字,则调用number函数进行处理,并把解析的结果存放在g_PCOutBuf。所有,最后只调用putC函数把g_PCOutBuf里的字符一个个的打印出来就可以了。scanf函数的原理和printf类似,这里不再进行解释.
2. main.c
完整代码如下: 
int main() 
{ 
int a = 0,b = 0; 
char *str = "hello world"; 
uart_init(); 
printf("%s\n",str); 
while (1) 
{
printf("please enter two number: \r\n"); 
scanf("%d %d", &a, &b); 
printf("\r\n"); 
printf("the sum is: %d\r\n", a+b); 
} 
return 0; 
} 
首先会打印“hello world”,然后从串口接收两个数字,最后输出它们的和。
详细代码下载链接:http://download.csdn.net/detail/klcf0220/5636023
S5PV210串口的更多相关文章
- 第三章之S5PV210串口初始化
		
1,在start.S中执行373行b lowlevel_init跳转到/board/samsung/goni/lowlevel.S中,此代码中初始化一样硬件. 找到241行,此行执行URAT初始化,如 ...
 - S5PV210 串口实验(中断方式)
		
结合之前的串口实验(轮询方式)与中断体系分析,我们来做下中断方式的串口接收实验. start.S .global _start .global IRQ_handle _start: /* 关 Watc ...
 - S5PV210 串口配置与实验(轮询方式)
		
S5PV210 UART 相关说明 通用异步收发器简称 UART, 即 UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTER,它用来传输串行数据.发送数据时, ...
 - ARM-Linux S5PV210 UART驱动(3)----串口核心层、关键结构体、接口关系
		
尽管一个特定的UART设备驱动完全可以按照tty驱动的设计方法来设计,即定义tty_driver并实现tty_operations其中的成员函数,但是Linux已经在文件serial_core.c中实 ...
 - ARM-Linux S5PV210 UART驱动(4)----串口驱动初始化过程
		
对于S5PV210 UART驱动来说,主要关心的就是drivers/serial下的samsung.c和s5pv210.c连个文件. 由drivers/serial/Kconfig: config S ...
 - S5PV210开发板刷机(SD卡uboot、串口+USB-OTG刷机方法)
		
一.介绍 九鼎的S5PV210开发板,在出厂前已经默认刷了Android4.0系统.如果需要刷其它的系统或者是由于系统问题无法启动时,就需要对板子刷机. 其实,刷机是对210开发板的一个基础学习,目的 ...
 - ARM-Linux S5PV210 UART驱动(5)----串口的open操作(tty_open、uart_open)
		
串口驱动初始化后,串口作为字符驱动也已经注册到系统了,/dev目录下也有设备文件节点了. 那接下来uart的操作是如何进行的呢? 操作硬件之前都是要先open设备,先来分析下这里的open函数具体做了 ...
 - tiny210(s5pv210)移植u-boot(基于 2014.4 版本号)——移植u-boot.bin(打印串口控制台)
		
在之前我们移植的代码中,都没看到明显的效果,这节我们实现控制台的信息打印. 在上节.我们看到调用 relocate_code 重定位.在 u-boot 的帮助文档 doc/README.arm-rel ...
 - 在 S5PV210 的 开发板上 使用 串口 收发信息
		
参考学习教程:周立功嵌入式Linux开发教程-(上册) 材料:首先 准备一个 安装好 Linux 的 开发板 使用 xshell 工具 连接 开发板 ,winscp 工具 连接 开发板 , 准 ...
 
随机推荐
- module模块和包(十七)
			
在前面的几个章节中我们脚本上是用 python 解释器来编程,如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了. 为此 Python 提供了一个办法,把这些定义存放在文 ...
 - Kafka配置文件server.properties(三个版本)
			
前言 其实每个版本都有些许改动,只不过改动大小而已,但是网上的教程都真的太老了,其实更新一下也费不了多少时间 0.9.0 # Licensed to the Apache Software Found ...
 - mac subLime3 JSON 格式化插件安装
			
1.首先找到路径:/Users/hou***in/Library/Application' 'Support/Sublime' 'Text' '3/Packages/ 2.git clone http ...
 - ELK技术实战-安装Elk 5.x平台
			
ELK技术实战–了解Elk各组件 转载 http://www.ywnds.com/?p=9776 ELK技术实战-部署Elk 2.x平台 ELK Stack是软件集合Elasticsearch. ...
 - Python IPy模块
			
#!/usr/bin/env python # -*- coding: utf-8 -* # Created by YangYongming at 2018/09/17 20:22 # FileNam ...
 - 20190313 org.apache.commons.lang3.builder.EqualsBuilder的两种典型用法
			
org.apache.commons.lang3.builder.EqualsBuilder的两种典型用法 public boolean equals(Object obj) { if (obj == ...
 - GBDT用于分类问题
			
一.简介 GBDT在传统机器学习算法里面是对真实分布拟合的最好的几种算法之一,在前几年深度学习还没有大行其道之前,gbdt在各种竞赛是大放异彩.原因大概有几个 一:效果确实挺不错. 二:既可以用于分类 ...
 - Java记录-SpringMVC整合Echarts画地图加散点图
			
1.搭建eclipse+JDK+Maven+SpringMVC+Spring+Mybatis后台架构,详细就不过多阐述了 2.下载百度eharts插件:http://echarts.baidu.com ...
 - hud   2554    N对数的排列问题     (规律)
			
题目链接 Problem Description 有N对双胞胎,他们的年龄分别是1,2,3,--,N岁,他们手拉手排成一队到野外去玩,要经过一根独木桥,为了安全起见,要求年龄大的和年龄小的排在一起,好 ...
 - Thymeleaf在IDEA中的使用
			
让html页面的thymeleaf 标签不显示刺眼的红色波浪线,解决方法如下 IDEA官方链接:https://www.jetbrains.com/help/idea/2017.1/thymeleaf ...