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)
- {
- }
- }
留言
張貼留言