【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.mzph.cn/diannao/67062.shtml

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

相关文章

Linux简介和环境搭建

Linux 介绍和环境搭建 1、发行版本 Linux 操作系统有多个主流发行版本&#xff0c;每个版本根据不同的目标、特点和使用场景为用户提供了不同的功能和体验。 Ubuntu • 特点&#xff1a;Ubuntu 是最为人熟知的 Linux 发行版之一&#xff0c;强调易用性和用户友好性&#xff…

代码随想录刷题day07|(数组篇)58.区间和

目录 一、数组理论基础 二、前缀和 三、相关算法题目 四、总结 五、待解决问题 一、数组理论基础 数组是存放在连续内存空间上的相同类型数据的集合。 代码随想录 (programmercarl.com) 特点&#xff1a; 1.下标从0开始&#xff0c;内存中地址空间是连续的 2.查询快&…

多模态论文笔记——CLIP

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍这几年AIGC火爆的隐藏功臣&#xff0c;多模态模型&#xff1a;CLIP。 文章目录 CLIP&#xff08;Contrastive Language-Image Pre-training&#xff09…

【论文笔记】SmileSplat:稀疏视角+pose-free+泛化

还是一篇基于dust3r的稀疏视角重建工作&#xff0c;作者联合优化了相机内外参与GS模型&#xff0c;实验结果表明优于noposplat。 abstract 在本文中&#xff0c;提出了一种新颖的可泛化高斯方法 SmileSplat&#xff0c;可以对无约束&#xff08;未标定相机的&#xff09;稀疏多…

Linux学习day2

经过上次我们完成了linux云服务器的安装&#xff0c;今天我们学习一些linux基本指令&#xff0c;是我们使用linux系统的基础 思考&#xff1a;输入指令&#xff0c;让操作系统执行&#xff0c;其实是在做什么呢&#xff1f; Linux环境中&#xff0c;做类似于windows的操作。l…

给DevOps加点料:融入安全性的DevSecOps

从前&#xff0c;安全防护只是特定团队的责任&#xff0c;在开发的最后阶段才会介入。当开发周期长达数月、甚至数年时&#xff0c;这样做没什么问题&#xff1b;但是现在&#xff0c;这种做法现在已经行不通了。 采用 DevOps 可以有效推进快速频繁的开发周期&#xff08;有时…

【2024年华为OD机试】 (B卷,100分)- 座位调整(Java JS PythonC/C++)

一、问题描述 题目描述 疫情期间课堂的座位进行了特殊的调整&#xff0c;不能出现两个同学紧挨着&#xff0c;必须隔至少一个空位。 给你一个整数数组 desk 表示当前座位的占座情况&#xff0c;由若干 0 和 1 组成&#xff0c;其中 0 表示没有占位&#xff0c;1 表示占位。 …

提供的 IP 地址 10.0.0.5 和子网掩码位 /26 来计算相关的网络信息

网络和IP地址计算器 https://www.sojson.com/convert/subnetmask.html提供的 IP 地址 10.0.0.5 和子网掩码位 /26 来计算相关的网络信息。 子网掩码转换 子网掩码 /26 的含义二进制表示:/26 表示前 26 位是网络部分&#xff0c;剩下的 6 位是主机部分。对应的子网掩码为 255…

IMX6U Qt 开发环境

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、交叉编译 1. 安装通用 ARM 交叉编译工具链 2. 安装 Poky 交叉编译工具链 二、编译出厂源码 1. U-boot 2. 内核和模块 3. 编译出厂 Qt GUI 综合 Demo 前言…

【2024年华为OD机试】(B卷,100分)- 找终点 (Java JS PythonC/C++)

一、问题描述 题目描述 给定一个正整数数组&#xff0c;设为 nums&#xff0c;最大为100个成员&#xff0c;求从第一个成员开始&#xff0c;正好走到数组最后一个成员&#xff0c;所使用的最少步骤数。 要求&#xff1a; 第一步必须从第一元素开始&#xff0c;且 1<第一…

RabbitMQ-集群

RabbitMQ集群----主备关系&#xff0c;在运行的时候&#xff0c;如果非主要节点宕机&#xff0c;程序操作 不受影响&#xff1b; 如果主节点宕机了&#xff0c; 程序会中断操作。 而Rabbitmq集群&#xff0c;会马上让没有宕机的节点参选&#xff0c;选出新的主要节点。 程序重试…

postgresql分区表相关问题处理

1.使用pg_cron按日创建分区表&#xff0c;会出现所在数据库对应用户权限不足的问题。 原因是pg_cron运行在postgres数据库中&#xff0c;是用superuser进行执行的&#xff0c;对应的分区表的owner为postgres&#xff0c;所以需要单独授权对表的所有操作权限。不知道直接改变ow…

网络数据链路层以太网协议

网络数据链路层以太网协议 1. 以太网协议介绍 以太网是一个数据链路层协议&#xff0c;数据链路层的作用是用于两个设备&#xff08;同一种数据链路节点&#xff09;之间进行传递。 以太网不是一种具体的网络&#xff0c;而是一种网络技术标准&#xff0c;既包含了数据链路层…

Kotlin 循环语句详解

文章目录 循环类别for-in 循环区间整数区间示例1&#xff1a;正向遍历示例2&#xff1a;反向遍历 示例1&#xff1a;遍历数组示例2&#xff1a;遍历区间示例3&#xff1a;遍历字符串示例4&#xff1a;带索引遍历 while 循环示例&#xff1a;计算阶乘 do-while 循环示例&#xf…

【STM32】HAL库USB实现软件升级DFU的功能操作及配置

【STM32】HAL库USB实现软件升级DFU的功能操作及配置 文章目录 DFUHAL库的DFU配置修改代码添加条件判断和跳转代码段DFU烧录附录&#xff1a;Cortex-M架构的SysTick系统定时器精准延时和MCU位带操作SysTick系统定时器精准延时延时函数阻塞延时非阻塞延时 位带操作位带代码位带宏…

使用WebdriverIO和Appium测试App

1.新建项目 打开Webstorm新建项目 打开终端输入命令 npm init -y npm install wdio/cli allure-commandline --save-dev npx wdio config 然后在终端依次选择如下&#xff1a; 然后在终端输入命令&#xff1a; npm install wdio/local-runnerlatest wdio/mocha-frameworkla…

uniapp小程序开发,配置开启小程序右上角三点的分享功能

直接全局配置一个分享的功能&#xff0c;要不然需要一个一个页面去单独配置就太麻烦了&#xff01;&#xff01;&#xff01; 1.新建一个share.js文件&#xff0c;并配置代码&#xff0c;调用onShareMessage()和onShareTimeline()两个函数。 其中&#xff1a; title&#xff1…

行业案例:高德服务单元化方案和架构实践

目录 为什么要做单元化 高德单元化的特点 高德单元化实践 服务单元化架构 就近接入实现方案 路由表设计 路由计算 服务端数据驱动的单元化场景 总结 系列阅读 为什么要做单元化 单机房资源瓶颈 随着业务体量和服务用户群体的增长,单机房或同城双机房无法支持服…

ip属地什么条件会改变?多角度深入探讨

IP属地&#xff0c;即IP地址的归属地&#xff0c;是互联网上设备连接时的一个关键信息&#xff0c;它通常反映了设备连接互联网时的地理位置。随着社交软件及各大平台推出IP归属地显示功能&#xff0c;IP属地的变化问题逐渐受到广大用户的关注。那么&#xff0c;IP属地在什么条…

【干货】交换网络环路介绍

定义 以太网交换网络中为了提高网络可靠性&#xff0c;通常会采用冗余设备和冗余链路&#xff0c;然而现网中由于组网调整、配置修改、升级割接等原因&#xff0c;经常会造成数据或协议报文环形转发&#xff0c;不可避免的形成环路。如图7-1所示&#xff0c;三台设备两两相连就…