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); /*用户实现的回调函数*/ memcpy(uart1_tx_dma_buf,uart1_rx_buf,data_len1); HAL_UART_Transmit_DMA(&huart1, uart1_tx_dma_buf, data_len1); memset(uart1_rx_buf,0,sizeof(uart1_rx_buf)); // 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); }
原文:https://www.cnblogs.com/icaowu/p/13760112.html