STM32串口寄存器USART_SR中的TC标志位

本文介绍了STM32串口通信中TC(Transmission Complete)标志位的重要性和潜在问题。当TC标志位在串口初始化后默认为1,若不清零可能导致数据发送覆盖。通过示例代码解释了为何在连续发送数据时必须先清除TC标志位,以及如何使用TXE标志位正确控制数据发送。解决方法是确保在发送新数据前清零TC标志位,确保数据正确传输。
摘要由CSDN通过智能技术生成

1、TC标志位介绍

可以看到USART_SR寄存器复位值位0X00C0,而TC在位6,所以复位值置1。也可以用以下程序验证:

#include "stm32f10x.h"                  
#include "USART1.h"                
#include "LED.h"                
int main(void)
{
	USART1_Config();   //串口初始化
	/*********证明当串口初始化后,TC标志位置1**********/
	LED_G_Init();     //LED初始化
	uint8_t i = 0;
	i = USART_GetFlagStatus(USART1, USART_FLAG_TC);
	if(i == 1)  //如果初始化后TC位为1,则亮绿灯
	{
		LED_G_ON();
	}
	while(1)
	{
		
	}
}

2、USART1.c

#include "stm32f10x.h"
//串口TX引脚为PA9,RX为PA10
void USART1_Config(void)
{
	//打开GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	//打开USART1串口时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//将USART1_TX配置为复用推挽输出
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//将USART1_RX配置为浮空输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//配置串口的工作方式
	USART_InitTypeDef USART_InitStructure;
	//波特率
	USART_InitStructure.USART_BaudRate = 115200;
	// 配置硬件流控制
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	// 配置工作模式,收发一起
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	// 配置校验位
	USART_InitStructure.USART_Parity = USART_Parity_No;
	// 配置停止位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	// 配置 数据帧字长
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	// 完成串口的初始化配置
	USART_Init(USART1, &USART_InitStructure);
	
	//使能串口
	USART_Cmd(USART1, ENABLE);
}

/**
  * @brief   发送8位数据的数组
  * @param   选择串口,参数可以是USART1、USART2...
  * @param   数组首地址
  * @param   数组大小,或者需要发送数组前Num个数组元素
  * @retval  无
  */
void Usart_SendArray(USART_TypeDef* USARTx, uint8_t* Array, uint8_t Num)
{
	uint8_t i;
	for(i=0; i<Num; i++)
	{
		USART_SendData(USARTx, Array[i]);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
	}
}

3、LED.c

#include "stm32f10x.h"
//LED_G为GPIOB寄存器的PB0端口

void LED_G_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_0);  //初始化默认关闭LED
}

//开启绿灯
void LED_G_ON(void)
{
	GPIO_ResetBits(GPIOB, GPIO_Pin_0);
}

//关闭绿灯
void LED_G_OFF(void)
{
	GPIO_SetBits(GPIOB, GPIO_Pin_0);
}

4、TC位复位值为1,如果不清零可能会带来的问题

当连续发送多个8位数据时,如果采用检测TC标志位置1作为发送完成,那么会导致第一个8位数据被覆盖,这里先用代码演示,之后解释原因:

#include "stm32f10x.h"                 
#include "USART1.h"                
#include "LED.h"                
/**
  * @brief   发送8位数据的数组
  * @param   选择串口,参数可以是USART1、USART2...
  * @param   数组首地址
  * @param   数组大小,或者需要发送数组前Num个数组元素
  * @retval  无
  */
void Usart_SendArray(USART_TypeDef* USARTx, uint8_t* Array, uint8_t Num)
{
	uint8_t i;
	for(i=0; i<Num; i++)
	{
		USART_SendData(USARTx, Array[i]);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
	}
}

int main(void)
{
	uint8_t a[10] = {1,2,3,4,5,6,7,8,9,10};
	USART1_Config();                 //串口初始化
	Usart_SendArray(USART1, a, 10);  
	while(1)
	{
		
	}
}

预想结果是把数组a[10]中的数据全部通过串口发送出去,但结果却如下所示:

导致上述情况的原因在这部分代码:

	for(i=0; i<Num; i++)
	{
		USART_SendData(USARTx, Array[i]);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
	}

之前有说过,串口初始化后,TC标志位为1,这样会导致第一个for循环中的while循环直接跳出进入第二个for循环,进而导致第一个数组中的第一个数据刚写入到USART_DR寄存器,还没来得及转到移位寄存器,数组中的第二个数据又写入到USART_DR寄存器,进而覆盖了第一个数据。
可能会有人问,那第二个、第三个…,为什么没有被覆盖,这里解释以下:
在这里插入图片描述
红线框着的内容说明了如何清除TC标志位的其中一种方法,而while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);这一条语句就是读USART_SR寄存器,USART_SendData(USARTx, Array[i]);这一条语句就是写USART_DR寄存器。这样,每一次for循环的结束,和下一次for循环的开始,其结合作用就是清除TC标志位,所以这也就是为什么数组中的其他位数据不被覆盖的原因。

5、解决方法

  1. 连续发送多个数据之前先清除TC标志位
  2. 采用TXE标志位来控制数据的发送是否完成,即把上述for循环中的代码换成如下代码即可:
	for(i=0; i<Num; i++)
	{
		USART_SendData(USARTx, Array[i]);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

可可斯蒂彳亍

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

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

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

打赏作者

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

抵扣说明:

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

余额充值