嵌入式入门3(UART)

955 阅读4分钟

UART:通用异步收发器(Universal Asynchronous Receiver and Transmitter),简称串口。主要用于:

  • 1、打印调试信息。
  • 2、外接各种模块,如:GPS、蓝牙。

一、UART协议

  • 1、收发双方约定好波特率(每一位占据的时间)
  • 2、规定传输协议:数据位、停止位、校验位、流量控制。

例如:115200 8n1,它表示发送的波特率为115200,8个数据位,无校验位,1个停止位,其中开始位固定为1位。也就是说:

1秒能传输115200位数据,即发送一位需要耗时t=1/115200秒。
每发送1byte数据,需要发送10位数据(开始位、数据位,停止位),耗时t=10/115200。
所以1秒钟能传输11520byte的数据。

二、UART传输流程

最常见的UART串口都是采用TTL/CMOS电平,即0V ~ 0.7V表示逻辑02V ~ 5V表示逻辑1

以传输字符'A'为例,其ASCII码为0x41,对应的二进制数据为0b0100,0001,当使用TTL/CMOS电平时,波形如下(注意这里是采用7位数据位):

image.png

  1. 初始时,TxD引脚电平为高电平。
  2. 开始发送数据时,ARM首先将TxD引脚电平拉低,并保持1bit时间。
  3. PC在低电平开始处计时。
  4. ARM根据数据依次驱动TxD的电平,发送数据。同时PC依次读取RxD引脚电平,获得数据。

但通常情况下,TTL电平满足不了长距离传输的要求,此时就引入RS-232电平,当电平在 +3V ~ +12V 时,表示逻辑0,当电平在 -3V ~ -12V 时,表示逻辑1。

image.png

三、UART打印调试信息

image.png

通过查阅芯片手册第11章UART,知道S3C2440支持3个Uart口。引脚如下

image.png

然后查看JZ2440电路图,可以知道USB串口采用的是UART0。

image.png

所以我们可以通过配置UART0,来打印调试信息。

3.1、设置引脚用于串口

首先配置GPH2、GPH3为串口引脚,并使能其上拉电阻,因为TTL电平的UART空闲状态为高电平。

image.png

image.png

//设置引脚用于串口
//GPH2,3用于TxD0,RxD0
GPHCON &= ~((3<<4)|(3<<6));
GPHCON |=  ((2<<4)|(2<<6));

//使能内部上拉
GPHUP &= ~((1<<2)|(1<<3));

3.2、配置UART0

1、设置波特率和时钟

image.png

我们通过设置UBRDIVn分频,可以分频串口的时钟,来满足我们所期望的波特率。公式如下:

UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1

芯片手册也给了例子,但我们在上一章中,我们将PCLK设置为50MHz,所以我们代入上式,得到UBRDIVn=26。即此时UART clock为50MHz,波特率为115200。

此时,我们重点关注,如何将PCLK设置为UART clock。

image.png

这里设置UCON0[11:10]为00或10,让UART clock等于PCLK的50MHz。

image.png

Tx Interrupt Type、Rx Interrupt Type:中断类型,由于我们没有使用到中断,使用默认值。
Rx Time Out:读超时
Loopback Mode:回环模式,用来测试串口,数据发送后,能立即收到。

image.png

然后指定UCON0[3:2]和UCON0[1:0]为01,开启中断或查询模式。

//设置波特率
//UBRDIVn = (int)(UART clock / (buad rate x 16)) - 1
//UART clock = 50M
//UBRDIVn = 26
//PCLK,中断/查询模式
UCON0 = 0x00000005;
UBRDIV0 = 26;

2、设置数据格式

常见的数据格式为8n1,即8个数据位,无校验位,一个停止位。

image.png

//设置数据格式
ULCON0 = 0x00000003;//8n1

3、发送和接收数据

image.png

当UTRSTATn[2]=1时,表示发送buffer和移位控制器都是空的,此时可以继续发送数据。
当UTRSTATn[0]=1时,表示接收buffer中有数据,此时可以进行读取数据。

image.png

我们只需将数据存入UTXHn寄存器中,数据将会被UART自动发送出去。同时通过读取URXHn寄存器,来读取UART接收到的数据。

3.3、完整代码

uart.c

#include "s3c2440_soc.h"
#include "uart.h"

void uart_init()
{
    //设置引脚用于串口
    //GPH2,3用于TxD0,RxD0
    GPHCON &= ~((3<<4)|(3<<6));
    GPHCON |=  ((2<<4)|(2<<6));

    //使能内部上拉
    GPHUP &= ~((1<<2)|(1<<3));

    //设置波特率
    //UBRDIVn = (int)(UART clock / (buad rate x 16)) - 1
    //UART clock = 50M
    //UBRDIVn = 26
    //PCLK,中断/查询模式
    UCON0= 0x00000005;
    UBRDIV0 = 26;

    //设置数据格式
    ULCON0 = 0x00000003;//8n1
}

int uart_putchar(int c)
{
    while(!(UTRSTAT0 & (1<<2)));
    UTXH0 = (unsigned char)c;
}

int uart_getchar(void)
{
    while(!(UTRSTAT0 & (1<<0)));
    return URXH0;
}

int uart_puts(const char *s)
{
    while(*s) {
        uart_putchar(*s);
        s++;
    }
}

main.c

#include "uart.h"

int main(void)
{
    unsigned char c;

    uart_init();
    uart_puts("Hello, world!\n\r");

    while(1)
    {
        c = uart_getchar();
        uart_putchar(c);
    }
    return 0;
}

修改s3c2440_soc.h

......
#define     __REG(x)					(*(volatile unsigned int *)(x)) 
#define     __REG_BYTE(x)				(*(volatile unsigned char *)(x)) 

......

#define     UTXH0                    __REG_BYTE(0x50000020)  //UART 0 transmission hold 
#define     URXH0                    __REG_BYTE(0x50000024)  //UART 0 receive buffer    

......