【STM32-学习笔记-7-】USART串口通信

文章目录

  • USART串口通信
    • Ⅰ、硬件电路
    • Ⅱ、常见的电平标准
    • Ⅲ、串口参数及时序
    • Ⅳ、STM32的USART简介
      • 数据帧
      • 起始位侦测
      • 数据采样
      • 波特率发生器
    • Ⅴ、USART函数介绍
    • Ⅵ、USART_InitTypeDef结构体参数
      • 1、USART_BaudRate
      • 2、USART_WordLength
      • 3、USART_StopBits
      • 4、USART_Parity
      • 5、USART_Mode
      • 6、USART_HardwareFlowControl
    • Ⅶ、串口发送数据
      • 可变参数函数,模拟实现printf
    • Ⅷ、串口接收数据(包含发送)
    • Ⅸ、USART收发数据包
      • 1、收发HEX数据包
      • 2、收发文本数据包

USART串口通信

USARTUniversal Synchronous/Asynchronous Receiver/Transmitter,通用同步/异步收发器)是一种用于串行通信的硬件模块,它支持同步(需要SCL时钟线)和异步两种通信模式

Ⅰ、硬件电路

image-20241228154308723

  • TX 为发送端, RX 为接收端
  • 若是设备之间的电平标准不一致时,则需要加上电平转换芯片

Ⅱ、常见的电平标准

  1. TTL电平
    • 供电范围在0~5V
    • 输出:
      • 高电平1大于2.7V
      • 低电平0小于0.5V
    • 输入:
      • 高电平1大于2.0V
      • 低电平0小于0.8V
    • TTL电平输入脚悬空时内部认为是高电平,且TTL电平输出不能驱动CMOS电平输入
  2. CMOS电平
    • 供电范围在3~15V
    • 输出:
      • 高电平1大于4.6V
      • 低电平0小于0.05V
    • 输入:
      • 高电平1大于3.5V
      • 低电平0小于1.5V
  3. LVTTL电平
    • 是TTL的一种低功耗变种,供电电压通常小于等于3.3V
    • 输出:
      • 高电平1大于2.4V
      • 低电平0小于0.4V
    • 输入:
      • 高电平1大于2.0V
      • 低电平0小于0.8V
  4. RS232电平
    • 输出:
      • -5~-15V 输出1
      • +5~+15V 输出0
    • 输入:
      • -3~-15V 输入1
      • +3~+15V 输入0
  5. LVDS电平
    • 低电压差分信号,驱动器由驱动差分线对的电流源组成,电流通常为3.5mA
    • 接收器具有很高的输入阻抗,输入端允许信号上携带的直流偏置电平范围为0.227~2.173V
  6. RS485电平
    • 采用差分传输方式,输出A、B之间的电压差:高电平+2~+6V低电平-2~-6V
  • STM32使用的是TTL电平

Ⅲ、串口参数及时序

  1. 波特率(Baud Rate)
    • 波特率是串口通信中每秒传输的符号数,通常以bps(位/秒)为单位
    • 波特率必须在通信双方之间匹配,否则会导致数据传输错误
  2. 数据位(Data Bits)
    • 数据位是指每个字符中用于传输实际数据的位数
    • 常见的数据位设置有8位
  3. 停止位(Stop Bits)
    • 停止位是在每个字符传输结束后,用于标识字符结束的位数
    • 可以是1位、1.5位或2位停止位
  4. 奇偶校验(Parity)
    • 奇偶校验是一种错误检测机制,通过在数据位后面添加一个校验位来实现
    • 可以设置为无校验(None)、奇校验(Odd)、偶校验(Even)或标记/空格校验(Mark/Space)
  • 波特率:串口通信的速率

  • 起始位:标志一个数据帧的开始,固定为低电平

  • 数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

  • 校验位:用于数据验证,根据数据位计算得来

  • 停止位:用于数据帧间隔,固定为高电平

  • 一个数据帧10位
    • 起始位:1bit
    • 数据位:8bit(1byte)
    • 停止位:1bit

image-20241228160015933

  • 一个数据帧11位
    • 起始位:1bit
    • 数据位:8bit
    • 校验位:1bit
    • 停止位:1bit

image-20241228160032152

  • 实测串口时序

image-20241228160155805

Ⅳ、STM32的USART简介

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

  • 自带波特率发生器,最高达4.5Mbits/s(可据此配置通讯的波特率

  • 可配置数据位长度(无校验位8bit,有校验位9bit)、停止位长度(0.5/1/1.5/2 确定了帧的间隔

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

  • 支持同步模式(有时钟CLK输出)、硬件流控制(可控的发送和接收数据)、DMA(串口支持DMA转运数据)、智能卡、IrDA、LIN

  • STM32F103C8T6 USART资源: USART1(挂载在上APB2总线上)、 USART(APB1)、 USART3(APB1

image-20241229145512719

  • 流控:
    • nCTS: 清除发送,若是高电平,在当前数据传输结束时阻断下一次的数据发送(判断对方是否准备好接收数据
    • nRTS: 发送请求,若是低电平,表明USART准备好接收数据(告诉对方自己是否准备好接收数据

image-20241229152925780

  • TXERXNE 是判断发送状态和接收状态的重要标志位

image-20241229165609863

  • TDRRDR都是通过DR寄存器来实现其功能

数据帧

image-20241229170041255

image-20241229172307272

起始位侦测

image-20241229172941339

数据采样

image-20241229173342805

  • 进行三次数据采样,增加容错
  • 采样时钟是波特率的16倍

波特率发生器

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

  • 计算公式:

    • 波特率 = f P C L K 2 / 1 16 ∗ D I V 波特率 = \frac{f_{PCLK2/1} }{16 * DIV} 波特率=16DIVfPCLK2/1

    • 解释:PCLK1或PLCK2的时钟频率除以16倍的DIV

image-20241229174442754

  • DIV分为整数部分(12bit)和小数部分(4bit),整数部分高位补0,小数部分低位补0

Ⅴ、USART函数介绍

// 重置指定的USART为默认值
void USART_DeInit(USART_TypeDef* USARTx);// 初始化指定的USART,根据初始化结构体配置参数
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
// 初始化USART初始化结构体的默认值
void USART_StructInit(USART_InitTypeDef* USART_InitStruct);
// 初始化指定的USART时钟,根据时钟初始化结构体配置参数
void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);
// 初始化USART时钟初始化结构体的默认值
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct);// 开启或关闭指定的USART
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);// 开启或关闭USART的中断
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);// 开启或关闭USART的DMA请求
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);// 设置USART地址
void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address);// 配置USART唤醒模式
void USART_WakeUpConfig(USART_TypeDef* USARTx, uint16_t USART_WakeUp);// 开启或关闭USART接收器唤醒功能
void USART_ReceiverWakeUpCmd(USART_TypeDef* USARTx, FunctionalState NewState);// 配置USART LIN断裂检测长度
void USART_LINBreakDetectLengthConfig(USART_TypeDef* USARTx, uint16_t USART_LINBreakDetectLength);// 开启或关闭USART LIN模式
void USART_LINCmd(USART_TypeDef* USARTx, FunctionalState NewState);// 通过USART发送数据
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
// 通过USART接收数据
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);// 发送USART断点信号
void USART_SendBreak(USART_TypeDef* USARTx);// 设置USART保护时间
void USART_SetGuardTime(USART_TypeDef* USARTx, uint8_t USART_GuardTime);// 设置USART预分频器
void USART_SetPrescaler(USART_TypeDef* USARTx, uint8_t USART_Prescaler);// 开启或关闭USART智能卡模式
void USART_SmartCardCmd(USART_TypeDef* USARTx, FunctionalState NewState);
// 开启或关闭USART智能卡NACK应答
void USART_SmartCardNACKCmd(USART_TypeDef* USARTx, FunctionalState NewState);
// 开启或关闭USART半双工模式
void USART_HalfDuplexCmd(USART_TypeDef* USARTx, FunctionalState NewState);// 开启或关闭USART 8位过采样模式
void USART_OverSampling8Cmd(USART_TypeDef* USARTx, FunctionalState NewState);// 开启或关闭USART单线方法
void USART_OneBitMethodCmd(USART_TypeDef* USARTx, FunctionalState NewState);// 配置USART IrDA模式
void USART_IrDAConfig(USART_TypeDef* USARTx, uint16_t USART_IrDAMode);// 开启或关闭USART IrDA模式
void USART_IrDACmd(USART_TypeDef* USARTx, FunctionalState NewState);// 获取USART标志状态
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
// 清除USART标志
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);// 获取USART中断状态
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
// 清除USART中断待处理位
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

Ⅵ、USART_InitTypeDef结构体参数

成员名称描述
uint32_t USART_BaudRateUSART通信波特率,使用公式计算:IntegerDivider = ((PCLKx) / (16 * USART_BaudRate))
uint16_t USART_WordLength指定每帧传输或接收的数据位数量,可以是8位、9位等,取决于@ref USART_Word_Length
uint16_t USART_StopBits指定传输的停止位数量,可以是1位或2位,取决于@ref USART_Stop_Bits
uint16_t USART_Parity指定奇偶校验模式,包括奇校验、偶校验或无校验,取决于@ref USART_Parity
uint16_t USART_Mode指定是否启用接收或发送模式,取决于@ref USART_Mode
uint16_t USART_HardwareFlowControl指定是否启用硬件流控制模式,如RTS/CTS,取决于@ref USART_Hardware_Flow_Control成员名称

1、USART_BaudRate

  • 类型uint32_t(无符号32位整数)
  • 用途配置USART通信的波特率
  • 说明:通过设置这个成员,可以定义USART通信的速率,即每秒传输的比特数。波特率的计算涉及到外设时钟频率(PCLKx)和这个成员的值。计算公式如前所述,用于确定整数除数和分数除数,以设置USART的时钟分频,确保正确的波特率

2、USART_WordLength

  • 类型uint16_t(无符号16位整数)

  • 用途指定每帧传输或接收的数据位数量

  • 说明:这个参数决定了数据帧中数据位的长度。它可以是8位、9位等,具体值取决于@ref USART_Word_Length枚举

    • @ref USART_Word_Length:

    • 配置USART(通用同步/异步收发传输器)的数据位长度

      宏定义

      1. USART_WordLength_8b
        • ((uint16_t)0x0000)
        • 描述:定义了一个8位数据长度的宏。当USART配置为8位数据长度时,每个数据帧包含8个数据位
      2. USART_WordLength_9b
        • ((uint16_t)0x1000)
        • 描述:定义了一个9位数据长度的宏。当USART配置为9位数据长度时,每个数据帧包含9个数据位

      宏函数

      1. IS_USART_WORD_LENGTH(LENGTH)
        • 描述:这是一个宏函数,用于检查给定的数据位长度是否有效
        • 参数LENGTH,代表USART的数据位长度
        • 功能:检查LENGTH是否等于USART_WordLength_8bUSART_WordLength_9b
        • 返回值:如果LENGTH有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      USART_WordLength_8b0x00008位数据长度
      USART_WordLength_9b0x10009位数据长度
      宏函数描述
      IS_USART_WORD_LENGTH(LENGTH)检查LENGTH是否为有效的USART数据位长度

3、USART_StopBits

  • 类型uint16_t(无符号16位整数)

  • 用途指定传输的停止位数量

  • 说明:这个参数定义了在数据帧结束后传输的停止位的数量,可以是1位或2位,具体值取决于@ref USART_Stop_Bits枚举

    • @ref USART_Stop_Bits:

    • 定义了USART(通用同步/异步收发传输器)的停止位配置

      宏定义

      1. USART_StopBits_1
        • ((uint16_t)0x0000)
        • 描述:定义了一个1个停止位的宏。在USART通信中,1个停止位是最常见的配置
      2. USART_StopBits_0_5
        • ((uint16_t)0x1000)
        • 描述:定义了0.5个停止位的宏。这种配置不常见,主要用于某些特定的通信协议
      3. USART_StopBits_2
        • ((uint16_t)0x2000)
        • 描述:定义了2个停止位的宏。这种配置用于提高数据传输的可靠性,特别是在噪声较大的通信环境中
      4. USART_StopBits_1_5
        • ((uint16_t)0x3000)
        • 描述:定义了1.5个停止位的宏。这种配置同样不常见,主要用于某些特定的通信协议

      宏函数

      1. IS_USART_STOPBITS(STOPBITS)
        • 描述:这是一个宏函数,用于检查给定的停止位设置是否有效
        • 参数STOPBITS,代表USART的停止位设置
        • 功能:检查STOPBITS是否等于USART_StopBits_1USART_StopBits_0_5USART_StopBits_2USART_StopBits_1_5中的任一个
        • 返回值:如果STOPBITS有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      USART_StopBits_10x00001个停止位
      USART_StopBits_0_50x10000.5个停止位
      USART_StopBits_20x20002个停止位
      USART_StopBits_1_50x30001.5个停止位
      宏函数描述
      IS_USART_STOPBITS(STOPBITS)检查STOPBITS是否为有效的USART停止位设置

4、USART_Parity

  • 类型uint16_t(无符号16位整数)

  • 用途指定奇偶校验模式

  • 说明:这个参数决定了是否启用奇偶校验,以及使用哪种类型的校验(奇校验、偶校验或无校验)。当启用校验时,计算出的校验位会被插入到传输数据的最高有效位(MSB)位置。具体值取决于@ref USART_Parity枚举

    • @ref USART_Parity:

    • 定义了USART(通用同步/异步收发传输器)的奇偶校验配置

      宏定义

      1. USART_Parity_No
        • ((uint16_t)0x0000)
        • 描述:定义了一个无奇偶校验的宏。当设置为无奇偶校验时,USART通信不包含校验位
      2. USART_Parity_Even
        • ((uint16_t)0x0400)
        • 描述:定义了一个偶校验的宏。当设置为偶校验时,USART通信中的数据帧会包含一个校验位,使得数据位加上校验位的总和为偶数
      3. USART_Parity_Odd
        • ((uint16_t)0x0600)
        • 描述:定义了一个奇校验的宏。当设置为奇校验时,USART通信中的数据帧会包含一个校验位,使得数据位加上校验位的总和为奇数

      宏函数

      1. IS_USART_PARITY(PARITY)
        • 描述:这是一个宏函数,用于检查给定的奇偶校验设置是否有效
        • 参数PARITY,代表USART的奇偶校验设置
        • 功能:检查PARITY是否等于USART_Parity_NoUSART_Parity_EvenUSART_Parity_Odd中的任一个
        • 返回值:如果PARITY有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      USART_Parity_No0x0000无奇偶校验
      USART_Parity_Even0x0400偶校验
      USART_Parity_Odd0x0600奇校验
      宏函数描述
      IS_USART_PARITY(PARITY)检查PARITY是否为有效的USART奇偶校验设置

5、USART_Mode

  • 类型uint16_t(无符号16位整数)

  • 用途指定是否启用接收或发送模式

  • 说明:这个参数决定了USART是处于接收模式、发送模式,还是两者都启用。具体值取决于@ref USART_Mode枚举

    • @ref USART_Mode:

    • 定义了USART(通用同步/异步收发传输器)的工作模式

      宏定义

      1. USART_Mode_Rx
        • ((uint16_t)0x0004)
        • 描述:定义了一个仅接收模式的宏。当设置为仅接收模式时,USART仅用于接收数据
      2. USART_Mode_Tx
        • ((uint16_t)0x0008)
        • 描述:定义了一个仅发送模式的宏。当设置为仅发送模式时,USART仅用于发送数据

      宏函数

      1. IS_USART_MODE(MODE)
        • 描述:这是一个宏函数,用于检查给定的工作模式设置是否有效
        • 参数MODE,代表USART的工作模式设置
        • 功能:检查MODE是否为有效的接收模式、发送模式或两者的组合(即接收和发送模式)。它通过与0xFFF3进行按位与操作来确保只有接收和发送模式位被设置,其他位应为0。同时,也检查MODE不为0,因为0表示没有启用任何模式
        • 返回值:如果MODE有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      USART_Mode_Rx0x0004仅接收模式
      USART_Mode_Tx0x0008仅发送模式
      宏函数描述
      IS_USART_MODE(MODE)检查MODE是否为有效的USART工作模式设置

6、USART_HardwareFlowControl

  • 类型uint16_t(无符号16位整数)

  • 用途指定是否启用硬件流控制模式

  • 说明:硬件流控制用于控制数据的传输速率,以防止接收器溢出。这个参数决定了是否启用硬件流控制,如RTS/CTS(请求发送/清除发送)。具体值取决于@ref USART_Hardware_Flow_Control枚举

    • @ref USART_Hardware_Flow_Control:

    • 定义了USART(通用同步/异步收发传输器)的硬件流控制配置

      宏定义解释

      1. USART_HardwareFlowControl_None
        • ((uint16_t)0x0000)
        • 描述:定义了一个无硬件流控制的宏。当设置为无硬件流控制时,USART通信不使用任何硬件流控制信号
      2. USART_HardwareFlowControl_RTS
        • ((uint16_t)0x0100)
        • 描述:定义了一个仅使用请求发送(RTS)信号的硬件流控制宏。RTS信号用于通知接收设备是否准备好接收数据
      3. USART_HardwareFlowControl_CTS
        • ((uint16_t)0x0200)
        • 描述:定义了一个仅使用清除发送(CTS)信号的硬件流控制宏。CTS信号用于通知发送设备是否应该开始发送数据
      4. USART_HardwareFlowControl_RTS_CTS
        • ((uint16_t)0x0300)
        • 描述:定义了一个同时使用RTS和CTS信号的硬件流控制宏。这种配置提供了双向的硬件流控制,以确保数据传输的同步和可靠性

      宏函数

      1. IS_USART_HARDWARE_FLOW_CONTROL(CONTROL)
        • 描述:这是一个宏函数,用于检查给定的硬件流控制设置是否有效
        • 参数CONTROL,代表USART的硬件流控制设置
        • 功能:检查CONTROL是否等于USART_HardwareFlowControl_NoneUSART_HardwareFlowControl_RTSUSART_HardwareFlowControl_CTSUSART_HardwareFlowControl_RTS_CTS中的任一个
        • 返回值:如果CONTROL有效,返回1(真),否则返回0(假)

      表格:

      宏定义描述
      USART_HardwareFlowControl_None0x0000无硬件流控制
      USART_HardwareFlowControl_RTS0x0100使用RTS硬件流控制
      USART_HardwareFlowControl_CTS0x0200使用CTS硬件流控制
      USART_HardwareFlowControl_RTS_CTS0x0300同时使用RTS和CTS硬件流控制
      宏函数描述
      IS_USART_HARDWARE_FLOW_CONTROL(CONTROL)检查CONTROL是否为有效的USART硬件流控制设置

Ⅶ、串口发送数据

#include "stm32f10x.h"                  // Device header
#include <stdio.h>	//为了移植printf
//USART串口
//TX-->PA9void Serial_Init(void)
{//使能GPIO和USART时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//初始化GPIOGPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;GPIO_Init(GPIOA, &GPIO_InitStruct);//配置USARTUSART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 9600;//配置波特率USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//是否选择硬件流控USART_InitStruct.USART_Mode = USART_Mode_Tx;//仅发送模式USART_InitStruct.USART_Parity = USART_Parity_No;//无校验USART_InitStruct.USART_StopBits = USART_StopBits_1;//1个停止位USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据帧包含8个数据位USART_Init(USART1, &USART_InitStruct);//初始化USATR1USART_Cmd(USART1, ENABLE);//开启USART串口通信
}//发送一个字节
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte);//发送一个字节//获取USART标志状态(等待)传输数据寄存器空标志while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}/*************************************************************************************** 名称		Serial_SendArray* 功能		通过串口发送数组* 参数		uint16_t* Arr数组指针* 参数		uint16_t Length数组长度* 返回值	无*****************************/
void Serial_SendArray(uint8_t* Arr, uint16_t Length)
{uint16_t i = 0;for(i = 0;i<Length;i++){Serial_SendByte(Arr[i]);}
}/*************************************************************************************** 名称		Serial_SendString* 功能		通过串口发送字符串* 参数		char* String("xxxxxxx")* 返回值	无*****************************/
void Serial_SendString(char* String)
{while(*String != '\0'){Serial_SendByte(*String);String++;}
}//返回num的SQ次方(内部函数)
static uint32_t Serial_GetSquare(const int num, int SQ)
{uint32_t ret = 1;while(SQ--)ret *= num;return ret;
}
/*************************************************************************************** 名称		Serial_SendNum* 功能		通过串口发送数字* 参数		数字,及数字长* 返回值	无*****************************/
void Serial_SendNum(uint32_t Num, uint8_t Length)
{uint8_t i = 0;for(i = 0; i < Length; i++){Serial_SendByte((Num / Serial_GetSquare(10, Length - i - 1) % 10) + '0');//'\0'是为了偏移,可将数字转换为其对应的ASCII字符}
}//重定向printf,须勾选魔法棒中的Use MicroLlB
int fputc(int ch, FILE *stream)
{Serial_SendByte(ch);return ch;
}

可变参数函数,模拟实现printf

#include <stdarg.h>void Serial_Printf(char* format, ...)
{char String[200];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_SendString(String);
}

Ⅷ、串口接收数据(包含发送)

#include "stm32f10x.h"                  // Device header
#include <stdio.h>	//为了移植printf
//USART串口
//TX-->PA9
//RX-->PA10uint8_t Serial_RxData = 0;//接收的数据
uint8_t Serial_RxFlag = 0;//标志位void Serial_Init(void)
{//使能GPIO和USART时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//初始化发送GPIOGPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;GPIO_Init(GPIOA, &GPIO_InitStruct);//初始化接收GPIOGPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOA, &GPIO_InitStruct);//配置USARTUSART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 9600;//配置波特率USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//是否选择硬件流控USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送+接收模式USART_InitStruct.USART_Parity = USART_Parity_No;//无校验USART_InitStruct.USART_StopBits = USART_StopBits_1;//1个停止位USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据帧包含8个数据位USART_Init(USART1, &USART_InitStruct);//初始化USATR1//开启USART的中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//设置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置嵌套向量中断控制器(NVIC)的优先级分组NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;//选择IRQ通道NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//启用这个IRQ通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//设置抢占优先级为1NVIC_InitStruct.NVIC_IRQChannelSubPriority  = 1;//设置响应优先级为1NVIC_Init(&NVIC_InitStruct);	USART_Cmd(USART1, ENABLE);//开启USART串口通信
}//发送一个字节
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte);//发送一个字节//获取USART标志状态(等待)传输数据寄存器空标志while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}/*************************************************************************************** 名称		Serial_SendArray* 功能		通过串口发送数组* 参数		uint16_t* Arr数组指针* 参数		uint16_t Length数组长度* 返回值	无*****************************/
void Serial_SendArray(uint8_t* Arr, uint16_t Length)
{uint16_t i = 0;for(i = 0;i<Length;i++){Serial_SendByte(Arr[i]);}
}/*************************************************************************************** 名称		Serial_SendString* 功能		通过串口发送字符串* 参数		char* String("xxxxxxx")* 返回值	无*****************************/
void Serial_SendString(char* String)
{while(*String != '\0'){Serial_SendByte(*String);String++;}
}//返回num的SQ次方(内部函数)
static uint32_t Serial_GetSquare(const int num, int SQ)
{uint32_t ret = 1;while(SQ--)ret *= num;return ret;
}
/*************************************************************************************** 名称		Serial_SendNum* 功能		通过串口发送数字* 参数		数字,及数字长* 返回值	无*****************************/
void Serial_SendNum(uint32_t Num, uint8_t Length)
{uint8_t i = 0;for(i = 0; i < Length; i++){Serial_SendByte((Num / Serial_GetSquare(10, Length - i - 1) % 10) + '0');//'\0'是为了偏移,可将数字转换为其对应的ASCII字符}
}//重定向printf,须勾选魔法棒中的Use MicroLlB
int fputc(int ch, FILE *stream)
{Serial_SendByte(ch);return ch;
}
//**********************************************************************************
uint8_t Serial_GetFlag(void)//获取标志
{if(Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}uint8_t Serial_GetData(void)//获取数据
{return Serial_RxData;
}//中断函数
void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//判断中断标志位{Serial_RxData = USART_ReceiveData(USART1);Serial_RxFlag = 1;USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}

Ⅸ、USART收发数据包

1、收发HEX数据包

包头:FF

包尾:FE

image-20250102193414382

image-20250102193525005

含包头包尾固定包长的数据包
uint8_t Serial_RxPacketFlag = 0;//数据包标志位uint8_t Serial_RxPacket[4] = { 0 };//接收数据包的缓冲数组...
...
//**********************************************************************************
uint8_t Serial_GetPacketFlag(void)//获取数据包标志
{if(Serial_RxPacketFlag == 1){Serial_RxPacketFlag = 0;return 1;}return 0;
}/*************************************************************************************** 名称		Serial_SendPacket* 功能		发送数据量为4字节的HEX数据包* 参数		Serial_RxPacket_4bt* 返回值	无*****************************/
void Serial_SendPacket(uint8_t* Serial_RxPacket_4bt)
{Serial_SendByte(0xFF);//发送包头Serial_SendArray(Serial_RxPacket_4bt, 4);//发送数据Serial_SendByte(0xFE);//发送包尾
}//中断函数
void USART1_IRQHandler(void)
{static uint8_t RxState = 0;//初始化状态static uint8_t Count = 0;//记录接收数据的个数if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//判断中断标志位{uint8_t RxData = USART_ReceiveData(USART1);//获取数据if(RxState == 0)//等待包头{if(RxData == 0xFF)//接收到包头{RxState = 1;//转移至状态1Count = 0;}}else if(RxState == 1)//接收数据{Serial_RxPacket[Count] = RxData;Count++;if(Count >= 4){RxState = 2;//转移至状态2Count = 0;//状态清零}}else if(RxState == 2)//等待包尾{if(RxData == 0xFE)//接收到包尾{RxState = 0;//转移至状态0Serial_RxPacketFlag = 1;//接收到数据包表标志位}			}USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}

2、收发文本数据包

包头:@

包尾:换行符

image-20250103161415797

image-20250103161500805

含包头包尾固定包长的数据包
#include "stm32f10x.h"                  // Device header
#include <stdio.h>	//为了移植printf
//USART串口
//TX-->PA9
//RX-->PA10#define RxPacket_Length_MAX 200	//接收文本数据包的最大长度
uint8_t Serial_RxPacketFlag = 0;//数据包标志位//需要手动清零char Serial_RxPacket[RxPacket_Length_MAX] = { 0 };//接收文本数据包的缓冲数组void Serial_Init(void)
{//使能GPIO和USART时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//初始化发送GPIOGPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;GPIO_Init(GPIOA, &GPIO_InitStruct);//初始化接收GPIOGPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOA, &GPIO_InitStruct);//配置USARTUSART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate = 9600;//配置波特率USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//是否选择硬件流控USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送+接收模式USART_InitStruct.USART_Parity = USART_Parity_No;//无校验USART_InitStruct.USART_StopBits = USART_StopBits_1;//1个停止位USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据帧包含8个数据位USART_Init(USART1, &USART_InitStruct);//初始化USATR1//开启USART的中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//设置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置嵌套向量中断控制器(NVIC)的优先级分组NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;//选择IRQ通道NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//启用这个IRQ通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//设置抢占优先级为1NVIC_InitStruct.NVIC_IRQChannelSubPriority  = 1;//设置响应优先级为1NVIC_Init(&NVIC_InitStruct);	USART_Cmd(USART1, ENABLE);//开启USART串口通信
}//发送一个字节
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte);//发送一个字节//获取USART标志状态(等待)传输数据寄存器空标志while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}/*************************************************************************************** 名称		Serial_SendArray* 功能		通过串口发送数组* 参数		uint16_t* Arr数组指针* 参数		uint16_t Length数组长度* 返回值	无*****************************/
void Serial_SendArray(uint8_t* Arr, uint16_t Length)
{uint16_t i = 0;for(i = 0;i<Length;i++){Serial_SendByte(Arr[i]);}
}/*************************************************************************************** 名称		Serial_SendString* 功能		通过串口发送字符串* 参数		char* String("xxxxxxx")* 返回值	无*****************************/
void Serial_SendString(char* String)
{while(*String != '\0'){Serial_SendByte(*String);String++;}
}//返回num的SQ次方(内部函数)
static uint32_t Serial_GetSquare(const int num, int SQ)
{uint32_t ret = 1;while(SQ--)ret *= num;return ret;
}
/*************************************************************************************** 名称		Serial_SendNum* 功能		通过串口发送数字* 参数		数字,及数字长* 返回值	无*****************************/
void Serial_SendNum(uint32_t Num, uint8_t Length)
{uint8_t i = 0;for(i = 0; i < Length; i++){Serial_SendByte((Num / Serial_GetSquare(10, Length - i - 1) % 10) + '0');//'\0'是为了偏移,可将数字转换为其对应的ASCII字符}
}//重定向printf,须勾选魔法棒中的Use MicroLlB
int fputc(int ch, FILE *stream)
{Serial_SendByte(ch);return ch;
}/*************************************************************************************** 名称		Serial_SendHEXPacket* 功能		发送数据量为4字节的HEX数据包* 参数		Serial_RxPacket_4bt* 返回值	无*****************************/
void Serial_SendHEXPacket(uint8_t* Serial_RxPacket_4bt)
{Serial_SendByte(0xFF);//发送包头Serial_SendArray(Serial_RxPacket_4bt, 4);//发送数据Serial_SendByte(0xFE);//发送包尾
}//中断函数
void USART1_IRQHandler(void)
{static uint8_t RxState = 0;//初始化状态static uint8_t Count = 0;//记录接收数据的个数if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//判断中断标志位{uint8_t RxData = USART_ReceiveData(USART1);//获取数据if(RxState == 0)//等待包头{if(RxData == '@' && Serial_RxPacketFlag == 0)//接收到包头(且防止传输过快导致数据错位){RxState = 1;//转移至状态1Count = 0;}}else if(RxState == 1)//接收数据{if(RxData == '\r')//判断是否是包尾1{RxState = 2;//转移至状态2}else{Serial_RxPacket[Count] = RxData;Count++;}}else if(RxState == 2)//等待包尾{if(RxData == '\n')//接收到包尾2{RxState = 0;//转移至状态0Serial_RxPacket[Count] = '\0';//添加结束标志位				Serial_RxPacketFlag = 1;//接收到数据包标志位}}USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}

.h头文件

#ifndef __SERIAL_H__
#define __SERIAL_H__
#include "stdint.h"extern char Serial_RxPacket[];//接收文本数据包的缓冲数组
extern uint8_t Serial_RxPacketFlag;//数据包标志位//需要手动清零void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t* Arr, uint16_t Length);
void Serial_SendString(char* String);
void Serial_SendNum(uint32_t Num, uint8_t Length);void Serial_SendHEXPacket(uint8_t* Serial_RxPacket_4bt);//发送数据量为4字节的数据包#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/2218.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为深度学习创建PyTorch张量 - 最佳选项

为深度学习创建PyTorch张量 - 最佳选项 正如我们所看到的&#xff0c;PyTorch张量是torch.Tensor​ PyTorch类的实例。张量的抽象概念与PyTorch张量之间的区别在于&#xff0c;PyTorch张量为我们提供了一个可以在代码中操作的具体实现。 在上一篇文章中&#xff0c;我们看到了…

RabbitMQ(四)

SpringBoot整合RabbitMQ SpringBoot整合1、生产者工程①创建module②配置POM③YAML④主启动类⑤测试程序 2、消费者工程①创建module②配置POM③YAML文件内配置&#xff1a; ④主启动类⑤监听器 3、RabbitListener注解属性对比①bindings属性②queues属性 SpringBoot整合 1、生…

项目练习:若依管理系统字典功能-Vue前端部分

文章目录 一、情景说明二、若依Vue相关代码及配置1、utils代码2、components组件3、api接口代码4、Vuex配置5、main.js配置 三、使用方法1、html部分2、js部分 一、情景说明 我们在做web系统的时候&#xff0c;肯定会遇到一些常量选择场景。 比如&#xff0c;性别&#xff1a;…

【 PID 算法 】PID 算法基础

一、简介 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&#xff09;、Differential&#xff08;微分&#xff09;的缩写。也就是说&#xff0c;PID算法是结合这三种环节在一起的。粘一下百度百科中的东西吧。 顾名思义&#xff0c;…

微信小程序原生与 H5 交互方式

在微信小程序中&#xff0c;原生与 H5 页面&#xff08;即 WebView 页面&#xff09;之间的交互通常有以下几种方式&#xff1a; 1. 使用 postMessage 进行通信 微信小程序的 WebView 页面和原生小程序页面可以通过 postMessage 来进行数据传递。 WebView 页面向原生小程序发…

c++领域展开第十二幕——类和对象(STL简介——简单了解STL)超详细!!!!

文章目录 前言STL简介什么是STLSTL的版本STL的六大组件STL的重要性如何学习STL 总结 前言 上篇博客我们了解了初阶的模版函数&#xff0c;以及有关的一些使用方法。 今天我们来了解了解STL库的有关知识 跟我一起上车吧 STL简介 什么是STL STL&#xff1a;是C标准库的重要组成…

音频语言模型与多模态体系结构

音频语言模型与多模态体系结构 多模态模型正在创造语言、视觉和语音等以前独立的研究领域的协同效应。这些模型使用通用架构,将每种模式视为不同的“token”,使它们能够以一种与人类认知非常相似的方式联合建模和理解世界。 ​ ​可以将多模态分为两个主要领域:输入空间(…

HTML中最基本的东西

本文内容的标签&#xff0c;将是看懂HTML的最基本之基本 &#xff0c;是跟您在写文章时候一样内容。一般想掌握极其容易&#xff0c;但是也要懂得如何使用&#xff0c;过目不忘&#xff0c;为手熟尔。才是我们学习的最终目的。其实边看边敲都行&#xff0c;或者是边看边复制粘贴…

LVGL移植高通点阵字库GT30L24A3W

字库芯片: GT30L24A3W MCU:STM32F429 LVGL版本:V8.4 一、实现gt_read_data() 和 r_dat_bat() 请参考下面视频 如何在32位MCU上使用高通点阵字库_哔哩哔哩_bilibili 高通字库使用教程(1)硬件链接与注意事项部分_哔哩哔哩_bilibili 高通字库使用教程(2)SPI底层函数使用_哔哩…

计算机的错误计算(二百一十二)

摘要 利用两个大模型计算 实验表明&#xff0c;两个大模型均进行了中肯的分析。另外&#xff0c;其中一个大模型给出了 Python代码&#xff0c;运行后&#xff0c;结果中有7位错误数字&#xff1b;而一个大模型进行加减运算时出错。 例1. 计算 下面是与一个大模型的对话…

蓝桥与力扣刷题(709 转换成小写字母)

题目&#xff1a;给你一个字符串 s &#xff0c;将该字符串中的大写字母转换成相同的小写字母&#xff0c;返回新的字符串。 示例 1&#xff1a; 输入&#xff1a;s "Hello" 输出&#xff1a;"hello"示例 2&#xff1a; 输入&#xff1a;s "here…

9.7 visual studio 搭建yolov10的onnx的预测(c++)

1.环境配置 在进行onnx预测前&#xff0c;需要搭建的环境如下: 1.opencv环境的配置&#xff0c;可参考博客:9.2 c搭建opencv环境-CSDN博客 2.libtorch环境的配置&#xff0c;可参考博客&#xff1a;9.4 visualStudio 2022 配置 cuda 和 torch (c)-CSDN博客 3.cuda环境的配置…

自建RustDesk服务器

RustDesk服务端 下面的截图是我本地的一个服务器做为演示用&#xff0c;你自行的搭建服务需要该服务器有固定的ip地址 1、通过宝塔面板快速安装 2、点击【安装】后会有一个配置信息&#xff0c;默认即可 3、点击【确认】后会自动安装等待安装完成 4、安装完成后点击【打开…

浅谈云计算15 | 存储可靠性技术(RAID)

存储可靠性技术 一、存储可靠性需求1.1 数据完整性1.2 数据可用性1.3 故障容错性 二、传统RAID技术剖析2.1 RAID 02.2 RAID 12.3 RAID 52.4 RAID 62.5 RAID 10 三、RAID 2.0技术3.1 RAID 2.0技术原理3.1.1 两层虚拟化管理模式3.1.2 数据分布与重构 3.2 RAID 2.0技术优势3.2.1 自…

Android JecPack组件之LifeCycles 使用详解

一、背景 LifeCycle 是一个可以感知宿主生命周期变化的组件。常见的宿主包括 Activity/Fragment、Service 和 Application。LifeCycle 会持有宿主的生命周期状态的信息&#xff0c;当宿主生命周期发生变化时&#xff0c;会通知监听宿主的观察者。 LifeCycle 的出现主要是为了…

Facebook 隐私风波:互联网时代数据安全警钟

在社交媒体飞速发展的今天&#xff0c;个人数据的隐私保护已成为全球关注的焦点。作为全球最大的社交平台之一&#xff0c;Facebook面临的隐私问题&#xff0c;尤其是数据泄露事件&#xff0c;频繁引发公众的广泛讨论。从用户信息被滥用到数据泄漏&#xff0c;Facebook的隐私挑…

candb++ windows11运行报错,找不到mfc140.dll

解决问题记录 mfc140.dll下载 注意&#xff1a;放置位置别搞错了

蓝桥杯备赛:顺序表和单链表相关算法题详解(上)

目录 一.询问学号&#xff08;顺序表&#xff09; 1.题目来源&#xff1a; 2.解析与代码实现&#xff1a; &#xff08;1&#xff09;解析&#xff1a; &#xff08;2&#xff09;代码实现&#xff1a; 二.寄包柜&#xff08;顺序表&#xff09; 1.题目来源&#xff1a; …

uni-app的学习

uni-app 有着跨平台支持、丰富的插件和生态系统、高性能、集成开发工具HBuilderX的配合使用。允许使用者仅通过一套代码发布到多平台使用。 uni-app官网 uni-app 是一个适合开发跨平台移动应用和小程序的框架&#xff0c;能够大幅提高开发效率。 一、了解 1.1 工具准备 从Git…

基于光偏振与光学调制实现白光干涉相移

基于光的偏振特性和一些光学元件对光的调制作用&#xff0c;实现白光干涉中的光学相移原理是一个复杂而精细的过程。以下是对这一原理的详细解释&#xff1a; 一、光的偏振特性 光的偏振是指光波在传播过程中&#xff0c;光矢量的方向和大小有规则变化的现象。圆偏振光的电场…