通用异步收发器UART

UART的介绍

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器),俗称串口。
通常计算机与外部设备通信的端口分为并行与串行:
a. 并行端口是指数据的各个位同时进行传送,其特点是传输速度快,但是当传输距离远、位数多时,通信线路变得复杂且成本提高;
b. 串行通信是指数据一位位地顺序传送,其特点是适合于远距离通信,通信线路简单,只要一对传输线就可以实现全双工通信,从而大大降低成本。

串行通信又分为异步与同步两种类型,两者之间最大的差别是:异步通信以一个字符为单位传输,同步通信以一个字符序列为单位传输。

UART的数据传输

目前常用的串口有9针和25针,最简单且常用的是三线制接法,即信号地、接收数据和发送数据三引脚相连。
数据线以“位”为最小单位传输数据;帧(frame)由具有完整意义的、不可分割的若干位组成,包括开始位、数据位、校验位(可有可无)和停止位。
发送数据之前,收发双方要约定好数据的传输速率(即传送一位所需的时间,其倒数成为波特率)和数据的传输格式(即多少个数据位、是否校验、有多少个停止位)。

注意:
1)数据线上没有数据传送时处于“空闲”状态,对应高电平,即1状态;
2)当要发送数据时,串口改变发送数据线的状态为低电平,即0状态;
3)串口一帧中可以有4、5、6、7或8位的数据,发送端一位位地改变数据线的电平状态将其发送,最低位先发送
4)数据位加上校验位后,使得“1”的位数为偶数(偶校验)或奇数(奇校验),以此来校验数据传输的正确性;
5)最后发送停止位,数据线恢复到“空闲”状态,即1状态。停止位的长度有3种:1位、1.5位和2位。

S5PV210的串口介绍

S5PV210有4个串口模块,提供了4个独立的异步串行输入/输出端口。它们可工作于中断模式或DMA模式,支持3Mbps的位速率。
每个串口通道包含2个FIFO缓存,用于接收和发送数据,其中通道0的FIFO支持256个字节,通道1支持64个字节,通道2和通道3支持16个字节。

串口还包含可编程的波特率、红外收发、1或2个停止位、5~8位数据位、校验位,并且每个串口模块都由波特率产生装置、发送装置、接收装置和控制单元组成。其中,波特率可由外部时钟或系统时钟提供,发送/接收装置分别由各自的FIFO和数据移位寄存器组成。

S5PV210的串口使用

本例使用串口通道0和通道1,具体操作步骤如下:
1)将串口通道的引脚配置为串口功能
所谓引脚配置,即上一章所讲的GPIO引脚设置,这里需要将GPA_0、GPA_1设置为串口的接收功能(RXD0)和发送功能(TXD0)。
2)时钟源选择及工作模式设置
通过配置UCON0寄存器(起始地址为0xE290_0004)选择时钟源和工作模式。
其中,UCON0[10]:S5PV210的时钟源可由外部时钟PCLK(0)或系统时钟SCLK_UART(1)提供。
3)设置波特率
根据设置的波特率(bps)和选择的时钟频率,利用以下公式确定UBRDIV0寄存器的值:
DIV_VAL = (所选时钟频率/(bps×16)-1),
该公式计算出的UBRDIV0寄存器的值未必是整数,UBRDIV0寄存器取其整数部分;
DIV_VAL小数部分*16,取整,再查表,就得UDIVSLOT0的值。
4)设置数据传输格式
通过ULCON0寄存器(地址为0xE290_0000)设置红外模式、校验模式、停止位宽度、数据位宽度,如下表所示:

ULCON0
保留[31:7]
红外模式[6]
校验模式[5:3]
停止位[2]
数据位[1:0]

问:数据位8位,停止位1位,奇校验,正常串口,怎么设置?
ULCON0=(3<<0)|(0<<2)|(4<<3)|(0<<6)
5)启用或禁用FIFO
配置寄存器 UFCONn实现是否使用FIFO、设置FIFO触发阈值、FIFO复位功能。
FIFO触发阈值:发送FIFO中有多少个数据时产生中断;接收FIFO中有多少个数据时产生中断。
6)收发数据(UTXH0寄存器,URXH0寄存器)
发送数据:CPU将数据写入寄存器 UTXHn ,UARTn将数据保存到缓冲区中,并自动发送出去;
接收数据:CPU读取URXHn寄存器即可获得数据。
7)收发数据状态的控制(UTRSTAT0寄存器)
由寄存器 UTRSTATn 可知数据是否收发完毕。
发送:while(!(UTRSTAT0 & (1<<2)){}
接受:while(!(UTRSTAT0 & (1<<0)){}
8)数据传输时的错误控制
由bit[0]~bit[3]分别表示是否溢出、是否校验错误、是否帧错误、是否检测到break信号。错误状态被读取后,寄存器自动清零。

实验实例

实验目的:通过串口接收数据“1”使LED1亮,“2”使LED1灭,“3”使LED2亮,“4”使LED2灭。
实验原理:UART0控制器与一个RS-232的电平转换模块相连,配置好UART0后,CPU发送给UART0的数据可以通过串口输出到PC机上(PC机上需要接收工具,比如SecureCRT)。

程序包括三部分:

  1. 启动代码
  2. UART设置
  3. 主程序(点亮LED)

默认PCLK为时钟源,且为66MHz。
1.启动代码
参考上一章GPIO实例,实现代码一致。
2.UART设置
(1)UART初始化

// GPIO、UART寄存器地址
#define GPA0CON		*((volatile unsigned int *)0xE0200000)
#define ULCON0 		*((volatile unsigned int *)0xE2900000)
#define UCON0 		*((volatile unsigned int *)0xE2900004)
#define UFCON0 		*((volatile unsigned int *)0xE2900008)
#define UTRSTAT0 	*((volatile unsigned int *)0xE2900010)
#define UTXH0  		*((volatile unsigned int *)0xE2900020)
#define URXH0 		*((volatile unsigned int *)0xE2900024)
#define UBRDIV0 	*((volatile unsigned int *)0xE2900028)
#define UDIVSLOT0	*((volatile unsigned int *)0xE290002C)

// 初始化UART0
void uart0_init()
{
	// 配置GPA0_0为UART_0_RXD,GPA0_1为UART_0_TXD
	GPA0CON &= ~0xFF;//清零
	GPA0CON |= 0x22;// bit[3:0]=0b0010,bit[7:4]=0b0010
	/* 配置串口的数据传输格式
		* 8位数据位 bit[1:0]=0x3
		* 1位停止位 bit[2]=0
		* 无校验    bit[5:3]=0xx
		* 正常模式  bit[6]=0
	*/
	ULCON0 = (3<<0)|(0<<2)|(0<<3)|(0<<6);
	/* 配置UCON0
	* 接收模式为中断或轮询 bit[1:0]=1
	* 发送模式为中断或轮询 bit[3:2]=1
	* 允许产生异常中断     bit[6]=1
	* 时钟选择外部时钟     bit[10]=0
	*/
	UCON0 = (1<<0) | (1<<2) | (1<<6) | (0<<10);	  
	// 不使用FIFO
	UFCON0 = 0;
	/* 波特率设置为115200
	* 已知PCLK=66MHz
	* DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
	* UBRDIV0 = 34(DIV_VAL的整数部分)
	* (num of 1's in UDIVSLOTn)/16 = 0.8
	* (num of 1's in UDIVSLOTn) = 13
	* UDIVSLOT0 = 0xDFDD (参考手册查表)
	*/
	UBRDIV0 = 34;
	UDIVSLOT0 = 0XDDDD;
	return;
}

(2)发送数据
本实验禁用FIFO,因此,在发送字符前,要判断上一个字符是否已经被发送出去。
当UTRSTAT0寄存器的bit[2]为1时,表示已经发送完毕,这样就可以向UTXH0寄存器中写入要发送的字符了。

void putc(unsigned char c)
{
	// 查询状态寄存器,等待发送缓存为空
	while (! (UTRSTAT0 & (1<<2)));  //课本97页,表7-3
	UTXH0 = c; // 写入发送寄存器
	return;
}

(3)接收数据
读数据之前要先查询UTRSTAT0寄存器的bit[0],当它为1时表示接收缓存中有数据,也就可以读取URXH0中的数据了。

unsigned char getc(void)
{
	// 查询状态寄存器,等待接收缓存有数据
	while (!(UTRSTAT0 & (1<<0)));
	return (URXH0);
}

(4)发送字符串数据
这是一个扩展功能,通过一个while循环将字符串拆分成一个一个的字符发送出去。

void puts(char *str)
{
	char *p = str;
	while (*p)
		putc(*p++);
}

3.主程序

#define GPC0CON		*((volatile unsigned int *)0xE0200060)
#define GPC0DAT		*((volatile unsigned int *)0xE0200064)
#define	GPC0_3_out	(1<<(3*4))
#define	GPC0_4_out	(1<<(4*4))
#define	GPC0_3_MASK	(0xF<<(3*4))
#define	GPC0_4_MASK	(0xF<<(4*4))

extern void uart0_init(void);
int main(void)
{
	char c;
	uart0_init(); 			// 初始化uart0
	GPC0CON &= ~(GPC0_3_MASK | GPC0_4_MASK); 	// 清bit[15:12]和bit[19:16]
	GPC0CON |= (GPC0_3_out | GPC0_4_out);		// 配置GPC0_3和GPC0_4为输出引脚
	GPC0DAT &= ~(0x3<<3);  // 向 bit[4:3]写入0熄灭LED1、LED2
	puts("=============================\r\n");
	puts("S5PV210 UART Test:\r\n");
	puts("1.LED1 on\r\n");
	puts("2.LED1 off\r\n");
	puts("3.LED2 on\r\n");
	puts("4.LED2 off\r\n");
	puts("=============================\r\n");
	while (1)
	{
		c = getc();		// 从串口终端获取一个字符
		putc(c);		// 回显
		if (c == '1')
			GPC0DAT |= 1 << 3;		// LED1亮
		else if (c == '2')
			GPC0DAT &= ~(1 << 3);	// LED1灭
		else if (c == '3')
			GPC0DAT |= 1 << 4;      // LED2亮
		else if (c == '4')
			GPC0DAT &= ~(1 << 4);   // LED2灭
	}
	return 0;
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值