当前位置: 首页 > news >正文

STM32第十四天串口

一:串口发送字符和字符串和printf重定向

usart.c

#include "stm32f10x.h"
#include "usart.h"
#include "stdio.h"void my_usart_Init()//千万不要和32库里面串口定于的名字一样,不然会报错
{GPIO_InitTypeDef my_usart_Initstruct;USART_InitTypeDef USART_Initstruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);my_usart_Initstruct.GPIO_Pin=GPIO_Pin_9 ;my_usart_Initstruct.GPIO_Mode=GPIO_Mode_AF_PP ;my_usart_Initstruct.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA, &my_usart_Initstruct);my_usart_Initstruct.GPIO_Pin=GPIO_Pin_10 ;my_usart_Initstruct.GPIO_Mode=GPIO_Mode_IN_FLOATING ;GPIO_Init(GPIOA, &my_usart_Initstruct);USART_Initstruct.USART_BaudRate=115200;USART_Initstruct.USART_HardwareFlowControl= USART_HardwareFlowControl_None  ;USART_Initstruct.USART_Mode= USART_Mode_Rx | USART_Mode_Tx;USART_Initstruct.USART_Parity= USART_Parity_No;USART_Initstruct.USART_StopBits=USART_StopBits_1  ;USART_Initstruct.USART_WordLength=USART_WordLength_8b;USART_Init(USART1,&USART_Initstruct );USART_Cmd(USART1, ENABLE);}
void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data)
{USART_SendData( USARTx, Data);while(USART_GetFlagStatus( USARTx, USART_FLAG_TXE) != SET);}void My_Usart_Send_Sting(USART_TypeDef* USARTx,char * str)
{uint16_t i=0;do{My_Usart_Send_Byte(USARTx,*(str+i));i++;}while(*(str+i) != '\0');while(USART_GetFlagStatus( USARTx, USART_FLAG_TC) != SET);}int fputc(int ch, FILE * p)
{USART_SendData( USART1, (u8)ch);while(USART_GetFlagStatus( USART1, USART_FLAG_TXE) != SET);return ch;}

usart.h

#ifndef USART_H_
#define USART_H_void my_usart_Init(void);
void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data);
void My_Usart_Send_Sting(USART_TypeDef* USARTx, char * str);#endif

main.c

#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "Bear.h"
#include "key.h"
#include "relay.h"
#include "shake.h"
#include "wireless.h"
#include "exti_key.h"
#include "usart.h"
#include "stdio.h"void delay(uint16_t time)//延时1ms  软件延时粗延时
{uint16_t i=0;while(time --){i=12000;while(i --);}}int  main()
{my_usart_Init();LED_Init();//	My_Usart_Send_Byte( USART1, 'A');
//	My_Usart_Send_Byte( USART1, 'B');
//	My_Usart_Send_Byte( USART1, 'C');//	My_Usart_Send_Sting( USART1, "kobe \r\n");printf("kobe is king \r\n");while(1){
//		USART_SendData( USART1,  'A');}}

代码心得

1:void My_Usart_Send_Sting(USART_TypeDef* USARTx,char * str)复习一下char*指针的用法和知识点

知识点说明
char* 本质指向字符内存地址的指针,用于表示字符串。
字符串终止符必须以 '\0' 结尾,否则函数会越界访问。
指针运算str++ 移动至下一字符;*str 访问当前字符。
函数参数传递传递字符串首地址,高效且节省内存。
const 安全性不修改字符串时使用 const char*,避免误操作只读数据。
常见错误修改字符串常量、未添加终止符会导致未定义行为。

 2:do-while循环详解

1.基本语法:do { // 循环体} while (condition);

执行顺序:先执行循环体内的语句,然后判断条件(condition)是否成立。若条件成立,则继续执行循环体;否则退出循环。

特点:循环体至少执行一次,即使条件一开始就不成立。

2. 与while循环的区别

while循环:先判断条件,再决定是否执行循环体(可能一次都不执行)。

do-while循环:先执行循环体一次,再判断条件(至少执行一次)。

3:理解USART_FLAG_TXE: Transmit data register empty flag  和USART_FLAG_TC: Transmission Complete flag

这两个标志位都是USART/UART通信中用于发送状态的重要标志,但它们指示的发送阶段不同,非常容易混淆。理解它们的区别对于正确使用串口发送数据至关重要:

一:USART_FLAG_TXE (Transmit Data Register Empty)

  1. USART_FLAG_TXE (Transmit Data Register Empty) - 发送数据寄存器空标志

    • 含义: 当USART_FLAG_TXE被置位(=1)时,表示发送数据寄存器 (TDR - Transmit Data Register) 已经空了

    • 触发时机: 当前正在发送的数据字节已经从TDR寄存器移入到发送移位寄存器 (Transmit Shift Register) 中。此时TDR寄存器是空的,可以安全地写入新的待发送数据。

    • 主要用途:

      • 判断是否可以写入新数据: 这是它的核心用途。在查询方式(非中断/DMA)发送时,你需要检查USART_FLAG_TXE是否为1。如果是1,说明TDR空了,你可以立即调用USART_SendData()写入下一个字节。在中断方式下,当TXEIE中断使能时,TXE事件会触发中断,在中断服务程序里你就可以写入下一个字节。

      • 避免覆盖未发送的数据:确保你在写入新数据时,硬件已经准备好接收它。

    • 关键点: TXE=1 并不表示 数据已经物理发送到线路上,只表示数据离开了TDR进入了下一个发送阶段(移位寄存器)。最后一个字节的数据可能还在移位寄存器中,正在一位一位地通过TX引脚发出。

二:USART_FLAG_TC (Transmission Complete)

  1. USART_FLAG_TC (Transmission Complete) - 传输完成标志

    • 含义: 当USART_FLAG_TC被置位(=1)时,表示一次完整的发送操作已经完成

    • 触发时机: 需要同时满足以下两个条件:

      1. 发送数据寄存器 (TDR) 为空 (USART_FLAG_TXE = 1)。

      2. 发送移位寄存器 (Transmit Shift Register) 也为空(即最后一位数据,包括停止位,已经完全从TX引脚发送出去)。

    • 主要用途:

      • 判断整个数据包是否发送完毕: 这是它的核心用途。当你发送一串数据(比如一个字符串)后,你需要确认所有字节(包括最后一个字节的所有位)都已经物理发送到线路上。此时应检查USART_FLAG_TC

      • 安全操作: 在确认TC=1之后,你可以安全地执行一些需要等待发送完全结束的操作,例如:

        • 关闭USART模块。

        • 改变通信参数(波特率、数据位等)。

        • 切换收发方向(在单线半双工通信中)。

        • 断言DE信号(在RS-485通信中释放总线)。

      • 在中断方式下,当TCIE中断使能时,TC事件会触发中断,通知你发送彻底完成。

    • 关键点: TC=1 明确表示数据已经物理离开了芯片的TX引脚,发送线路已经完全空闲。

 

形象比喻:

想象一个邮局(USART)有两个工作台:

  • TDR (工作台1 - 打包台): 工作人员在这里把信件(数据字节)装进信封(准备发送帧)。

  • 移位寄存器 (工作台2 - 寄送台): 工作人员从这里把信封投入邮筒(TX引脚),一位一位地塞进去(串行发送)。

  • TXE=1: 表示“打包台空了”。打包台的工作人员把信件装好信封后,递给了寄送台的工作人员。这时你可以把下一封信交给打包台的工作人员了。但之前装好的那封信,寄送台的工作人员可能还在往邮筒里塞呢(数据正在发送中)。

  • TC=1: 表示“打包台空了 并且 寄送台也空了”。不仅打包台没信了(TXE=1),寄送台的工作人员也已经把上一封信完全塞进了邮筒(所有位发送完毕)。整个发送流程彻底结束,线路空闲。

总结区别:

特性USART_FLAG_TXE (TXE)USART_FLAG_TC (TC)
全称Transmit Data Register EmptyTransmission Complete
含义发送数据寄存器 (TDR) 空传输完成 (TDR空  移位寄存器空)
指示阶段可以安全写入下一个字节上一个字节(及之前所有字节)已完全物理发出
硬件条件TDR寄存器空 (数据已移入移位寄存器)TDR寄存器空 并且 移位寄存器空 (线路空闲)
主要用途检查是否可以写入新数据 (查询/中断填充)检查发送是否彻底完成 (安全关闭/切换/后续操作)
发送状态数据可能还在移位寄存器中发送数据已完全离开TX引脚,发送线路空闲
中断关联TXEIE (发送数据寄存器空中断使能)TCIE (发送完成中断使能)
清除方式USART_SR寄存器 + 写USART_DR寄存器USART_SR寄存器 + 写USART_DR寄存器  软件序列(读SR后写DR)

 

4:串口需要换行要用\r\n

5:写串口函数一定要给串口外设使能

6:while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); 它的逻辑含义是:循环等待,直到USART1的发送数据寄存器空标志(TXE)被置位(即变为SET状态)才退出循环。

7:int fputc(int /*c*/, FILE * /*stream*/)

  • 返回值 int
    成功时返回写入的字符,失败时返回 EOF(通常是 -1)。

  • 参数1 int c
    要输出的字符(以 int 形式传递,支持 EOF 特殊值)。

  • 参数2 FILE *stream
    指向文件流的指针(如 stdout 标准输出)。

 

http://www.dtcms.com/a/267132.html

相关文章:

  • uniapp启动图被拉伸问题
  • 国产 OFD 标准公文软件数科 OFD 阅读器:OFD/PDF 双格式支持,公务办公必备
  • React Hooks 内部实现原理与函数组件更新机制
  • 【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
  • stm32的三种开发方式
  • Zigbee/Thread
  • 车载以太网-防火墙
  • 【深度学习】强化学习(Reinforcement Learning, RL)主流架构解析
  • 2025使用VM虚拟机安装配置Macos苹果系统下Flutter开发环境保姆级教程--下篇
  • React Native 开发环境搭建--mac--android--奔溃的一天
  • App爬虫实战篇-以华为真机手机爬取集换社的app为例
  • Pytest 测试发现机制详解:自动识别测试函数与模块
  • 在 Ubuntu 下配置 oh-my-posh —— 普通用户 + root 各自使用独立主题(共享可执行)
  • Redis Cluster 与 Sentinel 笔记
  • 文本方式和二进制方式打开文件的不同
  • Flutter 使用http库获取网络数据的方法(一)
  • Excel 数据透视表不够用时,如何处理来自多个数据源的数据?
  • MAX3485在MCU芯片AS32S601-485通信外设中的应用
  • 线程的礼让和加入
  • 1004、最大连续1的个数 III
  • SpringBatch使用介绍
  • 任务调度器(Scheduler)实现逻辑
  • Java 创建对象过程 JVM 内存分配并发安全笔记
  • JVM与JMM
  • Mysql底层专题(四)索引优化实战一
  • DeepSeek与诡秘之主
  • 在SoC数据加解密验证中使用 Python 的 gmssl 库
  • 03_性能优化:让软件呼吸更顺畅
  • 计算机网络(网页显示过程,TCP三次握手,HTTP1.0,1.1,2.0,3.0,JWT cookie)
  • 【网络协议安全】任务12:二层物理和单臂路由及三层vlanif配置方法