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

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

### STM32 UART 中断标志位解释使用 中断机制对于嵌入式开发至关重要,在STM32微控制器系列中,UART通信接口提供了多种方式来处理数据传输事件。当涉及到串口接收或发送操作时,了解如何正确配置和响应这些事件变得尤为关键。 #### UART状态寄存器 (SR) 在STM32内部,UART模块配备了一个专门的状态寄存器(SR),用于指示当前发生的各种条件。此寄存器包含了多个标志位,每一个都对应着特定类型的事件或错误情况[^1]: - **RXNE (Read Data Register Not Empty)**: 表明接收到的数据已准备好读取。 - **TC (Transmission Complete)**: 发送移位寄存器为空,意味着最近一次字符已经完全发出。 - **TXE (Transmit Data Register Empty)**: 数据寄存器可以接受新的待发字符。 - **IDLE**: 接收线路上检测到空闲总线。 - 错误标志如 ORE(Overrun Error), NE(Framing error), PE(Parity error)等也在此处标记。 为了有效地利用上述资源并实现高效可靠的通讯协议栈设计,开发者通常会在初始化阶段设置相应的中断使能位,并编写对应的ISR函数来进行实时处理。 ```c // 启用USART1全局中断 __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); void USART1_IRQHandler(void){ HAL_UART_IRQHandler(&huart1); } // 用户自定义回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){ if(huart->Instance==USART1){ // 处理接收到的数据... } } ``` 通过这种方式,可以在发生指定事件时触发CPU执行预先编写的程序逻辑,从而及时应对硬件层面上的变化而不必轮询查询各个可能的状态变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨小羽ovo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值