STM32CubeMX学习笔记-USART_DMA

news2024/10/7 18:20:18

STM32CubeMX学习笔记-USART_DMA

  • 一、DMA的概念
  • 二、数据传输方式
    • 普通模式
    • 循环模式
  • 三、以串口方式讲解
    • 串口DMA方式发送函数:HAL_UART_Transmit_DMA
    • 串口DMA方式接收函数:HAL_UART_Receive_DMA
    • 获取未传输数据个数函数:__HAL_DMA_GET_COUNTER
    • 关闭DMA数据流:__HAL_DMA_DISABLE
  • 四、DMA2
    • 4.1 配置串口2
    • 4.2 配置DMA
    • 4.3 生成代码
    • 4.4 USART+DMA数据发送
    • 4.5 USART+DMA数据接收
    • 4.6 串口IDLE空闲中断+DMA数据接收

一、DMA的概念

直接存储器访问(DMA):用于在外设与存储器之间以及存储器与存储器之间进行高速数据传输。DMA传输过程的初始化和启动由CPU完成,传输过程由DMA控制器来执行,无需CPU参与,从而节省CPU资源,提高利用率。
在这里插入图片描述

DMA数据传输的四个要素:
①传输源:DMA数据传输的来源
②传输目标:DMA数据传输的目的
③传输数量:DMA传输数据的数量
④触发信号:启动一次DMA数据传输的动作

STM32的DMA控制器特点
1.STM32F411微控制器具备两个DMA控制器:DMA1和DMA2,每个控制器有8个数据流,每个数据流可以映射到8个通道(或请求);
2.每一个DMA控制器用于管理一个或多个外设的存储器访问请求,并通过总线仲裁器来协调各个DMA请求的优先级;
3.数据流(stream)是用于连接传输源和传输目标的数据通路,每个数据流可以配置为不同的传输源和传输目标,这些传输源和传输目标称为通道(Channel);
4.具备16字节的FIFO。使能FIFO功能后,源数据先送入FIFO,达到FIFO的触发阈值后,再传送到目标地址。

二、数据传输方式

普通模式

传输结束后(即要传输数据的数量达到零),将不再产生DMA操作。若开始新的DMA传输,需在关闭DMA通道情况下,重新启动DMA传输。

循环模式

可用于处理环形缓冲区和连续数据流(例如ADC扫描模式)。当激活循环模式后,每轮传输结束时,要传输的数据数量将自动用设置的初始值进行加载,并继续响应DMA请求。

三、以串口方式讲解

串口DMA方式发送函数:HAL_UART_Transmit_DMA

函 数 原 型 | HAL_StatusTypeDef HAL_UART_Transmit_DMA (UART_HandleTypeDef *huart,uint8_t *pData, uint16_t Size)
------------------ | ---------------DMA
功能描述 | 在DMA方式下发送一定数量的数据
入口参数1 | huart:串口句柄的地址
入口参数2 | pData:待发送数据的首地址
入口参数3 | Size:待发送数据的个数
返回值 | HAL状态值:HAL_OK表示发送成功;HAL_ERROR表示参数错误;HAL_BUSY表示串口被占用
注意事项 | 1.该函数将启动DMA方式的串口数据发送2.完成指定数量的数据发送后,可以触发DMA中断,在中断中将调用发送中断回调函数HAL_UART_TxCpltCallback进行后续处理3.该函数由用户调用

串口DMA方式接收函数:HAL_UART_Receive_DMA

函 数 原 型HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart,uint8_t *pData, uint16_t Size)
功能描述在DMA方式下接收一定数量的数据
入口参数1huart:串口句柄的地址
入口参数2pData:待收数数据的首地址
入口参数3Size:待收数数据的个数
返回值HAL状态值:HAL_OK表示发送成功;HAL_ERROR表示参数错误;HAL_BUSY表示串口被占用
注意事项1.该函数将启动DMA方式的串口数据接收2.完成指定数量的数据接收后,可以触发DMA中断,在中断中将调用接收中断回调函数HAL_UART_RxCpltCallback进行后续处理3.该函数由用户调用

获取未传输数据个数函数:__HAL_DMA_GET_COUNTER

函 数 原 型HAL_DMA_GET_COUNTER(HANDLE)
功能描述获取DMA数据流中未传输数据的个数
参数HANDLE_:串口句柄的地址
返回值NDTR寄存器的内容,即DMA数据流中无传输数据的个数
注意事项1.该函数是宏函数,进行宏替换,不发生函数调用2.该函数需要由用户调用,用于获取未传输数据的个数

关闭DMA数据流:__HAL_DMA_DISABLE

函数原型HAL_DMA_DISABLE(HANDLE_)
功能描述关闭指定的DMA数据流
参数HANDLE_:串口句柄的地址
返回值
注意事项1.该函数是宏函数,进行宏替换,不发生函数调用2.该函数需要由用户调用,用于关闭指定的DMA数据流3.关闭DMA数据流后触发DMA中断,最终调用串口收发的回调函数

四、DMA2

4.1 配置串口2

Connectivity 中选择 USART2 设置,并选择 Asynchronous 异步通信
基础参数:波特率为115200 Bits/s。传输数据长度为8 Bit奇偶检验无,停止位1 接收和发送都使能
在这里插入图片描述
NVIC Settings 一栏使能接收中断
在这里插入图片描述

4.2 配置DMA

在这里插入图片描述
根据DMA通道预览可以知道,点击 DMA Settings 添加 USART2 TX 和 USART2 RX 分别对应DMA1 的通道5和通道6。

●Direction: 传输方向

外设到内存 Peripheral To Memory
内存到外设 Memory To Peripheral
内存到内存 Memory To Memory
外设到外设 Peripheral To Peripheral

●Priority: 传输速度

最高优先级 Very Hight
高优先级 Hight
中等优先级 Medium
低优先级;Low

当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器也管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在 DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通 道编号,编号越低优先权越高,比如通道 0 高于通道 1。在大容量产品和互联型产品中,DMA1 控制器拥有高于 DMA2 控制器的优先级。

■DMA Request Setting: DMA传输的对应外设

●Mode:传输模式

Normal 正常模式。表示当一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次。
Circular 循环模式。表示传输完成后又重新开始继续传输,不断循环永不停止。

●Increment Address:

Peripheral 表示外设地址自增。
Memory 表示内存地址自增。

串口发送数据是将数据不断存进串口的发送数据寄存器(USARTx_TDR)。所以外接的地址是不递增。而内存储器存储的是要发送的数据,所以地址指针要递增才能将所以的数据发送出去。

●Data Width:
Byte 一个字节。
Half Word 半个字,等于两字节。
Word 一个字,等于四字节。
串口数据发送寄存器只能存储8bit,每次发送一个字节,所以数据长度选择Byte。
在这里插入图片描述

4.3 生成代码

输入项目名和项目路径
在这里插入图片描述

选择应用的 IDE 开发环境 MDK-ARM V5
在这里插入图片描述

每个外设生成独立的 ’.c/.h’ 文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。
在这里插入图片描述

点击 GENERATE CODE 生成代码
在这里插入图片描述

4.4 USART+DMA数据发送

新建一个变量

uint8_t sendBuff[] = "USART test by DMA\r\n";

在 man.c 中的主循环添加以下代码:

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    HAL_UART_Transmit_DMA(&huart2, (uint8_t *)sendBuff, sizeof(sendBuff));
    HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

通过串口助手可以看到在接收区有数据不断的打印输出
在这里插入图片描述

注意:如果不开启串口中断,则程序只能发送一次数据,程序不能判断DMA传输是否完成,USART一直处于busy状态。

4.5 USART+DMA数据接收

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t rxSize = 1;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_DMA(&huart2, (uint8_t *)Buffer, rxSize);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

stm32f1xx_it.c 这个文件的最下面添加 HAL_UART_RxCpltCallback()

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART2)
  {
    // 在这里处理接收到的数据,例如将数据存储到缓冲区或者显示在UI上
    memcpy(Buffer, (uint8_t *)&huart2->Instance->DR, rxSize);
    HAL_UART_Receive_DMA(&huart2, (uint8_t *)Buffer, rxSize);
  }
}

通过串口助手发送 OK,可以看到接收到 O,这是因为设置的接收数据是一个字符,如果要接收更多字符,请加大 Buffer。
在这里插入图片描述

4.6 串口IDLE空闲中断+DMA数据接收

特点:

●可以实现任意字符串接收并输出。
●在串口无数据接收的情况下,不会产生,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一但接收的数据断流,没有接收到数据,即产生IDLE中断。
在 main.c 中添加以下变量:

uint8_t recvBuff[BUFFER_SIZE];  //接收数据缓存数组
volatile uint8_t recvLength = 0;  //接收一帧数据的长度
volatile uint8_t recvDndFlag = 0; //一帧数据接收完成标志

在 main.h 中添加以下宏定义与变量:

#define BUFFER_SIZE 256
extern uint8_t recvBuff[BUFFER_SIZE];  //接收数据缓存
extern volatile uint8_t recvLength;  //接收一帧数据的长度
extern volatile uint8_t recvDndFlag; //一帧数据接收完成标志

在 main.c 中,while 循环前,串口初始化后,添加空闲中断和DMA接收开启函数,这样在第一次接收到数据的时候才会触发中断。

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断
  HAL_UART_Receive_DMA(&huart1, recvBuff, BUFFER_SIZE);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

stm32f1xx_it.c 这个文件的最下面修改 USART1_IRQHandler()

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
    uint32_t tmpFlag = 0;
    uint32_t temp;
    tmpFlag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
    if((tmpFlag != RESET))//idle标志被置位
    { 
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
        
        HAL_UART_DMAStop(&huart1); //
        temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数   
        recvLength  =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
        recvDndFlag  = 1;   // 接受完成标志位置1    
        HAL_UART_Transmit_DMA(&huart1, recvBuff, recvLength);
        recvLength = 0;//清除计数
        recvDndFlag = 0;//清除接收结束标志位

        memset(recvBuff,0,recvLength);
        HAL_UART_Receive_DMA(&huart1, recvBuff, BUFFER_SIZE);//重新打开DMA接收,不然只能接收一次数据
     }
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

通过串口助手发送不定长数据
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1062106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IIS解决上传文件大小限制

IIS解决上传文件大小限制 目的&#xff1a;通过配置文件和IIS来解决服务器对上传文件大小的限制 1&#xff1a;修改配置文件&#xff08;默认为4M 值的大小根据自己情况进行修改&#xff09; <httpRuntime maxRequestLength"2048000" /> 2&#xff1a;修改IIS配…

LVGL_基础控件Switch_Button

LVGL_基础控件Switch_Button 1、创建switch_button /* 创建一个 switch 部件(对象) */ lv_obj_t * sw lv_switch_create(lv_scr_act()); // 创建一个 switch 部件(对象),他的父对象是活动屏幕对象 lv_obj_center(sw); // 方法1&…

我的创作纪念日-第1024天

文章目录 一、机缘二、收获三、日常四、憧憬 一、机缘 不知不觉&#xff0c;已经加入CSDN这个大家庭5年多了&#xff0c;回想起3年前发布第一篇博客的时候&#xff0c;那时我记得很清楚&#xff0c;我在做项目时遇到报错&#xff0c;解决问题之后&#xff0c;然后想起了好多人…

10分钟了解数据架构、数据模型

写在前面&#xff1a;很多小伙伴分不清数据架构与数据模型&#xff0c;同时如何做好数据建模也有一定的疑问 1. 数据架构、数据模型、数据建模区别与联系 企业架构包含业务架构、数据架构、应用架构和技术架构。数据架构的主要目标是有效的管理数据&#xff0c;以及有效地管理…

Docker---cgroups资源限制

目录 一、cpu资源控制 1、 设置cpu使用率上限 2、设置cpu资源占用比&#xff08;设置多个容器时才有效&#xff09; 3、设置容器绑定指定的CPU 三、内存资源控制 四、磁盘IO配额控制 1、限制Block IO 2、限制bps和iops进行限制 一、cpu资源控制 cgroups是一个非常强大的…

Vue组件路由

1&#xff0c;安装vue-router组件&#xff0c;终端输入&#xff1a; npm i vue-router3.5.3 2&#xff0c;在src文件夹下创建router目录 3&#xff0c;创建index.js文件&#xff0c;配置路由&#xff0c;导入需要路由的组件。以后每次添加路由只要在routes中改变即可。 impo…

YOLOV7改进实操-添加Wise IoU,实现有效提点

1、打开utils->general.py&#xff0c;找到bbox_iou&#xff08;&#xff09;&#xff0c;345行左右&#xff0c;将下面的与源码进行替换 wiou有三个版本&#xff0c;可以替换&#xff0c;看看哪一个提点多 class WIoU_Scale: monotonous: {None: origin v1True: monotoni…

NEFU数字图像处理(1)绪论

一、简介 1.1什么是数字图像 图像是三维场景在二维平面上的影像。根据其存储方式和表现形式&#xff0c;可以将图像分为模拟图像和数字图像两大类 图像处理方法&#xff1a;光学方法、电子学方法 模拟图像&#xff1a;连续的图像数字图像&#xff1a;通过对时间上和数值上连续…

PHP 选课管理系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 选课管理系统是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 php 选课管理系统 代码 https://download.csdn.net/download/qq_41221322/88389656 二…

笔记本休眠,USB仍对外供电,关闭方法

如下图的&#xff0c;联想笔记本电脑不紧有对外USB供电功能&#xff0c;还有大对外大电流供电功能&#xff08;1A&#xff0c;带电池符号的USB&#xff09;。 如何关闭“关机/休眠时仍对外供电”的功能&#xff1f;比如&#xff0c;让笔记本在休眠时&#xff0c;所连接的USB风…

代码随想录算法训练营第23期day11 | 20. 有效的括号、1047. 删除字符串中的所有相邻重复项 、150. 逆波兰表达式求值

目录 一、&#xff08;leetcode 20&#xff09;有效的括号 二、&#xff08;leetcode 1047&#xff09;删除字符串中的所有相邻重复项 用栈存放 将字符串直接当成栈 三、&#xff08;leetcode 150&#xff09;逆波兰表达式求值 一、&#xff08;leetcode 20&#xff09;…

websocket实现go(server)与c#(client)通讯

go 服务端 使用到github.com/gorilla/websocket package mainimport ("fmt""github.com/gorilla/websocket""log""net/http" )func main() {var upgrader websocket.Upgrader{ReadBufferSize: 1024,WriteBufferSize: 1024,CheckOr…

GPU如何成为AI的加速器

0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自己学习的理解&#xff0c;虽然参考了他人的宝贵见解&#xff0c;但是内容可能存在不准确的地方。如果发现文中错误&#xff0c;希望批评指正&#xff0c;共同进步。 本文关键词&#xff1a;GPU、深度学习、GP…

MySQL:温备份和恢复-mysqldump (4)

介绍 温备&#xff1a;同样是在数据库运行的时候进行备份的&#xff0c;但对当前数据库的操作会产生影响。&#xff08;只可以读操作&#xff0c;不可以写操作&#xff09; 温备份的优点&#xff1a; 1.可在表空间或数据文件级备份&#xff0c;备份时间短。 2.备份时数据库依然…

智能AI创作系统ChatGPT商业运营版源码+AI绘画系统/支持GPT联网提问/支持Midjourney绘画+Prompt应用+支持国内AI提问模型

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&…

纯css实现3D鼠标跟随倾斜

老规矩先上图 为什么今天会想起来整这个呢?这是因为和我朋友吵架, 就是关于这个效果的,就是这个 卡片懸停毛玻璃效果, 我朋友认为纯css也能写, 我则坦言他就是在放狗屁,这种跟随鼠标的3D效果要怎么可能能用纯css写, 然后吵着吵着发现,欸,好像真能用css写哦,我以前还写过这种…

【算法|动态规划No.12】leetcode152. 乘积最大子数组

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

2023.10.5 文件操作IO 经典例题

目录 例题一 例题二 例题一 扫描指定目录&#xff0c;并找到名称中包含指定字符的所有普通文件&#xff08;不包含目录&#xff09;&#xff0c;并且后续询问用户是否删除该文件 代码如下&#xff1a; package io;import java.io.File; import java.util.Scanner;//扫描指定目…

无约束优化方法(optimtool.unconstrain)

import optimtool as oo from optimtool.base import np, sp, pltpip install optimtool >2.4.2无约束优化方法&#xff08;optimtool.unconstrain&#xff09; import optimtool.unconstrain as ou ou.[方法名].[函数名]([目标函数], [参数表], [初始迭代点])f ( x ) ∑ …

数值分析学习笔记——绪论【华科B站教程版本】

绪论 数值分析概念 用计算机求解数学问题的数值方法和理论 三大科学研究方法 实验理论分析科学计算&#xff08;用计算机去辅助研究&#xff09;&#xff1a;数值方法计算机 解析解和近似解 解析解&#xff1a;使用数学方法求出或推导出的结果&#xff0c;往往可以求解出…