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一個中斷。


  1. #include "stdlib.h"
  2. #include "stdio.h"
  3. #include "NUC200Series.h"
  4.  
  5. #define PLL_CLOCK 48000000
  6.  
  7. void SYS_Init(void)
  8. {
  9. /*---------------------------------------------------------------------------------------------------------*/
  10. /* Init System Clock */
  11. /*---------------------------------------------------------------------------------------------------------*/
  12.  
  13. /* Enable Internal RC 22.1184MHz clock */
  14. CLK_EnableXtalRC(CLK_PWRCON_OSC22M_EN_Msk);
  15.  
  16. /* Waiting for Internal RC clock ready */
  17. CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);
  18.  
  19. /* Set core clock as PLL_CLOCK from PLL */
  20. CLK_EnablePLL(CLK_PLLCON_PLL_SRC_HIRC, PLL_CLOCK);
  21.  
  22. CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk);
  23.  
  24. /* Switch HCLK clock source to Internal RC and HCLK source divide 1 */
  25. CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1));
  26.  
  27. /* Enable UART module clock */
  28. CLK_EnableModuleClock(UART0_MODULE);
  29.  
  30. /* Select UART module clock source */
  31. CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART_S_HIRC, CLK_CLKDIV_UART(1));
  32.  
  33. /* Update System Core Clock */
  34. SystemCoreClockUpdate();
  35.  
  36. /*---------------------------------------------------------------------------------------------------------*/
  37. /* Init I/O Multi-function */
  38. /*---------------------------------------------------------------------------------------------------------*/
  39.  
  40. /* Set GPB multi-function pins for UART0 RXD(PB.0) and TXD(PB.1) */
  41. SYS->GPB_MFP &= ~(SYS_GPB_MFP_PB0_Msk | SYS_GPB_MFP_PB1_Msk);
  42. SYS->GPB_MFP |= SYS_GPB_MFP_PB0_UART0_RXD | SYS_GPB_MFP_PB1_UART0_TXD;
  43. }
  44.  
  45. void UART02_IRQHandler(void)
  46. {
  47. //printf("UART0 interrupt happen.\r\n");
  48. if(UART_GET_INT_FLAG(UART0, UART_ISR_TOUT_INT_Msk))
  49. {
  50. uint8_t i, str[30];
  51. printf("UART0 RX timeout.\r\n");
  52. for(i=0; !(UART0->FSR & UART_FSR_RX_EMPTY_Msk); i++) str[i] = UART0->RBR;
  53. UART_Write(UART0, str, i);
  54. }
  55. if(UART_GET_INT_FLAG(UART0, UART_ISR_RDA_INT_Msk))
  56. {
  57. uint8_t i, str[30];
  58. printf("UART0 FIFO ready.\r\n");
  59. for(i=0; i<30 i="" str="" uart0-="">RBR;
  60. UART_Write(UART0, str, 30);
  61. }
  62. }
  63.  
  64. void UART0_Init()
  65. {
  66. /*---------------------------------------------------------------------------------------------------------*/
  67. /* Init UART */
  68. /*---------------------------------------------------------------------------------------------------------*/
  69. /* Reset UART0 module */
  70. SYS_ResetModule(UART0_RST);
  71.  
  72. /* Configure UART0 and set UART0 Baudrate */
  73. UART_Open(UART0, 115200);
  74. }
  75.  
  76. int main()
  77. {
  78. SYS_UnlockReg();
  79. SYS_Init();
  80. SYS_LockReg();
  81. UART0_Init();
  82. //將FIFO中斷閥值設為30個Byte
  83. UART0->FCR &= ~(UART_FCR_RFITL_Msk);
  84. UART0->FCR |= UART_FCR_RFITL_30BYTES;
  85. //設定接收超時比較值
  86. UART_SetTimeoutCnt(UART0, 0xf0);
  87. //啟用FIFO中斷及接收超時中斷
  88. UART_EnableInt(UART0, UART_IER_RDA_IEN_Msk | UART_IER_TOUT_IEN_Msk);
  89. printf("\r\nNUC220 ok\r\n");
  90. PA10=1;
  91. GPIO_SetMode(PA, BIT10, GPIO_PMD_QUASI);
  92. while(1)
  93. {
  94. }
  95. }

留言

這個網誌中的熱門文章

無法被取代的指針型三用電表(一):前言

關於新唐科技NuMicro ISP的介紹和使用方式

科風 BNT-1000AP 黑武士系列不斷電系統開箱拆解、簡易評測及經驗分享