串口DMA接收不定长数据

news2024/11/18 7:05:17

STM32F767—>串口通信接收不定长数据的处理方法_stm32串口超时中断-CSDN博客

STM32-HAL库串口DMA空闲中断的正确使用方式+解析SBUS信号_stm32 hal usart2 dma-CSDN博客

#define USART1_RxBuffSize 100
extern DMA_HandleTypeDef hdma_usart1_rx;	//此处声明的变量在其他地方定义
uint8_t USART1_RxBuffer[USART1_RxBuffSize];		//串口接收缓冲区
uint8_t USART1_RxLen = 0;	//接收到的数据长度
uint8_t data[USART1_RxBuffSize];
volatile uint8_t rxComplete = 0;  // 接收完成标志

// 重定向printf start
//_write函数在syscalls.c中, 使用__weak定义以可以直接在其他文件中定义_write函数
int _write(int file, char *ptr, int len)
{
	 if(HAL_UART_Transmit(&huart1,(uint8_t *)ptr,len,0xffff) != HAL_OK)
	 {
		 Error_Handler();
		 return -1;
	 }
	 return len;
}
// 重定向printf end
  • 串口控制数据收发!DMA仅仅用于传输数据,减轻CPU负担。

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);
    
    • 将 DMA(Direct Memory Access,直接内存访问)与 UART(通用异步收发传输器)进行绑定的,在usart.cHAL_UART_MspInit硬件初始化中。
    • USART1 的接收操作能够通过 DMA 直接将数据传输到内存中,减少了 CPU 的参与,提高了数据处理的效率。

方法一:串口空闲中断+DMA

/* 开启串口DMA空闲中断接收,内部会使能串口空闲中断,并设置串口接收类型为空闲中断
   * 空闲的定义是总线上在一个字节的时间内没有再接收到数据,即空闲帧 */
  HAL_UARTEx_ReceiveToIdle_DMA(&huart1, USART1_RxBuffer, USART1_RxBuffSize);
/* 串口空闲中断回调函数 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == USART1)
	{
		/* 获取DMA中已经传输的数据个数
		 * __HAL_DMA_GET_COUNTER访问DMA的NDTR寄存器(只读,用于指示要传输的剩余数据项数,每次DMA传输后,此寄存器将递减) */
		USART1_RxLen = USART1_RxBuffSize - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);

		/* 内存复制
		 * 数据帧:帧头:0x65(A),帧长:4个字节 */
		if (USART1_RxBuffer[0] == 0x41 && USART1_RxLen == 4)	//接受完一帧数据
		{
			memcpy(data, USART1_RxBuffer, USART1_RxLen);
		}

		HAL_UART_Transmit_DMA(huart, USART1_RxBuffer, USART1_RxLen);
		// 再次开启串口DMA空闲中断,HAL_UARTEx_ReceiveToIdle_DMA → UART_Start_Receive_DMA
		HAL_UARTEx_ReceiveToIdle_DMA(huart, USART1_RxBuffer, USART1_RxBuffSize);
	}
}

方法二:串口接收超时中断+DMA

/* 接收超时中断
   * 波特率:串口通信的速率,即串口通信时每秒钟可以传输多少个二进制位
   * 时钟分频后,传输1bit所需的时钟周期数为1个时钟周期
   * 波特率 = 系统时钟频率 / (过采样倍数(8或16) * 时钟分频值)
   * 数据帧的格式:起始位 + 数据位 + 停止位
   * USART_RTOR的RTO[23:0]:此位域用于提供接收器的超时值(以波特时钟数为单位)
   * 	在标准模式下,如果在接收到最后一个字符后,在RTO值对应的时间内未检测到新的起始位,则RTOF标志置1
   * 	in terms of number of bits
   * 	写入超时多少个位数 */
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_RTO);	//使能接收超时中断
  HAL_UART_ReceiverTimeout_Config(&huart1, 28800);	//设置接收超时时间,比如3*9600=28800,超时3s(波特率9600bit/s)
  HAL_UART_EnableReceiverTimeout(&huart1);	//使能接收超时功能
  HAL_UART_Receive_DMA(&huart1, USART1_RxBuffer, USART1_RxBuffSize);	//此函数检查功能CR2_RTOEN从而开启中断CR1_RTOIE

while (1)
  {
	  ProcessReceivedData();
  }
/* 串口接收超时中断回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART1)
	{
		USART1_RxLen = USART1_RxBuffSize - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); // 计算接收的数据长度
		rxComplete = 1; //设置接收完成标志
		memcpy(data, USART1_RxBuffer, USART1_RxLen); //复制接收缓冲区到数据
		memset(USART1_RxBuffer, 0, USART1_RxBuffSize); //清空接收缓冲区,避免残留数据干扰下一次接收
		HAL_UART_Receive_DMA(huart, USART1_RxBuffer, USART1_RxBuffSize); //重新开启DMA+串口接收
	}
}
// 在主循环或独立任务中进行协议处理
// 在中断处理程序中,应该尽量减少复杂的处理,避免阻塞系统
// 一般来说,回调函数只用于标记接收数据的完成状态,而实际的数据解析和协议处理可以放在主循环或独立的任务中来执行
//(回调函数里不要调用print打印信息!)
void ProcessReceivedData(void)
{
    if (rxComplete)
    {
        rxComplete = 0; // 清除接收完成标志

        // 协议解析

        printf("ReceivedValidData: \r\n"); //printf必须带\r\n,否则不显示
        HAL_UART_Transmit_DMA(&huart1, data, USART1_RxLen); // 发送响应数据
    }
}
  • USART1_IRQHandlerHAL_UART_IRQHandler

    在代码中,UART 的接收超时(RTO)中断处理流程如下:

    1. 检测 UART 超时中断标志

      if (((isrflags & USART_ISR_RTOF) != 0U) && ((cr1its & USART_CR1_RTOIE) != 0U))
      

      这里 USART_ISR_RTOF 表示接收超时标志位,USART_CR1_RTOIE 表示接收超时中断使能位。如果 USART_ISR_RTOF 被置位且 USART_CR1_RTOIE 已启用,则会进入接收超时中断的处理流程。

    2. 清除 UART 超时标志

      __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_RTOF);
      

      该行代码清除 UART 接收超时标志,以防止重复触发中断。

    3. 设置错误代码

      huart->ErrorCode |= HAL_UART_ERROR_RTO;
      

      HAL_UART_ERROR_RTO 添加到 huart->ErrorCode 中,记录接收超时错误。

    4. 进入错误处理
      代码随后检查 huart->ErrorCode 是否包含任何错误。如果 ErrorCode 不为 HAL_UART_ERROR_NONE,代码会根据错误类型采取相应的处理措施:

      • 如果错误被视为“阻塞性错误”,例如接收超时(RTO)、溢出错误(ORE)或 DMA 模式下的错误,则会中止接收传输,调用 UART_EndRxTransferHAL_DMA_Abort_IT 函数中止 DMA。
      • 如果错误是非阻塞性错误,会直接调用用户定义的 ErrorCallback
    5. 进入用户回调函数
      当代码检测到错误并将错误处理完成后,进入错误回调:

      #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
          huart->ErrorCallback(huart);
      #else
          HAL_UART_ErrorCallback(huart);
      #endif
      

      这里调用了 HAL_UART_ErrorCallback 或用户注册的 ErrorCallback

  • HAL_UART_ErrorCallback

    __weak void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
    

    重写错误回调(当前为接收超时RTO)函数。

调试debug

  • 串口助手+STM32CubeIDE
  1. 点击调试debug,烧录程序并进入调试模式;

  2. 点击继续,运行程序;

  3. 串口助手选择串口,配置波特率等,以接收超时中断为例,发送字符AC,则大概3秒之后,串口助手窗口会返回AC;

  4. 若要实时查看变量的值,则在现场表达式进行调试;

  5. 若用表达式查看变量的值,需要点击暂挂,暂停程序运行才能查看:

    请添加图片描述

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

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

相关文章

【Linux】进程字段、环境变量与进程地址空间

🌈 个人主页:谁在夜里看海. 🔥 个人专栏:《C系列》《Linux系列》《算法系列》 ⛰️ 丢掉幻想,准备斗争 目录 一、查看进程字段 1.字段说明 2.进程优先级 二、环境变量 1.概念 2.指令与PATH 3.环境变…

无人机场景 - 目标检测数据集 - 车辆检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍:无人机场景车辆检测数据集,真实场景高质量图片数据,涉及场景丰富,比如无人机场景城市道路行驶车辆图片、无人机场景城市道边停车车辆图片、无人机场景停车场车辆图片、无人机场景小区车辆图片、无人机场景车辆遮挡、车…

【C++】vector 类模拟实现:探索动态数组的奥秘

🌟 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。🌟 如果你对string,vector还存在疑惑,欢迎阅读我之前的作品 : 之前文章🔥&#x1f52…

小程序-基于java+SpringBoot+Vue的驾校预约平台设计与实现

项目运行 1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

初识算法 · 模拟(1)

目录 前言: 替换所有的问号 题目解析 算法原理 算法编写 提莫攻击 题目解析 算法原理 算法编写 外观数列 题目解析 算法原理 算法编写 前言: ​本文的主题是模拟,通过三道题目讲解,一道是提莫攻击,一道是…

使用 Vue 和 Create-Vue 构建工程化前端项目

目录 前言1. 工程化的意义与 Vue 的生态支持2. 搭建 Vue 工程化项目2.1 环境准备2.2 使用 create-vue 创建项目2.2.1 初始化项目2.2.2 安装依赖2.2.3 本地运行 3. Vue 项目的目录结构解析4. Vue 开发流程详解4.1 项目入口与根组件4.1.1 main.js 的作用4.1.2 App.vue 的结构 4.2…

Android中的AMS(Activity Manager Service)详解

Android中的AMS(Activity Manager Service)详解 AMS (Activity Manager Service) 是 Android 系统中非常核心的服务之一,它负责管理应用程序的生命周期、任务栈、进程、广播、服务等功能。AMS 是整个 Android Framework 的调度中心&#xff…

31.3 XOR压缩和相关的prometheus源码解读

本节重点介绍 : xor 压缩value原理xor压缩过程讲解xor压缩prometheus源码解读xor 压缩效果 xor 压缩value原理 原理:时序数据库相邻点变化不大,采用异或压缩float64的前缀和后缀0个数 xor压缩过程讲解 第一个值使用原始点存储计算和前面的值的xor 如果XOR值为0&…

UNIAPP发布小程序调用讯飞在线语音合成+实时播报

语音合成能够将文字转化为自然流畅的人声,提供100发音人供您选择,支持多语种、多方言和中英混合,可灵活配置音频参数。广泛应用于新闻阅读、出行导航、智能硬件和通知播报等场景。 在当下大模型火爆的今日,语音交互页离不开语音合…

【蓝牙协议栈】【BLE】【BAS】精讲蓝牙电池服务

1. 蓝牙电池服务(Bluetooth Battery Service)概念 蓝牙电池服务是蓝牙设备与其他设备通信时用于报告其剩余电池电量的标准服务。它让用户能够随时了解蓝牙设备(如无线耳机、智能手表、蓝牙鼠标/键盘等)的电池状态,从而方便地管理这些设备的续航与电源使用。 BAS通常用于在…

无线迷踪:陈欣的网络之旅

第一章 陈欣是一名资深的网络工程师,工作在一家领先的科技公司。她的生活平静而有序,直到有一天,公司的无线网络突然出现了严重的问题。员工们的设备频繁断开连接,无法正常使用。这个问题不仅影响了工作效率,还引起了…

【redis】—— 环境搭建教程

上一节,我们大致了解了Redis的几个重要版本,在本教程中,我们选择了5.0版本,因为5.0已经具备了大部分的功能特性,并且与7.0版本相比,其安装使用过程更为简便。 Redis的官方并不直接支持微软的Windows操作系统…

如何查看python源代码

众所周知,Python内建了许多函数模块,并且我们可能还会安装许多第三方模块等等。 下面以getpass为例查看其源代码。 1.help(getpass) 输入该命令找到file路径,并且可以查看其其提供的功能。 2.利用getpass.__file__查看位置 最后找到该文件…

java笔试练习题笔记(10)

关于继承和实现说法正确的 是 ? ( )A.类可以实现多个接口,接口可以继承(或扩展)多个接口 B.类可以实现多个接口,接口不能继承(或扩展)多个接口 C.类和接口都可以实现多个接口 D.类和接口都不…

前端开发之打印功的使用和实例(vue-print-nb)

通过插件来进行实现 前言效果图1、安装插件vue2vue32、 引入Vue项目2、 使用2.1、在项目中创建按钮并且使用v-print绑定绑定打印事件2.2、编写要打印的内容,给内容附加唯一的id2.3、绑定的时间的方法和参数3、整体代码(此代码是通过vue3来进行实现的但是逻辑都是一样的)前言…

NavVis VLX3的精度怎么去进行验证?【上海沪敖3D】

01、精度评价现状 三维捕捉行业还没有建立一个用于估算或验证移动激光扫描系统精度的统一标准。因此,需要高精度交付成果的专业人士很难相信设备所标注的精度规格,也就很难知道基于SLAM的移动激光扫描系统是否适合当前的项目。 NavVis将通过展示一种严格…

Java | Leetcode Java题解之第564题寻找最近的回文数

题目&#xff1a; 题解&#xff1a; class Solution {public String nearestPalindromic(String n) {long selfNumber Long.parseLong(n), ans -1;List<Long> candidates getCandidates(n);for (long candidate : candidates) {if (candidate ! selfNumber) {if (ans…

ES6标准-Promise对象

目录 Promise对象的含义 Promise对象的特点 Promise对象的缺点 Promise对象的基本用法 Promise对象的简单例子 Promise新建后就会立即执行 Promise对象回调函数的参数 Promise参数不会中断运行 Promise对象的then方法 Promise对象的catch()方法 Promise状态为resolv…

如何利用CSS制作导航菜单

1.利用CSS技术&#xff0c;结合链接和列表&#xff0c;设计并实现“山水之间”页面 示例代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>山水之间</title><style>.all{width:900px;}.top{width:900px;h…

Github 2024-11-17 php开源项目日报 Top10

根据Github Trendings的统计,今日(2024-11-17统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10JavaScript项目2Nextcloud服务器:安全的数据之家 创建周期:2796 天开发语言:PHP, JavaScript协议类型:GNU Affero General Public…