1、目的
串口通訊咱們並不陌生,咱們常常用串口來進行數據傳輸,可並不清楚它是如何工做
的。那這一節咱們就來揭開 ARM S3c2410 UART(Universal Asynchronous Receiver and
Transmitter) 串口通訊的神祕面紗。html
2、代碼
咱們先來分析文件 crt0.s
@ 文件 crt0.s
@ 做用:設置堆棧指針
.text
.global _start
_start:
ldr sp, =1024*4
bl main
halt_loop:
b halt_loop
你可能會有疑問,這個彙編文件有什麼用?呵呵,這是由於咱們的串口通訊代碼要用 C
編寫(用匯編可讀性太差了)。可這又和這個 crt0.s 有什麼關係呢?這得從 C 語言程序的
編譯提及。C 語言程序執行的第一條指令並不在 main 函數裏。當生成一個 C 語言程序時
編譯器老是在咱們的代碼前加一段固定的代碼--crt0.o,它是編譯器自帶的一個文件,用來
設置 C 程序的堆棧等,而後調用 main 函數。惋惜在咱們的裸板上它自帶的 crt0.o 的代
碼是不能運行的,咱們得本身動手寫,這就是爲何要有 crt0.s 這個文件。稍後你將看到,
這個 crt0.s 被編譯成咱們本身的 crt0.o 文件。linux
/* 頭文件 serl.h
* 做用:定義相關寄存器、UART 初始化函數聲明、串口讀寫函數的聲明
*/
#ifndef __SERL_H__
#define __SERL_H__
#define GPHCON (*(volatile unsigned long *)0x56000070)
/* PORT PULL-UP REGISTER*/
#define GPHUP (*(volatile unsigned long *)0x56000078)
/* UART FIFO control register 0*/
#define UFCON0 (*(volatile unsigned long *)0x50000008)
/* UART line control register 0*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
/* UART control register 0*/
#define UCON0 (*(volatile unsigned long *)0x50000004)
/* UART modem control register 0*/
#define UMCON0 (*(volatile unsigned long *)0x5000000C)
/* UART baud rate divisor register 0*/
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
/* UART TX/RX status register 0*/
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
/* UART transmit buffer register 0*/
#define UTXH0 (*(volatile unsigned char *)0x50000020)
/* UART receive buffer register 0*/
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define TXD0_READY 0x2
#define RXD0_READY 0x1
void init_uart();
void putc(unsigned char ch);
unsigned char getc();
#endif編程
/* 文件 serl.c*/
#include "serl.h"
void init_uart() {
GPHCON |= 0xa0; /* GPH2, GPH3 used as RXD0, TXD0*/
GPHUP = 0x0c; /* GPH2, GPH3 poll-up */
ULCON0 = 0x03; /* normal mode, no parity, one stop bit, 8-bit*/
UCON0 = 0x05; /* Loopback mode*/
UFCON0 = 0x00; /* not use FIFO*/
UMCON0 = 0x00; /* disable flow control*/
UBRDIV0 = 12; /* baud rate 57600*/
}
void putc(unsigned char ch) {
while (!(UTRSTAT0 & TXD0_READY));
UTXH0 = ch;
}
unsigned char getc(){
while (! (UTRSTAT0 & RXD0_READY));
return URXH0;
}
函數
咱們選用最簡單的方法,用 UART0 進行實驗,用到的寄存器有8個多,初始化用去5
個,餘下的3個用於接收、發送數據。初始化設置的代碼說明以下:
1. GPHCON 的 GPH二、GPH3用控制接收數據寄存器 RXD0 和發送數據寄存器 TXD0
手冊中GPH二、GPH3描述以下:oop
GPHCON | Bit | Description | |
GPH3 | [7:6] | 00 = Input | 01 = Output |
10 = RXD0 | 11 = reserved | ||
GPH2 | [5:4] | 00 = Input | 01 = Output |
10 = TXD0 | 11 = Reserved |
2. ULCON0 設置爲 0x03, 含義是正常操做模式、無校驗、中止位一、8個數據位
3. UCON0 設置爲 0x05 表示發送、接收數據都使用查詢方式
4. UFCON0 設置爲 0x00 爲不使用 FIFO (每一個UART內部都有一個16字節的發送和接收
FIFO)
5. UMCON0 設置爲 0x00 爲不使用流控
6. UBRDIV0 設置爲 12 含義爲 波特率設爲 57600, 由下面公式算得:
UBRDIVn = (int) (PCLK/bps*16) - 1
其中 PCLK = 12MHz學習
發送/接收數據的代碼說明以下:
1. UTRSTA0 (UART TX/RX status register 0 )
bit[1]:無數據發送時自動設爲1,咱們要用串口發送數據時,先讀此位以判斷是否有
數據正在發送。
bit[0]:接收緩衝區是否有數據,若是有,此位自動設爲1,咱們須要讀此位來判斷是
否接收到了數據。
2. UTXH0: 把要發送的數據寫入此寄存器
3. URXH0: 讀此寄存器會獲得串口接收到的數據測試
/*
* 測試代碼 main.c
* 做用:將從串口接收的數據發回串口
*/
#include "serl.h"
int main(void) {
unsigned char ch;
init_uart();
while (1) {
ch = getc();
/* 若是接收到的是回車符就發送回車和換行符*/
if (ch == 0x0d) {
putc(0x0d);
putc(0x0a);
}
else {
putc(ch);
}
}
}
spa
# 文件 Makefile
# 由代碼文件生成目標文件,並鏈接目標文件
# 最後將鏈接生成的目標文件轉換成二進制格式
main:crt0.s serl.c main.c
arm-linux-gcc -c -o crt0.o crt0.s
arm-linux-gcc -c -o serl.o serl.c
arm-linux-gcc -c -o main.o main.c
arm-linux-ld -Ttext 0x00000000 crt0.o serl.o main.o -o main_tmp.o
arm-linux-objcopy -O binary -S main_tmp.o main
clean:
rm -f *.o
rm -f main指針