Stm32L0串口中斷接收使用
最新在做LoRa的項目,使用的是STM32L072和SX1276,需要做一個串口透傳模塊,剛開始做demo的時候不考慮功耗,所以串口發送和接收直接使用下列函數執行:
HAL_UART_Transmit(&Sensor_UartHandle,(unsigned char *)&readcommand, sizeof(vcom_read_command_t), VCOM_START_DELAY); HAL_UART_Receive(&Sensor_UartHandle,(unsigned char *)read_temp,UART_BUFFER_MAX_LEN, VCOM_RECV_TIMEOUT);
都涉及到了超時時間,而超時時間依賴的是systick中斷,接收發送100字節沒問題。
但現在需要做低功耗,那麽就不允許systick頻繁中斷了,於是考慮到串口中斷接受,但stm32的庫提供的函數讓人看不明白:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
嘗試一個晚上,現在收發沒問題了,網上寫的步驟不夠詳細,先將我的做法例舉如下:
1.在串口初始化的時候打開串口中斷,M0的芯片只有串口中斷,不區分發送或者接收中斷:
void CommandUartInit(void) { Sensor_UartHandle.Instance = SENSOR_USARTX; Sensor_UartHandle.Init.BaudRate = 4800; Sensor_UartHandle.Init.WordLength = UART_WORDLENGTH_9B; /*8-bit data and 1-bit even bit*/ Sensor_UartHandle.Init.StopBits = UART_STOPBITS_1; Sensor_UartHandle.Init.Parity = UART_PARITY_EVEN; Sensor_UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; Sensor_UartHandle.Init.Mode = UART_MODE_TX_RX; if(HAL_UART_Init(&Sensor_UartHandle) != HAL_OK) { /* Initialization Error */ Error_Handler(); } NVIC_EnableIRQ(USART2_IRQn); NVIC_ClearPendingIRQ(USART2_IRQn); }
2.添加中斷處理函數,按照stm32文件慣例,中斷函數在stm32xxx_it.c裏面添加:
void USART2_IRQHandler(void) { HAL_UART_IRQHandler(&Sensor_UartHandle); }
這裏需要說明的是,串口發送和接受的處理庫已經幫我們做好了,全部封裝在 void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) 這個函數裏,我們需要做的就是在中斷處理函數裏面調用這個函數而已,參數填寫正確的串口號。
3. 在主循環中調用發送接收函數:
HAL_UART_Transmit_IT(&Sensor_UartHandle,(unsigned char *)&readcommand, sizeof(vcom_read_command_t)); do{ uart_receive_status = HAL_UART_Receive_IT(&Sensor_UartHandle,(unsigned char *)read_temp,UART_BUFFER_MAX_LEN); temp_state=HAL_UART_GetState(&Sensor_UartHandle); if(temp_state==HAL_UART_STATE_BUSY_RX || temp_state==HAL_UART_STATE_BUSY_TX_RX) { receive_timeout ++; } }while(Sensor_UartHandle.RxXferCount != 0 && receive_timeout < 10000);
這裏有幾點需要說明:
1)發送沒什麽好說的,直接調用HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)就可以將數據發送出去,可以發送任意size的數據。
2)接收函數做的比較惡心,HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size),每調用一次只接收一個字節,自己可以去分析static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)。
3)說一下這幾個函數之間的關系:
調用HAL_UART_Receive_IT()相當於開啟接收中斷--->如果有數據,會觸發中斷USART2_IRQHandler() ---> HAL_UART_IRQHandler() ---> UART_Receive_IT()
可以看到在HAL_UART_Receive_IT中設置的各種參數,在UART_Receive_IT中都會用到,uhdata = (uint16_t) READ_REG(huart->Instance->RDR);這個就是從串口數據寄存器中獲取到的數據。
4)重新說明下,不管是發送數據還是接收數據都會觸發中斷,進而最終會調用到 UART_Receive_IT()這個函數,在這個函數裏面分別對接收和發送做了處理,可以看看源碼。
5)為了實現接受任意長度的數據,我定義了一個255字節的數組用於接受,然後加了一個超時時間,網上很多用系統時鐘做超時,但我為了做低功耗,沒有開啟systick中斷,所以就直接加了一個u32的變量去計數,超時時間要根據自己接收的最長數據調整。
6)很多人說在接收大數據的時候這個庫函數有問題,項目太急,暫時就不研究了,等遇到的時候再研究吧。
Stm32L0串口中斷接收使用