在工作中經常將平台的串口和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);
- elseif(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\r2, 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);
- }
#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\r2, 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);
}
運行結果如下圖所示
串口調試軟件下載點擊我下載
