zoukankan      html  css  js  c++  java
  • STM32—cubeMX+DMA+USART 接收任意长度的数据

    前言

    原文:https://blog.csdn.net/u014470361/article/details/79206352

    之前的一篇文章中我为了可以实现USART接收任意长度的数据,对HAL的库进行了修改,可以实现接收以0x0a结尾的任意长度数据,即认为接收到0x0a时接收结束,见链接:HAL USART接收任意长度
      然而,上述这种方法并不合适,原则上HAL库一般不去修改,不便于其他人移植程序,降低了程序中库的适用性,这是很不好的习惯,所以这种方法并不可取。
      后查资料得知STM32中还可以利用DMA的方式实现串口的任意长度数据的接收,故开始学习DMA+串口接收任意长度的数据这种方式。

    cubeMX软件配置过程

    首先,第一步都是进行时钟树的配置,配置好系统的时钟,不同的芯片配置不同的时钟频率,如图。
    这里写图片描述
    接着,配置USART1,选择异步asynchronous,软件自动配置了PA9和PA10管脚。
    这里写图片描述
    然后,继续添加USART1的发送和接收DMA,其余默认即可。
    这里写图片描述
    接着,勾选上USART1的中断使能。
    这里写图片描述
    最后,生成MDK-ARM V5版本环境的程序。
    这里写图片描述

    UASRT串口程序

    //添加变量,为什么用关键字volatile见链接:[链接](http://blog.csdn.net/u014470361/article/details/78830147)
    volatile uint8_t rx_len=0;
    volatile uint8_t recv_end_flag=0;
    uint8_t rx_buffer[200];
    static void MX_USART1_UART_Init(void)
    {
    
      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(__FILE__, __LINE__);
      }
      //上面的usart配置代码为cubemx自动生成的,在下方添加使能idle中断和打开串口DMA接收语句
    	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能idle中断
    	HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//打开DMA接收,数据存入rx_buffer数组中。	
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    接下来修改串口中断函数。

    void USART1_IRQHandler(void)
    {
    	uint32_t tmp_flag = 0;
    	uint32_t temp;
    	tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
    	if((tmp_flag != RESET))//idle标志被置位
    	{ 
    		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
    		temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
    		temp = huart1.Instance->DR; //读取数据寄存器中的数据
    		HAL_UART_DMAStop(&huart1); //
    		temp  = hdma_usart1_rx.Instance->NDTR;// 获取DMA中未传输的数据个数,NDTR寄存器分析见下面
    		rx_len =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
    		recv_end_flag = 1;	// 接受完成标志位置1	
    	 }
      HAL_UART_IRQHandler(&huart1);
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

    typedef struct
    {
      __IO uint32_t CR;     /*!< DMA stream x configuration register      */
      __IO uint32_t NDTR;   /*!< DMA stream x **number of data register**     */
      __IO uint32_t PAR;    /*!< DMA stream x peripheral address register */
      __IO uint32_t M0AR;   /*!< DMA stream x memory 0 address register   */
      __IO uint32_t M1AR;   /*!< DMA stream x memory 1 address register   */
      __IO uint32_t FCR;    /*!< DMA stream x FIFO control register       */
    } DMA_Stream_TypeDef;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里写图片描述
    接着,编写主函数中串口中断的处理函数。

    int main(void)
    {
      HAL_Init();
      SystemClock_Config();
      MX_GPIO_Init();
      MX_DMA_Init();
      MX_USART1_UART_Init();
      while (1)
      {
    		if(recv_end_flag ==1)
    		{
    			printf("rx_len=%d
    ",rx_len);//打印接收长度
    			HAL_UART_Transmit(&huart1,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;//清除接收结束标志位
    		}
    		HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//重新打开DMA接收		
      }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    程序的运行效果如下图所示 ,输入任意长度数据,串口打印出接收的数据长度并打印出接收的数据。本程序设置的接收长度最大BUFFER_SIZE是200,若想接收更长的数据,也可以把BUFFER_SIZE和数组长度改大。
    这里写图片描述
    ###DMA参数和函数解析
    DMA的基本原理、参数和函数解析在下一篇文章进行分析(链接)

    本文章的源代码下载地址:https://download.csdn.net/download/u014470361/10234803

     
  • 相关阅读:
    几种回文算法的比较
    算法与数据结构(五)树表的查找
    算法与数据结构(四)利用哈夫曼树编码解码
    算法与数据结构(三)线性表的查找算法
    主存和cache的地址映射
    算法与数据结构(二)三元组矩阵行列式的计算(用递归)
    算法与数据结构(一)将一个数组中的各节点按照层次遍历插入构成完全二叉树
    服务器被攻击,我真是个人才。
    想学嘛,不想学? 自学是门手艺
    想学嘛,技术人, 请不要封闭自己
  • 原文地址:https://www.cnblogs.com/pacexdong/p/12118193.html
Copyright © 2011-2022 走看看