Universal asynchronous receiver transmitter (UART)
UART基本介紹:
通用異步收發器UART他的功能非常強大
我們只使用UART的全雙工異步通信功能,使用中斷接收數據。
UART_RX:串行數據輸入。
UART_TX:串行數據輸出。
硬件支持:
連接串口(RS232)實現在超級終端裏輸入輸出
軟件支持:
超級終端,teraterm-4.75
1、配置UART,我們使用UART2
(1)設置波特率為115200,設置數據字段長為8字,使用1個停止位,無基偶校驗,UART Clock disabled,打開發送和接收使能
以上基本設置使用一個函數進行封裝設置:
函數內部實現:
設置數據字段長為8字:UART2->CR1 |= 0x00;
使用1個停止位: UART2->CR3 |= 0x00;
使用基數位校驗:UART2->CR1 |= 0x00;
UART Clock disabled、打開發送和接收使能等等
(2)打開接收中斷,當接收發生或者溢出發生時候,產生接收中斷
(3)UART使能
UART2->CR1 &= (uint8_t)(~0x02);
(4)全局中斷使能
enableInterrupts();
總體UART配置函數實現如下代碼所示:
1 static void UART2_Config(void) 2 { 3 /* EVAL COM (UART) configuration -----------------------------------------UART2_Config*/ 4 /* USART configured as follow: 5 - BaudRate = 115200 baud 6 - Word Length = 8 Bits 7 - One Stop Bit 8 - Odd parity 9 - Receive and transmit enabled 10 - UART Clock disabled 11 */ 12 UART2_Init((uint32_t)115200, UART2_WORDLENGTH_8D,UART2_STOPBITS_1, UART2_PARITY_NO,13 UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE); 14 15 /* Enable the UART Receive interrupt: this interrupt is generated when the UART 16 receive data register is not empty */ 17 UART2_ITConfig(UART2_IT_RXNE_OR, ENABLE); 18 19 /* Enable the UART Transmit complete interrupt: this interrupt is generated 20 when the UART transmit Shift Register is empty */ 21 UART2_ITConfig(UART2_IT_TXE, ENABLE); 22 23 /* Enable UART */ 24 UART2_Cmd(ENABLE); 25 26 /* Enable general interrupts */ 27 enableInterrupts(); 28 }
2、UART輸出功能
如果直接使用C語言的printf函數,只會在編譯器的Terminal-I/O中輸出,不會在我們想要的超級終端裏面輸出,所以需要對輸出函數做重定向;
實現每次想要輸出的時候,將信息打印到超級終端中,故重定向putchar (int c)函數,在函數內使用UART的傳送數據功能就可以了,即將要輸出的信息寫入UART的數據寄存器
1 #define PUTCHAR_PROTOTYPE int putchar (int c) 2 ... 3 /** 4 * @brief Retargets the C library printf function to the UART. 5 * @param c Character to send 6 * @retval char Character sent 7 */ 8 PUTCHAR_PROTOTYPE 9 { 10 /* Write a character to the UART2 */ 11 UART2_SendData8(c); 12 /* Loop until the end of transmission */ 13 while (UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET); 14 15 return (c); 16 }
3、UART輸入功能
輸入功能實際上是字符串處理過程的實現,在超級終端中輸入內容實際上是在UART的數據寄存器裏寫內容,所我們只需要去數據寄存器裏面讀取並處理字符串即可;
- 處理函數功能
首先我們得定義一個支持終端回顯的函數uart_GetStr,其中功能包括:
(1)當有我們在終端裏敲鍵盤的時候會立馬有正確的內容顯示;
(2)當按下特殊按鍵的時候會有正確的反應;比如backspace會刪除一個字符;return會表示輸入完畢進入發送;
(3)對於其他特殊案件處理不了應當屏蔽;比如不想實現delete功能,刪除剛剛讀入的delete字符,並不會回顯;
- 函數實現:
uart_GetStr傳入的第一個參數是指向接收數據數組的指針,第二個參數表示是否允許回顯;
幾個有用變量:
__IO uint8_t ReciveBuff = 0; //save the current char
uint8_t RxBuffer[32] = {0}; //save the input string
__IO uint8_t RxCounter = 0; //the length of valid string
所以,RxBuffer就是uart_GetStr函數的第一個參數,在uart_GetStr函數內部會對每一個字符進行處理,正確的字符才放入RxBuffer中;
1 //==================================================================================== 2 //Function Name | dbg_GetStr 3 //Description | Get string via UART port. 4 //Input | *p_recv_buff : pointer to receive data buffer 5 // | b_echo_on : echo back on or off 6 //Output | detect terminal(0x0d character) :TRUE or FALSE 7 //Remark | 8 //==================================================================================== 9 uint8_t uart_GetStr(uint8_t *p_recv_buff, bool b_echo_on) 10 { 11 uint8_t b_end = 0; 12 int i; 13 static uint8_t len = 0; 14 static uint8_t pos = 0; 15 static uint8_t esc_seq = 0; 16 uint8_t c; 17 18 // Get a character. 19 if((c = ReciveBuff) == 0){ 20 return 0; 21 } 22 // echo back 23 if(b_echo_on){ 24 printf("%c",c); //show the input 25 } 26 27 //Check 28 switch(esc_seq){ 29 // Normal 30 case 0: 31 // Return(Terminate) 32 if(c == 0x0d){ 33 p_recv_buff[len] = 0; 34 len = pos = 0; // clear 35 if(b_echo_on){ 36 printf("\n"); 37 } 38 b_end = 1; 39 } 40 // Back Space 41 else if(c == 0x08){ 42 if(len){ 43 if(b_echo_on){ 44 printf(" "); 45 printf("%c",0x08); // BS 46 } 47 len--; // update length info. 48 pos--; // update pos info 49 } 50 } 51 // ESC 52 else if(c == 0x1b){ 53 esc_seq = 1; 54 } 55 // DEL 56 else if(c == 0x7f){ 57 if(len){ 58 DeleteChar(pos, len, &p_recv_buff[0]); 59 len --; // update length info 60 if(b_echo_on){ 61 printf("%s",&p_recv_buff[pos]); 62 printf(" "); 63 printf("%c",0x08); // BS 64 // move cursor to character end. 65 for(i = 0; i < len - pos; i++){ 66 printf("%c",0x1b); // ESC 67 printf("%c",‘[‘); 68 printf("%c",‘D‘); 69 } 70 } 71 } 72 } 73 // Other 74 else{ 75 p_recv_buff[pos] = c; 76 len++; // update length info 77 pos++; // update pos info 78 } 79 break; 80 // ESC SEQ -> 1st 81 case 1: 82 if(c == ‘[‘){ 83 esc_seq = 2; // Next seq. 84 } 85 else{ 86 esc_seq = 0; // not support(to normal) 87 } 88 break; 89 //ESC SEQ -> 2nd 90 case 2: 91 if(c==‘D‘){ 92 if(pos){ 93 pos--; // "<-" key 94 } 95 } 96 else if(c==‘C‘){ 97 if(pos < len){ 98 pos++; // "->" key 99 } 100 } 101 esc_seq = 0; // To normal 102 break; 103 } 104 105 return (b_end); 106 }uart_GetStr
uart_GetStr函數值為0或者為1,只有在終端中輸入回車時才會返回1,其他情況均返回0;
有了這一特點,我們在使用這個函數的時候,只需要獲取返回值,當返回0時,把處理過後的、用戶正確輸入的字符串打印出來看;
- 運行流程
(1)當終端中有輸入的時候,即數據寄存器不為空,從而觸發接收中斷;
(2)在接收中斷中,我們每次從數據寄存器UART2->DR中讀取一個字節,賦值到ReciveBuff;
(3)然後調用uart_GetStr函數,對當前輸入字符進行處理;(即每一個輸入調用一次處理函數)
(4)將uart_GetStr函數的返回值賦值給RT;
1 INTERRUPT_HANDLER(UART2_RX_IRQHandler, 21) 2 { 3 4 /* Read one byte from the receive data register and send it back */ 5 6 ReciveBuff = (UART2_ReceiveData8() & 0x7F); //get input char 7 8 RT = uart_GetStr(RxBuffer, TRUE); //operate the char 9 10 }interrupt
(5)在主函數裏死等,直到RT的值變為1(表示有return發生,即一次輸入完畢);
(6)當RT=1時,主函數輸出正確的輸入字符串RxBuffer(這裏可以實現更強大的功能,此處只是簡單實現驗證功能,可以對正確字符串做判斷後實現更強大的功能)
1 void main(void) 2 { 3 /* Clock configuration -----------------------------------------*/ 4 CLK_Config(); 5 6 /* TIM4 configuration -----------------------------------------*/ 7 TIM4_Config(); 8 9 10 /* UART2 configuration -----------------------------------------*/ 11 UART2_Config(); 12 13 14 while(1){ 15 printf("\n\rplease input something: \n\r"); 16 17 while(1){ //wait until input something 18 19 if(RT) // return occurred 20 { 21 RT = 0; //clear flag 22 23 printf("your put is:"); 24 printf("%s\n\r",RxBuffer); //verify the input 25 26 /*-- operate the string --*/ 27 /*------------------------*/ 28 29 //memset(RxBuffer,0,32); //clear the buffer 30 break; //operation finished 31 } 32 33 } 34 35 /*-- or operate the string here --*/ 36 if(strcmp(RxBuffer, "Hello") == 0) 37 { //case sensitive 38 printf("\n\rHello World !!\n\r"); 39 } 40 /*--------------------------------*/ 41 42 } 43 44 }main
- 說明:
這裏的打印和上面的回顯雖然都是輸出到終端,但是不同的是,回顯是為了讓用戶知道自己是在實時輸入內容的,而打印是把用戶本次輸入的字符串處理之後再一並返回給終端,方便用戶檢查自己輸入的內容;
如用戶輸入:ABCED‘backspace‘‘backspace‘DE
在終端中實時回顯的就是字符串:ABCED‘backspace‘‘backspace‘DE
而打印的字符串是處理過後的字符串,為:ABCDE
把uart_GetStr的第二個參數分別設置為TRUE和FALSE後觀察終端輸入操作的不同,這樣就能明白他們的不同了。
Universal asynchronous receiver transmitter (UART)