STM32
直播中

爱吃果冻

12年用户 884经验值
私信 关注
[问答]

如何利用IDLE中断进行串口不定长数据的接收呢

利用IDLE中断进行串口不定长数据的接收有何优势?

如何利用IDLE中断进行串口不定长数据的接收呢?

回帖(1)

李启华

2021-12-8 09:21:44
简介

  1、使用到的软件 STM32CubeMX 6.1.0 和keil 5.33
2、芯片 STM32L071CBT6
3、实现功能,按帧接收串口数据,数据存入接收buff,帧长存入全局变量
  实现原理

当一帧数据传输结束之后,总线IDLE会维持高电平状态,此时就可以触发MCU的IDLE中断。因此利用IDLE中断进行串口不定长数据的接收。省去了用于检测传输是否完成的判断动作。



  

然而在HAL库中并未集成IDLE中断的处理,所以,我们可以在串口的中断处理中添加对IDLE总线状态的判断,以检测当前帧是否传输完成。
  工程实现

  1、CubeMX工程配制
  (使能两个串口,串口1发送,串口2接收)   
  

  

   串口DMA设置   
  

  

  中断使能   2、代码编辑
  main.c全局变量定义

/* USER CODE BEGIN 0 */
uint8_t gcRXDBuffer[50], gcRXDPointer;    //接收的缓冲区、接收指针
uint16_t gcRXDLength; //接收的帧长度
uint8_t gcTXDBuffer[50], gcTXDPointer, gcTXDLength;    //发送的缓冲区,发送指针,发送的长度
uint8_t recv_end_flag; //接收完成标识
/* USER CODE END 0 */


函数 MX_USART2_UART_Init(void) 中添加


  /* USER CODE BEGIN USART2_Init 2 */
        __HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);  //使能idle中断
        HAL_UART_Receive_DMA(&huart2,gcRXDBuffer,sizeof(gcRXDBuffer));  //打开DMA串口接收
  /* USER CODE END USART2_Init 2 */


串口中断处理函数中modify


extern uint8_t gcRXDBuffer[50], gcRXDPointer ;    //接收的缓冲区、接收指针、接收的帧长度
extern uint16_t gcRXDLength;
extern uint8_t recv_end_flag;


void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
        uint32_t tmp_flag = 0;
        uint32_t temp;
        tmp_flag =__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE); //获取IDLE标志位
        if((tmp_flag != RESET))//idle标志被置位
        {
                __HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除标志位
                HAL_UART_DMAStop(&huart2); //
                temp  = __HAL_DMA_GET_COUNTER(huart2.hdmarx);// 获取DMA中未传输的数据个数
                gcRXDLength =  sizeof(gcRXDBuffer) - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
                recv_end_flag = 1;        // 接受完成标志位置1       
               
                HAL_UART_Receive_DMA(&huart2,gcRXDBuffer,sizeof(gcRXDBuffer));//重新打开DMA接收
         }
  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */


  /* USER CODE END USART2_IRQn 1 */
}


主函数main中


  /* USER CODE BEGIN 2 */
        strcpy((char*)gcTXDBuffer,"this is test message!");  //include
        uint8_t sendBuff[] = {"123456789"};
  /* USER CODE END 2 */


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  int i=0;
  while (1)
  {
    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */
                HAL_Delay(500);
                                       
                i++;
                if(i%2)
                        HAL_UART_Transmit(&huart1, gcTXDBuffer,10,0XFFFF);
                else
                        HAL_UART_Transmit(&huart1, sendBuff,8,0XFFFF);
               
                HAL_Delay(100);
               
                if(recv_end_flag ==1)
                {
                        //add code to deal UART message
                       
                        gcRXDLength=0;//清除计数
                        recv_end_flag=0;//清除接收结束标志位
                }
                               
                HAL_Delay(500);
  }
  /* USER CODE END 3 */



  

CNDTR寄存器设置说明

HAL_UART_Receive_DMA(&huart2,gcRXDBuffer,sizeof(gcRXDBuffer));  ====》》
UART_Start_Receive_DMA(huart, pData, Size) ====》》
HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, (uint32_t)huart->pRxBuffPtr, Size)   ====》》   
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength)====》》
                          /* Configure DMA Channel data length */
                                  hdma->Instance->CNDTR = DataLength;
通过以上调用,最终在DMA_SetConfig函数中,对CNDTR寄存器进行了设置。
  
举报

更多回帖

发帖
×
20
完善资料,
赚取积分