Nuvoton NUC200 NUC220使用FIFO觸發中斷及接收超時中斷處理UART接收的資料
NUC200NUC220_BSP當中所提供之UART_Read(uart, pu8RxBuf, u32ReadBytes)函式屬於輪詢方式,接收緩衝器為空時這個函式就會在原地等待,屆時CPU沒辦法做其他事情。本篇介紹使用中斷的方式處理UART接收到的資料。
在這邊我們使用到UART兩個中斷源,分別是"接收資料可用中斷"及"接收超時中斷"。
接收資料可用中斷的發生條件為,當接收到的位元組大於等於所設定之閥值發生,而閥值可由UART->FCR[7:4] RFITL設定1Byte、4Bytes、8Bytes、14Bytes、30Bytes、46Bytes及62Bytes。在這邊要注意,NUC220的UART0才有提供到64Bytes的接收緩衝區,UART1及UART2只提供了16Bytes的接收緩衝區,當閥值設定超過14Bytes則以14Bytes為準。清除接收資料可用中斷的中斷旗標只要讀取RBR即可。
接收超時中斷的發生條件為,當超時計數器的值大於等於超時比較器(UART->TOR[7:0] TOIC)的值發生接收超時中斷。超時計數器在每一個Byte進來時會歸零並且開始計時,而計數器的時脈等於Baudrate,所以建議將TOIC設定在40~255之間,以避免在下一個Byte進來以前就發生了超時中斷。若要清除接收超時中斷的中斷旗標同樣讀取RBR即可。
那麼為甚麼我們要使用這兩種中斷? 首先我們將緩衝區設定在30Bytes會發生中斷,若進來資料是一長串的話可以每30Bytes收一次以降低CPU的負擔。問題是如果進來的資料不剛好整除30個Byte怎麼辦? 這些不到30Bytes的資料就透過超時中斷來處理。假設進來的資料剛好是30個Byte,那很好就剛好把30個Byte收完以後就結束了,如果大於30個Byte則會在超時中斷發生時將剩下的幾個Byte讀取完畢。
下面的程式透過接收中斷的方式將RX接收到的資料傳回TX,所以TX應傳出RX所接收到的資料。由Arduino IDE的Serial Monitor來輸入資料及監測程式運作的狀況。記得UART0的中斷服務程式要叫做"UART02_IRQHandler"。
1. 首先輸入一個不到30Bytes的字串會發生超時中斷,並將這些字元存入軟體buffer然後再傳出來。
2. 輸入"012345678901234567890123456789",怎麼發生了FIFO ready及timeout兩種中斷? 因為我們在Serial Monitor下方的傳輸設定將傳出的字串尾端自動加入New line及Carriage return,故會多出兩個Byte。
3. 所以我們輸入"0123456789012345678901234567"28個Byte,加上New line及Carriage return共30個Byte則只會發生FIFO ready一個中斷。
在這邊我們使用到UART兩個中斷源,分別是"接收資料可用中斷"及"接收超時中斷"。
接收資料可用中斷的發生條件為,當接收到的位元組大於等於所設定之閥值發生,而閥值可由UART->FCR[7:4] RFITL設定1Byte、4Bytes、8Bytes、14Bytes、30Bytes、46Bytes及62Bytes。在這邊要注意,NUC220的UART0才有提供到64Bytes的接收緩衝區,UART1及UART2只提供了16Bytes的接收緩衝區,當閥值設定超過14Bytes則以14Bytes為準。清除接收資料可用中斷的中斷旗標只要讀取RBR即可。
接收超時中斷的發生條件為,當超時計數器的值大於等於超時比較器(UART->TOR[7:0] TOIC)的值發生接收超時中斷。超時計數器在每一個Byte進來時會歸零並且開始計時,而計數器的時脈等於Baudrate,所以建議將TOIC設定在40~255之間,以避免在下一個Byte進來以前就發生了超時中斷。若要清除接收超時中斷的中斷旗標同樣讀取RBR即可。
那麼為甚麼我們要使用這兩種中斷? 首先我們將緩衝區設定在30Bytes會發生中斷,若進來資料是一長串的話可以每30Bytes收一次以降低CPU的負擔。問題是如果進來的資料不剛好整除30個Byte怎麼辦? 這些不到30Bytes的資料就透過超時中斷來處理。假設進來的資料剛好是30個Byte,那很好就剛好把30個Byte收完以後就結束了,如果大於30個Byte則會在超時中斷發生時將剩下的幾個Byte讀取完畢。
下面的程式透過接收中斷的方式將RX接收到的資料傳回TX,所以TX應傳出RX所接收到的資料。由Arduino IDE的Serial Monitor來輸入資料及監測程式運作的狀況。記得UART0的中斷服務程式要叫做"UART02_IRQHandler"。
1. 首先輸入一個不到30Bytes的字串會發生超時中斷,並將這些字元存入軟體buffer然後再傳出來。
2. 輸入"012345678901234567890123456789",怎麼發生了FIFO ready及timeout兩種中斷? 因為我們在Serial Monitor下方的傳輸設定將傳出的字串尾端自動加入New line及Carriage return,故會多出兩個Byte。
3. 所以我們輸入"0123456789012345678901234567"28個Byte,加上New line及Carriage return共30個Byte則只會發生FIFO ready一個中斷。
#include "stdlib.h" #include "stdio.h" #include "NUC200Series.h" #define PLL_CLOCK 48000000 void SYS_Init(void) { /*---------------------------------------------------------------------------------------------------------*/ /* Init System Clock */ /*---------------------------------------------------------------------------------------------------------*/ /* Enable Internal RC 22.1184MHz clock */ CLK_EnableXtalRC(CLK_PWRCON_OSC22M_EN_Msk); /* Waiting for Internal RC clock ready */ CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk); /* Set core clock as PLL_CLOCK from PLL */ CLK_EnablePLL(CLK_PLLCON_PLL_SRC_HIRC, PLL_CLOCK); CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk); /* Switch HCLK clock source to Internal RC and HCLK source divide 1 */ CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1)); /* Enable UART module clock */ CLK_EnableModuleClock(UART0_MODULE); /* Select UART module clock source */ CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART_S_HIRC, CLK_CLKDIV_UART(1)); /* Update System Core Clock */ SystemCoreClockUpdate(); /*---------------------------------------------------------------------------------------------------------*/ /* Init I/O Multi-function */ /*---------------------------------------------------------------------------------------------------------*/ /* Set GPB multi-function pins for UART0 RXD(PB.0) and TXD(PB.1) */ SYS->GPB_MFP &= ~(SYS_GPB_MFP_PB0_Msk | SYS_GPB_MFP_PB1_Msk); SYS->GPB_MFP |= SYS_GPB_MFP_PB0_UART0_RXD | SYS_GPB_MFP_PB1_UART0_TXD; } void UART02_IRQHandler(void) { //printf("UART0 interrupt happen.\r\n"); if(UART_GET_INT_FLAG(UART0, UART_ISR_TOUT_INT_Msk)) { uint8_t i, str[30]; printf("UART0 RX timeout.\r\n"); for(i=0; !(UART0->FSR & UART_FSR_RX_EMPTY_Msk); i++) str[i] = UART0->RBR; UART_Write(UART0, str, i); } if(UART_GET_INT_FLAG(UART0, UART_ISR_RDA_INT_Msk)) { uint8_t i, str[30]; printf("UART0 FIFO ready.\r\n"); for(i=0; i<30 i="" str="" uart0-="">RBR; UART_Write(UART0, str, 30); } } void UART0_Init() { /*---------------------------------------------------------------------------------------------------------*/ /* Init UART */ /*---------------------------------------------------------------------------------------------------------*/ /* Reset UART0 module */ SYS_ResetModule(UART0_RST); /* Configure UART0 and set UART0 Baudrate */ UART_Open(UART0, 115200); } int main() { SYS_UnlockReg(); SYS_Init(); SYS_LockReg(); UART0_Init(); //將FIFO中斷閥值設為30個Byte UART0->FCR &= ~(UART_FCR_RFITL_Msk); UART0->FCR |= UART_FCR_RFITL_30BYTES; //設定接收超時比較值 UART_SetTimeoutCnt(UART0, 0xf0); //啟用FIFO中斷及接收超時中斷 UART_EnableInt(UART0, UART_IER_RDA_IEN_Msk | UART_IER_TOUT_IEN_Msk); printf("\r\nNUC220 ok\r\n"); PA10=1; GPIO_SetMode(PA, BIT10, GPIO_PMD_QUASI); while(1) { } } 30>
留言
張貼留言