stm32中分析UART中IDLE,RXNE,TC,TXE这些标志位的作用

下面将基于 STM32 标准库,结合之前提到的不同应用场景,给出使用 TXETCIDLERXNE 标志位的代码示例及分析。

1. 连续数据发送(使用 TXE

应用场景

向外部设备连续发送大量数据,如向显示屏发送显示数据、向传感器发送配置指令序列等。

代码示例
复制代码
#include "stm32f10x.h"

void USART1_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    // 使能 USART1 和 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置 PA9 为复用推挽输出(TX)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置 USART1
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);

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

void USART1_SendString(const char* str) {
    while (*str) {
        // 等待发送数据寄存器为空
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        // 写入新的数据
        USART_SendData(USART1, (uint8_t)*str++);
    }
}

int main(void) {
    USART1_Configuration();
    const char* message = "Hello, World!";
    USART1_SendString(message);

    while (1) {
        // 主循环
    }
}
代码分析
  • USART1_Configuration 函数:
    • 使能 USART1 和 GPIOA 的时钟。
    • 配置 PA9 为复用推挽输出,用于 USART1 的发送功能。
    • 初始化 USART1,设置波特率为 115200,数据位为 8 位,停止位为 1 位,无校验位,无硬件流控制,仅使能发送模式。
    • 使能 USART1。
  • USART1_SendString 函数:
    • 使用 USART_GetFlagStatus 函数检查 TXE 标志位,当该标志位为 SET 时,表示发送数据寄存器为空。
    • 使用 USART_SendData 函数将字符串中的字符依次发送出去。
  • main 函数:
    • 调用 USART1_Configuration 函数初始化 USART1。
    • 调用 USART1_SendString 函数发送字符串 "Hello, World!"。

2. 数据发送完成确认(使用 TC

应用场景

在对数据完整性要求较高的场景中,确保整个数据帧完整无误地发送到目标设备。

代码示例
复制代码
#include "stm32f10x.h"

void USART1_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    // 使能 USART1 和 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置 PA9 为复用推挽输出(TX)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置 USART1
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);

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

void USART1_SendDataAndWaitComplete(uint8_t data) {
    // 等待发送数据寄存器为空
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    // 写入数据
    USART_SendData(USART1, data);
    // 等待发送完成
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}

int main(void) {
    USART1_Configuration();
    uint8_t command = 0xAA;
    USART1_SendDataAndWaitComplete(command);

    while (1) {
        // 主循环
    }
}
代码分析
  • USART1_Configuration 函数:与连续数据发送场景中的配置函数相同。
  • USART1_SendDataAndWaitComplete 函数:
    • 先使用 USART_GetFlagStatus 函数检查 TXE 标志位,当该标志位为 SET 时,将数据写入 DR 寄存器。
    • 然后使用 USART_GetFlagStatus 函数检查 TC 标志位,当该标志位为 SET 时,表示整个数据帧发送完成。
  • main 函数:
    • 调用 USART1_Configuration 函数初始化 USART1。
    • 调用 USART1_SendDataAndWaitComplete 函数发送一个字节的命令 0xAA

3. 数据帧边界识别(使用 IDLE

应用场景

接收不定长的数据帧,如从传感器接收实时数据、从其他设备接收通信协议数据等。

代码示例
复制代码
#include "stm32f10x.h"
#include <stdio.h>

#define BUFFER_SIZE 256
uint8_t rx_buffer[BUFFER_SIZE];
uint8_t rx_index = 0;

void USART1_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 使能 USART1 和 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置 PA10 为浮空输入(RX)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置 USART1
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);

    // 使能 USART1 的 IDLE 中断
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);

    // 配置 NVIC
    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);

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

void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) {
        // 清除 IDLE 标志位
        USART_ClearITPendingBit(USART1, USART_IT_IDLE);
        uint8_t temp = USART_ReceiveData(USART1); // 读取数据以清除 IDLE 标志

        // 处理一帧数据接收完成事件
        // 这里简单打印接收到的数据长度
        printf("Received %d bytes of data.\n", rx_index);

        // 清空缓冲区和索引
        rx_index = 0;
    } else if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        // 读取接收缓冲区的数据
        rx_buffer[rx_index++] = USART_ReceiveData(USART1);
        // 清除 RXNE 标志位
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

int main(void) {
    USART1_Configuration();

    while (1) {
        // 主循环
    }
}
代码分析
  • USART1_Configuration 函数:
    • 使能 USART1 和 GPIOA 的时钟。
    • 配置 PA10 为浮空输入,用于 USART1 的接收功能。
    • 初始化 USART1,设置波特率为 115200,数据位为 8 位,停止位为 1 位,无校验位,无硬件流控制,仅使能接收模式。
    • 使能 USART1 的 IDLE 中断,并配置 NVIC。
    • 使能 USART1。
  • USART1_IRQHandler 函数:
    • IDLE 中断发生时,使用 USART_ClearITPendingBit 函数清除 IDLE 标志位,读取数据以彻底清除该标志。处理接收到的数据(这里简单打印数据长度),并清空缓冲区和索引。
    • RXNE 中断发生时,将接收到的数据存入缓冲区,并清除 RXNE 标志位。
  • main 函数:
    • 调用 USART1_Configuration 函数初始化 USART1。
    • 进入主循环等待中断。

4. 实时数据接收(使用 RXNE

应用场景

实时处理接收到的数据,如实时监测传感器数据、接收外部设备的控制指令等。

代码示例
复制代码
#include "stm32f10x.h"

void USART1_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 使能 USART1 和 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置 PA10 为浮空输入(RX)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置 USART1
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);

    // 使能 USART1 的 RXNE 中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    // 配置 NVIC
    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);

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

void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        uint8_t data = USART_ReceiveData(USART1); // 读取接收缓冲区的数据
        // 简单处理接收到的数据,这里假设点亮一个 LED
        if (data == '1') {
            GPIO_SetBits(GPIOA, GPIO_Pin_0);  // 点亮 PA0
        } else if (data == '0') {
            GPIO_ResetBits(GPIOA, GPIO_Pin_0);  // 熄灭 PA0
        }
        // 清除 RXNE 标志位
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

int main(void) {
    // 使能 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    // 配置 PA0 为推挽输出
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART1_Configuration();

    while (1) {
        // 主循环
    }
}
代码分析
  • USART1_Configuration 函数:
    • 使能 USART1 和 GPIOA 的时钟。
    • 配置 PA10 为浮空输入,用于 USART1 的接收功能。
    • 初始化 USART1,设置波特率为 115200,数据位为 8 位,停止位为 1 位,无校验位,无硬件流控制,仅使能接收模式。
    • 使能 USART1 的 RXNE 中断,并配置 NVIC。
    • 使能 USART1。
  • USART1_IRQHandler 函数:
    • RXNE 中断发生时,使用 USART_ReceiveData 函数读取接收缓冲区的数据。
    • 根据接收到的数据内容,控制 PA0 引脚的电平,实现点亮或熄灭 LED 的功能。
    • 使用 USART_ClearITPendingBit 函数清除 RXNE 标志位。
  • main 函数:
    • 使能 GPIOA 时钟,配置 PA0 为推挽输出。
    • 调用 USART1_Configuration 函数初始化 USART1。
    • 进入主循环等待中断。
相关推荐
恒锐丰-罗生38 分钟前
宽压大电流同步降压优选|CN3906 DC-DC 电源芯片,车载 / 工控 / IoT 全能供电方案
嵌入式硬件·硬件工程
happygrilclh4 小时前
STM32,串口单字节中断接受,每次上电后,会收到一个0x00的解决办法。
单片机·嵌入式硬件
智闲电子设计5 小时前
STM32 独立看门狗 IWDG 实战:系统跑飞,它来兜底复位
stm32·单片机·嵌入式硬件
zcmodeltech6 小时前
智能制造教学实训沙盘模型多系统协同控制系统设计:基于STM32与Modbus RTU的工业机器人-智慧工厂-数字孪生全场景联动方案
数据库·stm32·嵌入式硬件·机器人·制造·多分类
程序员与背包客_CoderZ6 小时前
Linux D-Bus通信协议详解:从入门到C/C++编码实战
linux·服务器·c语言·c++·嵌入式硬件·嵌入式软件·dbus
嵌入式阿蔡8 小时前
HAL库 vs LL库 vs 寄存器:到底用哪个?
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
天空'之城9 小时前
单片机基础核心知识点汇总(三)
单片机·嵌入式硬件
嵌入式阿蔡9 小时前
CAN总线入门:从协议帧到STM32实战
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
恒锐丰科技韩生10 小时前
率能 SS8847E|2.7~15V 双通道 H 桥电机驱动 ETSSOP16 散热封装 家电 / 打印 / 舞台灯光专用
嵌入式硬件·硬件工程
离凌寒10 小时前
一、对stm32mp157配置freertos后,任务挂掉无法启动问题总结
stm32·单片机·嵌入式硬件