STM32cubeIDE|STM32cubeIDE-DMA收发串口不定长数据

硬件:STM32F103RCT6
软件:STM32CubeIDE Version: 1.8.0
时钟参数 STM32cubeIDE|STM32cubeIDE-DMA收发串口不定长数据
文章图片


增加串口 STM32cubeIDE|STM32cubeIDE-DMA收发串口不定长数据
文章图片


增加DMA STM32cubeIDE|STM32cubeIDE-DMA收发串口不定长数据
文章图片


增加中断 STM32cubeIDE|STM32cubeIDE-DMA收发串口不定长数据
文章图片


修改main.c
int main(void)
{
………………………………………………
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init(); //注意这里的语句顺序,与CubeIDE生成的顺序不同。默认的顺序,使用DMA传输时,串口只能收到最后一个字节。
/* USER CODE BEGIN 2 */
//使能DMA接收
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
/* USER CODE END 2 */
………………………………………………
}

static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断
/* USER CODE END USART1_Init 2 */
}

修改stm32f1xx_it.c
/* USER CODE BEGIN EV */
#define BUFFER_SIZE 100
volatile uint8_t rx_len = 0; //接收到的数据长度
volatile uint8_t recv_end_flag = 0; //一帧数据接收完成
uint8_t rx_buffer[BUFFER_SIZE]={0}; //DMA接收数据缓存
uint8_t tmp_buffer[BUFFER_SIZE]; //MCU串口数据缓存
/* USER CODE END EV */

void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint32_t tmp_flag = 0;
uint32_t temp;
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
if(USART1 == huart1.Instance)
{
tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志
if((tmp_flag != RESET))//idle标志被置
{
recv_end_flag = 1; // 接受完成标志位置1
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除标志
HAL_UART_DMAStop(&huart1); //
temp=__HAL_DMA_GET_COUNTER(&hdma_usart1_rx); // 获取DMA数据缓冲中未使用的数据数量
rx_len =BUFFER_SIZE - temp; //缓冲区长度减去未使用的数据个数,得到已经接收的数据长度。
if(rx_len>0)
{
memcpy(tmp_buffer,rx_buffer,rx_len); //将DMA接收数据缓存里的数据复制到MCU串口数据缓存。防止数据被后面的memset语句覆盖,或者是下一帧数据覆盖。
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)tmp_buffer, rx_len); //使用DMA方式将接收到的数据原封不动的发送出去。发送数据保存在MCU串口数据缓存tmp_buffer。由于是异步发送,后续的语句和发送过程在执行时间上是不确定的,所以需要上一条语句将数据复制到其他地址。(根据使用场景不同可以选择乒乓缓冲或者环形缓冲队列等方法快速处理DMA接收到的数据)
memset(rx_buffer,0,rx_len); //将DMA接收数据缓存复位为0。
}
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE); //重新打开DMA接收
}
}
/* USER CODE END USART1_IRQn 1 */
}

实验结果: STM32cubeIDE|STM32cubeIDE-DMA收发串口不定长数据
文章图片

【STM32cubeIDE|STM32cubeIDE-DMA收发串口不定长数据】

    推荐阅读