1、UART原理簡介
在介紹2440的UART控制器之前,我們首先來了解一下UART的原理 UART:Universal Asynchronous Receiver/Transmitter(通用異步收發(fā)送器),用來傳輸串行數(shù)據(jù),發(fā)送數(shù)據(jù)時,CPU將并行數(shù)據(jù)寫入UART,UART按照一定格式在TxD線上串行發(fā)出;接收數(shù)據(jù)時,UART檢測到RxD線上的信號,將串行收集放到緩沖區(qū)中,CPU即可讀取UART獲得的這些數(shù)據(jù)。 UART最精簡的連線形式只有3根線,TXD用于發(fā)送,RXD用于接收,GND用于提供參考電平。UART之間以幀作為數(shù)據(jù)傳輸單位,幀由具有完整意義的若干位組成,它包含開始位、數(shù)據(jù)位、校驗位和停止位。發(fā)送數(shù)據(jù)之前,互相通信的UART之間要約定好數(shù)據(jù)傳輸速率(波特率的倒數(shù))、數(shù)據(jù)的傳輸格式(多少個數(shù)據(jù)位、是否使用校驗位、奇校驗還是偶校驗、多少個停止位)。
2、S3C2440 UART的特性 S3C2440的通用異步收發(fā)器(UART)配有3個獨立異步串行I/O(SIO)端口,每個都可以通過產(chǎn)生中斷或DMA請求來進行CPU和UART之間的數(shù)據(jù)傳輸。如圖1所示:每個UART包含一個波特率發(fā)生器、發(fā)送器、接收器和一個控制單元, 圖1 2440UART方框圖(帶FIFO) 波特率發(fā)生器可以由PCLK、FCLK/n或UEXTCLK(外部輸入時鐘)時鐘驅(qū)動。UART通過使用系統(tǒng)時鐘可以支持最高115.2Kbps的比特率。如果是使用外部器件提供UEXTCLK的UART,則UART可以運行在更高的速度。發(fā)送器和接收器各包含一個64字節(jié)的FIFO和數(shù)據(jù)移位器。要發(fā)送數(shù)據(jù)時,先將數(shù)據(jù)寫入到FIFO接著在發(fā)送前復制到發(fā)送移位器中,隨后將數(shù)據(jù)從發(fā)送數(shù)據(jù)引腳(TXDn)移出;接收數(shù)據(jù)時,從接收數(shù)據(jù)引腳(RXDn)移入收到的數(shù)據(jù),接著從移位器復制到FIFO。
3、S3C2440 UART的使用 對于S3C2440,使用UART之前,首選需要對2440的UART模塊進行初始化,需要設置波特率、傳輸格式(多少個數(shù)據(jù)位、是否使用校驗位、奇校驗或偶校驗、多少個停止位、是否使用流量控制)、選擇所涉及的管腳為UART功能、選擇UART通道的工作模式為中斷模式或DMA模式。設置好之后,往相關寄存器寫入數(shù)據(jù)即可發(fā)送,讀取相關寄存器即可接收到數(shù)據(jù),還可以通過查詢狀態(tài)寄存器或設置中斷來獲知數(shù)據(jù)是否發(fā)送完畢、是否接收到數(shù)據(jù)。 我用的開發(fā)板是天嵌的TQ2440,該開發(fā)板用SP3232EEN擴展了一個RS232串口,電路連接如圖2 所示: 圖2 RS232原理圖 波特率發(fā)生器 每個UART的波特率發(fā)生器為發(fā)送器和接收器提供串行時鐘,波特率發(fā)生器的時鐘源可以選擇S3C2440A的內(nèi)部時鐘系統(tǒng)或者UEXTCLK。波特率時鐘是通過16和由UART波特率分頻寄存器(UBRDIVn)(n=0,1,2)指定的16位分頻系數(shù)來分頻源時鐘(PCLK,F(xiàn)CLK/n或者UEXTCLK)產(chǎn)生的,UBRDIVn由下列表達式確定: UBRDIVn=(int)(UART時鐘/(波特率*16))-1 UART時鐘:PCLK,F(xiàn)CLK/n或者UEXTCLK,例如,如果波特率為115200bps并且UART時鐘為40MHz,則UBRDIVn為: UBRDIVn=(int)(40000000/(115200*16))-1=(int)(21.7)-1(取最接近的整數(shù))=22-1=21
介紹發(fā)送和接收操作之前,先介紹幾個重要的寄存器 UBRDIVn寄存器:設置波特率,S3C2440 UART的時鐘源有兩種選擇:PCLK、UEXTCLK、FCLK/n,其中n的值通過UCON0-UCON2聯(lián)合設置 ULCONn寄存器:設置傳輸格式 UCONn寄存器:它用于選擇UART時鐘源、設置UART中斷方式 UFCONn寄存器、UFSTATn寄存器,UFCONn寄存器用于設置是否使用FIFO,設置各FIFO的觸發(fā)闕值,即發(fā)送FIFO中有多少個數(shù)據(jù)時產(chǎn)生中斷、接收FIFO中有多少個數(shù)據(jù)時產(chǎn)生中斷。并可以通過設置UFCONn寄存器來復位各個FIFO。讀取UFSTATn寄存器可以知道各個FIFO是否已經(jīng)滿,其中有多少個數(shù)據(jù)。 UMCONn寄存器、UMSTATn寄存器,這兩類寄存器用于流量控制,具體看數(shù)據(jù)手冊
UTRSTATn寄存器,它用來表明數(shù)據(jù)是否已經(jīng)發(fā)送完畢、是否已經(jīng)接收到數(shù)據(jù) UERSTATn寄存器,用來表示各種錯誤是否發(fā)生 UTXHn寄存器,CPU將數(shù)據(jù)寫入這個寄存器,UART即會將它保存到緩沖區(qū)中,并自動發(fā)送出去 URXHn寄存器,當UART接收到數(shù)據(jù)時,CPU讀取這個寄存器,即可獲得數(shù)據(jù)。 下面通過實際的代碼來理解2440的UART 首選是UART的初始化,TQ2440將UART0引了一個接口出來,就介紹UART0吧 2440的UART引腳是掛接在GPH上的,所以使用UART之前需要先對GPH的引腳功能進行配置。 void uart0_init(void)
{
GPHCON |= 0xaa; // GPH0,GPH1,GPH2,GPH3分別nCTS0,nRTS0,TXD0,RXD0
GPHUP = 0x7ff; //內(nèi)部上拉被禁止 UFCON0 = 0x00; // 不使用FIFO
UMCON0 = 0x00; // 不使用流控
ULCON0 = 0x03; // 8N1(8個數(shù)據(jù)位,無校驗,1個停止位)
UCON0 = 0x245;
// 查詢方式,UART時鐘源為PCLK,中斷請求方式為Tx-電平,Rx-脈沖
rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 ); //設置波特率
} 接下來幾個是進行數(shù)據(jù)的發(fā)送和接收的函數(shù) //======此函數(shù)的作用是向UART發(fā)送一個字符,不用FIFO,直接用UART發(fā)送 void Uart_SendByte(char data) { if(data=='\n') { while(!(rUTRSTAT0 & 0x2)); 取出rUTRSTAT0(UART0發(fā)送/接收寄存器)寄存器中的第2位,含義為Transmit buffer是否為空,為1時表示空。在發(fā)送緩沖器為空時,再發(fā)送 // Delay(1); //because the slow response of hyper_terminal WrUTXH0('\r'); //將數(shù)據(jù)寫入到UART0發(fā)送緩沖器中 } while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty. // Delay(1); WrUTXH0(data); } //========發(fā)送字符串的函數(shù) void Uart_SendString(char *pt) { while(*pt) Uart_SendByte(*pt++); }
//C語言的可變參數(shù),為了達到printf的功能 //例如:Uart_Printf(“my name is %s”a[10]) ;就相當于Uart_SendString(“my name is XX”);XX是a[10]的內(nèi)容 void Uart_Printf(char *fmt,...) { va_list ap; char string[256];
va_start(ap,fmt); vsprintf(string,fmt,ap); Uart_SendString(string); va_end(ap); }
//==等待,直到UART的發(fā)送器為空,就是發(fā)送完畢 void Uart0_TxEmpty() { while(!(rUTRSTAT0 & 0x4)); //Wait until Tx shifter is empty. }
//===從終端上獲取敲入的字符,返回值為char類型。RdURXH0有數(shù)據(jù)時,返回URXH的數(shù)據(jù)。當URXH沒有數(shù)據(jù)時,總是等待,直到有數(shù)據(jù)。
char Uart_Getch(void) { while(!(rUTRSTAT0 & 0x1)); //接收緩沖器接收到有效數(shù)據(jù) return RdURXH0(); //從UART0接收緩沖器(URXH0)接收數(shù)據(jù) } //===Uart_GetKey 這個與Uart_Getch 不同的是,當URXH沒有數(shù)據(jù)時返回0。有數(shù)據(jù)時,返回數(shù)據(jù),這個函數(shù)可以用來查看當前URXH中的值。 char Uart_GetKey(void) { if(rUTRSTAT0 & 0x1) //Receive data ready return RdURXH0(); else return 0; } //==這個函數(shù)用于從終端得到一個字符串,并儲存到string中 void Uart_GetString(char *string) { char *string2 = string; char c; while((c = Uart_Getch())!='\r')//’\r’是回車鍵 { if(c=='\b')//’\b’是backspace按鍵 { if( (int)string2 < (int)string ) { Uart_Printf("\b \b");//因為backspace,所以刪除最后一個顯示的字符 string--; } } else { *string++ = c; //不是回車和退格鍵,則儲存到string中 Uart_SendByte(c); //每輸入一個字符,都將它輸出到終端中 } } *string='\0'; Uart_SendByte('\n'); }
|