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

相关推荐
DIY机器人工房1 小时前
[6-1] TIM定时中断 江协科技学习笔记(45个知识点)
笔记·科技·stm32·单片机·学习
602寝室长3 小时前
RT-THREAD RTC组件中Alarm功能驱动完善
stm32·单片机·rt-thread·rtos
Lester_11013 小时前
嵌入式学习笔记 - 关于单片机的位数
笔记·单片机·学习
又熟了7 小时前
WDG看门狗(独立看门狗和窗口看门狗)
c语言·stm32·单片机·嵌入式硬件
△曉風殘月〆13 小时前
C#串口通信
嵌入式硬件·c#·串口
我不是帅戈17 小时前
STM32+安信可Ai-WB2-12F连接阿里云物联网平台
stm32·物联网·阿里云·云计算·安信可
教练、我想打篮球17 小时前
04 基于 STM32 的时钟展示程序
stm32·单片机·嵌入式硬件
大鱼YY17 小时前
STM32系统定时器以及微秒延时函数分析
stm32·滴答定时器
芯岭技术18 小时前
普冉MS32C001单片机,国产32位单片机,芯片特性和功能介绍
单片机·嵌入式硬件