stm32之USART

目录

  • 1.引入
    • [1.1 通信接口](#1.1 通信接口)
    • [1.2 串口](#1.2 串口)
  • 2.USART
    • [2.1 简介](#2.1 简介)
    • [2.2 框图](#2.2 框图)
    • [2.3 基本机构图](#2.3 基本机构图)
    • [2.4 数据帧](#2.4 数据帧)
    • [2.5 波特率发生器](#2.5 波特率发生器)
    • [2.6 数据包](#2.6 数据包)
      • [2.6.1 数据模式](#2.6.1 数据模式)
      • [2.6.2 HEX数据包](#2.6.2 HEX数据包)
      • [2.6.3 文本数据包](#2.6.3 文本数据包)
      • [2.6.4 HEX数据包接收](#2.6.4 HEX数据包接收)
      • [2.6.5 文本数据包接收](#2.6.5 文本数据包接收)
  • 3.结构体和相关API
    • [3.1 结构体](#3.1 结构体)
    • [3.2 API](#3.2 API)
      • [3.2.1 **初始化相关函数**](#3.2.1 初始化相关函数)
        • [`void USART_DeInit(USART_TypeDef* USARTx)`](#void USART_DeInit(USART_TypeDef* USARTx))
        • [`void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)`](#void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct))
        • [`void USART_StructInit(USART_InitTypeDef* USART_InitStruct)`](#void USART_StructInit(USART_InitTypeDef* USART_InitStruct))
      • [3.2.2 **时钟相关函数**](#3.2.2 时钟相关函数)
        • [`void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct)`](#void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct))
        • [`void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct)`](#void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct))
      • [3.2.3 **控制相关函数**](#3.2.3 控制相关函数)
        • [`void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)`](#void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState))
        • [`void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)`](#void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState))
        • [`void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)`](#void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState))
      • [3.2.4 **数据收发函数**](#3.2.4 数据收发函数)
        • [`void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)`](#void USART_SendData(USART_TypeDef* USARTx, uint16_t Data))
        • [`uint16_t USART_ReceiveData(USART_TypeDef* USARTx)`](#uint16_t USART_ReceiveData(USART_TypeDef* USARTx))
      • [3.2.5 **状态和中断相关函数**](#3.2.5 状态和中断相关函数)
        • [`FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)`](#FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG))
        • [`void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)`](#void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG))
        • [`ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)`](#ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT))
        • [`void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)`](#void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT))
  • 4.实验
    • [4.1 串口发送](#4.1 串口发送)
    • [4.2 串口发送 + 接收](#4.2 串口发送 + 接收)
    • [4.3 HEX数据包收发](#4.3 HEX数据包收发)
    • [4.4 文本数据包收发](#4.4 文本数据包收发)
  • [5.FlyMcu串口下载&STLINK Utility](#5.FlyMcu串口下载&STLINK Utility)
    • [5.1 FlyMcu](#5.1 FlyMcu)
    • [5.2 STLINK Utility](#5.2 STLINK Utility)

1.引入

1.1 通信接口

通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统

通信协议:制定通信的规则,通信双方按照协议规则进行数据收发

名称 引脚 双工 时钟 电平 设备
USART TX、RX 全双工 异步 单端 点对点
I2C SCL、SDA 半双工 同步 单端 多设备
SPI SCLK、MOSI、MISO、CS 全双工 同步 单端 多设备
CAN CAN_H、CAN_L 半双工 异步 差分 多设备
USB DP、DM 半双工 异步 差分 点对点

1.2 串口

具体一点的内容看嵌入式驱动开发中的UART子系统对串口的硬件简介。

串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信

单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力

上图左边是USB转串口模块,中间是陀螺仪传感器模块(左边的是接串口、右边的引脚接I2C),右边是蓝牙串口模块


数据低位先行

  • 简单双向串口通信有两根通信线(发送端TX和接收端RX)
  • TX与RX要交叉连接
  • 当只需单向的数据传输时,可以只接一根通信线
  • 当电平标准不一致时,需要加电平转换芯片

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

  • TTL电平:+3.3V或+5V表示1,0V表示0
  • RS232电平:-3-15V表示1,+3+15V表示0
  • RS485电平:两线压差+2+6V表示1,-2-6V表示0(差分信号)

串口参数及时序:

  • 波特率:串口通信的速率,每秒传送的码元个数(二进制调制下就等同于每秒传递的比特数)
  • 起始位:标志一个数据帧的开始,固定为低电平
  • 数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行
  • 校验位:用于数据验证,根据数据位计算得来
  • 停止位:用于数据帧间隔,固定为高电平

串口时序:

2.USART

对应芯片参考手册的USART部分

2.1 简介

USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器

USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里

自带波特率发生器,最高达4.5Mbits/s。其实就是个分频器,波特率发生器对时钟进行一个分频,就能得到想要的波特率时钟,在该时钟下进行收发,就是指定的通信波特率。

可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)

可选校验位(无校验/奇校验/偶校验)

支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN

STM32F103C8T6 USART资源: USART1(APB2总线上的)、 USART2(APB1总线上的)、 USART3(APB1总线上的)

2.2 框图

来自参考手册

1. 数据接口模块

  • TX/RX:分别为串行数据发送和接收引脚,是USART的主要外部接口,用于与外部设备通信。
  • nRTS/nCTS:硬件流控引脚,分别表示请求发送(Request to Send)和清除发送(Clear to Send)信号。如果发送数据发送的太快,接收方来不及接收,就会发生数据丢失或覆盖的情况,为解决这种情况就靠这两根引脚。nRTS:你能不能发数据给我(接对方的nCTS);nCTS:我能不能发数据给你(接对方的nRTS)
  • IrDA模块:支持红外通信的编码和解码模块,可通过配置CR3寄存器启用。

2. 发送器部分

发送数据寄存器 (TDR)

  • 用于存储需要发送的数据,写操作通过CPU或DMA完成。
  • 数据从TDR被传输至发送移位寄存器,开始按位输出到TX引脚。

发送移位寄存器

  • 数据从TDR进入移位寄存器,并以配置的波特率逐位发送。
  • 发送时序由USART_BRR寄存器提供的分频时钟控制。

发送控制逻辑

  • 控制寄存器CR1中的TE位:使能发送功能。
  • 状态寄存器 (SR)中的TXE中断:当TDR为空时触发,提示CPU或DMA准备下一个数据。

3. 接收器部分

接收移位寄存器

  • 从RX引脚按位接收数据,并将其组合成完整的数据字节。
  • 数据组合完成后传递到接收数据寄存器 (RDR)。

接收数据寄存器 (RDR)

  • 接收的数据存储在RDR中,可通过CPU读取。
  • 数据从RDR读取后,触发RXNE中断,提示CPU完成一次数据接收。

接收控制逻辑

  • 控制寄存器CR1中的RE位:使能接收功能。
  • 状态寄存器 (SR)中的RXNE标志:指示RDR中有新数据可供读取。

4. 控制逻辑模块

中断控制

  • 中断源 (CR1, CR2, CR3)

    • CR1中的TXEIE、RXNEIE等控制发送和接收中断。
    • CR2控制错误中断,如帧错误和过载错误。
    • CR3用于流控中断,如CTS中断。
  • 状态寄存器 (SR)

    • 包括多种标志位,如TXE(发送数据寄存器空)、RXNE(接收数据寄存器非空)和PE(奇偶校验错误)。

5. 时钟生成模块

USART_BRR寄存器

  • 波特率寄存器,用于配置发送和接收的波特率。
  • 波特率计算公式:
    其中,DIV_Mantissa表示整数部分,DIV_Fraction表示小数部分。
  • 波特率由系统时钟提供,并通过分频器(/16)生成。

6. 模式配置模块

CR1、CR2、CR3寄存器

  • CR1:基本功能配置,例如使能USART、发送、接收等。
  • CR2:帧格式设置(停止位长度、时钟使能)。
  • CR3:高级功能,例如DMA支持、流控和红外功能。

7. DMA支持

  • 支持通过DMA直接操作TDR和RDR寄存器,减轻CPU负担。
  • DMA触发器:根据TXE(发送)和RXNE(接收)状态,触发DMA完成数据传输。

8. 数据传递路径

  1. 发送路径
    • CPU/DMA将数据写入TDR。
    • 数据进入发送移位寄存器。
    • 移位寄存器按照波特率逐位发送到TX引脚。
  1. 接收路径
    • RX引脚接收到串行数据。
    • 数据进入接收移位寄存器,组合成数据字节。
    • 数据传递至RDR,等待CPU读取。

2.3 基本机构图

注意:无论是发送还是接收,数据都是低位先行。

2.4 数据帧

字长设置:

在时钟的上升沿进行数据的读取。对于9位字长,一般第9位会选择为校验位,毕竟前面8位刚好就是1字节,uint8。同理对于8位字长的数据,一般最后一位不选择为校验位。


停止位配置:

stm32的停止位可以配置停止位长度为0.5、1、1.5、2,就是停止位是时长不同。


起始位侦测采样:

对于输入的数据,要对其进行采用,最后就时钟的上升沿采用的时候刚好对于数据位的正中间,防止因为一些噪声等导致数据位有波形,造成采洋不准。

而为了实现这部分的功能,输入的这部分电路对采样时钟进行了细分,会以波特率的16倍频率进行采样(即在一位的时间里可以对一位的数据进行16次采样)。

而上图就是对起始位进行16次的采样,出现下降沿时,采样采到0,而后面还会继续采样,防止下降沿是因为某些抖动而导致的,并不是代表起始位。当在每3次采样里至少有2个0,就代表这个位确实是起始位。


数据采样:

这部分就是前面提到的,为了保证数据的正确,尽量在数据位的中间对该为数据进行采样。

2.5 波特率发生器

发送器和接收器的波特率由波特率寄存器BRR里的DIV确定

计算公式:波特率 = fPCLK2/1 / (16 * DIV)

为什么还要除以16???上面讲解数据采样的时候有说过,一位数据的采样次数是16次,也就是16个时钟的时间。因此 fPCLK2/1 /DIV取到的波特率还得除以16,才是实际上每秒传输码元的个数。

就当成时钟频率去理解就行,1位数据需要16个时钟,DIV分频后的时钟频率还得再去除以16,做到和每一位的数据相对应。

2.6 数据包

把多个字节(数据帧)给打包一起发送

2.6.1 数据模式

HEX模式/十六进制模式/二进制模式:以原始数据的形式显示

文本模式/字符模式:以原始数据编码后的形式显示

2.6.2 HEX数据包

这种为了避免载荷数据和包头包尾出现数据重复的现象,可以使用载荷数据限制大小、载荷数据限制长度和增加包头包尾的数量来解决。

至于可变包长,更适合载荷数据不会和包头包尾数据重复的情况下使用。

2.6.3 文本数据包

2.6.4 HEX数据包接收

2.6.5 文本数据包接收

3.结构体和相关API

3.1 结构体

c 复制代码
typedef struct
{
  uint32_t USART_BaudRate;            /*!< This member configures the USART communication baud rate.
                                           The baud rate is computed using the following formula:
                                            - IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))
                                            - FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5 */

  uint16_t USART_WordLength;          /*!< Specifies the number of data bits transmitted or received in a frame.
                                           This parameter can be a value of @ref USART_Word_Length */

  uint16_t USART_StopBits;            /*!< Specifies the number of stop bits transmitted.
                                           This parameter can be a value of @ref USART_Stop_Bits */

  uint16_t USART_Parity;              /*!< Specifies the parity mode.
                                           This parameter can be a value of @ref USART_Parity
                                           @note When parity is enabled, the computed parity is inserted
                                                 at the MSB position of the transmitted data (9th bit when
                                                 the word length is set to 9 data bits; 8th bit when the
                                                 word length is set to 8 data bits). */
 
  uint16_t USART_Mode;                /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.
                                           This parameter can be a value of @ref USART_Mode */

  uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled
                                           or disabled.
                                           This parameter can be a value of @ref USART_Hardware_Flow_Control */
} USART_InitTypeDef;

\1. USART_BaudRate

  • 作用:配置USART通信的波特率(每秒比特传输速率)。

  • 计算公式

    • PCLKx 是外设时钟频率。
    • BaudRate 是配置的波特率。
    • 波特率寄存器 USART_BRR 的整数部分由 USARTDIV 的整数值构成,小数部分由其余值通过四舍五入计算得出。
  • 取值范围 :常用波特率值(如 9600, 19200, 38400, 115200 等)。实际取值需确保 PCLKx 能支持目标波特率。


\2. USART_WordLength

  • 作用:指定每帧传输或接收的数据位数(包括有效数据位和可选的校验位)。

  • 可取值

    • USART_WordLength_8b:8位数据帧(默认)。
    • USART_WordLength_9b:9位数据帧(通常用于特殊协议或需要扩展数据位时)。
  • 注意

    • 如果使用奇偶校验,帧中最高位(第8或第9位)被用作校验位。

\3. USART_StopBits

  • 作用:设置每帧发送结束时的停止位数,用于标识帧结束。

  • 可取值

    • USART_StopBits_1:1个停止位(默认)。
    • USART_StopBits_0.5:0.5个停止位。
    • USART_StopBits_2:2个停止位(用于慢速通信或特定协议)。
    • USART_StopBits_1.5:1.5个停止位(特定场景)。
  • 注意:停止位设置需与接收设备保持一致。


\4. USART_Parity

  • 作用:配置是否启用奇偶校验以及校验模式(奇校验或偶校验)。

  • 可取值

    • USART_Parity_No:无校验(默认)。
    • USART_Parity_Even:偶校验。
    • USART_Parity_Odd:奇校验。
  • 注意

    • 启用校验后,帧中最高有效位会被占用,用于传输校验位。
    • 校验位由硬件自动生成,无需用户干预。

\5. USART_Mode

  • 作用:指定USART的工作模式(发送、接收或两者均启用)。

  • 可取值

    • USART_Mode_Rx:仅接收模式。
    • USART_Mode_Tx:仅发送模式。
    • USART_Mode_Tx_Rx:同时启用发送和接收模式。
  • 典型应用

    • 仅接收模式常用于传感器数据读取。
    • 同时启用发送和接收模式适用于双向通信(如UART调试、RS232通信等)。

\6. USART_HardwareFlowControl

  • 作用:设置硬件流控制模式,用于控制数据流的启停(基于RTS和CTS信号)。

  • 可取值

    • USART_HardwareFlowControl_None:无硬件流控(默认)。
    • USART_HardwareFlowControl_RTS:仅启用RTS流控(发送设备请求发送时使能)。
    • USART_HardwareFlowControl_CTS:仅启用CTS流控(接收设备允许发送时使能)。
    • USART_HardwareFlowControl_RTS_CTS:同时启用RTS和CTS流控。
  • 注意:硬件流控适用于需要精确控制数据流的场景,如避免数据溢出或丢失。

3.2 API

3.2.1 初始化相关函数

void USART_DeInit(USART_TypeDef* USARTx)
  • 作用:将指定USART外设的寄存器恢复为默认复位值。
  • 使用场景:在重新配置USART外设之前使用,确保状态清零。
  • 示例
c 复制代码
USART_DeInit(USART1); // 将USART1寄存器重置为默认值
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)
  • 作用 :根据USART_InitTypeDef结构配置USART的波特率、数据位、停止位、校验、工作模式和硬件流控。
  • 使用场景:初始化USART通信。
  • 示例
c 复制代码
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Tx_Rx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

USART_Init(USART1, &USART_InitStructure);
void USART_StructInit(USART_InitTypeDef* USART_InitStruct)
  • 作用 :将USART_InitTypeDef结构初始化为默认值。

  • 默认值

    • 波特率为9600
    • 8位数据帧。
    • 1个停止位。
    • 无校验。
    • 收发模式均启用。
    • 无硬件流控。
  • 示例

c 复制代码
USART_InitTypeDef USART_InitStructure;
USART_StructInit(&USART_InitStructure); // 初始化为默认值
USART_Init(USART1, &USART_InitStructure);

3.2.2 时钟相关函数

void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct)
  • 作用:配置USART同步模式下的时钟设置(如极性、相位等)。
  • 使用场景:仅在同步模式下(如SPI通信)配置时钟信号。
  • 示例
c 复制代码
USART_ClockInitTypeDef USART_ClockInitStructure;
USART_ClockInitStructure.USART_Clock = USART_Clock_Enable;
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA = USART_CPHA_1Edge;
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Enable;

USART_ClockInit(USART1, &USART_ClockInitStructure);
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct)
  • 作用 :将USART_ClockInitTypeDef结构初始化为默认值(同步模式时钟禁用)。
  • 示例
c 复制代码
USART_ClockInitTypeDef USART_ClockInitStructure;
USART_ClockStructInit(&USART_ClockInitStructure);
USART_ClockInit(USART1, &USART_ClockInitStructure);

3.2.3 控制相关函数

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)
  • 作用:使能或禁用USART外设。
  • 示例
c 复制代码
USART_Cmd(USART1, ENABLE); // 启用USART1
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
  • 作用:配置指定的USART中断。

  • 中断类型

    • USART_IT_TXE:发送数据寄存器空中断。
    • USART_IT_RXNE:接收数据寄存器非空中断。
    • USART_IT_PE:奇偶校验错误中断。
  • 示例

c 复制代码
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 启用接收非空中断
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)
  • 作用:使能或禁用USART的DMA请求。

  • 参数

    • USART_DMAReq_Tx:发送数据DMA请求。
    • USART_DMAReq_Rx:接收数据DMA请求。
  • 示例

c 复制代码
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 启用发送DMA

3.2.4 数据收发函数

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
  • 作用:发送一个数据帧。
  • 示例
c 复制代码
USART_SendData(USART1, 'A'); // 发送字符 'A'
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送完成
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
  • 作用:接收一个数据帧。
  • 示例
c 复制代码
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
    uint16_t data = USART_ReceiveData(USART1); // 接收数据
}

3.2.5 状态和中断相关函数

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
  • 作用:获取指定的USART标志状态。

  • 常见标志

    • USART_FLAG_TXE:发送数据寄存器空标志。
    • USART_FLAG_RXNE:接收数据寄存器非空标志。
    • USART_FLAG_ORE:溢出错误标志。
  • 示例

c 复制代码
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
    // 接收到数据
}
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)
  • 作用:清除指定标志位(如溢出错误等)。
  • 示例
c 复制代码
USART_ClearFlag(USART1, USART_FLAG_ORE); // 清除溢出错误标志
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
  • 作用:检查指定中断是否发生。
  • 示例
c 复制代码
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) {
    // 接收非空中断发生
}
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)
  • 作用:清除中断挂起标志。
  • 示例
c 复制代码
USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除接收非空中断挂起标志

4.实验

CH340 USB转串口的原理图

4.1 串口发送

📎9-1 串口发送.zip

User:

Hardware:


其中对于发送数据,仍然要注意的是低位数据开始传送!!!!这里是数据帧字长为8,从低位开始传输,这个其实也不用太在意,因为调用提供的USART_SendData函数的时候内部已经帮我们做好了。

但是当我们要传输数字的时候,需要注意将其每一位数都给拆开然后再挨个传输出去。比如你要发送21(十进制),那么就要先十位的2,在发送个位的1,就是要把每一位数都给转换成一个数据帧,在这里也就是uint8_t:

c 复制代码
/**
  * 函    数:串口发送一个字节
  * 参    数:Byte 要发送的一个字节
  * 返 回 值:无
  */
void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);		//将字节数据写入数据寄存器,写入后USART自动生成时序波形
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	//等待发送完成
	/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}

/**
  * 函    数:次方函数(内部使用)
  * 返 回 值:返回值等于X的Y次方
  */
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;	//设置结果初值为1
	while (Y --)			//执行Y次
	{
		Result *= X;		//将X累乘到结果
	}
	return Result;
}

/**
  * 函    数:串口发送数字
  * 参    数:Number 要发送的数字,范围:0~4294967295
  * 参    数:Length 要发送数字的长度,范围:0~10
  * 返 回 值:无
  */
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)		//根据数字长度遍历数字的每一位
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');	//依次调用Serial_SendByte发送每位数字
	}
}

假设咱们调用了Serial_SendNumber(123,3);123是要传输的十进制的数(uinit32_t),得将每一位都给拆开成一个数据帧,也就是uint8_t a = 1、uint8_t b= 2、uint8_t c= 3,将a、b、c挨个传输。 逐位拆解数字并以 ASCII 码的形式发送。

这时候就可以采用取余的方式获取到低位。参2就是传这个数字的位数,这里是3。

通过调用Serial_Pow函数去对数字的不相关的位数进行去除,比如第一次for时,Serial_Pow传的参2是2,最后返回是100,123/100会得到1(注意是int的形式!!),1%10就可以知道百位数就是1了。其余的位数也是同理。

调用 Serial_SendNumber(123, 3) 的具体过程:

  • 第1次循环(i=0):

    • Serial_Pow(10, 3-0-1) = Serial_Pow(10, 2) = 100
    • 123 / 100 = 11 % 10 = 1,对应字符 '1'
    • 发送 '1'
  • 第2次循环(i=1):

    • Serial_Pow(10, 3-1-1) = Serial_Pow(10, 1) = 10
    • 123 / 10 = 1212 % 10 = 2,对应字符 '2'
    • 发送 '2'
  • 第3次循环(i=2):

    • Serial_Pow(10, 3-2-1) = Serial_Pow(10, 0) = 1
    • 123 / 1 = 123123 % 10 = 3,对应字符 '3'
    • 发送 '3'

4.2 串口发送 + 接收

📎9-2 串口发送+接收.zip

User:

Hardware:

4.3 HEX数据包收发

📎9-3 串口收发HEX数据包.zip

User:

Hardware:


需要注意的是:

32中中断是可以嵌套的。如果在OLED显示数据的时候,中途又发生了中断进行接收数据,对Serial_RxPacket数组进行写入,就可能会导致输出的前一半是上次的数据,后一半是新来的数据。这个需要注意。

但是这种HEX数据包多是用于传感器的各个独立数据、陀螺仪的XYZ数据等,它们相邻的数据包都是具有连续性的,即使相邻数据混在一起了也没啥关系。如果想避免这种问题,可以在中断处理函数中添加一个标志位,在上一个数据发送完后再标志为可以接收。

4.4 文本数据包收发

📎9-4 串口收发文本数据包.zip

User:

Hardware:


当在发送区输入指定的数据包点击发送后,会调用到中断函数USART1_IRQHandler,根据数据包进行解析,将载荷数据放置到全局数组Serial_RxPacket中。然后在main函数中通过strcmp函数去对该数组和对应的指令进行比较,执行相应的操作:

stm32通过Serial_SendString函数将是LED否开启成功的状态通过串口传输到串口助手,会在接收区显示。

5.1 FlyMcu

通过串口给stm32下载程序。

📎FlyMcu程序烧录软件.zip


需要先将设置成:系统存储器模式。

红色是跳线帽地接法,之后记得按一次复位键。

需要注意的是这个烧录软件只支持USART1下的引脚。


打开keil中的工程,编译生成一个.hex文件

之后重新编译一下:

就可以看到串口下载所需要的文件


之后打开烧录助手,进行相关配置,选择.hex文件,开始编程进行烧录即可。


之后将32的跳线帽重新接回主闪存启动模式,点击复位键,就可以看到程序的运行现象。

📎STLINK Utility.zip

相关推荐
森焱森1 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白1 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D2 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术5 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt5 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘5 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang5 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n8 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件
linweidong10 小时前
物联网MQTT协议与实践:从零到精通的硬核指南
物联网·mqtt·websocket·嵌入式·iot·tdengine·工业物联网
Despacito0o11 小时前
ESP32-s3摄像头驱动开发实战:从零搭建实时图像显示系统
人工智能·驱动开发·嵌入式硬件·音视频·嵌入式实时数据库