STM32 UART详细解读(代码的编写)

news2025/1/15 20:51:41

文章目录

  • 前言
  • 一、查询方式编写串口发送和接收的代码
  • 二、中断方式编写串口发送和接收的代码
  • 总结


前言

本篇文章来给大家讲解USART的代码详细讲解和使用步骤。

一、查询方式编写串口发送和接收的代码

在这里插入图片描述
串口查询发送函数:

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)

参数:
huart(UART_HandleTypeDef 结构体指针): 这是一个指向 UART_HandleTypeDef 结构体的指针,该结构体包含了UART相关的配置信息,例如UART的硬件寄存器基地址、波特率、数据位数等。

pData(uint8_t 指针): 这是一个指向要发送数据缓冲区的指针。

Size(uint16_t 类型): 这是要发送的数据的字节数。

Timeout(uint32_t 类型): 这是发送数据的超时时间,单位是毫秒。如果设置为 HAL_MAX_DELAY,则表示无限等待。

返回值:
函数的返回值是 HAL_StatusTypeDef 类型,表示函数执行的状态。可能的返回值包括:

HAL_OK: 操作成功完成。
HAL_BUSY: 操作正在进行中,不能启动新的操作。
HAL_ERROR: 操作失败。

函数作用:
HAL_UART_Transmit 函数的主要作用是通过UART发送数据。它接收一个指向要发送数据的缓冲区的指针和数据的字节数,然后将这些数据通过配置好的UART通道发送出去。函数会根据配置的超时时间等待发送完成或超时。

HAL_UART_Transmit函数内部机制讲解:

这里只讲解比较重要的代码部分

    while (huart->TxXferCount > 0U)
    {
      if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }
      if (pdata8bits == NULL)
      {
        huart->Instance->DR = (uint16_t)(*pdata16bits & 0x01FFU);
        pdata16bits++;
      }
      else
      {
        huart->Instance->DR = (uint8_t)(*pdata8bits & 0xFFU);
        pdata8bits++;
      }
      huart->TxXferCount--;
    }

上面代码的解读:

1.首先先检查要发送的数据是否大于0

2.检查TXE寄存器,判断TDR寄存器中的数据是否被发送出去

3.把数据写入DR数据寄存器中

4.让TxXferCount数据量减1

使用示例:

HAL_UART_Transmit(&huart1, "Hello World", sizeof("Hello World"), 1000);

串口查询接收函数:

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

参数:
huart:UART 句柄,指定了你要使用的 UART 外设。

pData:指向要存储接收到数据的缓冲区的指针。

Size:要接收的数据的数量,以字节为单位。

Timeout:超时时间,以毫秒为单位。如果在超时时间内没有接收到足够的数据,则函数会返回。可以使用 HAL_MAX_DELAY 作为超时参数来指定无限超时,直到接收到足够的数据。

返回值:
函数的返回值是一个 HAL_StatusTypeDef 类型的枚举值,表示函数执行的结果。可能的返回值包括:

HAL_OK:函数执行成功,接收到了指定数量的数据。

HAL_TIMEOUT:超时,未能在指定的时间内接收到足够的数据。

HAL_ERROR:发生了错误,可能是由于参数错误或者硬件问题引起的。

上面代码的解读:

1.首先先检查要接收的数据是否大于0

2.检查RXNE寄存器,判断RDR寄存器中是否有数据可以接收

3.将DR中的数据读取出来

4.让RxXferCount数据量减1

使用示例:

uint8_t rx_data[10]; // 接收数据缓冲区

while (1)
{
    HAL_UART_Receive(&huart1, rx_data, sizeof(rx_data), HAL_MAX_DELAY);

    // 处理接收到的数据
    // 可以在这里进行数据处理或者将数据发送到其他地方
}

二、中断方式编写串口发送和接收的代码

开启中断:
在这里插入图片描述
串口发送函数(中断方式)

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)

参数:
huart:UART 句柄,指定了你要使用的 UART 外设。

pData:指向要传输的数据缓冲区的指针。

Size:要传输的数据的数量,以字节为单位。

返回值:
函数的返回值是一个 HAL_StatusTypeDef 类型的枚举值,表示函数执行的结果。可能的返回值包括:

HAL_OK:函数执行成功,数据已经被成功传输。

HAL_ERROR:发生了错误,可能是由于参数错误或者硬件问题引起的。

HAL_BUSY:UART 外设忙,不能执行传输。

HAL_TIMEOUT:超时,传输未能在指定的时间内完成。

HAL_UART_Transmit_IT函数调用的分析:

HAL_UART_Transmit_IT函数并没有直接进行数据的发送而是开启TEX发送数据寄存器空中断。
在这里插入图片描述
串口1中断函数:
在这里插入图片描述
在HAL_UART_IRQHandler函数中调用了UART_EndTransmit_IT。
在这里插入图片描述
发送完最后一个数据后使能TC发送完成中断。
在这里插入图片描述
在这里插入图片描述
发送最后一个数据完成调用HAL_UART_TxCpltCallback回调函数:
在这里插入图片描述
串口中断发送数据方式总结:

1.使能TXE中断,将数据一个个的发送出去。

2.当只有最后一个数据的时候使能TC发送完成中断

3.当最后一个数据发送完成后调用HAL_UART_TxCpltCallback回调函数。

使用示例:


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &huart1)
    {
        // 发送完成回调函数
    }
}


HAL_UART_Transmit_IT(&huart1, tx_data, strlen((char *)tx_data)); // 发送数据

串口接收函数(中断方式)

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

参数:

huart:一个指向 UART_HandleTypeDef 结构体的指针,该结构体包含了 UART 外设的配置和状态信息。
pData:一个指向要存储接收数据的缓冲区的指针。
Size:要接收的数据的字节数。

返回值 (HAL_StatusTypeDef):该函数返回一个 HAL_StatusTypeDef 类型的值,用于表示函数执行的状态。可能的返回值包括:

HAL_OK:函数执行成功。
HAL_BUSY:UART 正在忙于处理其他操作。
HAL_ERROR:发生了错误,导致函数执行失败。
HAL_TIMEOUT:函数执行超时。

HAL_UART_Receive_IT函数会马上返回不会一直等待到有数据才返回。
在这里插入图片描述
在UART_Start_Receive_IT中调用__HAL_UART_ENABLE_IT函数开启RXNE中断。
在这里插入图片描述
在这里插入图片描述
接收数据:
在这里插入图片描述
当接收数据完成后会调用HAL_UART_RxCpltCallback回调函数:
在这里插入图片描述

uint8_t rx_data = 0;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &huart1)
    {
        // 处理接收到的数据
        // 可以在这里进行数据处理或者将数据发送到其他地方
        HAL_UART_Receive_IT(&huart1, rx_data, 1); // 继续接收下一个字节
    }
}

HAL_UART_Receive_IT(&huart1, rx_data, 1); // 启动接收中断,每次接收一个字节

总结

本篇文章深入的讲解了UART发送和接收查询方式和中断方式的具体函数使用和内部原理。

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

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

相关文章

第2.4章 StarRocks表设计——分区分桶与副本数

目录 一、数据分布 1.1 概述 1.2 数据分布方式 1.2.1 Round-Robin 1.2.2 Range 1.2.3 List 1.2.4 Hash 1.3 StarRocks的数据分布方式 1.3.1 不分区 Hash分桶 1.3.2 Range分区Hash分桶 三、分区 3.1 分区概述 3.2 创建分区 3.2.1 手动创建分区 3.2.2 批量创建分区…

MIT-BEVFusion系列九--CUDA-BEVFusion部署2 create_core之参数设置

目录 加载命令行参数main 函数中的 create_core图像归一化参数体素化参数稀疏卷积网络参数真实世界几何空间参数 (雷达坐标系下体素网格的参数)解码后边界框的参数构建 bevfusion::Core 存储推理时需要的参数 本章开始,我们将一起看CUDA-BEVFusion的代码流程&#x…

Sample Pairing(ICLR 2018)

paper:Data Augmentation by Pairing Samples for Images Classification 本文的创新点 本文提出了一种新的应用于图像分类的数据增强方法SamplePairing,这种简单的数据增强技术显著提高了所有测试的数据集的分类精度。此外当训练集中的样本数量非常少…

vue3+element Plus+ts 自定义主题色,以及生成主题色各种透明度

目录 思路 安装css-color-function【接收一个颜色值,生成不同的透明度】 获取后台配置的主题色或者使用ColorPicker修改主题色 最终结果如下 思路 本篇文章的主体思路是从element Plus官网引申而来。结合了我以前用vue2element-ui配置主题色生成透明度&#x…

fastApi笔记01-路径参数

路径参数 使用与 Python 格式化字符串相同的语法来声明路径"参数"或"变量" from fastapi import FastAPIapp FastAPI()app.get("/items/{item_id}") def read_item(item_id):return {"item_id": item_id} http://127.0.0.1:8000/i…

年薪最高开到160万,鸿蒙开发人才紧缺!

华为鸿蒙开发人才紧缺 如今,鸿蒙与安卓彻底切割时间似乎越来越近,一批嗅觉灵敏的互联网厂商已经完成或开始启动开发鸿蒙原生App,包括美团、网易、今日头条、钉钉等。随着头部App厂商启动鸿蒙(HarmonyOS)原生应用开发&…

智慧公厕管理系统:让城市智慧驿站更加智慧舒适

智慧公厕管理系统是城市智慧驿站中不可或缺的一部分,它通过全方位的信息化解决方案,为公共厕所的使用、运营和管理提供了一种智能化的方式。作为城市智慧驿站的重要组成部分,智慧公厕管理系统发挥着重要的作用,为城市社会民生提供…

提升生产3D渲染效率与品质:挖掘渲染农场的潜力

在当今数字化时代,3D渲染已成为跨越多个领域不可缺少的技术,无论是在建筑视觉化、电影制作、互动媒体还是虚拟现实领域。随着对动态、逼真视觉效果的需求不断增长,3D渲染农场因其出色的运算能力和经济性成为行业中的关键解决方案。本篇文章旨…

使用LangChain结合通义千问API基于自建知识库的多轮对话和流式输出

使用LangChain结合通义千问API基于自建知识库的多轮对话和流式输出 本文章的第三弹,由于LangChain本文不支持直接使用通义千问API进行多轮对话和流式输出,但是自建知识库呢,还需要LangChain,因此我尝试了一下,自建知识库用LangCh…

Spring源码:手写SpringIOC

文章目录 一、分析二、实现1、版本1:实现Bean注入IOC容器,并从容器中获取1)定义BeanDefinition2)定义BeanDefinition实现类3)定义BeanDefinitionRegistry4)定义Beanfactory5)定义默认Beanfactor…

学会Requests库,就学会了Python接口自动化

在 Python 中进行网络请求是日常开发中的一个常见任务,而 requests 库是处理这类任务的一种强大工 具。requests 提供了简单而灵活的接口,使得发送 HTTP 请求和处理响应变得非常容易。在这篇文章中,我们将深入研究如何使用 requests 库执行各…

grid新建主从一对多

目录 总结一、步骤前端1.第一步-编写tabs的modelBody2.第二步编辑表扩展js 后端--重写表的add和Update方法1.第一步 总结 编写tabs的modelBody后编辑表扩展js在重写后端partial的Service 一、步骤 前端 1.第一步-编写tabs的modelBody 复制下面代码该改的改 <template&…

Golang for 循环

从基础知识到高级技术、并发和通道 Go&#xff08;Golang&#xff09;编程语言中的“for”循环是一个基本而多功能的结构&#xff0c;用于迭代集合、重复执行代码块以及管理循环控制流。Golang的“for”循环语法简洁却强大&#xff0c;为处理多样的循环场景提供了一系列能力。无…

【2024软件测试面试必会技能】adb命令操作

前言&#xff1a; adb的全称为(Android Debug Bridge&#xff09;就是调试桥的作用。Adb 命令存放在 SDK 的Tools文件夹下&#xff0c;又称为手机和电脑连接的桥梁命令。 借助这个工具&#xff0c;我们可以管理设备或手机模拟器的状态。还可以进行以下的操作&#xff1a; 快…

计算机功能简介:EC, NVMe, SCSI/ISCSI与块存储接口 RBD,NUMA

一 EC是指Embedded Controller 主要应用于移动计算机系统和嵌入式计算机系统中&#xff0c;为此类计算机提供系统管理功能。EC的主要功能是控制计算机主板上电时序、管理电池充电和放电&#xff0c;提供键盘矩阵接口、智能风扇接口、串口、GPIO、PS/2等常规IO功能&#xff0c;…

C#分部类的应用:记录学生信息

目录 一、分部类及其用途 二、实例 再发一个分部类的应用&#xff0c;巩固一下。 一、分部类及其用途 C#中的部分类也被称为分部类。 C#中的部分类是一种将类的定义分成多个部分&#xff0c;每个部分都位于自己的文件中&#xff0c;然后在编译时合并在一起的机制。 部分类…

SNAT与DNAT公私网地址转换

前言 SNAT和DNAT是两种重要的网络地址转换技术&#xff0c;它们允许内部网络中的多个主机共享单个公共IP地址&#xff0c;或者将公共IP地址映射到内部网络中的特定主机。这些技术在构建企业级网络和互联网应用程序时非常重要&#xff0c;因为它们可以帮助保护内部网络安全&…

75.SpringMVC的拦截器和过滤器有什么区别?执行顺序?

75.SpringMVC的拦截器和过滤器有什么区别&#xff1f;执行顺序&#xff1f; 区别 拦截器不依赖与servlet容器&#xff0c;过滤器依赖与servlet容器。拦截器只能对action请求(DispatcherServlet 映射的请求)起作用&#xff0c;而过滤器则可以对几乎所有的请求起作用。拦截器可…

阿里云服务器操作系统有哪些?如何选择?

阿里云服务器镜像怎么选择&#xff1f;云服务器操作系统镜像分为Linux和Windows两大类&#xff0c;Linux可以选择Alibaba Cloud Linux&#xff0c;Windows可以选择Windows Server 2022数据中心版64位中文版&#xff0c;阿里云服务器网aliyunfuwuqi.com来详细说下阿里云服务器操…

深入理解java虚拟机---自动内存管理

2.2 运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途&#xff0c;以及创建和销毁的时间&#xff0c;有的区域随着虚拟机进程的启动而一直存在&#xff0c;有些区域则是依赖用户线程的启动和结束而建立和销…