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)。
程序包括三部分:
- 启动代码
- UART设置
- 主程序(点亮LED)
默认PCLK为时钟源,且为66MHz。 1.启动代码 参考上一章GPIO实例,实现代码一致。 2.UART设置 (1)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)
void uart0_init()
{
GPA0CON &= ~0xFF;
GPA0CON |= 0x22;
ULCON0 = (3<<0)|(0<<2)|(0<<3)|(0<<6);
UCON0 = (1<<0) | (1<<2) | (1<<6) | (0<<10);
UFCON0 = 0;
UBRDIV0 = 34;
UDIVSLOT0 = 0XDDDD;
return;
}
(2)发送数据 本实验禁用FIFO,因此,在发送字符前,要判断上一个字符是否已经被发送出去。 当UTRSTAT0寄存器的bit[2]为1时,表示已经发送完毕,这样就可以向UTXH0寄存器中写入要发送的字符了。
void putc(unsigned char c)
{
while (! (UTRSTAT0 & (1<<2)));
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();
GPC0CON &= ~(GPC0_3_MASK | GPC0_4_MASK);
GPC0CON |= (GPC0_3_out | GPC0_4_out);
GPC0DAT &= ~(0x3<<3);
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;
else if (c == '2')
GPC0DAT &= ~(1 << 3);
else if (c == '3')
GPC0DAT |= 1 << 4;
else if (c == '4')
GPC0DAT &= ~(1 << 4);
}
return 0;
}
|