USART_串口通讯轮询案例(HAL库实现)

引言

       前面讲述的串口通讯案例是使用寄存器方式实现的,有利于深入理解串口通讯底层原理,但其开发效率较低;对此,我们这里再讲基于HAL库实现的串口通讯轮询案例,实现高效开发。当然,本次案例需求仍然和前面寄存器实现的案例一样,故这里就不再赘述相关需求以及电路设计,如果不清楚可参考下面链接跳转查看:USART_串口通讯轮询案例(一)(寄存器实现)-CSDN博客https://blog.csdn.net/2301_79475128/article/details/145222170?spm=1001.2014.3001.5501


一、案例需求描述

二、硬件电路设计

       由于本次案例和前面寄存器实现的案例相同,故这里不再赘述,可直接点击上面链接跳转查看,感谢支持!


三、软件设计

       话不多说,我们本次就基于HAL库来二次实现一下串口通讯轮询方式下的案例。首先我们必然是进入STM32CubeMX软件创建好工程并进行相应配置。

3.1 STM32CubeMX配置

首先,我们进入STM32CubeMX,开始创建工程

3.1.1 创建工程

       单击【ACCESS TO MCU SELECTOR】,然后选择自己使用的芯片类型双击它即可创建新的工程。

3.1.2 工程配置

        接下来,我们对其中相关部分进行配置,首先最基本的配置即【System Core】中【SYS】和【RCC】时钟等的配置,本次还涉及到收发数据使用的GPIO口,也会在其中进行配置。

       所以,单击【System Core】,选择【SYS】,配置调试器Debug串行单线【serial wire】,这样我们STLink下载器才能使用。

          然后,选择【RCC】,配置时钟,先是外部时钟,全部修改为晶振或者石英振荡器【Crystal/Ceramic Reasonator】即可

然后配置内部时钟,此时直接继续单击【Clock Configuration】,做如下配置即可

       接着,我们需要配置串口涉及到的GPIO,正常情况我们应该是去图形化芯片上设置对应引脚进行配置,但是由于串口通讯模块对应一个数据连接通讯的部分,在STM32CubeMX中有相应的选项可以直接进行配置,所以我们不必直接去配GPIO,可以直接在【Connectivity】中进行所有串口的相关配置。

          然后就可以开始配置串口了,首先我们目前只是使用串口异步功能,所以【Mode】一栏选择异步【Asynachronous】即可,然后下面的硬件流控【Hardware Flow control】不开启,即默认【Disable】就可以。 

        紧接着,我们看向下方,会发现有五个选项,分别是参数配置【Parameter Settings】(串口自身基本参数)、使用常量【User Constants】NVIC设置【NVIC Settings】(和中断相关)、DMA设置【DMA Settings】(DMA相关)、GPIO设置【GPIO Settings】(GPIO相关)。当前我们因为只是最简单的异步收发,只使用了TX和RX,所以只涉及两个GPIO口以及串口的一些参数设置。因此这里我们只要看看参数配置和GPIO设置就好了

单击进入参数设置【Parameter Settings】,可以看见HAL库默认给我们配置的一些参数

        显然,以及包含了我们前面使用寄存器配置串口的内容,这意味着后面自动生成的代码就已经帮我们基本做好了串口的初始化,而这里只需要我们图形化选择一下即可,很显然简单了很多。关于该部分的配置就按照其默认的配(如上图所示)即可。

       然后,我们单击进入GPIO设置【GPIO Settings】,如下图,看看发现以及给我们自动配置好了GPIO的东西,仔细检查一下,就和我们前面寄存器配置GPIO的模式是一样的,即PA9 TX端配置为复用功能的推挽输出模式、PA10 RX端配置成浮空输入模式即可

        最后,我们再进入【Project Manager】【Project】设置一下该工程的名字、路径以及工具链,然后进入【Code Generator】勾选些选项即可。

最后,我们点击【GENERATOR CODE】生成代码,如果在keil中打开工程即可

3.1.3 Keil中配置

        在keil中打开工程后,进入【魔法棒】,然后进入【Debug】,点击进入【Settings】,接着进入【Flash Download】,勾选【Reset and Run】;然后进入【Pack】,取消勾选【Enable】,最后不要忘记🆗保存了。

最后就可以退出keil了。然后进入vscode开始看看代码。

3.2 代码补充

        配置都做好了以后,我们就来看看代码,进入vscode,然后将刚才创建的工程导入进来,然后看看主要代码,首先是GPIO文件中的

       可以发现,这里主要是时钟配置,因为我们HAL库对GPIO的配置主要都放在USART文件中了

然后我们看看USART文件

       显然,这里就看见GPIO口的配置了,同时我们会发现,上面它定义了一个【huart1】变量,我们ctrl+单击这个前面的类型看看这是啥

        显然,这是一个结构体定义,然后看看其中的内容,会发现这实际上都是定义的和串口有关的东西,也就是说,huat1一个串口相关功能的结构体定义。因此下图这一部分全是关于串口的参数配置

       看完这俩以后,我们发现,当时寄存器编写的代码主要就是串口初始化的内容,然而这里HAL库做的时候代码以及全部自动生成了,意味着我们只需要去写一下发送接收的逻辑,同时HAL库也为我们提供了接收和发送数据的相关函数,直接调用即可。

       那么现在,我们来编写一下发送数据的测试逻辑,直接来个发送或者接收字符串吧,这样可以的话说发送单字符也肯定可以了。

        由于我们这里直接调用相应函数即可,这里就直接展示一下对应函数的使用了,main.c中如下图

一句发送,一句延时即可,我们借助这个简单逻辑测试一下,直接编译烧录看现象

显然,没有问题,测试成功。

       然后我们继续测试接收数据功能,实现一个“先接受一个字符串,然后发送”的逻辑,main.c代码如下,先创建两个变量用于存放字符串

然后,while循环中写接收并发送代码,这里和我们前面接收发送点区别:

       多了一个判断,因为这里HAL库中的发送是无脑直接拿到数据就发的,我们现在在循环中,没有发之前给的buffer,虽然我们没写入数据,但是其初始化是0,所以此时接收到的就是0,即发送就会直接把“\0”全部发出来。而为了避免这种情况,我们对接收函数做一个判断,因为其是有返回值的,就是为了避免接收有问题,当它确实正确接收到数据后,就会返回HAL_OK,所以我们这里判断它是否等于这个,等于即说明接收到我们发的了,这样我们再把数据发出来就好了。

然后我们测试一下,编译烧录看效果

显然,我们发送10个字符,他就能正确接收到。说明测试没问题

        当然了,我们发现我们调用接收函数传入的参数需要我们给出接收字符长度,这意味着我们只能接收定长的字符串,如果我们发送任意长的字符串的话,则会产生不符合需求的现象。

        因此,我们要怎么接收变长数据呢?实际上HAL库也提供了发送变长数据的函数,只不过名称稍微有些变化,我们想,之前寄存器实现边长数据的接收时多利用了一个检测空闲帧的位IDLE,所以在HAL库中关于变长数据的接收函数名上就带了IDLE,即如下图

        上图所示函数的描述就是我们用来接收变长数据的函数了。可以发现这里参数的变化就在于之前我们要传入的字符长度这里变成了两个参数,即一个是我们接收字符的总长度Size、另一个是指针表示,显然就是表示我们接收到的字符实际的长度*RxLen

那么·,我们现在就来对此测试一下,代码如下,就是把接收函数换了一个

我们编译烧录看看效果

显然,这里我们成功接收并发送了变长数据,说明本次测试成功了!

       这样,我们本次轮询方式的HAL库实现就完毕了,主要就是做了定长数据的发送或接收以及变长数据的接收和发送

        其中,关于一些异常情况我们这里没有展示,当然大家可以自己去试试看,当定长数据的接收与发送时,如果电脑给芯片发了不是规定长度的字符会出现什么情况。


3.3 相关函数介绍

       本次我们调用了几个HAL库提供的库函数,这里展示一下官方提供的详细的函数说明,只不过是英文的,可以当作锻炼自己翻译能力,或者如果实在看不懂也可以去用翻译软件翻译一下。

3.3.1 发送数据函数 HAL_UART_Transmit

/*** @brief  Sends an amount of data in blocking mode.* @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),*         the sent data is handled as a set of u16. In this case, Size must indicate the number*         of u16 provided through pData.* @param  huart Pointer to a UART_HandleTypeDef structure that contains*               the configuration information for the specified UART module.* @param  pData Pointer to data buffer (u8 or u16 data elements).* @param  Size  Amount of data elements (u8 or u16) to be sent* @param  Timeout Timeout duration* @retval HAL status*/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);/*** @brief  HAL Status structures definition*/
typedef enum
{HAL_OK       = 0x00U,HAL_ERROR    = 0x01U,HAL_BUSY     = 0x02U,HAL_TIMEOUT  = 0x03U
} HAL_StatusTypeDef;

3.3.2 接收定长数据函数 HAL_UART_Receive

/*** @brief  Receives an amount of data in blocking mode.* @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),*         the received data is handled as a set of u16. In this case, Size must indicate the number*         of u16 available through pData.* @param  huart Pointer to a UART_HandleTypeDef structure that contains*               the configuration information for the specified UART module.* @param  pData Pointer to data buffer (u8 or u16 data elements).* @param  Size  Amount of data elements (u8 or u16) to be received.* @param  Timeout Timeout duration* @retval HAL status*/
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);/*** @brief  HAL Status structures definition*/
typedef enum
{HAL_OK       = 0x00U,HAL_ERROR    = 0x01U,HAL_BUSY     = 0x02U,HAL_TIMEOUT  = 0x03U
} HAL_StatusTypeDef;

3.3.3 接收变长数据函数 HAL_UARTEx_ReceiveToIdle

/*** @brief Receive an amount of data in blocking mode till either the expected number of data is received or an IDLE event occurs.* @note   HAL_OK is returned if reception is completed (expected number of data has been received)*         or if reception is stopped after IDLE event (less than the expected number of data has been received)*         In this case, RxLen output parameter indicates number of data available in reception buffer.* @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M = 01),*         the received data is handled as a set of uint16_t. In this case, Size must indicate the number*         of uint16_t available through pData.* @param huart   UART handle.* @param pData   Pointer to data buffer (uint8_t or uint16_t data elements).* @param Size    Amount of data elements (uint8_t or uint16_t) to be received.* @param RxLen   Number of data elements finally received (could be lower than Size, in case reception ends on IDLE event)* @param Timeout Timeout duration expressed in ms (covers the whole reception sequence).* @retval HAL status*/
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen, uint32_t Timeout)

以上便是本次文章的所有内容,欢迎各位朋友在评论区讨论,本人也是一名初学小白,愿大家共同努力,一起进步吧!

鉴于笔者能力有限,难免出现一些纰漏和不足,望大家在评论区批评指正,谢谢!

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

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

相关文章

后端面试题分享第一弹(状态码、进程线程、TCPUDP)

后端面试题分享第一弹 1. 如何查看状态码,状态码含义 在Web开发和调试过程中,HTTP状态码是了解请求处理情况的重要工具。 查看状态码的步骤 打开开发者工具: 在大多数浏览器中,您可以通过按下 F12 键或右键单击页面并选择“检查…

Apache Hive3定位表并更改其位置

Apache Hive3表 1、Apache Hive3表概述2、Hive3表存储格式3、Hive3事务表4、Hive3外部表5、定位Hive3表并更改位置6、使用点表示法引用表7、理解CREATE TABLE行为 1、Apache Hive3表概述 Apache Hive3表类型的定义和表类型与ACID属性的关系图使得Hive表变得清晰。表的位置取决于…

OpenEuler学习笔记(九):安装 OpenEuler后配置和优化

安装OpenEuler后,可以从系统基础设置、网络配置、性能优化等方面进行配置和优化,以下是具体内容: 系统基础设置 更新系统:以root用户登录系统后,在终端中执行sudo yum update命令,对系统进行更新&#x…

Vue | 搭建第一个Vue项目(安装node,vue-cli)

一.环境搭建: 1.安装node: 进入网站,下载对应版本的node.js Index of /dist/ (nodejs.org) 我这里下载的是: 解压到对应的目录下: 并新建两个文件夹node_cache和node_global: 2.配置环境: …

日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件

日历热力图,月度数据可视化图表,vue组件 先看效果👇 在线体验https://www.guetzjb.cn/calanderViewGraph/ 日历图简单划分为近一年时间,开始时间是 上一年的今天,例如2024/01/01 —— 2025/01/01,跨度刚…

2024年第十五届蓝桥杯青少组国赛(c++)真题—快速分解质因数

快速分解质因数 完整题目和在线测评可点击下方链接前往: 快速分解质因数_C_少儿编程题库学习中心-嗨信奥https://www.hixinao.com/tiku/cpp/show-3781.htmlhttps://www.hixinao.com/tiku/cpp/show-3781.html 若如其他赛事真题可自行前往题库中心查找,题…

[Computer Vision]实验三:图像拼接

目录 一、实验内容 二、实验过程及结果 2.1 单应性变换 2.2 RANSAC算法 三、实验小结 一、实验内容 理解单应性变换中各种变换的原理(自由度),并实现图像平移、旋转、仿射变换等操作,输出对应的单应性矩阵。利用RANSAC算法优…

FPGA自分频产生的时钟如何使用?

对于频率比较小的时钟,使用clocking wizard IP往往不能产生,此时就需要我们使用代码进行自分频,自分频产生的时钟首先应该经过BUFG处理,然后还需要进行时钟约束,处理之后才能使用。

【喜讯】海云安荣获“数字安全产业贡献奖”

近日,国内领先的数字化领域独立第三方调研咨询机构数世咨询主办的“2025数字安全市场年度大会”在北京成功举办。在此次大会上,海云安的高敏捷信创白盒产品凭借其在AI大模型技术方面的卓越贡献和突出的技术创新能力,荣获了“数字安全产业贡献…

ceph基本概念,架构,部署(一)

一、分布式存储概述 1.存储分类 存储分为封闭系统的存储和开放系统的存储,而对于开放系统的存储又被分为内置存储和外挂存储。 外挂存储又被细分为直连式存储(DAS)和网络存储(FAS),而网络存储又被细分网络接入存储(NAS)和存储区域网络(SAN)等。 DAS(D…

Markdown Viewer 浏览器, vscode

使用VS Code插件打造完美的MarkDown编辑器(插件安装、插件配置、markdown语法)_vscode markdown-CSDN博客 右键 .md 文件,选择打开 方式 (安装一些markdown的插件) vscode如何预览markdown文件 | Fromidea GitCode - 全球开发者…

wx036基于springboot+vue+uniapp的校园快递平台小程序

开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…

AIGC的企业级解决方案架构及成本效益分析

AIGC的企业级解决方案架构及成本效益分析 一,企业级解决方案架构 AIGC(人工智能生成内容)的企业级解决方案架构是一个多层次、多维度的复杂系统,旨在帮助企业实现智能化转型和业务创新。以下是总结的企业级AIGC解决方案架构的主要组成部分: 1. 技术架构 企业级AIGC解决方…

LeetCode 热题 100_全排列(55_46_中等_C++)(递归(回溯))

LeetCode 热题 100_两数之和(55_46) 题目描述:输入输出样例:题解:解题思路:思路一(递归(回溯)): 代码实现代码实现(思路一&#xff08…

2025发文新方向:AI+量化 人工智能与金融完美融合!

2025深度学习发论文&模型涨点之——AI量化 人工智能的融入,使量化交易实现了质的突破。借助机器学习、深度学习等先进技术,人工智能可高效处理并剖析海量市场数据,挖掘出数据背后错综复杂的模式与趋势,从而不仅提升了数据分析…

3.CSS的背景

通过CSS背景属性,可以给页面元素添加背景样式。 背景属性可以设置背景颜色、背景图片、背景平铺、背景图片位置、背景图像固定等。 3.1 背景颜色 background-color属性定义了元素的背景颜色 background-color:颜色值; 一般情况下元素背景颜色默认值…

AIGC视频生成模型:Stability AI的SVD(Stable Video Diffusion)模型

大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Stability AI的视频生成模型SVD(Stable Video Diffusion)模型,这家公司在图像生成领域富有盛名,开发并维护了知名开源项目SD系列…

【若依】添加数据字典

接下来,在生成代码的页面将“学科”字段改为下拉框,然后选择数据字典 然后,将生成的代码中的index文件复制到vue3的index中,替换掉之前的index文件 修改数据库中的subject的值,这样就可以通过数据字典来查询 以上操作成…

基于quartz,刷新定时器的cron表达式

文章目录 前言基于quartz,刷新定时器的cron表达式1. 先看一下测试效果2. 实现代码 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&…

MySQL中的关联查询:方式、区别及示例

MySQL中的关联查询:方式、区别及示例 在数据库操作中,我们常常需要从多个相关的表中获取数据,这就用到了关联查询。MySQL提供了多种关联查询方式,每种方式都有其特点和适用场景。下面我们就来详细探讨这些关联查询的使用方式、它…