S3C2440—5.UART的使用
文章目录
一.S3C2440中的UART介绍
UART(universal asynchronous receive transmitter)通用异步收发器,用来收发串行数据,以全双工的形式进行通信,UART使用的电平标准是TTL/CMOS,一帧数据通常包含开始位、数据位、校验位、停止位,UART传输的双方要统一波特率。
S3C2440中有三个UART独立通道,功能类似,下面分块介绍一下UART比较重要的部分。
UART的用途一般有俩种:
1.作为与上位机的通信接口,打印调试信息
2.作为外设模块的驱动接口,连接驱动外设,比如:蓝牙、GPS等
1.1 电平匹配
ARM串口电平为TTL,要根据PC的匹配电平来选择电平转换芯片。
UART直接输出的电平是TTL电平,以前上位机PC端都有RS-232电平(九针接口),所以以前ARM与上位机连接需要TTL转RS-232电平的芯片。RS-232适合长距离传输。
现在,PC上基本没有RS-232接口了,取而代之的是USB接口,所以现在ARM与PC的UART通信都使用TTL转USB芯片了。
1.2 UART数据帧与波特率
一帧数据通常包含开始位、数据位、校验位、停止位。
开始位:UART空闲时,TxD数据线是高电平的(因此需要给相应引脚上拉引脚),将要发送数据时,TxD数据线会以拉低电平作为起始信号,所以“0”电平就相当于开始位。
数据位:数据位包含了要发送的信息,数据位的大小可以通过配置寄存器来确定,通常是8bit。
校验位:为了保证数据传输的准确性,有时会在数据位后面加上一个校验位,分为奇、偶校验,校验规则:数据位+校验位中为1的个数是奇数或者偶数。一般不用。
停止位:会给出一段持续的高电平作为停止信号,持续时间可以通过配置寄存器来设置,一般设置停止位的持续时间为1位长度。
最常用的数据帧格式为:8n1(意为:8位数据位,不使用校验位,停止位长度为一位)
波特率:每秒发送的bit(位)
1.3UART框图
框图如下:
UART发送数据的流程:CPU从内存中将数据取到FIFO,FIFO中的数据发送到移位器,由移位器逐位发送数据。
UART接收数据的流程:移位器逐位接收数据,将接收到的数据放在FIFO中,CPU将数据从FIFO中取到内存。
UART中FIFO深度为64Byte,不使用FIFO时,将数据放在接收/保持寄存器中(1Byte)。
数据发送、接收完成,可以利用中断进行处理,也可以不断查询寄存器标志位。
波特率由波特率发生器产生,涉及到时钟源和分频因子的选择
二.UART的配置
这里介绍一下最基本的UART配置,即:使用UART0、满足收发数据功能、不使用FIFO(使用1Byte的寄存器)、收发状态可以通过中断或查询标志位获知。
2.1 UART引脚的配置
S3C2440中UART0的引脚对应关系为:TxD:GPH2 RxD:GPH3
首先要将俩个引脚的模式设置为UART模式,寄存器配置如下:
/* 设置引脚 */
//TxD0:GPH2 RxD0:GPH3
GPHCON &= ~((3<<4)|(3<<6));
GPHCON |= ((2<<4)|(2<<6));
由于数据线平时是高电平,所以要设置引脚的内部上拉。
我们要将内部上拉电阻与引脚连接,通过配置寄存器可以控制,上拉电阻与引脚的连接状态由GPHUP寄存器控制:
我们要使能GPH2、GPH3的内部上拉,将2、3位复位
/* 使能引脚的内部上拉 */
GPHUP &= ~( (1<<2)|(1<<3) );
2.2 波特率的配置
波特率计算如下:
通过设置分频系数DIV、选择时钟源来配置波特率
UCON0寄存器可以选择时钟源:
一般默认PCLK为时钟源,所以不必专门配置时钟源。
UBRDIV寄存器负责分频因子设置:
直接将分频因子写入寄存器即可:
/* 设置波特率 */
/* 波特率设置格公式:UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1 */
/* 实现波特率:115200 b/s 时钟源采用PCLK:50MHz 分频因子:26 (本来26.127,忽略误差可以) */
/* 默认PCLK:UCON0 &= ~(3<<10)*/
UBRDIV0 = 26;
2.3 数据帧的配置
数据帧的配置主要包括对:校验位、停止位、数据位的配置
ULCON0寄存器配置:
/* 设置数据格式 */
/* 数据帧格式:8n1 */
ULCON0 = 0x00000003;
2.4 收发模式配置
UCON0寄存器也用来配置RxD、TxD的模式:可以通过中断和查询寄存器标志位来获取收发的状态
默认选择时钟(PLCK=50MHz)、Rx、Tx模式(中断和查询)
/* 收发模式:中断+查询 */
UCON0 = 0x00000005;
收发状态的查询通过UTRSTAT0寄存器来确定:
可以通过如下程序配合寄存器查询获取收发的状态:
/* 输出数据 */
int putchar( int c )
{
/* 等待传输数据寄存器空 */
while( !(UTRSTAT0 & (1<<2)) );
/* 不使用FIFO,对数据传输寄存器UTXH0直接写 */
UTXH0 = (unsigned char)c;
}
/* 接收数据 */
int getchar( void )
{
while( !(UTRSTAT0 & (1<<0)));
/* 接收数据寄存器URXH0 */
return URXH0;
}
2.5 收发数据寄存器
直接对寄存器进行读写就可以。
发送数据寄存器:
接收数据寄存器:
三.代码
话不多说,直接上代码,程序的框架是:main.c+uart.h+start.S
main.c:
#include "s3c2440_soc.h"
#include "uart.h"
int main(void)
{
unsigned char c;
uart0_init();
puts("Hello, world!\n\r");
while(1)
{
c = getchar();
if (c == '\r')
{
putchar('\n');
}
if (c == '\n')
{
putchar('\r');
}
putchar(c);
}
return 0;
}
uart.c:
#include "s3c2440_soc.h"
#include "uart.h"
void uart0_init( void )
{
/* 设置引脚 */
//TxD0:GPH2 RxD0:GPH3
GPHCON &= ~((3<<4)|(3<<6));
GPHCON |= ((2<<4)|(2<<6));
/* 使能引脚的内部上拉 */
GPHUP &= ~( (1<<2)|(1<<3) );
/* 设置波特率 */
/* 波特率设置格公式:UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1 */
/* 实现波特率:115200 b/s 时钟源采用PCLK:50MHz 分频因子:26 (本来26.127,忽略误差可以) */
/* 默认PCLK:UCON0 &= ~(3<<10)*/
UBRDIV0 = 26;
/* 设置数据格式 */
/* 数据帧格式:8n1 */
ULCON0 = 0x00000003;
/* 收发模式:中断+查询 */
UCON0 = 0x00000005;
}
/* 输出数据 */
int putchar( int c )
{
/* 等待传输数据寄存器空 */
while( !(UTRSTAT0 & (1<<2)) );
/* 不使用FIFO,对数据传输寄存器UTXH0直接写 */
UTXH0 = (unsigned char)c;
}
/* 接收数据 */
int getchar( void )
{
while( !(UTRSTAT0 & (1<<0)));
/* 接收数据寄存器URXH0 */
return URXH0;
}
/* 连续发送字符串 */
int puts( const char *s )
{
while( *s )
{
putchar( *s );
s++;
}
}
start.S:
.text
.global _start
_start:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
ldr r0, =0x4C000000
ldr r1, =0xFFFFFFFF
str r1, [r0]
/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */
ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0]
/* 设置CPU工作于异步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0)
* m = MDIV+8 = 92+8=100
* p = PDIV+2 = 1+2 = 3
* s = SDIV = 1
* FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
*/
ldr r0, =0x4C000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]
/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
* 然后CPU工作于新的频率FCLK
*/
/* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
moveq sp, #4096 /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */
bl main
halt:
b halt
代码参考韦东山嵌入式教程。
S3C2440—5.UART的使用的更多相关文章
- s3c2440裸机-UART编程(二、UART编程实现)
UART编程 1.初始化 我们的2440支持3个UART串口,以uart0为例讲解. 那么我们需要实现以下这几个函数完成串口的最基本功能: (1)uart0_init()用于初始化串口 (2)putc ...
- s3c2440裸机-UART编程(一、UART硬件介绍及传输原理)
1.uart硬件介绍 UART的全称是Universal Asynchronous Receiver and Transmitter(异步收发器). uart主要用于: 1.打印调试 2.数据传输 串 ...
- 八、mini2440裸机程序之UART(1)简单介绍【转】
转自:http://blog.csdn.net/shengnan_wu/article/details/8298869 一.概述 S3C2440通用异步接收和发送(UART)提供了三 ...
- JZ2440 裸机驱动 第11章 通用异步收发器UART
本章目标: 了解UART原理: 掌握S3C2410/S3C2440中UART的使用 11.1 UART原理及UART内部使用方法 11.1.1 UART原理说明 UART用于传输串行数据: ...
- s3c2440串口详解
一.UART原理说明 通用异步收发器简称UART(Universal Asynchronous Receiver/Transmitter),它用来传输串行数据:发送数据时,CPU将并行数据写入UART ...
- C与ARM汇编结合实现mini2440串口uart简单程序
最近学完了ARM的一些基础知识,开始在mini2440上开发一些简单的程序,串口发送程序是一开始涉及多个寄存器的例子,稍有繁多的步骤应该是开发过程中要慢慢适应的境况 下面的程序的目的是实现mini24 ...
- Smart210学习记录------linux串口驱动
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...
- (三) UART 串口通讯
UART : university asynchronous receiver and transmitter UART // 通用异步接收器和发送器 为什么要有串口:因为许多嵌入式设备没有显示屏 ...
- Linux学习 : 裸板调试 之 配置UART
1.UART原理说明 发送数据时,CPU将并行数据写入UART,UART按照一定的格式在一根电线上串行发出:接收数据时,UART检测另一根电线上的信号,串行收集然后放在缓冲区中,CPU即可读取UART ...
随机推荐
- php操作redis集群哨兵模式
前段时间项目里正好用到了redis的集群哨兵部署,因为此前并无了解过,所以一脸懵逼啊,查阅了几篇资料,特此综合总结一下,作为记录. 写在前沿:随着项目的扩张,对redis的依赖也越来越大,为了增强re ...
- Leetcode 递归题
24. 两两交换链表中的节点 题目描述: 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表. 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换. 示例: 给定 1->2-&g ...
- Adaptive AUTOSAR 学习笔记 5 - 架构 - 物理视图
本系列学习笔记基于 AUTOSAR Adaptive Platform 官方文档 R20-11 版本 AUTOSAR_EXP_PlatformDesign.pdf 缩写 AP:AUTOSAR Adap ...
- 如何少走弯路安装NLTK?
NLP中分词是一件麻烦事,nltk可以一定程度上优雅的解决一些需求 如果你去搜索"nltk安装",那么多半会得到以下的代码 import nltk nltk.download() ...
- DNS配置【正向解析】
DNS配置.正向解析 一.BIND域名服务基础 1)DNS的定义 2)域名结构 ...
- C语言:文件
文件是数据源的一种,最主要的作用是保存数据.在操作系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件.对这些文件的操作,等同于对磁盘上普通文件的操作.例如: 通常把显示器称为 ...
- endless 如何实现不停机重启 Go 程序?
转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/584 前几篇文章讲解了如何实现一个高效的 HTTP 服务,这次我们来 ...
- MQTT 4 ——MQTT的Spring Mvc 配置接收字节流数据
本篇记录一下MQTT整合Spring Mvc配置直接收发字节流数据 设备方是纯C开发,并且为了交互数据的安全,将传送的数据用了AES CBC进行了加密. 接下来正常方便做法应该是 将加密后的字节流转换 ...
- 前端开发入门到进阶第五集【安装SublimeServer】
参考:https://www.cnblogs.com/jf-67/p/8031614.html 1.我们可以直接在sublime text里面安装,Ctrl+shift+p进入命令模式,输入insta ...
- 前端之html基础演示
1.本地服务:下载淘宝镜像node.js :https://npm.taobao.org/mirrors/npm :本次下载的版本是 v10.0.0 2.下载成功后,到cmd窗口输入 node -v, ...