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、解决方法
- 连续发送多个数据之前先清除TC标志位
- 采用TXE标志位来控制数据的发送是否完成,即把上述
for
循环中的代码换成如下代码即可:
for(i=0; i<Num; i++)
{
USART_SendData(USARTx, Array[i]);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}
