STM32 HAL库串口不定长度接收方法

参考:https://blog.csdn.net/u014470361/article/details/79206352

我这里使用的芯片是 F1 系列的,主要是利用 DMA 数据传输方式实现的,在配置工程的时候要注意配置好 DMA,并开启中断。

1、利用STM32 cubemx 建立一个工程,工程建立请参考我以前的文章:https://www.cnblogs.com/xingboy/p/9597464.html

2、利用STM32 cubemx 生成代码后,我们先定义一些变量来使用

/*    自己添加代码部分    */
volatile uint8_t rx_len=0;                            //接收数据长度
volatile uint8_t recv_end_flag=0;                     //接收完成标记位
uint8_t  rx_buffer[100];                              //接收缓存
char          BUFFER_SIZE=100;                        //不定长数据的最大长度,设置为200则最大长度为200

这里为什么要定义volatile 关键字呢?

       主要是因为volatile 关键字提醒编译器定义的变量是易变的,编译后的程序每次需要存储或读取该变量时,会直接从变量地址读取数据。在中断或多线程中使用volatile关键字可以避免不同优化等级时程序出错,提高程序的鲁棒性。

接着对串口初始化添加一些代码,程序如下:

/* USART2 init function */
static void MX_USART2_UART_Init(void)
{

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
    
    /*    自己添加代码部分    */
     __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);        //使能idle中断
   HAL_UART_Receive_DMA(&huart2,rx_buffer,BUFFER_SIZE);  //打开DMA接收,数据存入rx_buffer数组中。

}

3、接收函数我写在了另一个文件上,其他文件要用到上面 main文件里面定义的变量就要声明一个外部变量

extern volatile uint8_t rx_len;
extern volatile uint8_t recv_end_flag;
extern uint8_t  rx_buffer[100];
extern char      BUFFER_SIZE;

4、接着修改串口回调函数,在串口回调函数里添加接收代码,代码如下:

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);  //清除标志位
        temp = huart2.Instance->SR;    //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
        temp = huart2.Instance->DR;    //读取数据寄存器中的数据
        HAL_UART_DMAStop(&huart2);         temp  = hdma_usart2_rx.Instance->CNDTR;   //获取DMA中未传输的数据个数,NDTR寄存器分析见下面
        rx_len =  BUFFER_SIZE - temp;         //总计数减去未传输的数据个数,得到已经接收的数据个数
        recv_end_flag = 1;                //接受完成标志位置1    
     }
 
  /* USER CODE END USART2_IRQn 0 */ 
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

DMA通道结构体中定义了CNDTR寄存器,那为什么是未传输的数据数呢,STM32的中文手册给出了该寄存器的具体说明。

/** 
  * @brief DMA Controller
  */
typedef struct
{
  __IO uint32_t CCR;
  __IO uint32_t CNDTR;
  __IO uint32_t CPAR;
  __IO uint32_t CMAR;
} DMA_Channel_TypeDef;

寄存器说明如下:

5、接着编写接收处理函数,代码如下:

/***************************************************************
    *函数名:Data_Turn
    *输  入:无
    *说  明:串口接收完成,返回串口查看接收情况
    *返回值:无
  **/
void Data_Turn(void)
{

  if(recv_end_flag ==1)        
  {
      printf("rx_len=%d\r\n",rx_len);                           //打印接收长度
      HAL_UART_Transmit(&huart2,rx_buffer, rx_len,200);        //接收数据打印出来
      for(uint8_t i=0;i<rx_len;i++)
      {
         rx_buffer[i]=0;   //清接收缓存
      }
      rx_len=0;        //清除计数
      recv_end_flag=0;    //清除接收结束标志位
   }
}

运行效果如下图,我的代码是接收到Do-0:1字符串,判断字符串,返回我需要的字符串,效果正确。

猜你喜欢

转载自www.cnblogs.com/xingboy/p/9714907.html