您的位置:首页 > 其它

裸板之UART驱动

2014-04-07 15:06 120 查看
1、什么是UART?

UART就是通用异步收发器。这个异步怎么体现呢?因为它没有时钟。

UART有 3条线:TX、RX、GND。
这里没有时钟线,那怎么知道什么时候发送,接收数据呢?

比如我们要发送字母'A',它的16进制是0x41, 2进制为 0100,0001.  那怎么发送呢?

平时发送引脚为高电平,那么串口怎么通知PC端要发送数据了呢?

要发送时,把发送引脚拉低,并维持一断时间,多久呢,维持一位的时间。这位叫做起始位。

然后发送8位数据0100,0001(从高开始发送,即先发0),发送完后维持一位的高电平,这个就叫做停止位。
发送方:开始位--数据--停止位。

      一开始为高电平,要发送时拉为低电平,通知要发送了,即开始位。
接收方:检测到低电平,知道要发送数据了。

  这就是串口的协议。

  每一位占多长时间(波特率);开始位、数据位、校验位、停止位各多少。

  发送:把要发送的数据写到缓冲区(操作寄存器),硬件自动的一位一位发送。

  接收:把数据一位一位存在缓冲区中。

2、进入代码分析

1)程序先从启动代码start.S开始运行,这个和以前的差不多,就不放上来了。

2)启动化,进入main()函数运行。
#include "uart.h"
int main()
{
char c;
init_uart(); /* 波特率,数据位,停止位... */
while (1)
{
c = getchar();
putchar(c+1);
}
return 0;
}
main 函数主要实现调用串口初始化函数,然后等待串口输入一个字符,加1后输出。  看一下初始化串口怎么做?
3)初始化串口

#define GPACON    (*((volatile unsigned long *)0x7F008000))
#define ULCON0    (*((volatile unsigned long *)0x7F005000))
#define UCON0     (*((volatile unsigned long *)0x7F005004))
#define UFCON0    (*((volatile unsigned long *)0x7F005008))
#define UMCON0    (*((volatile unsigned long *)0x7F00500C))
#define UFSTAT0   (*((volatile unsigned long *)0x7F005018))
#define UTXH0     (*((volatile unsigned char *)0x7F005020))           /*这里是char型,只能存一个字符*/
#define URXH0     (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0   (*((volatile unsigned short *)0x7F005028))
#define UDIVSLOT0 (*((volatile unsigned short *)0x7F00502C))

void init_uart(void)
{
/* 设置GPA0,GPA1作为RxD0, TxD0 */
GPACON &= ~0xff;
GPACON |= 0x22;

ULCON0 = 0x3;  /* 8个数据位,8n1 */
UCON0  = 0x5;  /* 使能UART, 时钟源PCLK */
UFCON0 = 0x1;  /* FIFO enable */
UMCON0 = 0;    /* 无流控 */

/* 设置波特率 */
/* DIV_VAL = (PCLK / (bps x 16 ) ) - 1
* bps  = 115200
* PCLK = 66500000 Hz
* DIV_VAL = 66500000 / (115200 x 16) - 1 = 35.08
* x/16 = 0.08
*    x = 1
*
*/
UBRDIV0   = 35; /* 实际波特率 = 115451 */
UDIVSLOT0 = 0x1;
}

char getchar(void)
{
/* 判断有无数据 */
/* 有数据的状态:
* 1. UFCON0 & (1<<6) == 1
* 或
* 2. UFCON0 & (1<<6) == 0, &&, (UFCON0 & 0x3f) > 0
* 无数据: UFCON0 & (1<<6) == 0, && (UFCON0 & 0x3f) == 0
*/

while ((UFSTAT0 & 0x7f) == 0);

return URXH0;     /*直接把这个接收寄存器的值取出来就可以,得到一个接收到的字符*/
}

void putchar(char c)
{
/* 判断状态 */
while (UFSTAT0 & (1<<14));   /* 如果TX FIFO满,等待 */
UTXH0 = c;             /*直接把要发送的字符放到这个发送寄存器就可以*/
}
1》 从原理图上得知,RXD0接GPA0,TXD0接GPA1。

那我们就要将这个gpio设置成 串口功能,GPACON设置成 0010 为串口功能。

2》 UFCON0

这个是FIFO 控制寄存器,什么是FIFO呢?



FIFO就是这个64字节的缓冲区,发数据时可以一次性发64字节的数据全部放到这个缓冲区中,然后硬件会一位一位的取走。因为串口的发送是很慢的,如果不用这个缓冲区只能一位一位的发,等取走后才能发下一位。             UFSTAT0 是缓冲区的状态,0:5 表示有多少位数据,第6位表示满或不满。  (UFSTAT0
& 0x7f) == 0 就表缓冲区中示没有数据。

3)波特率设置

假设我们的系统时钟 PCLK=66.5MHZ,要得到的波特率baudrate=115200.怎么得到?

 DIV_VAL = (PCLK / (bps x 16 ) ) −1      (公式1)

代进去算一下: DIV_VAL =(66.5*10^6/(115200*16))-1=35.008

DIV_VAL = UBRDIVn + (num of 1’s in UDIVSLOTn)/16   (公式2)

UBRDIVn =35   后面部分为小数, UDIVSLOTn算得为12.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: