[STM32 HAL库]串口中断编程思路
一、前言
最近在准备蓝桥杯比赛(嵌入式赛道),研究了以下串口空闲中断+DMA
接收不定长的数据,感觉这个方法的接收效率很高,十分好用。方法配置都成功了,但是有一个点需要进行考虑,就是一般我们需要对串口接收的数据进行处理,这个数据处理是在中断的回调函数
里面处理还是在主函数
里面处理好呢?以下就这两个方法进行分析:
二、方法分析
目前我想到的有两种方法:
方法一
在回调函数里直接处理数据
优点:
- 实时性强:数据接收完成后立即处理,减少了数据处理的延迟。
- 代码简洁:数据接收和处理逻辑在同一个地方,代码易于理解和维护。
缺点:
- 占用中断处理时间:如果数据处理逻辑复杂或耗时,会影响中断的响应速度,进而影响系统其他功能的实时性。
- 可维护性差:如果数据处理逻辑复杂,中断处理函数会变得冗长,难以维护。
方法二
在回调函数中设置标志位,在主函数里读取标志位再进行数据处理
优点:
- 保护中断响应速度:中断处理函数只负责设置标志位,数据处理在主循环中进行,保证了中断的响应速度。
- 代码结构清晰:中断处理函数和数据处理逻辑分离,代码结构更清晰,易于维护和扩展。
- 资源利用率高:可以在主循环中根据系统状态灵活调度数据处理,避免在中断中处理复杂逻辑造成的资源浪费。
缺点:
- 增加了一定的复杂性:需要额外管理标志位,以及同步数据接收和处理的逻辑。
- 可能引入延迟:数据处理被推迟到主循环中进行,可能会引入一定的处理延迟。
总结
- 数据处理的复杂度:如果数据处理逻辑复杂或耗时,建议采用方法二,以保护中断响应速度。
- 系统的实时性要求:如果系统对实时性要求较高,且数据处理不是非常耗时,方法一可能更合适。但如果数据处理可能影响到系统的其他实时功能,方法二则更为稳妥。
- 代码的可维护性和扩展性:如果希望代码结构更清晰,易于维护和扩展,方法二通常是更好的选择。
三、实际操作
配置的方法可以看之前写的文章
链接: [STM32 HAL库]串口空闲中断+DMA接收不定长数据
实验现象:将电脑发来的数据,原封不到的发送回去。特别注意
BUFF_SIZE
的大小,太小会造成接收数据的丢失。
方法一
在这个方法中,在中断的回调函数
里直接发送回去数据,并手动开启下一次的中断。
#define BUFF_SIZE 128
uint8_t rx_buffer[BUFF_SIZE]; // 创建接收缓存,大小为BUF_SIZE
int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,BUFF_SIZE);//手动开启串口DMA模式接收数据__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); //手动关闭DMA_IT_HT中断 while (1){}
}
void SystemClock_Config(void)
{//...
}
/* 串口接收完成回调函数 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if (huart->Instance == USART1){HAL_UART_Transmit(&huart1, rx_buffer, Size, 0xffff);// 将接收到的数据再发出HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, BUFF_SIZE); // 接收完毕后重启串口DMA模式接收数据__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);// 手动关闭DMA_IT_HT中断memset(rx_buffer, 0, BUFF_SIZE);// 清除接收缓存 }
}
/* 串口错误回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef * huart)
{if(huart->Instance == USART1){HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, BUFF_SIZE); // 接收完毕后重启串口DMA模式接收数据__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);// 手动关闭DMA_IT_HT中断memset(rx_buffer, 0, BUFF_SIZE);// 清除接收缓存}
}
方法二
在这个方法中,在串口接收完成的回调函数
置接收完成的标志位,然后在主函数
中进行判断。判断成立则进行数据的发送,并手动开启下一次的中断和清除标志位。
需要注意的是,不要在
回调函数
里面手动开启下一次的中断,因为有可能会出现主函数
数据还未处理完成,下一个串口数据就到来而覆盖上一次的串口数据。
所以,这里程序的处理方法是:程序处理完本次数据,则开启下一次中断接收;程序未处理完本次数据,则不开启下一次中断接收。
#define BUFF_SIZE 128
uint8_t rx_buffer[BUFF_SIZE]; // 创建接收缓存,大小为BUF_SIZE
_Bool u1_rx_end_flag = 0; //USART1接收数据完成标志位 1:接收完成
uint16_t u1_rx_size; //USART1接收数据实际长度
int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,BUFF_SIZE);//手动开启串口DMA模式接收数据__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); //手动关闭DMA_IT_HT中断 while (1){/* 判断接收是否完成 */if(u1_rx_end_flag == 1){/* 对接收的数据进行处理 */HAL_UART_Transmit(&huart1, rx_buffer, u1_rx_size, 0xffff);// 将接收到的数据再发出memset(rx_buffer, 0, BUFF_SIZE); // 清除接收缓存/* 开启下一次中断 */HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,BUFF_SIZE);//手动开启串口DMA模式接收数据__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);//手动关闭DMA_IT_HT中断 /* 清除标志位 */u1_rx_end_flag = 0;}}
void SystemClock_Config(void)
{//...
}
/* 串口接收完成回调函数 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if (huart->Instance == USART1){u1_rx_end_flag = 1; //置标志位u1_rx_size = Size; //获取接收数据长度}
}
/* 串口错误回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef * huart)
{if(huart->Instance == USART1){HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, BUFF_SIZE);//手动开启串口DMA模式接收数据__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);// 手动关闭DMA_IT_HT中断memset(rx_buffer, 0, BUFF_SIZE);// 清除接收缓存}
}
值得一提的是,若是没有手动开启
串口空闲中断
,那么串口错误中断
也不会被开启,也就无法进入串口错误回调函数
。
四、实验现象
两个方法实现现象一致
应该还有更好的串口接收模式,现在来说,这个方法应该够用了。
相关文章:
[STM32 HAL库]串口中断编程思路
一、前言 最近在准备蓝桥杯比赛(嵌入式赛道),研究了以下串口空闲中断DMA接收不定长的数据,感觉这个方法的接收效率很高,十分好用。方法配置都成功了,但是有一个点需要进行考虑,就是一般我们需要…...
会议签到系统的架构和实现
会议签到系统的架构和实现 摘要:通过定制安卓会议机开机APP呈现签到界面,并且通过W/B结构采集管理签到信息,实现会议签到的功能。为达到此目标本文将探讨使用Redis提供后台数据支持;使用SocketIo处理适时消息;使用Flask进行原型开…...
复位信号的同步与释放(同步复位、异步复位、异步复位同步释放)
文章目录 背景前言一、复位信号的同步与释放1.1 同步复位1.1.1 综述1.1.2 优缺点 1.2 recovery time和removal time1.3 异步复位1.3.1 综述1.3.2 优缺点 1.4 同步复位 与 异步复位1.5 异步复位、同步释放1.5.1 总述1.5.2 机理1.5.3 复位网络 二、思考与补充2.1 复…...
TL3562/3568移植无锡沐创N500L-AM4驱动进内核源码,报错及其解决方案
前言 创龙官方提供的资料无锡沐创N500L-AM4驱动是rnpgbe-0.1.0.rc60-dd9f3cf.tar.gz;无锡沐创官方,截止目前,最新驱动是rnpgbe-0.2.3-f26b9a4.tar.gz。考虑到开发的稳妥性,先选用创龙尝试过的rnpgbe-0.1.0.rc60-dd9f3cf.tar.gz来移…...
埃氏算法C++实现: 快速输出质数( 素数 )
目录 1.简介 算法原理 算法特点 应用场景 2.一般求素数方法 3.埃氏算法求素数 3.1.无动态分配 3.2.有动态分配 1.简介 埃氏算法(Eratosthenes Sieve),全称为埃拉托斯特尼筛法,是一种由古希腊数学家埃拉托斯特尼在公元…...
Kubernetes 集群中安装和配置 Kubernetes Dashboard
前言 上篇成功部署Kubernetes集群后,为了方便管理和监控集群资源,安装Kubernetes Dashboard显得尤为重要。Kubernetes Dashboard 是一个通用的、基于 Web 的 UI,旨在让用户轻松地部署容器化应用到 Kubernetes 集群,并对这些应用进…...
力扣-数组-414 第三大的数
解析 先利用set去重,然后用逆向遍历找到第三大的数 代码 class Solution { public:int thirdMax(vector<int>& nums) {set<int> numsToset;for(int i 0; i<nums.size(); i){numsToset.insert(nums[i]);}int index;if(numsToset.size() > …...
python实现答题游戏
有这样一个需求:使用python实现一个游戏,一共有10个问题,依次回答每个问题,每个用户可以输入问题的答案,但是互相不能看到,有一个管理员可以看到所有人的答案,并且当所有人都填写完成后可以公布…...
OneData体系架构详解
阿里巴巴的 OneData 体系架构方法论,主要分为三个阶段:业务板块、规范定义 和 模型设计。每个阶段的核心目标是确保数据的高效管理、共享与分析能力。 一. 业务板块(Business Segment) 业务板块是OneData体系架构中的第一步&…...
五、华为 RSTP
RSTP(Rapid Spanning Tree Protocol,快速生成树协议)是 STP 的优化版本,能实现网络拓扑的快速收敛。 一、RSTP 原理 快速收敛机制:RSTP 通过引入边缘端口、P/A(Proposal/Agreement)机制等&…...
解锁Java中的国密算法:安全保障的密钥
一、引言 在数字化浪潮席卷全球的当下,信息安全已然成为国家、企业乃至个人无法忽视的重要议题。国密算法,作为我国自主研发的密码算法体系,宛如坚固的盾牌,为国家信息安全筑起了一道坚不可摧的防线。它的诞生,不仅承载…...
docker-registry
安装依赖 apt install apache2-utils设置密码 htpasswd -Bbn 用户名 密码 >/data/registry_hub/passwd#docker私服部署 docker run -d -p 5000:5000 --name docker-registry -v /data/registry_hub/:/var/lib/registry -v /data/registry_hub/passwd:/auth/htpasswd \ -e …...
QTableWidget的简单使用
1.最简单的表格示例: ui->tableWidget->setRowCount(2);// 设置行数ui->tableWidget->setColumnCount(3);// 设置列数,一定要放在设置行表头之前QStringList rowHeaderList;// 行表头rowHeaderList << QStringLiteral("姓名"…...
第三天 学习JavaScript基础,掌握变量、数据类型、运算符、流程控制
学习JavaScript基础是成为一名前端开发者的重要一步。以下是关于变量、数据类型、运算符和流程控制的一些基础知识和示例代码。 1. 变量 变量用于存储数据。在JavaScript中,使用var、let或const关键字来声明变量。 // 使用 var 声明变量(不推荐&#…...
Python - itertools- pairwise函数的详解
前言: 最近在leetcode刷题时用到了重叠对pairwise,这里就讲解一下迭代工具函数pairwise,既介绍给大家,同时也提醒一下自己,这个pairwise其实在刷题中十分有用,相信能帮助到你。 参考官方讲解:itertools --- 为高效循…...
C语言程序设计十大排序—选择排序
文章目录 1.概念✅2.选择排序🎈3.代码实现✅3.1 直接写✨3.2 函数✨ 4.总结✅5.十大排序 1.概念✅ 排序是数据处理的基本操作之一,每次算法竞赛都很多题目用到排序。排序算法是计算机科学中基础且常用的算法,排序后的数据更易于处理和查找。在…...
微前端qiankun的基本使用(vue-element-admin作为项目模版)
微前端qiankun的基本使用(vue-element-admin作为项目模版) qiankun架构特点主应用netmoni_master改造工程项目目录结构子项目配置:子应用注册配置项container:子应用挂载节点配置项activeRule:子应用路由子应用netmoni_child1改造目录结构项目配置:src/settings中配置子应…...
MySQL用户授权、收回权限与查看权限
【图书推荐】《MySQL 9从入门到性能优化(视频教学版)》-CSDN博客 《MySQL 9从入门到性能优化(视频教学版)(数据库技术丛书)》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) MySQL9数据库技术_夏天又到了…...
Ansible fetch模块详解:轻松从远程主机抓取文件
在自动化运维的过程中,我们经常需要从远程主机下载文件到本地,以便进行分析或备份。Ansible的fetch模块正是为了满足这一需求而设计的,它可以帮助我们轻松地从远程主机获取文件,并将其保存到本地指定的位置。在这篇文章中…...
skynet 源码阅读 -- 启动主流程
Skynet 启动主流程分析 Skynet 是一个轻量级、高并发的服务器框架。它在启动时会进行一系列初始化操作,并启动多个不同功能的线程(Monitor、Timer、Worker、Socket),从而实现消息分发、定时器、网络I/O等核心功能。本文主要从 ma…...
【Linux】Linux入门(三)权限
目录 前提权限概念whoami指令 Linux权限管理文件访问者的分类(人)file指令权限信息权限的表示方法 chmod指令 更改权限chown指令 修改文件,文件夹所属用户和用户组 权限掩码umask(权限掩码) 粘滞位 前提 请先看下面这…...
FluentCMS:基于 ASP.NET Core 和 Blazor 技术构建的开源CMS内容管理系统
推荐一个基于 ASP.NET Core 和 Blazor 技术构建的、功能完善的开源CMS内容管理系统。 01 项目简介 FluentCMS 是一个基于强大的 ASP.NET Core 和创新的 Blazor 技术构建的现代内容管理系统(CMS)。 FluentCMS 设计为快速、灵活且用户友好,它…...
【阿里云】使用docker安装nginx后可以直接访问
一、创建目录 mkdir -p config/{cert,conf.d} html logs二、上传nginx.conf的配置文件 user nginx; worker_processes auto;error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid;events {worker_connections 1024; }http {include /etc/ngin…...
leetcode-84-柱状图最大的矩形
柱状图中最大的矩形 已解答 算术评级: 7 同步题目状态 困难 相关标签 相关企业 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 1. stack 计算位置在…...
Vue | 搭建第一个Vue项目(安装node,vue-cli)
一.环境搭建: 1.安装node: 进入网站,下载对应版本的node.js Index of /dist/ (nodejs.org) 我这里下载的是: 解压到对应的目录下: 并新建两个文件夹node_cache和node_global: 2.配置环境: …...
Redis 持久化机制:RDB 和 AOF
Redis 持久化机制:RDB 和 AOF Redis 主要提供了两种持久化方式:**RDB(Redis Database)**和 AOF(Append-Only File)。它们各自的实现原理、优缺点以及适用场景如下。 1. RDB(Redis Database&…...
ToDesk云电脑、顺网云、网易云、易腾云、极云普惠云横测对比:探寻电竞最佳拍档
一、云电脑:电竞新宠崛起 在电竞游戏不断发展的今天,硬件性能成为了决定游戏体验的关键因素。为了追求极致的游戏画面与流畅度,玩家们往往需要投入大量资金购置高性能电脑。然而,云电脑技术的出现,为玩家们提供了一种…...
GPT 结束语设计 以nanogpt为例
GPT 结束语设计 以nanogpt为例 目录 GPT 结束语设计 以nanogpt为例 1、简述 2、分词设计 3、结束语断点 1、简述 在手搓gpt的时候,可能会遇到一些性能问题,即关于是否需要全部输出或者怎么节约资源。 在输出语句被max_new_tokens 限制,…...
【达梦数据库】两地三中心环境总结
目录 架构监视器位置异步备库同步频率配置:dmtimer.ini断网测试异地切换过程&回切:允许丢数据模式切换回切 架构 2(1主1实时备库)1(实时备库)1(异步备库),分别为节点1、2、3、4监视器位置 …...
C语言进阶习题【1】指针和数组(4)——指针笔试题3
笔试题5:下面代码输出是是什么? int main() {int a[5][5];int(*p)[4];p a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0; }分析 代码结果 笔试题6:下面代码输出是是什么࿱…...
Qt——引用第三方SDK lib库的使用方法
【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C++语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实战》 《实用硬件方案设计》 《结构建模设…...
Grafana系列之Dashboard:新增仪表板、新增变量、过滤变量、变量查询、导入仪表板、变量联动、Grafana Alert
概述 关于Prometheus和Grafana的安装,略过。 写在前面 Dashboard:仪表板,可包含多个PanelPanel:面板,Dashboard中的组件 如有写得不对的地方,烦请指出。 新增仪表板 点击右上角的 选择New dashboard…...
管道符、重定向与环境变量
个人博客站—运维鹿: http://www.kervin24.top CSDN博客—做个超努力的小奚: https://blog.csdn.net/qq_52914969?typeblog 一、重定向 将命令和文件结合 标准输入重定向(STDIN,文件描述符为0):默认从键盘输入&am…...
如何使用 Redis 作为高效缓存
如何使用 Redis 作为高效缓存 Redis(Remote Dictionary Server)是一个高性能的 内存存储系统,通常被用作 缓存 来加速数据访问,提高应用的吞吐量和响应速度。本文详细讲解如何使用 Redis 作为高效缓存,包括基本原理、…...
simulink入门学习01
文章目录 1.基本学习方法2.图形环境--模块和参数3.激活菜单---添加到模型3.1输入选项3.2添加到模型3.3更改运算3.4验证要求 4.乘以特定值--Gain模块4.1引入gain模块4.2更改增益参数4.3接入系统4.4大胆尝试 1.基本学习方法 今天突然想要学习这个simulink的相关知识,…...
接上篇基于Alertmanager 配置钉钉告警
Alertmanager 是一个用于处理和管理 Prometheus 警报的开源工具。它负责接收来自 Prometheus 服务器的警报,进行去重、分组、静默、抑制等操作,并通过电子邮件、PagerDuty、Slack 等多种渠道发送通知。 主要功能 去重:合并相同或相似的警报&a…...
【Elasticsearch】index.mapping.source.mode
在Elasticsearch中,当设置 index.mapping.source.mode 为 synthetic 时,Elasticsearch会自动生成和存储源文档的合成版本。这些合成版本的内容取决于你索引的字段和映射定义。具体来说,synthetic 模式会存储以下内容: ### 合成源文…...
GBase8c aes_encrypt和aes_decrypt函数
在数据库中,aes_encrypt和aes_decrypt函数进行加解密时使用的块加密模式。 GBase8c 与 MySQL 的aes_encrypt和aes_decrypt函数区别: 1、GBase8c 中的初始化向量init_vector不能为空 2、MySQL的加密模块block_encryption_mode 为aes-128-ecb,…...
【Unity】ScrollViewContent适配问题(Contentsizefilter不刷新、ContentSizeFilter失效问题)
最近做了一个项目,菜单栏读取数据后自动生成,结果用到了双重布局 父物体 尝试了很多方式,也看过很多大佬的文章,后来自己琢磨了一下,当子物体组件自动生成之后,使用以下以下代码效果会好一些: …...
第二届国赛铁三wp
第二届国赛 缺东西去我blog找👇 第二届长城杯/铁三 | DDLS BLOG web Safe_Proxy 源码题目 from flask import Flask, request, render_template_stringimport socketimport threadingimport htmlapp Flask(__name__)app.route(/, methods"GET"])de…...
对称二叉树(力扣101)
这道题翻译过来就是判断根节点的左右子树是否可以通过翻转,变得完全一样。如果可以,则这棵二叉树为对称二叉树。那么什么样的左右子树可以通过翻转相互变换呢?它们的节点的数值一定对称分布。那么我们就需要同时遍历左右树,不断比…...
postgresql15的停止
PostgreSQL是一个功能非常强大的、源代码开放的客户/服务器关系型数据库管理系统,且因为许可证的灵活,任何人都可以以任何目的免费使用、修改和分发PostgreSQL。介绍过postgresql的启动方法,就很有必要介绍下postgresql的停止方法。 一、停止…...
3.1 Go函数调用过程
在 Go 语言中,函数调用的核心机制依赖于内存的栈区分配和指针操作,理解这一原理有助于掌握函数的执行过程。 1. 内存结构概述 在 Go 程序编译成可执行文件并启动后,操作系统会为其分配进程内存,进程内存主要分为以下区域&#x…...
Java导出通过Word模板导出docx文件并通过QQ邮箱发送
一、创建Word模板 {{company}}{{Date}}服务器运行情况报告一、服务器:总告警次数:{{ServerTotal}} 服务器IP:{{IPA}},总共告警次数:{{ServerATotal}} 服务器IP:{{IPB}},总共告警次数:{{ServerBTotal}} 服务器IP:{{IPC}}&#x…...
c++---------------------------模板进阶
1.非类型模板参数 模板参数分类类型形参与非类型形参 。 类型形参即:出现在模板参数列表中,跟在 class 或者 typename 之类的参数类型名称 。 非类型形参,就是用一个常量作为类 ( 函数 ) 模板的一个参数,在类 ( 函数 ) 模板中可…...
FPGA与ASIC:深度解析与职业选择
IC(集成电路)行业涵盖广泛,涉及数字、模拟等不同研究方向,以及设计、制造、封测等不同产业环节。其中,FPGA(现场可编程门阵列)和ASIC(专用集成电路)是两种重要的芯片类型…...
c++面试题,请使用STL的std::remove_if算法删除std::vector<int>容器中大于5的数字
请使用STL的std::remove_if算法删除std::vector容器中大于5的数字 在C 中, std::remove_if 算法并不会真正从容器中删除元素, 而是将满足条件的元素移动到容器末尾,并返回一个指向新的逻辑结束位置的迭代器。 你需要使用容器的 erase 成员函…...
阿里云-银行核心系统转型之业务建模与技术建模
业务领域建模包括业务建模和技术建模,整体建模流程图如下: 业务建模包括业务流程建模和业务对象建模 业务流程建模:通过对业务流程现状分析,结合目标核心系统建设能力要求,参考行业建 模成果,形成结构化的…...
快速搭建深度学习环境(Linux:miniconda+pytorch+jupyter notebook)
本文基于服务器端环境展开,使用的虚拟终端为Xshell。 miniconda miniconda是Anaconda的轻量版,仅包含Conda和Python,如果只做深度学习,可使用miniconda。 [注]:Anaconda、Conda与Miniconda Conda:创建和管…...
智能风控 数据分析 groupby、apply、reset_index组合拳
目录 groupby——分组 本例 apply——对每个分组应用一个函数 等价用法 reset_index——重置索引 使用前编辑 注意事项 groupby必须配合聚合函数、 关于agglist 一些groupby试验 1. groupby对象之后。sum(一个列名) 2. groupby对象…...