https://blog.csdn.net/u012523921/article/details/105411008
https://jiejie.blog.csdn.net/article/details/80563422
1、查詢(基本不用)
2、中斷
3、中斷+DMA
操作分3個步驟
1、設置STM32cubeMX,初始化代碼在stm32f4xx_hal_msp.c,執行代碼在main.C
2、打開中斷和接收相關函數
//開啟空閑中斷 __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //UART_IT_IDLE 空閑中斷 //UART_IT_RXNE //UART_IT_TXE //UART_IT_PE //UART_IT_TC //UART_IT_LBD //UART_IT_CTS //UART_IT_ERR //開啟DMA接收, HAL_UART_Receive_DMA(&huart1, (uint8_t*)uart1_rx_buf, USART1_RX_BUF_SIZE); //@file stm32f4xx_hal_uart.c /* 阻塞模式Blocking mode:通信以輪詢模式執行。 (+) HAL_UART_Transmit() (+) HAL_UART_Receive() 非阻塞模式Non-Blocking:使用中斷執行通信,這些API會返回HAL狀態 (+) HAL_UART_Transmit_IT() (+) HAL_UART_Receive_IT() (+) HAL_UART_IRQHandler() 非阻塞模式Non-Blocking:使用DMA執行通信或,這些API會返回HAL狀態 (+) HAL_UART_Transmit_DMA() (+) HAL_UART_Receive_DMA() (+) HAL_UART_DMAPause() (+) HAL_UART_DMAResume() (+) HAL_UART_DMAStop() 非阻塞模式Non-Blocking回調函數: (+) HAL_UART_TxHalfCpltCallback() (+) HAL_UART_TxCpltCallback() (+) HAL_UART_RxHalfCpltCallback() (+) HAL_UART_RxCpltCallback() (+) HAL_UART_ErrorCallback() 非阻塞模式Non-Blocking中止執行函數: (+) HAL_UART_Abort() (+) HAL_UART_AbortTransmit() (+) HAL_UART_AbortReceive() (+) HAL_UART_Abort_IT() (+) HAL_UART_AbortTransmit_IT() (+) HAL_UART_AbortReceive_IT() (+) HAL_UART_AbortCpltCallback() (+) HAL_UART_AbortTransmitCpltCallback() (+) HAL_UART_AbortReceiveCpltCallback() */
3、處理相關函數
處理相關函數一般放在中斷函數,或者回調函數內。先判斷中斷串口號,中斷類型,清除中斷類型。
/** * @brief This function handles USART1 global interrupt. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ USER_UART_IRQHandler(&huart1); //加入自己的中斷處理函數 /* USER CODE END USART1_IRQn 1 */ }
//下面是自己的空閑中斷處理函數 void USER_UART_IRQHandler(UART_HandleTypeDef *huart) { if(USART1 == huart->Instance) //判斷是否是串口1 { if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) //判斷是否是空閑中斷 { __HAL_UART_CLEAR_IDLEFLAG(&huart1); //清楚空閑中斷標志(否則會一直不斷進入中斷) USAR_UART_IDLECallback(huart); //調用中斷處理函數 } } }
//空閑中斷回調函數 void USAR_UART_IDLECallback(UART_HandleTypeDef *huart) { if(USART1 == huart->Instance){ uint8_t data_len1; //停止本次DMA傳輸 data_len1 = USART1_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //計算接收到的數據長度 fifo_uart1_rx.tail = data_len1; if(fifo_uart1_rx.head <= fifo_uart1_rx.tail) { fifo_uart1_rx.DMAsize = fifo_uart1_rx.tail - fifo_uart1_rx.head; } else if(fifo_uart1_rx.head > fifo_uart1_rx.tail) { fifo_uart1_rx.DMAsize = USART1_RX_BUF_SIZE - fifo_uart1_rx.head + fifo_uart1_rx.tail; } fifo_uart1_rx.flag = 1;//置位標志,表示接收到數據 __HAL_DMA_DISABLE(huart->hdmarx); //__HAL_DMA_SET_COUNTER(huart->hdmarx, USART1_RX_BUF_SIZE); __HAL_DMA_ENABLE(huart->hdmarx); /*用戶實現的回調函數*/ uart1_get_data(uart1_tx_dma_buf,fifo_uart1_rx.DMAsize); HAL_UART_Transmit_DMA(&huart1, uart1_tx_dma_buf,fifo_uart1_rx.DMAsiz);
// HAL_UART_Transmit_DMA(&huart1, uart1_rx_buf, sizeof(uart1_rx_buf) - 1); // 采用DMA發送 str,按照str實際大小發送,不發送字符串末尾的'0' // if(p_uart1_rx_complete_callback != NULL) // (*p_uart1_rx_complete_callback)(); // //這里是定義的回調函數指針, // //用戶可以自己定義這個回調函數, // //因為我做的這個模塊是要打包給別人使用的, // //這種用戶實現的函數都是通過函數指針定義的, // //這樣用戶可以自己定義回調函數的函數名,如果不需要回調,可以將這里注釋掉; } }
//串口接收環形緩沖區取出函數 //參數1:串口接收環形緩沖區對象指針 //參數2:串口接收環形緩沖區最大長度 //參數3:取出的數據緩沖區地址 //參數4:取出的數據長度 //返回數據:取出的數據長度 uint16_t uart1_get_data(uint8_t *data_rsv,uint16_t len) { uint16_t i=0; if(fifo_uart1_rx.flag &&(fifo_uart1_rx.DMAsize > 0))//接收到數據 { for(;i<len;i++)//取出環形緩沖區的數據 { data_rsv[i] = fifo_uart1_rx.buf[fifo_uart1_rx.head]; fifo_uart1_rx.head ++; fifo_uart1_rx.head %= USART1_RX_BUF_SIZE; if(fifo_uart1_rx.head == fifo_uart1_rx.tail) { fifo_uart1_rx.flag = 0;//清空接收數據標志 i++; break; } } } return (i); }
//這里是發送和接收緩沖區的定義 __align(2) uint8_t uart1_tx_dma_buf[USART1_TX_BUF_SIZE]={0}; __align(2) uint8_t uart1_rx_buf[USART1_RX_BUF_SIZE]={0}; /*這里雖然是注釋部分,但是這是工程中用到的代碼,這里只是以這種方式進行說明一下: 關於fifo_uart1_rx的說明,在uart.h中定義的環形結構體:*/ typedef struct{ uint16_t head;//幀頭位置 uint16_t tail;//幀尾位置 uint16_t DMAsize;//硬件DMA發送的長度【接收幀長度】 uint8_t *buf; //內存起始地址, uint8_t flag; //幀標志 }uart_fifo_t; //串口1的環形緩沖區 static __IO uart_fifo_t fifo_uart1_tx={0,0,0,uart1_tx_dma_buf,0}; //串口1的環形緩沖區 static __IO uart_fifo_t fifo_uart1_rx={0,0,USART1_RX_BUF_SIZE,uart1_rx_buf,0};
#define RX_MAX_COUNT 255 // 串口接收最大字節數
#define USART1_TX_BUF_SIZE 255
#define USART1_RX_BUF_SIZE 255
//uint8_t USART1_RX_BUF_SIZE //uint8_t uart1_rx_buf[USART1_RX_BUF_SIZE]; __IO uint8_t aRxBuffer[RX_MAX_COUNT]={0}; // 接收緩沖區 __IO uint16_t RxCount=0; // 已接收到的字節數 __IO uint8_t Frame_flag=0; // 幀標志:1:一個新的數據幀 0:無數據幀
extern uint8_t uart1_rx_buf[USART1_TX_BUF_SIZE];