1. 程式人生 > >Stm32L0串口中斷接收使用

Stm32L0串口中斷接收使用

之間 demo 沒有 項目 typedef tro true def word

最新在做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串口中斷接收使用