1. 程式人生 > 其它 >Cortex-M3 (NXP LPC1788)之UART用法

Cortex-M3 (NXP LPC1788)之UART用法

技術標籤:LPC1788

在工作中經常將平臺的串列埠和PC機連線,通過串列埠列印資訊進行程式除錯。LPC1788共有5個串列埠Uart0~Uart4,根據開發板的資源,將使用Uart2進行簡單的串列埠輸出和輸入中斷的操作。開發板上使用74HC4052多路開關對UART2的RXD和TXD進行選擇,使用SP3243E進行3.0V到5.5V的RS-232電平轉換。檢視手冊配置好相關的跳線帽,保證DB口上的串列埠輸出採用的是Uart2。

下面介紹Uart相關係統配置和Uart模組的配置。Uart的時鐘採用PCLK,我們配置系統的CCLK為120M,PCLK為60M,後面設定串列埠的波特率就採用PLCK進行計算。要使用串列埠2的功能需要使能系統時鐘控制PCONP,以及配置GPIO管腳為Uart2的RXD和TXD功能。要實現通訊,我們需要設定資料的格式,包括傳輸的波特率,資料長度,停止位,以及校驗等,這些資料線上性控制暫存器UnLCR中控制。波特率的產生需要經過分數波特率分頻器UnFDR和主分頻器DLL,DLM。計數公式如下圖。

在這裡插入圖片描述

根據計算,當PLCK=60M,波特率為115200,資料位為8,停止位為1,無校驗,則DLL = 22, DLM =0, DivAddVal =1, MulVal = 2 ,線性控制暫存器中的值為0x3。

要通過串列埠傳送資料時,只需要把要傳送的資料寫入傳送保持暫存器UnTHR,系統就會通過移位暫存器將資料通過串列埠傳送。為了瞭解系統的傳送狀態,還需要線性狀態暫存器UnLSR,例如程式中使用該該暫存器的第5位判斷髮慫保持暫存器是否為空,防止資料溢位。

如果需要進行串列埠的中斷操作,還需要對串列埠中斷進行配置,如串列埠中斷使能暫存器UnIER和串列埠中斷標識暫存器UnIIR。程式中使用到了串列埠2的接收中斷,為此在中斷使能設定暫存器ISER中使能UART2中斷,在串列埠中斷使能暫存器UnIER中使能串列埠的接收中斷,該中斷同時使能了字元接收超時中斷。UART2的RXD管腳接收到資料將存放在FIFO中,程式中配置接收FIFO的觸發條件為1個位元組,即有接收到資料就觸發。中斷觸發後,我們可以根據中斷標識暫存器UnIIR判斷到底是串列埠的接收中斷,超時中斷,傳送中斷等。進入中斷以後,接收中斷和超時中斷,都可以通過讀取接收快取暫存器UnRBR進行中斷復位,使下次中斷可以發生。

下面的程式例子,程式開始列印選單,PC串列埠軟體傳送一個位元組資料給開發板,開發板接收到資料後將讀取UnRBR前後的中斷標識暫存器IIR的值,以及接收到的值傳送回給PC。如果是0x5a或者0xa5還可以開啟或者關閉LED指示燈。

#define CCLK		120000000
#define PCLK		 60000000
 
#define rFIO1DIR	(*(volatile unsigned*)(0x20098020))
#define rFIO1MASK 	(*(volatile unsigned*)(0x20098030))
#define rFIO1PIN	(*(volatile unsigned*)(0x20098034))
#define
rFIO1SET (*(volatile unsigned*)(0x20098038))
#define rFIO1CLR (*(volatile unsigned*)(0x2009803c)) #define rISER0 (*(volatile unsigned*)(0xE000E100)) #define rCLKSRCSEL (*(volatile unsigned *)(0x400FC10C)) //時鐘源選擇暫存器 #define rPLL0CON (*(volatile unsigned *)(0x400FC080)) //PLL0控制暫存器 #define rPLL0CFG (*(volatile unsigned *)(0x400FC084)) //PLL0配置暫存器 #define rPLL0STAT (*(volatile unsigned *)(0x400FC088)) //PLL0狀態暫存器 #define rPLL0FEED (*(volatile unsigned *)(0x400FC08C)) //PLL0饋送暫存器 #define rPLL1CON (*(volatile unsigned *)(0x400FC0A0)) #define rPLL1CFG (*(volatile unsigned *)(0x400FC0A4)) #define rPLL1STAT (*(volatile unsigned *)(0x400FC0A8)) #define rPLL1FEED (*(volatile unsigned *)(0x400FC0AC)) #define rCCLKSEL (*(volatile unsigned *)(0x400FC104)) //CPU時鐘選擇暫存器 #define rUSBCLKSEL (*(volatile unsigned *)(0x400FC108)) //USB時鐘選擇暫存器 #define rPCLKSEL (*(volatile unsigned *)(0x400FC1A8)) //外設時鐘暫存器 #define rPCON (*(volatile unsigned *)(0x400FC0C0)) #define rPXCONP (*(volatile unsigned *)(0x400FC0C4)) #define rSCS (*(volatile unsigned *)(0x400FC1A0)) //系統控制和狀態暫存器 #define rCLKOUTCFG (*(volatile unsigned *)(0x400FC1C8)) #define rIOCON_P0_10 (*(volatile unsigned *)(0x4002C028)) #define rIOCON_P0_11 (*(volatile unsigned *)(0x4002C02C)) #define rPCONP (*(volatile unsigned *)(0x400FC0C4)) #define rU2LCR (*(volatile unsigned *)(0x4009800C)) #define rU2FDR (*(volatile unsigned *)(0x40098028)) #define rU2DLL (*(volatile unsigned *)(0x40098000)) #define rU2DLM (*(volatile unsigned *)(0x40098004)) #define rU2TER (*(volatile unsigned *)(0x40098030)) #define rU2THR (*(volatile unsigned *)(0x40098000)) #define rU2RBR (*(volatile unsigned *)(0x40098000)) #define rU2FCR (*(volatile unsigned *)(0x40098008)) #define rU2IIR (*(volatile unsigned *)(0x40098008)) #define rU2LSR (*(volatile unsigned *)(0x40098014)) #define rU2IER (*(volatile unsigned *)(0x40098004)) #define rU2ACR (*(volatile unsigned *)(0x40098020)) void UART2_IRQHandler() { unsigned int intId; char tmp_char; intId = rU2IIR&0xf; rU2THR = intId; if(intId == 0xc || intId == 0x4) //RDA或者CTI中斷 { rU2LCR &= ~(0x1<<7); //DLAB=0 tmp_char = rU2RBR&0xff; rU2THR = tmp_char; } intId = rU2IIR&0xf; rU2THR = intId; if(tmp_char == 0xa5) rFIO1PIN |= (1<<18); else if(tmp_char == 0x5a) rFIO1PIN &= ~(1<<18); } void SystemInit() { rSCS &= ~(0x1<<4); //頻率12M rSCS |= (0x1<<5); //使能主振盪器 while(0 == (rSCS & (0x1<<6)));//等待主振盪器穩定 rCLKSRCSEL = 0x1; rPLL0CFG = 0x9; //配置CCLK = 120M rPLL0CON = 0x01; rPLL0FEED = 0xAA; rPLL0FEED =0x55; while(0 == (rPLL0STAT & (0x1<<10))); rCCLKSEL = (0x1 | (0x1<<8)); rPCLKSEL = 0x2; //配置PCLK = 60M rCLKOUTCFG = 0x0 | (0xb<<4) | (0x1<<8); } void Init_Uart2() { rPCONP |= 0x1<<24; //使能UART2功率控制 rIOCON_P0_10 = (rIOCON_P0_10 & (~0x7)) | 0x1; //P0.10 P0.11做UART2的傳送和接收管腳 rIOCON_P0_11 = (rIOCON_P0_11 & (~0x7)) | 0x1; rU2LCR |= 0x1<<7; //DLAB=1 rU2FDR = 1 | 2<<4; //波特率設定115200 rU2DLM = 0; rU2DLL = 22; rU2LCR &= ~(0x1<<7); //DLAB=0 rU2LCR |= 0x3; //8位資料位,無校驗,1個停止位 rU2TER |= 0x1<<7; //使能串列埠2的傳送 rU2IER |= 0x1; //使能串列埠2的接收中斷 rU2FCR |= 0x1; //復位FIFO,設定接收1個字元觸發中斷 rU2FCR |= 0x1<<1 | 0x1<<2; rISER0 |= 0x1<<7; //使能串列埠2中斷 } void Uart2SendC(char c) { rU2THR = c & 0xff; while(!(rU2LSR&(0x1<<5))); //等待rU2THR中的資料傳送完成,防止資料溢位 } void Uart2SendS(char *s) { while(*s) { Uart2SendC(*s); s++; } } int main(void) { char str[] = {"\n\r1, Display the U2IIR[3:0] + Data + U2IIR[3:0]\n\r"+ "2, Send 0x5a ---> Turn on the LED\n\r3, Send 0xa5 --->Turn off the LED\n\r"}; rFIO1DIR |= (1<<18); //GPIO1.18 -> OUTPUT Init_Uart2(); Uart2SendS(str); while(1); }

執行結果如下圖所示
在這裡插入圖片描述
本文章轉載自 Cortex-M3 (NXP LPC1788)之UART用法