关于STM32用DMA传输UART空闲中断中接收的数据时无法接收数据问题以及解决办法

一、stm32 cube ide 配置

1、DMA串口接收数据的ide配置如下图所示

 

        串口1相关的设置及printf函数的使用,这里没放,建议先实现串口打印功能

2、相关的知识点

        普通模式和循环模式的区别在于,普通模式下,DMA只会接收一次数据,接收完成后就会停止,需要接收时再开启;而循环模式下,DMA会一直接收数据,直到接收缓存区满或者手动停止

       根据自己需求定模式,如果是数据有间隔,空闲中断的这种情况下,处理一帧数据,建议用Normal,有很多例程用Circular模式的情况下处理一帧数据,还要在中断中使用函数HAL_UART_DMAStop(); 来停止此次接收,处理数据后再重新启动接收,就显得有点多次两举了,如果用Circular模式,没有用HAL_UART_DMAStop停止接收的话,DMA会一直循环填充数据,size为最大,因为数据是循环填充的,所以数据的位置不定,看上去是乱的。

        关于禁用DMA传输的半传输中断,在空闲中断接收数据时,因为是不定长,假如在开启接收最大长度为128,那么当接收到64字节数据的时候就会触发半传输中断,因为这个触发用不到,所以禁用了。当然不禁用也行,半传输中断的回调函数是HAL_UART_RxHalfCpltCallback();

 

 二、无法接收数据问题

1、初始化顺序不对导致DMA无法正常传输串口接收的数据。

        具体原因查看:

使用STM32 CUBE IDE配置STM32F7 用DMA传输多通道ADC数据_stm32cubeide 配置adc_一只小白啊的博客-CSDN博客        文章最后部分的注意事项。

解决办法:先初始化DMA再初始化串口。

2、开启传输失败,导致DMA传输被重置为标准接收模式,无法触发空闲中断。

        产生原因:在使用HAL_UARTEx_ReceiveToIdle_DMA时,如果出现错误,即函数返回值=HAL_ERROR时,会被重置为HAL_UART_RECEPTION_STANDARD 标准接收模式,即中断回调函数为HAL_UART_RxCpltCallback,触发条件为当接收的数据满启动时指定的Size,如启动接收时指定接收长度为128字节,当接收到128字节时就会触发一次中断(如果DMA为循环模式)。

        这个错误可能出现的情况:开启状态下已经触发了一个中断,比如溢出或者重启时别的设备发送了一串数据,触发了一个空闲中断,同时有数据在串口的缓冲区,就会导致开启HAL_UARTEx_ReceiveToIdle_DMA时产生一个错误返回值,同时被置为标准接收模式。

        解决办法:清空接收缓冲区(不清空的话,依旧会返回HAL_ERROR),同时清除错误标志。调用HAL_UART_AbortReceive函数可以同时满足停止DMA传输、清空接收缓冲区、清除标志。

三、代码实例

整个实现逻辑如下图所示:

1、基本设置

/******************************************************************************
 * 参数:UART
 *****************************************************************************/
#define USART_REC_LEN 128 // 一次最大接收的字节数

typedef struct
{
    uint8_t Receive_buffer[USART_REC_LEN]; // DMA数据接收缓存
    _Bool Receive_state;                   // 接收状态 表示一帧数据是否完成接收
    uint8_t Receive_length;                // 表示一帧数据长度,因为最大接收长度定义为128 所以uint8_t 够用
    _Bool Receive_flag;                    // 表示一帧数据正确,如果判断接收的数据为符合协议的能用的数据,则置1

} UART_Receive_Def;
UART_Receive_Def UART5_DMA;

/******************************************************************************
 * 功能:串口错误代码
 *****************************************************************************/
uint8_t Error_code_uart5;

/******************************************************************************
 * 功能:打印串口状态标志
 *****************************************************************************/
void print_uart_sr(UART_HandleTypeDef *huart)
{
    printf("UART_FLAG_RWU       UART_FLAG_SBKF -->  %X -->  %X\r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_RWU), __HAL_UART_GET_FLAG(huart, UART_FLAG_SBKF));
    printf("UART_FLAG_CMF       UART_FLAG_BUSY -->  %X -->  %X\r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_CMF), __HAL_UART_GET_FLAG(huart, UART_FLAG_BUSY));
    printf("UART_FLAG_ABRF      UART_FLAG_ABRE -->  %X -->  %X\r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_ABRF), __HAL_UART_GET_FLAG(huart, UART_FLAG_ABRE));
    printf("UART_FLAG_CTS       UART_FLAG_LBDF -->  %X -->  %X\r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_CTS), __HAL_UART_GET_FLAG(huart, UART_FLAG_LBDF));
    printf("UART_FLAG_TXE         UART_FLAG_TC -->  %X -->  %X\r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE), __HAL_UART_GET_FLAG(huart, UART_FLAG_TC));

    printf("UART_FLAG_RXNE      UART_FLAG_RTOF -->  %X -->  %X\r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE), __HAL_UART_GET_FLAG(huart, UART_FLAG_RTOF));
    printf("UART_FLAG_IDLE       UART_FLAG_ORE -->  %X -->  %X\r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE), __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE));
    printf("UART_FLAG_NE          UART_FLAG_FE -->  %X -->  %X\r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_NE), __HAL_UART_GET_FLAG(huart, UART_FLAG_FE));
    printf("UART_FLAG_PE                       --> %X \r\n", __HAL_UART_GET_FLAG(huart, UART_FLAG_PE));
}

2、初始化,不查看错误代码的话,启动只需要一条命令。

    /******************************************************************************
     * 功能:DMA接收,空闲中断
     *****************************************************************************/
    // 开启DMA传输UART空闲中断中接收的数据,并在接收到UART空闲中断后停止传输。
    Error_code_uart5 = HAL_UARTEx_ReceiveToIdle_DMA(&huart5, UART5_DMA.Receive_buffer, USART_REC_LEN);
    __HAL_DMA_DISABLE_IT(&hdma_uart5_rx, DMA_IT_HT);

    // 打印UART状态标志和错误码
    print_uart_sr(&huart5);
    printf("Error_code_uart5 --> %ld \r\n", Error_code_uart5);

    // 如果有错误的话
    if (Error_code_uart5 != HAL_OK)
    {
        // 清空缓冲,置位一些标志,具体看函数内部
        HAL_UART_AbortReceive(&huart5);
        // 重启接收
        Error_code_uart5 = HAL_UARTEx_ReceiveToIdle_DMA(&huart5, UART5_DMA.Receive_buffer, USART_REC_LEN);
    }

    // 打印UART状态标志和错误码
    print_uart_sr(&huart5);
    printf("Error_code_uart5 --> %ld \r\n", Error_code_uart5);

3、中断回调,触发了空闲中断,接收到了一帧数据

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *UartHandle, uint16_t Size)
{
    if (UartHandle == &huart5)
    {
        /******************************************************************************
         * 功能:DMA接收,空闲中断
         *****************************************************************************/
		
        //处理数据(UART5_DMA.Receive_buffer, Size)
        //串口1打印或者其他处理,调试查看等
        //HAL_UART_Transmit(&huart1, UART5_DMA.Receive_buffer, Size, 0xFFFF);
		//重启接收
        HAL_UARTEx_ReceiveToIdle_DMA(&huart5, UART5_DMA.Receive_buffer, USART_REC_LEN);
        __HAL_DMA_DISABLE_IT(&hdma_uart5_rx, DMA_IT_HT);
}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微前端(无界)

前言:微前端已经是一个非常成熟的领域了,但开发者不管采用哪个现有方案,在适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户核心诉求都或存在问题,或无法提供支持。本…

DS18B20温度传感器简介和1-Wire驱动程序

目录DS18B20简介DS18B20的两种供电方式64位ROM温度传感器1-Wire Bus简介DS18B20通信时序初始化ROM相关命令(后续包含任何数据交换的操作)功能相关命令(后续包含任何数据交换的操作)单个DS18B20读取温度值驱动多个DS18B20读取温度值驱动DS18B20简介 DS18B20数字温度计提供9位到…

学习系统编程No.7【进程替换】

引言: 北京时间:2023/3/21/7:17,这篇博客本来昨天晚上就能开始写的,但是由于笔试强训的原因,导致时间用在了做题上,通过快2个小时的垂死挣扎,我充分意识到了自己做题能力的缺陷和运用新知识的缺…

致远OA敏感信息泄露漏洞合集(含批量检测POC)

文章目录前言敏感信息泄露A6 status.jsp 信息泄露漏洞漏洞描述漏洞影响网络测绘漏洞复现POC 批量检测getSessionList.jsp Session泄漏漏洞漏洞描述网络测绘批量检测POC致远OA 帆软组件 ReportServer 目录遍历漏洞漏洞描述漏洞影响网络测绘POC(批量检测)A6 createMysql.jsp 数据…

Java stream性能比较

环境 Ubuntu 22.04IntelliJ IDEA 2022.1.3JDK 17CPU:8核 ➜ ~ cat /proc/cpuinfo | egrep -ie physical id|cpu cores physical id : 0 cpu cores : 1 physical id : 2 cpu cores : 1 physical id : 4 cpu cores : 1 physical id : 6 cpu cores : 1 physical id …

浏览器工作原理

一、JavaScript 的历史 JavaScript(简称JS)Web前端开发的脚本语言。 它诞生1995年,由网景公司的 Brendan Eich 开发。最初,JavaScript 被设计用于在网页上嵌入动态内容和交互式功能。 1996年,JavaScript 1.1 成为国…

C++虚函数与多态

C虚函数与多态虚函数抽象类纯虚函数虚析构函数多态虚函数的几个问题纯虚函数和ADT虚函数 virtual修饰的成员函数就是虚函数, 1.虚函数对类的内存影响:增加一个指针类型大小(32位和64位) 2.无论有多少个虚函数,只增加一…

【ansible】模块介绍超详解(下)

目录 六,软件包管理 1,yum_repository模块 (1)yum_repository模块常用选项 (2)yum_repository模块案例 2,mount模块 (1)mount模块选项 (2)mount模…

大数据简介

大数据概论和职业规划Linux服务器系统Hadoop概论HDFS分布式文件系统Hive数据仓库SparSQL指令Zepplin框架Sqoop框架Superset数据可视化大数据数仓实战-didi出行大数据概念大数据特点大数据应用场景大数据分析业务步骤大数据职业规划大数据学习路线。大数据概念数据:世…

基于YOLOv5的舰船检测与识别系统(Python+清新界面+数据集)

摘要:基于YOLOv5的舰船检测与识别系统用于识别包括渔船、游轮等多种海上船只类型,检测船舰目标并进行识别计数,以提供海洋船只的自动化监测和管理。本文详细介绍船舰类型识别系统,在介绍算法原理的同时,给出Python的实…

【系统开发】WebSocket + SpringBoot + Vue 搭建简易网页聊天室

文章目录一、数据库搭建二、后端搭建2.1 引入关键依赖2.2 WebSocket配置类2.3 配置跨域2.4 发送消息的控制类三、前端搭建3.1 自定义文件websocket.js3.2 main.js中全局引入websocket3.3 App.vue中声明websocket对象3.4 聊天室界面.vue3.5 最终效果一、数据库搭建 很简单的一个…

数据结构与算法——二叉树+带你实现表达式树(附源码)

📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段,因为最近参加新星计划算法赛道(白佬),所以加快了脚步,果然急迫感会增加动力>——…

ThreadLocal详解

一、什么是ThreadLocal 1、什么是ThreadLocal&为什么用ThreadLocal ThreadLocal,即线程本地变量,在类定义中的注释如此写This class provides thread-local variables。如果创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有…

C++基础算法④——排序算法(插入、桶附完整代码)

排序算法 1.插入排序 2.桶排序 1.插入排序 基本思想:将初始数据分为有序部分和无序部分;每一步将无序部分的第一个值插入到前面已经排好序的有序部分中,直到插完所有元素为止。步骤如下: 每次从无序部分中取出第一个值&#x…

图像分类卷积神经网络模型综述

图像分类卷积神经网络模型综述遇到问题 图像分类:核心任务是从给定的分类集合中给图像分配一个标签任务。 输入:图片 输出:类别。 数据集MNIST数据集 MNIST数据集是用来识别手写数字,由0~9共10类别组成。 从MNIST数据集的SD-1和…

在Clion开发工具上使用NDK编译可以在安卓上执行的程序

1. 前言 因为工作需要,我要将一份C语言代码编译成可执行文件传送到某安卓系统里执行。 众所周知,使用ndk编译代码有三种使用方式,分别是基于 Make 的 ndk-build、CMake以及独立工具链。以前进行ndk编程都是使用ndk-build进行的,新…

RocketMQ的基本概念、系统架构、单机安装与启动

RocketMQ的基本概念、系统架构、单机安装与启动 文章目录RocketMQ的基本概念、系统架构、单机安装与启动一、基本概念1、消息(Message)2、主题(Topic)3、标签(Tag)4、队列(Queue)5、…

C# 教你如何终止Task线程

我们在多线程中通常使用一个bool IsExit类似的代码来控制是否线程的运行与终止,其实使用CancellationTokenSource来进行控制更为好用,下面我们将介绍CancellationTokenSource相关用法。C# 使用 CancellationTokenSource 终止线程使用CancellationTokenSo…

【Leetcode】-有效的括号

作者:小树苗渴望变成参天大树 作者宣言:认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 文章目录前言前言 今天我们再来讲一期关于题目的博客,我挑选的是一道leet…

Git学习与gitlab中央仓库搭建(详细介绍)

环境:centos7.3一,Git的发展史git:分布式版本控制系统,是当前最流行的版本控制软件创始人:林纳斯.拖瓦兹二,部署Git环境1.安装git服务[rootlocalhost ~]# yum -y install git2.配置git环境不一定是data目录…
最新文章