STm32F070RB 有關串口通信的幾個坑以及硬件流控制

在整理串口庫函數時發現有幾個以前沒有注意到的問題

問題一:

   如果使能了接收中斷,即USART_ITConfig(USART1,USART_IT_RXNE,ENABLE),則默認ORE溢出中斷也開啓,且此時溢出中斷標誌USART_IT_ORE不能通過USART_GetITStatus()來檢測到,而只能通過USART_GetFlagStatus()檢測到,且此時USART_ClearITPendingBit(USART1, USART_IT_ORE)也不起作用。這種情況下,如果在中斷處理函數中有if(USART_GetITStatus(USART1,USART_IT_ORE) != RESET)判斷,則程序每接收一個字符都會進入到溢出中斷(不過暫時檢測到對接收數據的讀取沒有很大影響)

解決辦法:

   在串口初始化時使能溢出中斷USART_ITConfig(USART1,USART_IT_ORE,ENABLE);只有使能了這個USART_ClearITPendingBit(USART1, USART_IT_ORE)纔可以起作用

   在串口中斷處理函數中檢測溢出標誌,如果產生溢出中斷則清除標誌,且讀取串口RDR寄存器清空接收緩存器

 

問題二:

   在使用串口助手向單片機串口發送數據時,如果不勾選“發送新行”,則接收到的字符串將丟失最後一個字符;而只有勾選“發送新行”後,接收到的字符串纔是完整的

解決辦法:

   經過排查,查到了真正原因,和原子那邊的“串口接收定義收到換行符才判斷爲接收結束”沒有任何關係,真正原因在於我在串口中斷處理函數中檢測中斷標誌用的USART_GetFlagStatus()而不是USART_GetITStatus(),前者的返回值是中斷標誌位狀態(讀ISR寄存器),後者的返回值是中斷髮生與否(讀CR寄存器)。

    從CR寄存器中讀取的是RXNEIE,發生接收中斷時該位就被置位,且該標誌位的置位和清除都是通過軟件來完成的

    從ISR寄存器中讀取的是RXNE,這個位則是當RDR移位寄存器向USART_RDR寄存器移數據時,由硬件自動置位,它的清除可以通過讀取RDR寄存器內的數據清除或者軟件置位RXFRQ來完成

    所以我這裏的問題在於,我判斷RXNE Flag Status等於RESET後才進行數據的讀取,如果我發送的字符串是“helloworld”,那麼當我發完d後,因爲沒有新的數據發過來,所以就不存在有“RDRRDR移位寄存器向USART_RDR寄存器移數據”這個動作,因此ISR中的RXNE就不會被置位。所以最後一個"d"字母就沒有被存儲處理。這個時候其實還是進了中斷,只是不是USART_GetFlagStatus(USART1,USART_IT_RXNE)這一項,因而也就沒有對最後一位數據進行存儲處理。事實證明,當我再接着發送新的字符串時,之前的"d"字符會重新出現在新的字符串的第一位,同理這個時候新字符串的最後一位也沒有被存儲。

   同樣的,如果使用USART_GetFlagStatus(USART1,USART_IT_RXNE) != RESET判斷,即便我在串口助手中勾選了“發送新行”,根據得到的數據也可以發現串口接收buffer裏面丟了換行符(兩個ASCII值)的一個ASCII碼值。

 

細節三:

    在官方給的串口中斷處理函數中,讀取接收字符的代碼爲:RxBuffer[RxCount++] = (USART_ReceiveData(USART1) & 0x7F);這裏爲什麼與的不是0xFF而是0x7F,查看手冊瞭解到無論串口配置時選的數據寬度爲8bit還是9bit,其最高位一般保留爲奇偶檢驗的結果位,因此如果讀取實際數據的話應該省掉最高位

 

細節四:

    開啓串口的DMA中斷傳輸後,每次串口接收到一個字節後DMA就會自動去串口的RDR寄存器中讀取數據,這時串口接收中斷不會產生

	DMA_DeInit(DMA1_Channel3);
	DMA_InitTypeDef DMA_InitStructure;
	
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->RDR);
	DMA_InitStructure.DMA_BufferSize = (uint16_t)10;
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AckBuffer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_Init(DMA1_Channel3,&DMA_InitStructure);
	
//USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//USART_ITConfig(USART1,USART_IT_ORE,ENABLE);
	USART_Cmd(USART1,ENABLE);
	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
	/**************************************
	 * 查詢傳輸用 while(DMA_GetFlagStatus(DMA1_IT_TC3) == RESET)
	***************************************/
	DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);  
	DMA_Cmd(DMA1_Channel3,ENABLE);

 

細節五:重定向printf函數,記得#include <stdio.h>

#ifdef __GNUC__
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
	#define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)
#endif
	
PUTCHAR_PROTOTYPE
{
	USART_SendData(USART1, (uint16_t) ch);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET)
	{}
	return ch;
}

 

串口通信的硬件流控制

   流控制的相關解釋:https://blog.csdn.net/zeroboundary/article/details/8966586

串口設備使用硬件流控制的連接方式:

     TX   ————>  RX

   CTS  <————  RTS

    RX  <————   TX 

   RTS  ————>  CTS

 

因爲手上也沒有足夠的板子做測試,只能用串口助手做個簡單的測試,首先是配置CTS/RTS兩個複用GPIO口,然後配置硬件流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS;

 /******USART1 CTS/RTS GPIO_Pins Configuration*******/
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_1);   //CTS
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_1);   //RTS
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

我用的是串口USB轉接口,只有TX和RX,測試CTS,我在主程序中循環打印“hello world”,可以發現如果將PA11接高電平或者懸空,字符不能正常打印,只有接低電平時字符串才能正常打印。即CTS低電平有效

 

RS232 RS485不同協議和串口的應用(待補充)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章