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

代碼參考韋東山嵌入式教程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章