STM32CUBEMX(2)--USART通过DMA方式接收不定长数据

STM32CUBXME--2USART通过DMA方式接收不定长数据

  • 概述
  • 硬件准备
  • 选择芯片型号
  • 配置时钟源
  • 配置时钟树
  • 串口配置
  • 生成工程设置
  • 代码生成设置
  • 生成代码
  • 配置keil
  • 代码
  • 演示效果
  • 教学视频
  • 最后

概述

直接存储器访问(DMA)用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何CPU操作的情况下通过DMA快速传输传输。这样节省的CPU资源可供其它操作使用。

DMA允许在后台执行数据传输,无需Cortex-MO处理器干预。在此操作过程中,主处理器可以执行其它任务,仅当整个数据块需要处理时,才会中断主处理器。这样即使传输大量数据也不会对系统性能造成太大影响。

DMA主要用于为不同的外设模块实现集中数据缓冲存储(通常在系统SRAM中)。与分布式解决方案(其中每个外设都需要实现自己的本地数据存储)相比,DMA解决方案在硅片成本和功耗方面的成本较低。

根据使用的产品型号的不同,有一个或两个DMA模块。

STM32F0XX DMA控制器总共有5个通道用于DMA1,每个通道都专门管理来自一个或多个外设的存储器访问请求。它具有一个仲裁器,用于处理不同的DMA请求的优先级。

本篇文章主要介绍如何使用STM32CubeMX实现串口DMA读取,并且打印出去。
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第1张图片

硬件准备

首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板: STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第2张图片

选择芯片型号

使用STM32CUBEMX选择芯片stm32f030r8,如下所示:
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第3张图片

配置时钟源

HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第4张图片

配置时钟树

STM32F0的最高主频到48M,所以配置48即可:
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第5张图片

串口配置

本次实验使用的串口1进行串口通信,波特率配置为115200。
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第6张图片 配置DMA
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第7张图片
中断
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第8张图片

生成工程设置

STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第9张图片

代码生成设置

最后设置生成独立的初始化文件:
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第10张图片

生成代码

STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第11张图片

配置keil

STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第12张图片

代码

在main.c中,添加头文件,若不添加会出现 identifier “FILE” is undefined报错。

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

变量定义:

/* USER CODE BEGIN PV */
#define BUFFERSIZE 255           //可以接收的最大字符个数       
uint8_t ReceiveBuff[BUFFERSIZE]; //接收缓冲区
uint8_t recv_end_flag = 0,Rx_len;//接收完成中断标志,接收到字符长度
/* USER CODE END PV */

函数声明和串口重定向:

/* USER CODE BEGIN PFP */
void uart1_data(void);					//接收函数
#ifdef __GNUC__									//串口重定向
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif 
PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
/* USER CODE END PFP */

开启串口IDLE中断:

  /* USER CODE BEGIN 2 */
	printf("串口1DMA例程\r\n");
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能串口1 IDLE中断 
  /* USER CODE END 2 */

主循环:

/* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		uart1_data();//串口数据处理
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

串口DMA获取:

/* USER CODE BEGIN 4 */
void uart1_data(void)
{
	if(recv_end_flag ==1)//接收完成标志
	{
		printf("数据长度=%d\r\n",Rx_len);//打印接收到的数据长度 
		printf("数据内容:");
		for(int i=0;i<Rx_len;i++)
		{
			printf("%c",ReceiveBuff[i]);//向串口打印接收到的数据
            }
    printf("\r\n");          
    for(int i = 0; i < Rx_len ; i++) //清空接收缓存区
    ReceiveBuff[i]=0;//置0
    Rx_len=0;//接收数据长度清零
    recv_end_flag=0;//接收标志位清零
    }
    //开启下一次接收
    HAL_UART_Receive_DMA(&huart1,(uint8_t*)ReceiveBuff,BUFFERSIZE);
}
/* USER CODE END 4 */

#include "stm32f0xx_it.c"文件中断外部变量引用:

/* USER CODE BEGIN 0 */
#define BUFFERSIZE 255	//可接收的最大数据量
extern uint8_t recv_end_flag,Rx_len,bootfirst;
/* USER CODE END 0 */

串口1中断函数:

/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
	uint32_t temp;
	if(USART1 == huart1.Instance)//判断是否为串口1中断

	{      
		if(RESET != __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))//如果为串口1
		{
			__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除中断标志
      HAL_UART_DMAStop(&huart1);//停止DMA接收
     		temp  = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//获取DMA当前还有多少未填充
      		Rx_len =  BUFFERSIZE - temp; //计算串口接收到的数据个数
      		recv_end_flag = 1;
    	 }
        }	
  /* USER CODE END USART1_IRQn 1 */
}

演示效果

STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第13张图片

教学视频

https://www.bilibili.com/video/BV1vz4y1y7Ni

最后

以上的代码会在Q群里分享。QQ群:615061293。
或者关注微信公众号『记贴』,持续更新文章和学习资料,可加作者的微信交流学习!
STM32CUBEMX(2)--USART通过DMA方式接收不定长数据_第14张图片

你可能感兴趣的:(#STM32,单片机,嵌入式,stm32,单片机)