一、Demo说明
- 主控stm32f103rct6
- 串口1、2、3、4采用DMA+空闲中断方式实现接收数据
- 串口5采用接收中断+空闲中断实现接收数据
- 定时器1执行定时任务
二、HAL库配置
1. 系统配置
- 开启SWD下载
- 开启外部时钟
2. 串口1配置(串口2/3/4类似)
- 配置波特率
- 添加接收DMA
- 开启中断
3. 定时器配置
4. 时钟选择
硬件电路外部接有8M晶振所以选择外部8M晶振
5. 工程生成
三、代码编写
1. 初始化
串口接收使用DMA+空闲中断实现,初始化中需要开启串口空闲中断,以及串口5的接收中断。
void UserSys_Init(void)
{
HAL_NVIC_EnableIRQ(UART5_IRQn);
__HAL_UART_ENABLE_IT(&huart5, UART_IT_IDLE);
HAL_UART_Receive_IT(&huart5,(uint8_t*)&g_usart5_recv_byte,1);
HAL_NVIC_EnableIRQ(UART4_IRQn);
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart4, (uint8_t*)g_USART4_Recv_Data, RECV_DATA_MAX_LEN);
HAL_NVIC_EnableIRQ(USART3_IRQn);
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart3, (uint8_t*)g_USART3_Recv_Data, RECV_DATA_MAX_LEN);
HAL_NVIC_EnableIRQ(USART2_IRQn);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart2, (uint8_t*)g_USART2_Recv_Data, RECV_DATA_MAX_LEN);
HAL_NVIC_EnableIRQ(USART1_IRQn);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, (uint8_t*)g_USART1_Recv_Data, RECV_DATA_MAX_LEN);
HAL_TIM_Base_Start_IT(&htim1);
}
2. 串口空闲中断
2.1. 自定义串口空闲中断服务函数
- 串口5无法使用DMA传输,所以使用接收中断和空闲中断的方式实现,使用接收中断将数据保存后,利用空闲中断处理数据;
- 串口1、2、3、4采用空闲中断+DMA方式,具体流程如下:
- 判断是否为空闲中断
- 清除空闲中断标志
- 关闭DMA传输,关闭空闲中断(在主函数数据处理完成后开启)
- 备份数据
- 标志位置1
/** 空闲中断回调函数
* @brief HAL_UART_IdleCpltCallback
* @param huart 串口
* @retval None
*/
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{
//USART5 IDLE/RXNE
if(huart == &huart5)
{
//RXNE
g_USART5_Recv_Data[usart5_recv_cnt++] = g_usart5_recv_byte;
HAL_UART_Receive_IT(&huart5,(uint8_t*)&g_usart5_recv_byte,1);
//IDLE
if(RESET != __HAL_UART_GET_FLAG(&huart5,UART_FLAG_IDLE))
{
g_usart5_recv_len = usart5_recv_cnt;
__HAL_UART_CLEAR_IDLEFLAG(&huart5);//Clear the UART IDLE pending flag.(Otherwise it will continue to interrupt)
memset(g_USART5_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
memcpy(g_USART5_Recv_Data_BAK,g_USART5_Recv_Data,g_usart5_recv_len);
memset(g_USART5_Recv_Data,0,RECV_DATA_MAX_LEN);
usart5_recv_cnt = 0;
g_USART5_Recv_Flag = 1;
}
}
//USART4 IDLE
if(huart == &huart4)
{
if(RESET != __HAL_UART_GET_FLAG(&huart4,UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart4);
HAL_UART_DMAStop(&huart4); //关闭DMA传输
__HAL_UART_DISABLE_IT(&huart4, UART_IT_IDLE); //关闭空闲中断
g_usart4_recv_len = RECV_DATA_MAX_LEN - (__HAL_DMA_GET_COUNTER(&hdma_uart4_rx));//计算接收数据长度
memset(g_USART4_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
memcpy(g_USART4_Recv_Data_BAK,g_USART4_Recv_Data,g_usart4_recv_len);
memset(g_USART4_Recv_Data,0,RECV_DATA_MAX_LEN); //处理数据
g_USART4_Recv_Flag = 1; //标志位置位
}
}
//USART3 IDLE
if(huart == &huart3)
{
if(RESET != __HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart3);//Clear the UART IDLE pending flag.(Otherwise it will continue to interrupt)
HAL_UART_DMAStop(&huart3);
__HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE);
g_usart3_recv_len = RECV_DATA_MAX_LEN - (__HAL_DMA_GET_COUNTER(&hdma_usart3_rx));
memset(g_USART3_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
memcpy(g_USART3_Recv_Data_BAK,g_USART3_Recv_Data,g_usart3_recv_len);
memset(g_USART3_Recv_Data,0,RECV_DATA_MAX_LEN);
g_USART3_Recv_Flag = 1;
}
}
//USART2 IDLE
if(huart == &huart2)
{
if(RESET != __HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2);//Clear the UART IDLE pending flag.(Otherwise it will continue to interrupt)
HAL_UART_DMAStop(&huart2);
__HAL_UART_DISABLE_IT(&huart2, UART_IT_IDLE);
g_usart2_recv_len = RECV_DATA_MAX_LEN -(__HAL_DMA_GET_COUNTER(&hdma_usart2_rx));
memset(g_USART2_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
memcpy(g_USART2_Recv_Data_BAK,g_USART2_Recv_Data,g_usart2_recv_len);
memset(g_USART2_Recv_Data,0,RECV_DATA_MAX_LEN);
g_USART2_Recv_Flag = 1;
}
}
//USART1 IDLE
if(huart == &huart1)
{
if(RESET != __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//Clear the UART IDLE pending flag.(Otherwise it will continue to interrupt)
HAL_UART_DMAStop(&huart1);
__HAL_UART_DISABLE_IT(&huart1, UART_IT_IDLE);
g_usart1_recv_len = RECV_DATA_MAX_LEN -(__HAL_DMA_GET_COUNTER(&hdma_usart1_rx));
memset(g_USART1_Recv_Data_BAK,0,RECV_DATA_MAX_LEN);
memcpy(g_USART1_Recv_Data_BAK,g_USART1_Recv_Data,g_usart1_recv_len);
memset(g_USART1_Recv_Data,0,RECV_DATA_MAX_LEN);
g_USART1_Recv_Flag = 1;
}
}
}
2.2. 中断复位函数中调用
在中断服务函数中调用
3. 主函数中数据处理
- 判断接收标志位
- 标志位清零
- 数据解析操作
- 开启空闲中断、开启DMA接收
void Board_Run(void)
{
/*uart5--接收*/
if(g_USART5_Recv_Flag)
{
g_USART5_Recv_Flag = 0;
//数据处理 g_USART5_Recv_Data_BAK
HAL_UART_Transmit(&huart1,g_USART5_Recv_Data_BAK,g_usart5_recv_len,0xff);
}
/*uart4--接收*/
if(g_USART4_Recv_Flag)
{
g_USART4_Recv_Flag = 0;
/* USER CODE BEGIN 解析数据 内容:g_USART4_Recv_Data_BAK,长度:g_usart4_recv_len*/
HAL_UART_Transmit(&huart1,g_USART4_Recv_Data_BAK,g_usart4_recv_len,0xff);
/* USER CODE END */
/*解析完成打开中断*/
HAL_UART_AbortReceive(&huart4);
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart4, (uint8_t*)g_USART4_Recv_Data, RECV_DATA_MAX_LEN);
}
/*usart3--接收*/
if(g_USART3_Recv_Flag)
{
g_USART3_Recv_Flag=0;
/* USER CODE BEGIN 解析数据 内容:g_USART3_Recv_Data_BAK,长度:g_usart3_recv_len*/
HAL_UART_Transmit(&huart1,g_USART3_Recv_Data_BAK,g_usart3_recv_len,0xff);
/* USER CODE END */
HAL_UART_AbortReceive(&huart3);
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart3, (uint8_t*)g_USART3_Recv_Data, RECV_DATA_MAX_LEN);
}
/*usart2--接收*/
if(g_USART2_Recv_Flag)
{
g_USART2_Recv_Flag=0;
/* USER CODE BEGIN 解析数据 内容:g_USART2_Recv_Data_BAK,长度:g_usart2_recv_len*/
HAL_UART_Transmit(&huart1,g_USART2_Recv_Data_BAK,g_usart2_recv_len,0xff);
/* USER CODE END */
HAL_UART_AbortReceive(&huart2);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart2, (uint8_t*)g_USART2_Recv_Data, RECV_DATA_MAX_LEN);
}
/*usart1--接收*/
if(g_USART1_Recv_Flag)
{
g_USART1_Recv_Flag=0;
/* USER CODE BEGIN 解析数据 内容:g_USART1_Recv_Data_BAK,长度:g_usart1_recv_len*/
HAL_UART_Transmit(&huart1,g_USART1_Recv_Data_BAK,g_usart1_recv_len,0xff);
/* USER CODE END */
HAL_UART_AbortReceive(&huart1);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, (uint8_t*)g_USART1_Recv_Data, RECV_DATA_MAX_LEN);
}
}