TXE标志位

(针对 发送数据寄存器)

TXE为1:TDR里的数据全部移到了移位寄存器,且没有新的数据进TDR。

TXE为0:TDR里有数据,未空,则TXE为0。

TXE与"FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)"搭配使用来判断TDR中是否存在数据

int main (void){
My_ _USART1() ;
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);
while(1){}
}
//输出:H K G

TC标志位

(针对 发送数据寄存器)

TC为1:从TDR过来的数据全部被移送到TX引脚,且TDR里也没有新的数据。

TC为0:从TDR里过来的数据还没有全部移过来,或者之前TDR里的数据被移走了,但TDR里又来了新的数据。

int main (void){
My_ _USART1() ;
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);
while(1){}
}
//输出:K G

原因在于

关于TXE和TC标志位的小知识_重定向

//第10/11执行的是先写入DR,再读取SR,步骤刚好相反,那么TC标志位就没有清0
//因为它不等于RESET,所以会立马执行下一行,这时候"K"会将“H”覆盖掉
//在执行发送"G"的时候就已经执行过上图中的操作,满足了相关的条件

解决方法:

  1. 在发送"K"前先读USART_SR;

int main (void){
My_USART1() ;
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);
while(1){}
}

  1. 软件清“0”,需要用到下面的函数

//清除标志位
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
int main (void){
My_USART1() ;
USART_ClearFlag(USART1, uint16_t USART_FLAG);
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);
while(1){}
}

多组进行传输,需要查看对应的多个TXE标志位和一个TC标志位(TC为了确保最后一个字符从发送移位寄存器到TX)

重写USART_SendByte()使其可以重复写多个字符

void USART_SendByte(USART_TypeDef* USARTx, uint8_t Data){
assert_param(IS_USART_ALL PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
USARTx->DR = (Data & (uint16_t)0x01FF);
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}

发送字符串的函数

void USART SendString( USART_TypeDef * USARTx, char *str){
while(*str!='\0'){
USART_SendByte( USARTx, *str++ );
while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);
}
}

串口通信方式:轮询法、中断法。一般接收使用中断。

ITStatus值为1,表示可以读取数值了

ITStatus值为0,表示还不可以读取数值

可以通过while和if来进行判断


USART_GetITStatus()

USART_GetFlagStatus()

相同点

都是访问串口的SR状态寄存器


不同点

不仅会判断标志位是否置1,同时还会判断是否使能了相应的中断,所以在串口中断函数,通常使用该函数

只判断标志位,在没使能相应的中断时,通常使用该函数来判断标志位是否置1。

看懂一个库函数,需要结合具体的实例。

//不仅会判断标志位是否置1,同时还会判断是否使能了相应的中断,所以在串口中断函数,通常使用该函数
ITStatus USART_GetITStatus(USART_TypeDef* USART1,uint16_t USART_IT);

printf函数

在C语言中用于打印信息到控制台上。printf是单片机开发中调试的利器!

对printf底层函数进行重定向,使用fputc和fgetc

#include "stdio.h"
//fputc和fgetc是C语言的标准函数
//使用其FILE *f

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f){
USART_SendData (USART1,(uint8_t) ch);
while (USART_GetFlagStatus (USART1,USART_FLAG_TXE) == RESET);
return (ch);
}
//重定向c库函数scanf到串口,重写向后可使用scanf、getchar等 函数
int fgetc(FILE *f){
while (USART_GetFlagStatus (USART1,USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData (USART1);
}

printf()函数使用了半主机模式,会导致程序无法运行,因此要禁止这种模式

  1. 使用微库:使用微库时,就默认关闭了半主机模式
  1. 使用微库
  2. 引入stdio.h头文件
  3. 重写fputc和fgetc函数

关于TXE和TC标志位的小知识_数据_02

可能会出现"FIFLE" is underfined,加上

//在usart.h中写入
typedef struct __FILE FILE

  1. 不使用微库,但是需要加上下面的话

#include "stdio.h"

#pragma import(__use_no_semihousting)
struct __FILE
{
int handle;
};
FILE __stdout;
_sys_exit(int x)
{
x = x;
}

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f){
USART_SendData (USART1,(uint8_t) ch);
while (USART_GetFlagStatus (USART1,USART_FLAG_TXE) == RESET);
return (ch);
}
//重定向c库函数scanf到串口,重写向后可使用scanf、getchar等 函数
int fgetc(FILE *f){
while (USART_GetFlagStatus (USART1,USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData (USART1);
}

  • 两种方法相同点:
  • 1都使用“stdio.h"头文件
  • 都需要重写printf底层函数,fputs和fgets.
  • 两种方法不同点:
  • 是否勾选“Use MicroLIB”

半主机模式:半主机模式是ARM单片机的一种调试机制,它需要通过仿真器来连接电脑和ARM单片机,并调用相应的指令来实现单片机向电脑显示器打印信息。

微库是为小内存嵌入式设备而设计,可以减少代码所占空间。

尽量少使用微库

  • 相对于C标准库而言,支持的功能更少,主要体现在对操作系统的支持上。
  • 标准的东西相对更可靠。

两个函数的相关内容

区别

int fputc(int ch,FILE *fp)函数

int fgetc(FILE *fp)函数

功能

将一个字符写入到文件中

从文件中读出一个字符

参数

ch要写入的字符,fp指向FILE结构的指针

fp指向FILE结构的指针

返回值

成功,返回该字符;遇到文件尾或读取错误时,返回EOF(-1)

成功,返回该字符;遇到文件尾或读取错误时,返回EOF(-1)

如何更好学习单片机

  • 首先找一个合适字节的教程
  • 动手实践!!

感谢海创电子的视频教学

海创电子:​​https://space.bilibili.com/93630735/?spm_id_from=333.999.0.0​

51单片机:​​https://www.bilibili.com/video/BV1vJ411X7iZ?spm_id_from=333.999.0.0&vd_source=cf352bf665894b2751d802dc81299dd8​

STM32单片机:​​https://www.bilibili.com/video/BV1N7411x7Yk?spm_id_from=333.999.0.0&vd_source=cf352bf665894b2751d802dc81299dd8​