05-筆記:LPC1788-串口


概述

LPC178x/177x 系列 Cortex-M3 具有 5 個符合 16C550 工業標准的異步串行口 UART0、 UART1、UART2、UART3 和 UART4。
其中,各串行口的區別是:UART1 比 UART0、2、3 增 加了 Modem 接口;
UART4 較 UART0、2、3 增加了 IrDA 接口和符合 ISO7816-3 的智能卡接口, 其余都基本相同。
注:默認情況下, UART2 、 UART3 和 UART4 都被關閉,以節省功耗。若需使用 UART2 、 UART3 和 UART4 , 請設置 PCONP 寄存器的相關位。此外,在不啟用 Modem 、 IrDA 等模式時, UART1 和 UART4 也可以和 UART0 、 2 、 3 一樣,當普通 UART 來用。
 

特性

 數據大小為 5、6、7、8 位;
 奇偶發生和校驗:奇、偶標記,空格或沒有;
 1 個或 2 個停止位;
 16 字節收發 FIFO;
 內置波特率發生器,包括小數波特率分頻器用於各種功能;
 支持 DMA 發送和接收;
 自動波特率功能;
 間隔發生和檢測;
 多處理器尋址模式;
 UART1 包含標准 Modem 接口信號(CTS、DCD、DTS、DTR、RI、RTS);
 UART4 包含支持紅外通信的 IrDA 模式;
 UART0/2/3/4 支持軟件流控制;
 UART0/2/3/4 支持 RS-458/EIA-485,其中 UART4 支持 9-位模式和輸出使能;
 UART4 支持可選擇的同步發送或接收模式;
 UART4 支持可選擇的遵循 ISO 7816-3 規范的智能卡接口。
 

引腳描述

[1] 當 UARTn 的兩根或兩根以上 RXDn 腳啟用時,僅引腳編號最小的那根 RXD 腳有效,而成為 UARTn 的數據輸入引腳。此時,其它被復用為 RXD 的引腳對 UARTn 輸入沒有影響。例如 RXD3 對應的四根 引腳 P0.1 、 P0.3 、 P0.26 、 P4.29 若同時啟用為 UART 數據接收腳,那么,僅 P0.1 腳能有效接收數據。
[2] 當 UARTn 的 TXDn 腳全部啟用時,所有 TXDn 引腳都會彼此獨立地輸出相同信號。
只有 UART1 才具有 Modem 接口,因此 UART0、UART2、UART3 和 UART4 不具有 CTS1、
DCD1、DSR1、RI1、DTR1 和 RTS1 引腳。
只有 UART4 支持同步模式,因此 UART0、UART1、UART2 和 UART3 不具有 SCLK 引腳。
 
 
UART0 和 UART1、UART2、UART3、UART4 各有一個獨立波特率發生器,它們的功能
都是相同的,我們以 UART0 波特率發生器(U0BRG)為例進行說明。
U0BRG 產生 UART0 發送模塊所需的時鍾。UART0 波特率發生器時鍾源為 APB 時鍾
(PCLK)。 時鍾源與 U0DLL 和 U0DLM 寄存器所確定的除數相除得到 UART0 Tx 模塊所需時
鍾,該時鍾必須為目標波特率的 16 倍。
 
LPC178x/177x 系列 Cortex-M3 UART 部分的寄存器結構如圖 5.16 所示。其中,UART1 具
有 Modem 模塊,UART4 具有 IrDA 模塊和智能卡接口模塊,UART0/2/3/4 具有 485 模塊。
 
 
LPC178x/177x 系列 Cortex-M3 的五個 UART, 具有 16 字節的收發 FIFO,內置波特率發
生器,五個串口具有基本相同的寄存器,其中 UART1 帶有完全的調制解調器控制握手接口。
在大多數異步串行通訊的應用中,並不需要完整的 Modem 接口信號(輔助控制信號),而只使用
TXD、RXD 和 GND 信號即可。
 

UART 中斷

LPC178x/177x 系列 Cortex-M3 UART 接口具有中斷功能,而且由嵌套向量中斷控制器
(NVIC)管理,UART0、UART1、UART2、UART3 和 UART4 中斷分別位於 NVIC 中斷通道
21、通道 22、通道 23、通道 24 和通道 51。
以 UART0 為例,UART0 接口中斷與嵌套向量中斷 控制器(NVIC)的關系如圖 5.24 所示。
UART0 中斷占用 NVIC 的通道 21,中斷使能寄存器 ISER 用來控制 NIVC 通道的中斷使能。
當 ISER0[5]=1 時,通道 21 中斷使能,即 UART0 中斷使能。
中斷優先級寄存器 IPR 用來設定 NIVC 通道中斷的優先級。IPR1[15:11]用來設定通道 21
的優先級,即 UART0 中斷的優先級。具體的設定方法可參考“嵌套向量中斷控制器(NVIC)”
一節。
當 UART0 接口的優先級設定且中斷使能后,若觸發條件滿足時,則會觸發中斷。當處理
器響應中斷后將自動定位到中斷向量表,並根據中斷號從向量表中找出 UART0 中斷處理的入
口地址,然后 PC 指針跳轉到該地址處執行中斷服務函數。因此,用戶需要在中斷發生前將
UART0 的中斷服務函數地址(UART0_IRQHandler)保存到向量表中。
UART 中斷主要分為 5 類 :接收中斷、發送中斷、接收線狀態中斷、Modem 中斷和自動波
特率中斷,如圖 5.25 所示。其中, 接收線狀態中斷指接收過程中發生了錯誤,即接收錯誤中斷。
只有 UART1 接口具有 Modem 中斷,其它 UART 接口由於沒有 Modem 功能,所以沒有 Modem
中斷。自動波特率中斷包括自動波特率結束中斷和超時中斷。

UARTn 中斷標志寄存器(UnIIR,n = 0~4)

UnIIR 提供狀態碼用於指示掛起中斷 [1] 的中斷源 和優先級,5 個 UART 的 IIR 寄存器之概況如表 5.29
所列。其中,只有 UART1 具有 Modem 中斷。 [1] “掛起中斷”是指產生了但是未被響應的中斷請求。
在訪問 UnIIR 過程中,中斷被凍結。若訪問 UnIIR 時產生了中斷,該中斷將被記錄,下次訪問 UnIIR 時
便可將其讀出。UART 中斷標志寄存器描述如表 5.30 所列。
中斷的處理見表 5.31。給定了 UnIIR[3:0]的狀態,中斷處理程序就能確定中斷源以及如何 清除激活的中斷
(1)UART 接收線狀態中斷(RLS 中斷)
接收線狀態(UnIIR[3:1]=011)是最高優先級中斷。只要 UARTn 在接收數據時產生下面 4
個錯誤中的任意一個,UnIIR 將產生相應的中斷標志。
 溢出錯誤(OE);
 奇偶錯誤(PE);
 幀錯誤(FE);
 間隔中斷(BI)。
具體錯誤類型可通過查看 UnLSR[4:1]得到。 當讀取 UnLSR 寄存器時,自動清除該中斷標志。
(2)UART 接收數據可用中斷(RDA 中斷)
接收數據可用中斷(UnIIR[3:1]=010)與字符超時中斷(UnIIR[3:1]=110)共用第二優先級。
當 UARTn 接收 FIFO 達到 UnFCR[7:6]所定義觸發點時,RDA 中斷被激活。當 UARTn Rx FIFO
的深度低於觸發點時,RDA 中斷復位。當接收數據可用中斷激活時,CPU 可讀出由觸發點所
定義長度的數據塊。
(3)UART 字符超時中斷(CTI 中斷)
字符超時中斷(UnIIR[3:1]=110)為第二優先級中斷。當接收 FIFO 中的有效數據個數少於
觸發個數時(至少有一個),如果經過了一段時間 [1] 沒有數據到達,將觸發字符超時中斷,此時
CPU 就認為一個完整的字符串已經結束,然后將接收 FIFO 中的剩余數據。
[1] 這個觸發時間為:接收 3.5 到 4.5 個字符的時間。“ 3.5 ~ 4.5 個字符的時間”,其意思是在當前波特率下, 發送 3.5 ~ 4.5 個字節所需要的時間。
產生字符超時中斷后,對接收 FIFO 的以下操作都會清除該中斷標志:
 從接收 FIFO 中讀取數據,即,讀取 UnRBR 寄存器;
 有新的數據送入接收 FIFO,即,接收到新數據。
需要注意的是: 當接收 FIFO 中存在多個數據,從 UnRBR 讀取數據,但是沒有讀完所有數
據,那么在經過 3.5~4.5 個字節的時間后將再次觸發字符超時中斷;
例如,一個外設向 LPC178x/177x 系列 Cortex-M3 發送 85 個字符,而接收觸發值為 8 個字
符,那么前 80 個字符將使 CPU 接收 10 個接收數據可用中斷,而剩下的 5 個字符使 CPU 接收
1~5 個字符超時中斷(取決於服務程序)。
 
 

接收中斷

對於 UART 接口來說,有兩種情況可以觸發 UART 接收中斷:
接收字節數達到接收 FIFO 的觸發點(RDA)、接收超時(CTI)。
 
接收字節數達到接收 FIFO 中的觸發點(RDA)
LPC178x/177x系列Cortex-M3 UART接口 具有 16 字節的接收 FIFO,接收觸發點可以設
置為 1、4、8、14 字節, 當接收到的字節數達 到接收觸發點時,便會觸發中斷
如圖 5.26 所示,通過 UART FIFO 控制寄 存器 UnFCR,將接收觸發點設置為“8 字節觸
發”。那么當 UART 接收 8 個字節時,便會觸 發 RDA 中斷(注:在接收中斷使能的前提下)。
 
接收超時
當接收 FIFO 中的有效數據個數少於觸發個數 時(注:接收 FIFO 中至少有一個字節),如果長時
間沒有數據到達,將觸發 CTI 中斷。這個時間為: 3.5 到 4.5 個字符的時間。

接收線狀態中斷

在 UART 接收數據時,如果出現溢出錯誤(OE)、奇偶錯誤(PE)、幀錯誤(FE)和間隔中斷(BI)中的任意一個 錯誤時,都會觸發接收線狀態中斷。具體的錯誤標志可以通
過讀取 UART 狀態寄存器 UnLSR[4:1]得到。 當讀取 UnLSR寄存器時,會清除該中斷標志。
 
 
 
 

初始化

設置 UART 通信波特率,就是設置寄存器 UnDLL 和 UnDLM 的值,UnDLL 和 UnDLM 寄
存器是波特率發生器的除數鎖存寄存器,用於設置合適的串口波特率。
上面已經講過,寄存器
UnDLL 與 UnRBR/UnTHR、UnDLM 與 UnIER 具有同樣的地址,如果要訪問 UnDLL、UnDLM,
除數訪問位 DLAB 必須為 1。在不使用小數分頻器時,寄存器 UnDLL 和 UnDLM 的計算如下:
設置 UART 的 工作模式,如:字長度選擇、停止位個數、奇偶校驗位等。此外,還要根據實際情況設置中斷。
UART0 初始化示例,程序將串口波特率設置為 UART_BPS(如 115200), 8 位數據長度,1 位停止位,無奇偶校驗。
#define UART_BPS 115200  /*  定義通訊波特率 */
/**********************************************************************************************
**  函數名稱: UART0_Ini
**  函數功能:初始化串口 0 。設置為 8 位數據位, 1 位停止位,無奇偶校驗,波特率為 115200
**********************************************************************************************/
void UART0_Ini(void)
{
	uint32_t Fdiv = 0;
	U0LCR = 0x83;  /* DLAB = 1 ,可設置波特率 */
	Fdiv = (Fpclk / 16) / UART_BPS; /*  設置波特率 */
	U0DLM = Fdiv / 256;
	U0DLL = Fdiv % 256; 
	U0LCR = 0x03;  /* 鎖定除數訪問 */
	U0FCR  = 0x07;  /* 使能並復位 FIFO */
}
 

UART 發送數據

LPC178x/177x 系列 Cortex-M3 含有一個 16 字節的發送 FIFO,在發送數據的過程中,發送
FIFO 是一直使能的,即,UART 發送的數據首先保存到發送 FIFO 中,發送移位寄存器會從發
送 FIFO 中獲取數據,並通過 TXD 引腳發送出去,如圖 5.36 所示。
上面講過,寄存器 UnRBR 與 UnTHR 是同一地址,但物理上是分開的,讀操作時為 UnRBR,
而寫操作時為 UnTHR。
在寄存器 UnLSR 中,有兩個位可以用在 UART 發送過程中,UnLSR[5]和 UnLSR[6]
(1)UnLSR[5]——THRE
當發送 FIFO 為空時,THRE 置位。從上面的描述可知,當發送 FIFO 變空時,發送 FIFO
中的數據已經保存到了發送移位寄存器中,因此,移位寄存器此時正開始傳輸一個新的數據。
當再次向 UnTHR 寄存器中寫入數據時,THRE 位會自動清零。
(2)UnLSR[6]——TEMT
當發送 FIFO 和移位寄存器都為空時,TEMT 置位。由於所有發送的數據都是從移位寄存
器中發送出去的,因此,當 TEMT 置位時,表示 UART 數據已經發送完畢,而且,此時發送
FIFO 也已經沒有數據了。當再次向 UnTHR 寄存器中寫入數據時,TEMT 位會自動清零。
只要 TEMT 位置位,則 THRE 位也一定會置位的。
UART 接口發送操作可以采用兩種方式:中斷方式和查詢方式。如表 5.66 所示。
采用查詢方式發送一字節數據
/**********************************************************************************************
**  函數名稱: UART0_SendByte
**  函數功能:向串口發送字節數據,並等待發送完畢
**  入口參數: data  要發送的數據
**  出口參數:無
**********************************************************************************************/
void UART0_SendByte(uint8 data)
{
U0THR = data; /*  發送數據 */
while ( (U0LSR&0x40)==0 );  /*  等待數據發送完畢 */
}
 
 
 

UART 接收數據

寄存器 UnRBR 與 UnTHR 是同一地址,但物理上是分開的,讀操作時為 UnRBR,
而寫操作時為 UnTHR。
LPC178x/177x 系列 Cortex-M3 的四個 UART,各含有一個 16 字節的 FIFO,用來作為接收
緩沖區,緩沖區中的數據只能夠通過寄存器 UnRBR 來獲取。UnRBR 是 UARTn 接收 FIFO 的
最高字節,它包含了最早接收到的字符。每讀取一次 UnRBR,接收 FIFO 便丟掉一個字符。
可見,只要接收 FIFO 中含有數據,則寄存器 UnRBR 便不會為空,就會包含有效數據,即,
UnLSR[0] = 1。
UART 接收數據時,可以使用查詢方式接收,也可以使用中斷方式接收,如表 5.67 所示。
采用查詢方式接收一字節數據
/**********************************************************************************************
**  函數名稱: UART0_RcvByte
**  函數功能:從串口接收一個字節的數據。使用查詢方式
**  入口參數:無
**  出口參數:返回接收到的數據
**********************************************************************************************/
uint8 UART0_RcvByte(void)
{
uint8 rcv_data;
while ((U0LSR&0x01) == 0); /*  查詢數據是否接收完畢 */
rcv_data = U0RBR;
return (rcv_data);
}
 
 
使用中斷方式接收數據時,如果發生 RDA 中斷,則循環從 UnRBR 中讀取數據即可。如果
發生了字符超時中斷——CTI,可以通過 UnLSR[0]來判斷 FIFO 中是否含有有效數據,如圖 5.43
所示。
/**********************************************************************************************
**  函數名稱: UART_Exception
**  函數功能:串口中斷服務程序
**********************************************************************************************/
void UART_Exception(void)
{
……
switch(U0IIR & 0x0f)
{
case 0x04 : /*  發生 RDA 中斷 */
/*
**  從接收 FIFO 中讀取數據
*/
break;
case 0x0c : /*  發生字符超時中斷 ——CTI  */
while((U0LSR & 0x01) == 1) { 
/*
**  如果接收 FIFO 中含有有效數據,就讀取 UnRBR 寄存器
*/
RcvData[i++] = U0RBR;
break;
    ……
default :
break;
}
……
}
 
 
注:徹底清除 UART 中斷標志后才可退出中斷服務程序,否則會導致處理器反復陷入中斷。
 
綜上所述,UARTn 的基本操作方法:
 設置 I/O 連接到 UARTn;
 設置串口波特率(UnDLM、UnDLL);
 設置串口工作模式(UnLCR、UnFCR);
 發送或接收數據(UnTHR、UnRBR);
 檢查串口狀態字或等待串口中斷(UnLSR)。
 
 
 
 
#ifndef __DEBUGSERIAL_H_
#define __DEBUGSERIAL_H_

#include "sys.h"
#include "stdio.h"

extern u8 serialBuffer[256];
extern u16 serialStatus;

void Debug_Serial_Init(u32 baud);
void Debug_Serial_Send_Byte(u8 dat);
void Debug_Serial_Send_Buffer(u8 length,u8* buffer);

#endif

 

 
 
#include "debugSerial.h"

//加入printf支持
#pragma import(__use_no_semihosting)                            
struct __FILE
{
    int handle;
    /* Whatever you require here. If the only file you are using is */
    /* standard output using printf() for debugging, no file handling */
    /* is required. */
};

FILE __stdout;      

_sys_exit(int x)
{
    x = x;
} 

int fputc(int ch, FILE *f)
{     
    while(!((LPC_UART0->LSR) & 0x20));      //等待判斷LSR[5](即THRE)是否是1,1時表示THR中為空     
    LPC_UART0->THR = (u8)ch;                    //發送數據    
    return ch;
}



//定義一個256字節的緩沖區用於存放接收到的串口數據信息
//定義一個16位數據同時保存接收數據長度以及接收數據的狀態
u8 serialBuffer[256] = {0};
u16 serialStatus = 0;

//16字節的狀態
//低八位為當前存儲的有效數據長度
//15位為接收完成等待處理標志
//8位表示當前已經接受到回車符\r
//第9到十四位表示在等待處理期間系統冗余發送的數據量
//用於后期通訊系統的負載自適應
 
void TransSerialsCommand(u8 res)
{
    u8 lostCount;
    u8 receiveCount;

    //接收數據處理
    if(serialStatus & (1<<15))//已經接收完成,這個數據被拋棄
    {
        lostCount = ((u8)(serialStatus>>9))&0x3f;//漏掉的數據計數
        if(lostCount < 0x3f)lostCount++;
        serialStatus &= ~(0x3f<<9);
        serialStatus |= (lostCount<<9);
    }
    else//上一個命令沒有接收完
    {
        if(serialStatus & (1<<8))//接收到\r
        {
            //等待接收\N
            if(res == '\n')
            {
                //接收完成
                serialStatus |= 0x8000;
            }
            else//不是\n,這一次命令作廢
            {
                serialStatus = 0;
            }
        }
        else//沒收到\r
        {
            if(res == '\r')
            {
                serialStatus |= 0x0100;
            }
            else
            {
                receiveCount = (u8)(serialStatus&0xff);
                if(receiveCount < 255)
                {
                    serialBuffer[receiveCount] = res;
                    receiveCount++;
                    serialStatus &= 0xff00;
                    serialStatus |= receiveCount;
                }
                else
                {
                    //數據溢出,清空
                    serialStatus = 0;
                }
            }
        }
    }
}


void UART0_IRQHandler(void)
{
    u8 status = 0;
    u8 res = 0;
	
    //清除串口中斷掛起
    NVIC_ClearPendingIRQ(GPIO_IRQn);
    //清除串口接收中斷
    if(!(LPC_UART0->IIR & 0x01))//確認有中斷發生
    {
        status = LPC_UART0->IIR & 0x0e;
        if(status == 0x04)//確認是RDA中斷
        {
            //讀取串口接收值
            res = (LPC_UART0->RBR&0xff);
            //處理串口接收值
            TransSerialsCommand(res);
        }
    }
}


void Debug_Serial_Init(u32 baud)
{
    LPC_SC->PCONP |= (1<<3)|(1<<15);                //打開時鍾
	
    //配置io口
    LPC_IOCON->P0_2 = 0x00;                         //選擇TXD功能,禁止遲滯 不反向 正常推挽
    LPC_IOCON->P0_2 |= (1<<0)|(2<<3);               //上拉
    LPC_IOCON->P0_3 = 0x00;                         //選擇RXD功能,禁止遲滯 不反向 正常推挽
    LPC_IOCON->P0_3 |= (1<<0)|(2<<3);               //上拉
    LPC_UART0->LCR = 0x83;                          //設置串口數據格式,8位字符長度,1個停止位,無校驗,使能除數訪問
    LPC_UART0->DLM = ((ApbClock/16)/baud) / 256;    //除數高八位  , 沒有小數情況
    LPC_UART0->DLL = ((ApbClock/16)/baud) % 256;    //除數第八位
    LPC_UART0->LCR = 0x03;                          //禁止訪問除數鎖存器,鎖定波特率
    LPC_UART0->FCR  = 0x00;                         //禁止FIFO
    LPC_UART0->IER = 0x01;                          //使能接收中斷RDA

    NVIC_EnableIRQ(UART0_IRQn);                     //打開IRQ中斷
}

void Debug_Serial_Send_Byte(u8 dat)
{
    //當檢測到UARTn THR已空時,THRE就會立即被設置。寫UnTHR會清零THRE
    //0  -  UnTHR包含有效字符
    //1  -  UnTHR為空
    while(!((LPC_UART0->LSR) & 0x20));      //等待判斷LSR[5](即THRE)是否是1,1時表示THR中為空     
    LPC_UART0->THR = dat;                   //發送數據
}

void Debug_Serial_Send_Buffer(u8 length,u8* buffer)
{
    u8 i = 0;
	
    for(i = 0; i < length; i++)
    {
        Debug_Serial_Send_Byte(buffer[i]);
    }
    printf("\r\n");
}





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM