探索TXE、TC、RXNE标志位在串口通信中的轮询与中断应用

news2024/9/23 17:12:32

浅谈一下STM32串口中断之TXE,TC,RXNE标志位

之前做一个项目,用到了串口中断,但是对TXE、TC和RXNE标志位的作用和使用方法不是很清楚,导致在调试过程中遇到了一些问题。通过查阅相关资料和实际操作,我对这三个标志位有了更深入的了解,因此决定写这篇博客,分享我的经验和心得。如果对您有所帮助,点点关注,不迷路哦

墨小羽ovo个人主页

前言

在STM32中,串口通信是一种常用的通信方式,而串口中断是一种高效的通信方式,它可以在数据发送或接收时自动触发中断,从而实现数据的实时处理。在串口中断中,TXE、TC和RXNE是三个非常重要的标志位,它们分别表示发送数据寄存器为空、发送完成和接收数据寄存器非空。本文将简要介绍这三个标志位的作用和使用方法。

写这篇博客的原因

1.串口发送数据的时候出现丢包,调试代码调试不出来
2.我区分不出来串口中断,发送一串字符串时候,是不是每次都触发中断,还是只触发一次中断,是发送完第一个字符就触发串口发送中断,还是发送完所有字符才触发中断。

1. 串口通信代码编写流程

在STM32中,串口通信的代码编写流程如下:
    1. 配置串口引脚和时钟。
    2. 配置串口参数,如波特率、数据位、停止位等。
    3. 配置串口中断,如发送中断、接收中断等。初始化NVIC
    4. 启动串口。
    5. 在中断服务程序中处理数据发送和接收。

在这里插入图片描述

1.1 FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) 和void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)

1.第一个函数用于获取串口标志位的状态,第二个函数 用于清除标志位
2.这两个函数是轮询的方式,即不断检查标志位的状态,直到标志位为1或者超时。这种方式虽然简单,但是效率较低,因此在实际应用中,通常会使用中断的方式来处理数据发送和接收。

1.2 USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)和void USART_ITClearPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)

1.函数用于使能或禁用串口中断,

2.第二个函数是清除中断标志位的

1.3 USART_SendData(USART_TypeDef* USARTx, uint16_t Data)

函数用于向串口发送数据,其中USARTx表示串口类型,Data表示要发送的数据。函数返回值为void类型,没有返回值。

1.4 USART_ReceiveData(USART_TypeDef* USARTx)

函数用于从串口接收数据,其中USARTx表示串口类型。函数返回值为uint16_t类型,表示接收到的数据。

2.发送接收示意图

在这里插入图片描述

2.1 发送示意图

在这里插入图片描述

个人理解:
1.当要发送一个字符时,数据A放入TDR后,发送到移位寄存器后,触发TXE标志位,然后发送完成,触发TC标志位。

2. TXE标志位

TXE标志位表示发送数据寄存器为空,即可以发送数据。当发送数据寄存器为空时,TXE标志位会被置1,此时可以发送数据。在发送数据时,需要先判断TXE标志位是否为1,如果为1,则可以将数据写入发送数据寄存器,否则需要等待TXE标志位为1。

2.1 轮询方式发送-TXE标志位的使用

在发送数据时,需要先判断TXE标志位是否为1,如果为1,则可以将数据写入发送数据寄存器,否则需要等待TXE标志位为1。例如,以下代码演示了如何使用TXE标志位发送数据:
(1)发送一个字符

USART_SendData(USART1, 'A');

(2)发送两个字符(错误示范)

USART_SendData(USART1, 'A');

USART_SendData(USART1, 'B');
原因:1.USART_SendData()函数只是将数据放在TDR寄存器中,
2.还没来得及发送到移位寄存器,就又往TDR寄存器中放数据,导致数据丢失

(3)发送多个字符(正确示范)

USART_SendData (USART1,"H');
while (USART_GetFlagstatus(USART1,USART_FLAG_TXE) == RESET);USART_SendData (USART1,'K');
while (USART_GetFlagStatus ( USART1,USART_FLAG_TXE) == RESET);USART_SendData (USART1,”G');
while (USART_GetFlagstatus( USART1,USART_FLAG_TXE) == RESET);

输出运行结果:
HKG
(4)发送字符串
在这里插入图片描述

1.发送字符串时,最后加一个TC标志位的判断

2.不然,当发送最后一个字符时候,TXE标志位变为1,而此时最后一个字符只是发送到了移位寄存器,还没来得及
发送出去,所以需要等待TC标志位为1,才能关闭串口发送
,不然会导致数据丢失

2.2 中断方式发送-TXE标志位的使用

补充:1.TXE:发送寄存器空中断,使能TXE后
,当TDR发送数据寄存器为空时,会触发中断,在中断服务程序中发送数据。
2.TXE在复位后,默认为1,即默认开启发送中断。所以如果没有真正发送数据,TXE中断都会
触发,影响程序运行,所以初始化时候需要关闭TXE中断。
3. 使用TXE中断,发送字符,都是在中断服务程序中发送的。
示例程序:
void USART_SendByte(USART_TypeDef* USARTx, uint8_t *Data)
{
pDataByte = Data;
USART_ITConfig(USARTx, USART_IT_TXE, ENABLE); //使能发送中断
}
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
{
USART_SendData(USART1, *pDataByte);
pDataByte++;
if (*pDataByte == ‘\0’)
{
USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //发送完毕,关闭发送中断
}
}
}

3. TC标志位

TC标志位表示发送完成,即数据已经发送完毕。当数据发送完毕时,TC标志位会被置1,此时可以关闭串口发送中断,或者进行其他操作。在发送数据时,需要先判断TC标志位是否为1,如果为1,则可以关闭串口发送中断,否则需要等待TC标志位为1。
在这里插入图片描述

理解:
1.使用TC标志位,需要先读SR寄存器,再写入DR寄存器,或者是通过写入’0’来清除。

3.1 轮询方式发送-TC标志位的使用

while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData (USART1,"H');
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData (USART1,"k');
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData (USART1,"G');
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);

运行结果:
HKG

3.2 中断方式发送-TC标志位的使用

1. 使用TC标志位,是发送一个字节后进入中断的,后续的发送都是在中断服务函数中进行的。

2.可以在初始化时候,USART_ITConfig(USART1, USART_IT_TC, ENABLE);使能TC中断

  USART_ITConfig(USART1, USART_IT_TC, ENABLE);//Tramsimssion Complete后,才产生中断. 开TC中断必须放在这里,否则还是会丢失第一字节

  USART_Cmd(USART1, ENABLE); //使能USART1

示例程序:
1.使用TC标志位,需要先读SR寄存器,再写入DR寄存器,或者是通过写入’0’来清除。

void USART_SendByte(USART_TypeDef* USARTx, uint8_t *Data)
{
    pDataByte = Data;
   USART_ClearFlag(USARTX,USART_FLAG_TC); //清除TC标志位
  USART_SendData(USART1, *(pDataByte++) ); //必须要++,不然会把第一个字符t发送两次
    
}

void USART1_IRQHandler(void)
{
    if (USART_GetITStatus(USART1, USART_IT_TC) != RESET)
    {
        USART_SendData(USART1, *pDataByte++);
        if (*pDataByte == '\0')
        {
             USART_ClearFlag(USART1, USART_FLAG_TC);//不然TC一直是set, TCIE也是打开的,导致会不停进入中断.
        }
    }
}

4. RXNE标志位

在这里插入图片描述

理解:
1.当接收到一个字符时,数据A放入RDR寄存器,然后触发RXNE标志位,然后读取RDR寄存器中的数据,最后清除RXNE标志位。
补充: 当接收移位寄存器从RX引脚接收到
一个字节的数据后,数据会自动存入RDR寄存器,并触发RXNE标志位。这时候RXNE等于1,说明数据可以读出来。
2.当接收缓冲区为空时,RXNE标志位为0,此时可以等待接收数据。

3.当接收缓冲区非空时,RXNE标志位为1,此时可以读取接收缓冲区中的数据。

4.1 轮询方式接收-RXNE标志位的使用

  1. 有了TXE的经验
    2.不断轮询获取
    RXNE标志位,当RXNE为1时,读取RDR寄存器中的数据,然后清除RXNE标志位。

示例程序:

uint8_t USART ReceiveByte(USART_TypeDef USARTx)
{
while(USART_GetF1agStatus(USARTx,USART_FLAG_RXNE)==RESET);
return (uint8_tfUSART_ReceiveData(USART1) ; 
)

4.2 中断方式接收-

RXNE标志位的使用

注意:

1.初始化完串口接收中断的代码后,当接收数据时候,硬件会自动将数据放入RDR寄存器中,然后触发RXNE标志位

2. 硬件会检测到接收数据,自动跳转到中断处理函数

接收1个字节触发一次接收中断

3.RXNE(Receive Data register not empty interrupt)- 每接受到一个字节产生中断,接受寄存器不为空时,产生中断 —读寄存器DR清零,也可软件手动清零

使用方法:

1. 开启中断,初始化NVIC

NVIC结构体

NVIC_InitTypeDef NVIC_InitStructure;
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

2. 在中断服务函数中,读取RDR寄存器中的数据,然后清除RXNE标志位。

3. 在中断处理函数中,读取RXNE标志位,当RXNE==1时,说明接收到数据,可以读出数据了

void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
    uint16_t Data = USART_ReceiveData(USART1);
    // 处理接收到的数据
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    //可以把接收的数据再打印出来
    USART_SendData(USART1, Data);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}
}

参考资料

海创电子-STM32F103入门篇,阶段-阶段二

STM32串口通信
keysking串口原理与中断模式收发

总结

TXE、TC和RXNE等标志位在串口通信中扮演着至关重要的角色,它们的状态直接决定了数据的发送和接收过程。通过深入了解轮询和中断两种模式的工作原理和应用场景,我们可以更加灵活地选择适合自己项目的通信方式,从而实现更高效、更可靠的串口通信。希望本教程能够对大家在物联网开发过程中有所帮助。最后呢,在编写博客的过程中,我尽量保持内容的准确性和完整性,但也难免会有疏漏或错误之处。欢迎各位读者指出其中的问题,帮助我不断进步。谢谢大家的阅读,

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

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

相关文章

GD 32中断系统实现

1.0 中断的概念 中断:简单来说就是打断的意思,在计算机系统中CPU在执行一个操作的时候,有一个比当前任务更为紧急的任务需要执行,cpu暂停当前任务转而去执行更为紧急任务的操作,执行完更为紧急任务之后再返回来执行原来未执行完的…

FullCalendar日历组件集成实战(18)

背景 有一些应用系统或应用功能,如日程管理、任务管理需要使用到日历组件。虽然Element Plus也提供了日历组件,但功能比较简单,用来做数据展现勉强可用。但如果需要进行复杂的数据展示,以及互动操作如通过点击添加事件&#xff0…

两年经验前端带你重学前端框架必会的ajax+node.js+webpack+git等技术 Day2

前端框架必会的(ajaxnode.jswebpackgit)个人学习心得作业及bug记录 Day2 你好,我是Qiuner. 为帮助别人少走弯路和记录自己编程学习过程而写博客 这是我的 github https://github.com/Qiuner ⭐️ ​ gitee https://gitee.com/Qiuner 🌹 如果本…

LDR6282-显示器:从技术革新到视觉盛宴

显示器,作为我们日常工作和娱乐生活中不可或缺的一部分,承载着将虚拟世界呈现为现实图像的重要使命。它不仅是我们与电子设备交互的桥梁,更是我们感知信息、享受视觉盛宴的重要窗口。显示器在各个领域的应用也越来越广泛。在办公领域&#xf…

物料主数据BAPI 无法写入扩展(增强)字段问题

在使用BAPI_MATERIAL_SAVEDATA 去创建物料时,因为有增强字段。这时候需要通过extensionin 字段 进行赋值。 https://community.sap.com/t5/application-development-discussions/bapi-material-savedata-extensionin-dec-type-dump/m-p/11760099 但是赋值后仍然没…

不用SMTP实现联系表单提交后发信到指定邮箱

不使用SMTP,如何确保联系表单能安全发送至指定邮箱? 尽管SMTP是实现电子邮件发送的常用方法,但有时我们可能希望绕过SMTP,直接通过其他方式发送邮件到指定邮箱。AokSend将探讨如何在不用SMTP的情况下,实现联系表单提交…

基于mmap的读写工具封装案例

文章目录 注意事项C封装示例添加构造函数重载以支持追加模式支持文件大小动态变化异常安全性和资源泄漏预防提供更高级的数据访问接口示例代码改进 在很多高性能应用中,直接使用内存映射文件(mmap)进行文件的读写操作可以显著提高效率&#x…

【C++】stack和queue的模拟实现 双端队列deque的介绍

🔥个人主页: Forcible Bug Maker 🔥专栏: STL || C 目录 🌈前言🔥stack的模拟实现🔥queue的模拟实现🔥deque(双端队列)deque的缺陷 🌈为什么选择…

从无计划到项目管理高手,只需避开这两大误区!

在项目管理的过程中,制定计划是不可或缺的一环。然而,在实践中,我们往往会遇到两种常见的误区,这些误区不仅阻碍了计划的有效实施,还可能让我们在追求目标的道路上迷失方向。 误区一:认为没有什么可计划的…

充电桩开源平台,开发流程有图有工具

慧哥充电桩开源平台产品研发流程是确保产品从概念阶段到市场推广阶段的有序进行的关键。以下是对您给出的步骤的详细解释和建议: 设计业务流程: 在这一步,团队需要确定产品的核心功能、目标用户以及如何满足用户需求。进行市场调研,了解竞争…

无线网卡怎么连接台式电脑?让上网更便捷!

随着无线网络的普及,越来越多的台式电脑用户希望通过无线网卡连接到互联网。无线网卡为台式电脑提供了无线连接的便利性,避免了有线网络的束缚。本文将详细介绍无线网卡怎么连接台式电脑的四种方法,包括使用USB无线网卡、内置无线网卡以及使用…

探索企业信用巅峰:3A企业认证的魅力与价值

在现代商业环境中,企业的信用和信誉是其发展的核心要素之一。3A企业认证作为信用评级的最高等级,正在吸引越来越多企业的关注。究竟什么是3A企业认证?它为什么对企业如此重要?本文将深入探讨3A企业认证的独特魅力和巨大价值。 3A企…

使用vue3-treeselect问题

1.当vue3-treeselect是单选时,使用watch监听绑定value,无法监听到值清空 对照后将:value改为v-model,如图 2.使用vue3-treeselect全部清空按钮如何置空select的值,使用watch监听 多选:pageInfo.officeName(val) {// …

mybatis中的标签

在MyBatis中&#xff0c;除了基本的SQL映射功能外&#xff0c;还有许多用于动态SQL构建的标签。这些标签允许我们根据不同的条件和需求构建复杂的SQL语句。主要的动态SQL标签包括<if>, <choose>, <when>, <otherwise>, <trim>, <set>, <…

加密与安全_ 解读非对称密钥解决密钥配送问题的四个方案

文章目录 Pre对称密钥的死穴 - 经典的密钥配送问题什么是非对称密钥非对称密钥解决密钥配送问题的四个方案共享密钥密钥分配中心&#xff08;KDC&#xff09;Diffie-Hellman 密钥交换体系公钥密码体系RSA算法 Pre 对称密钥的死穴 - 经典的密钥配送问题 假设 Alice 和 Bob 两个人…

什么是海外仓管理自动化?策略及落地实施步骤指南

作为海外仓的管理者&#xff0c;你每天都面临提高海外仓运营效率、降低成本和满足客户需求的问题。海外仓自动化管理技术为这些问题提供了不错的解决思路&#xff0c;不过和任何新技术一样&#xff0c;从策略到落地实施&#xff0c;都有一个对基础逻辑的认识过程。 今天我们整…

安装 node.js 完整教程

安装 官方下载地址: https://nodejs.org/en/ 下载LTS版本&#xff08;长期稳定版本&#xff09; 安装可以更改安装路径 其余的都是选择 下一步, 安装 安装完成查看 node -v 查看node的版本 npm -v 查看npm的版本(新版的node安装自带安装npm) 配置环境变量 在nodejs文件夹…

关于SQL NOT IN判断失效的情况记录

1.准备测试数据 CREATE TABLE tmp_1 (val integer);CREATE TABLE tmp_2 (val integer, val2 integer);INSERT INTO tmp_1 (val) VALUES (1); INSERT INTO tmp_1 (val) VALUES (2); INSERT INTO tmp_2 (val) VALUES (1); INSERT INTO tmp_2 (val, val2) VALUES (NULL,0);2.测…

基于Address Sanitizer实现Android NDK的内存错误检测DEMO

1.简介 基于Address Sanitizer实现Android NDK的内存错误检测Demo。 ps:适用于Android 13&#xff08;API 级别 33&#xff09;以下的设备&#xff0c;Android 14&#xff08;API 级别 34&#xff09;或更高版本的 ARM64设备推荐使用HWAddress Sanitizer配置更简单。 GitHub源…

算法题:用JS实现删除链表的倒数第N个节点

学习目标&#xff1a; 删除链表的倒数第N个节点 leetcode原题链接 学习内容&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点 示例 1: 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2: 输入&a…