STM32CubeMX与HAL库开发教程八(串口应用/轮询/中断/DMA/不定长数据收发)

目录

前言

初识串口-轮询模式

串口中断模式收发

串口DMA模式

蓝牙模块与数据包解析


前言

前面我们简单介绍过串口的原理和初步的使用方式,例如怎么配置和简单的收发,同时我们对串口有了一个初步的了解,这里我们来深入的来使用一下串口

初识串口-轮询模式

这里我们不介绍如何使用STM32CubeMX配置串口,我们默认使用USART1同时波特率为115200,首先让我们来使用串口发送一些数据

这里我们定义了一个数组,数组的内容为Hello Wrold,在主循环中我们调用了一个函数

HAL_UART_Transmit(huart,pData,Size,Timeout)

huart      :第一个参数为要操作串口的指针,这里要填写 &huart1 如果设置2那就换成 &huart2

pData     :第二个参数填的是需要发送信息的指针  (uint8_t *)message

Size        :第三个参数填的是数据字符串的长度 我们可以使用关键字 strlen(message) 识别长度

Timeout :第四个为发送数据的时间,超过这个时间就停止发送  单位 毫秒

完整的代码例子 HAL_UART_Transmit(&huart1 , (uint8_t *)message , strlen(message) , 50 )

 发送的解决了之后,我们来使用轮询模式接收一些数据

让我们讲发送的代码注释掉,同时再定义一个接收用的数组,这里我们直接使用uint8_t来定义,他和char是相同的作用,串口接收的参收与串口发送的参数一模一样

第一个参数也使用哪个串口来接收数据,也是需要填地址,第二个参数是用来接收数据的指针,也就是receiveData的首地址,第三个还是一样,最后一个参数我们设置为 HAL_MAX_DELAY 为最大时间,就一直等待,没有超时时间,如果使用uint8_t定义数组,第二个参数就不需要强制类型转换了  

HAL_UART_Receive(&huart1 , receiveData , strlen(receiveData) , HAL_MAX_DELAY )

编写一个使用串口控制红绿蓝三个灯的颜色

上电默认电平为高,如果串口第二位接收到0了则将电平拉低,同时串口根据第一位接收的数据来控制红绿蓝灯的亮灭

轮询模式不够灵活,同时会阻塞程序或者程序会阻塞串口收发,而且只能确定串口数据长度,我们接下来会学习中断模式串口收发数据

串口中断模式收发

 中断的发送函数与普通轮询模式的发送函数差别不大只在后面加上了IT,同时没有超时时间

HAL_UART_Transmit_IT(&huart1 , receiveData , strlen(receiveData) )

接收的函数也大致相同,

HAL_UART_Receive_IT(&huart1 , receiveData , 2)

不过需要注意由于不会堵塞数据,也就是还没等到接收到数据,就会接着向下执行下去,这就会造成执行到下次循环时,可能上次的数据还没有接收完,就又开始执行串口中断接收了,所以我们需要放在循环前,只执行一次,注意接收一次之后需要重新开启接收中断

而当我们需要再次接收时,我们可以在串口中断回调函数中再次开启接收中断就可以了

我们将while中的逻辑代码复制粘贴到串口接收中断回调函数中,这样可以帮助节约cpu资源,使用中断非常简单,在cubemx中勾选开启中断,同时在函数后面加上_IT后缀,以及将处理逻辑移入到串口中断函数中即可,我们成功的解决了串口堵塞程序的问题,那如何接收不确定长度的数据呢,能否进一步减少CPU的占用呢

串口DMA模式

虽然中断方式相较于轮询模式已经节约了很多cpu资源,但对于cpu本身来说,却是屡屡被打断,疲于在中断搬运数据与处理正常任务代码间辗转反侧,那我们能否进一步提升效率,给cpu找一个帮助搬运数据的小助手,这时候DMA的用处就显现出来了,DMA全称叫直接内存访问

打开cubemx,找到USART1设置界面,找到DMA Settings,点击下面的Add就可以添加DMA通道

在这里设置的DMA发送通道,DMA通道7为专门为USART2发送设置的,数据搬运方向由内存向外设搬运,也就是从内存变量向发送数据寄存器进行搬运,优先级默认为低,可以自己选择,其他参数CubeMX已经帮我们配置好了,默认即可,之后我们再添加一个USART2_RX的通道就行了

DMA模式的发送函数也就是把中断的_IT切换成了DMA,参数依旧是用哪个串口发送,要发送的变量以及发送的字节数,接收函数也是一样

需要注意的是,即使使用了DMA,其实还是有中断参与其中的,例如中断接收回调函数RxCpltCallback还是由中断触发,当然这次就不是串口的中断了,而是DMA传输中断,说完了DMA的用法,我们来看看如何接收不定长数据

其实接收不定长数据非常简单,主要靠的是串口空闲中断,此中断的触发条件与接收的字节数无关,只有当RX引脚上无后续数据进入,也就是串口接受从忙率转变为空闲时才会触发,这里我们就可以认为,当串口空闲中断时,一帧数据包就发送完成了

这里我们需要将串口接收函数替换为HAL封装的一个拓展函数

HAL_UARTEx_ReceiveToIdle_DMA(&huart2 , receiveData , 50)

我们可以注意,这个函数也有阻塞DMA和中断三个版本,我们这里选择DMA模式,由于是接收不定长数据,这里我们可以将receiveData这个数组改大一点,改成50,而这函数的最后一个参数,是填写一次能接收的最大数据长度,一般就是填写接收数组的长度,来避免接收数据太长而导致数组越界

此时我们要用的中断函数也变了

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart , uint16_t size)

这个回调函数和中断回调函数的区别就是他的参数中多了一个 size 长度,因为之前中断回调函数是接收定长数据,我们已知了数据长度,我们需要size入参来得知本次到底接收了几字节的数据

我们在下面这个回调函数中先判断一下是不是USART2接收了,我们将接收到的函数重新发送回串口助手中,要注意这里发送函数的第三个参数要改成回调函数参数中的size,来发送与接收相同的字节数,最后别忘记再次开启接收中断

可以发现,我们再次发送R1,发现数据返回来了,但是灯没有点亮,也就能证明使用ReceiveToldle函数后,不再调用RxCpltCallback回调函数,而是使用了RxEventCallback回调函数,我们再尝试将数据增长,发现数据正常返回,这就说明我们完美的实现了不定长数据接收

我们需要注意在这个函数中需要重新开启接收中断,但是我们使用普通模式或者中断模式的Toldle函数也是可以的,唯独DMA模式有个恼人之处,DMA的传输过半中断,也会触发这个回调函数,就是说如果接收的数据量达到我们设置的最大值的一半的时候,也会触发一次回调函数,使用一个很大的接收数组虽然能解决问题,但也是治标不治本,此方案的正确解决办法则是关闭DMA传输过半中断

__HAL_DMA_DISABLE_IT(&hdma_usart2_rx , DMA_IT_HT)

第一个参数我们填写DMA通道的指针地址,第二个参数我们填写需要关闭的中断

注意别忘记在初始化中加上这一句,否则第一次接收依旧会出现问题

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

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

相关文章

Linux服务器(RedHat、CentOS系)安全相关巡检shell脚本

提示:巡检脚本可以使用crontab定时执行,人工根据执行结束时间点统一收集报告文件即可。 #!/bin/bash# Define output file current_date$(date "%Y%m%d") # Gets the current date in YYYYMMDD format echo >server_security_inspection_r…

【计算机网络】https的工作原理以及和http的区别

目录 前言 1. HTTP协议存在的问题 2. 什么是HTTPS协议? 3. HTTP和HTTPS有哪些区别? 4. HTTPS的工作原理 加密方式 前言 在日常的Web项目练习中,我们会发现老师会让我们在打开服务器之后使用 http://localhost/...进行项目效果测试和预览…

2.26OS分类,中断(内,外),系统调用,操作系统结构、引导,虚拟机(两类VMM),进程

外核可以申请分配连续的磁盘块以支持频繁的随机访问,其它的方式是采用虚拟存储 分层结构

iPhone 的健康数据采用的是 FHIR 传输格式

虽然感觉 FHIR 的数据传输格式还是有点繁琐的,但貌似现在也是唯一的事实上的标准。 通过 iPhone 健康上面查看的数据来看,有关健康的数据还是使用 FHIR 的数据传输格式。 不管怎么样,针对老旧的数据传输格式来看,FHIR 至少目前还是…

实现HBase表和RDB表的转化(附Java源码资源)

实现HBase表和RDB表的转化 一、引入 转化为HBase表的三大来源:RDB Table、Client API、Files 如何构造通用性的代码模板实现向HBase表的转换,是一个值得考虑的问题。这篇文章着重讲解RDB表向HBase表的转换。 首先,我们需要分别构造rdb和hba…

学习开发小程序的起航日记

2024年3月16日 不知不觉中三月份还只剩了一半的光景,我想写的内容还很多没有写,或者更应该说,是想积累的还有很多。现在最应该去完善Java的内容,可还是想先等等。想等搞清楚小程序部分,想等积累完小程序的内容。 这几…

网络安全——关于防火墙

网络安全防火墙是很重要的部分,关于防火墙我们要知道,他默认所有流量都是黑名单,只有开启允许通过才可以。 我们通过一个实验来学防火墙命令。 防火墙要登录才能使用,用户名是admin,默认密码是Admin123,在第一次登录…

Visual Studio配置libtorch(cuda安装一步到位)

Visual Studio配置libtorch visual Studio安装cuDNN安装CUDAToolkit安装libtorch下载Visual Studio配置libtorch(cuda版本配置) visual Studio安装 visual Studio点击安装 具体的安装和配置过程这里就不进行细讲了,可以参考我这篇博客Visual Studio配置OpenCV(保姆…

Java关于物联网消息引擎:EMQ X

1.背景 1、5G 时代,万物互联 随着5G的到来,万物互联已经成为现实,物联网行业得以蓬勃发展,催生了很多的应用,比如:物联网pass平台,车联网,面向云平台的IOT-Hub,NB-IoT蜂…

Simulink|局部遮荫下光伏组件多峰值PSO-MPPT控制

目录 主要内容 1.光伏电池工程数学模型的输出特性程序 2.普通扰动观察法进行MPPT 3.基于粒子群寻优的多峰输出特性 4.PSO_MPPT仿真模型 程序下载链接 主要内容 在实际的光伏发电系统中,由于环境多变等因素的影响,当局部出现被遮挡情况时光伏阵列的功率-电压(P-U)特…

【C语言】字符与字符串---从入门到入土级详解

🦄个人主页:修修修也 🎏所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 一.字符类型和字符数组(串)简介 1.ASCII 2.定义,初始化,使用 1>字符的定义及初始化 2>字符串的定义及初始化 二.…

flink1.18.0 自定义函数 接收row类型的参数

比如sql中某字段类型 array<row<f1 string,f2 string,f3 string,f4 bigint>> 现在需要编写 tableFunction 需要接受的参数如上 解决方案 用户定义函数|阿帕奇弗林克 --- User-defined Functions | Apache Flink

传输层/UDP/TCP协议

再谈端口号 TCP/IP协议用“源IP”&#xff0c;“源端口号”&#xff0c;“目的IP”&#xff0c;“目的端口号”&#xff0c;“协议号”&#xff0c;这样一个五元组来标识一个通信&#xff08;可以用netstat -n来查看&#xff09;。 端口号的划分和知名端口号 我们之前就说过&am…

Jenkins通知目标服务器拉取Harbor镜像部署

1.告诉目标服务器拉取哪个镜像 2.判断当前有没有正在运行此容器&#xff0c;有就删除 3.接着查看拉取的镜像目标服务器上是否已存在&#xff0c;有就删除 4.拉取Harbor镜像 5.运行容器 目标服务器编写脚本 创建个部署脚本 vim deploy.sh告诉目标服务器Harbor地址、仓库、镜像…

【SQL】1193. 每月交易 I 【年月日(日期)拼接相关函数】

前述 知识点学习&#xff1a; SQL 日期函数 day() 、month()、year() 各种使用方法mysql 两个字符年月拼接 题目描述 leetcode题目&#xff1a;1193. 每月交易 I 思路 先按照年月排&#xff0c;再按照country排列 日期拼接相关的函数 year(): 截取年份&#xff1b;month…

Java设计模式 | 设计模式概述和分类

独孤求败五重境界 利剑&#xff08;“凌厉刚猛&#xff0c;无坚不摧&#xff0c;弱冠前以之与河朔群雄争锋。”&#xff09;软剑&#xff08;“紫薇软剑&#xff0c;三十岁前所用&#xff0c;误伤义士不祥&#xff0c;乃弃之深谷。”&#xff09;重剑&#xff08;“重剑无锋&a…

宜搭faas服务器获取accessToken

可以用faas服务器的OpenAPIUtil.getCustomAccessTokenThenCache&#xff08;Client ID,Client Secret&#xff09;就可以获取 至于获取这个Client ID&#xff0c;Client Secret 就需要在钉钉开放平台创建一个应用 然后在这个应用的基础信息里面有 注意的是&#xff1a;如果需要…

「SpringBrick快速入门指南」:一款基于Spring Boot的高级插件化开发框架

文章目录 关于 | About技术文档 | Document开源项目 | Project 案例 | Demo项目结构 | Structure主程序配置集成 | Settings引入框架依赖 | Framework在配置文件加入配置 | YamlSpringBoot启动类改引导类 | Change 插件配置集成 | Settings引入依赖 | XML定义插件引导类 | Clas…

JUnit 面试题及答案整理,最新面试题

JUnit中的断言&#xff08;Assert&#xff09;有哪些类型&#xff1f; JUnit提供了多种断言类型来帮助测试代码的正确性。常见的断言类型包括&#xff1a; 1、assertEquals&#xff1a; 用于检查两个值是否相等。如果不相等&#xff0c;测试失败。 2、assertTrue和assertFal…

sqllab第二十五A关通关笔记

知识点&#xff1a; 数值型注入双写绕过 oorranand这里不能用错误注入&#xff08;固定错误回显信息&#xff09;联合注入 测试发现跟25关好像一样&#xff0c;就是过滤了and or # 等东西 构造payload:id1/0 发现成功运算了&#xff0c;这是一个数值型的注入 构造payload:id…