文章目录
- 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串口通信
USART
(Universal Synchronous/Asynchronous Receiver/Transmitter
,通用同步/异步收发器)是一种用于串行通信的硬件模块,它支持同步(需要SCL时钟线)和异步两种通信模式
Ⅰ、硬件电路
TX
为发送端,RX
为接收端- 若是设备之间的电平标准不一致时,则需要加上电平转换芯片
Ⅱ、常见的电平标准
- TTL电平:
- 供电范围在0~5V
- 输出:
- 高电平1:
大于2.7V
- 低电平0:
小于0.5V
- 输入:
- 高电平1:
大于2.0V
- 低电平0:
小于0.8V
- TTL电平输入脚悬空时内部认为是高电平,且TTL电平输出不能驱动CMOS电平输入
- CMOS电平:
- 供电范围在3~15V
- 输出:
- 高电平1:
大于4.6V
- 低电平0:
小于0.05V
- 输入:
- 高电平1:
大于3.5V
- 低电平0:
小于1.5V
- LVTTL电平:
- 是TTL的一种低功耗变种,供电电压通常小于等于3.3V
- 输出:
- 高电平1:
大于2.4V
- 低电平0:
小于0.4V
- 输入:
- 高电平1:
大于2.0V
- 低电平0:
小于0.8V
- RS232电平:
- 输出:
-5~-15V
输出1+5~+15V
输出0- 输入:
-3~-15V
输入1+3~+15V
输入0- LVDS电平:
- 低电压差分信号,驱动器由驱动差分线对的电流源组成,电流通常为3.5mA
- 接收器具有很高的输入阻抗,输入端允许信号上携带的直流偏置电平范围为0.227~2.173V
- RS485电平:
- 采用差分传输方式,输出A、B之间的电压差:高电平:
+2~+6V
,低电平:-2~-6V
- STM32使用的是TTL电平
Ⅲ、串口参数及时序
- 波特率(Baud Rate):
- 波特率是串口通信中每秒传输的符号数,通常以bps(位/秒)为单位
- 波特率必须在通信双方之间匹配,否则会导致数据传输错误
- 数据位(Data Bits):
- 数据位是指每个字符中用于传输实际数据的位数
- 常见的数据位设置有8位
- 停止位(Stop Bits):
- 停止位是在每个字符传输结束后,用于标识字符结束的位数
- 可以是1位、1.5位或2位停止位
- 奇偶校验(Parity):
- 奇偶校验是一种错误检测机制,通过在数据位后面添加一个校验位来实现
- 可以设置为无校验(None)、奇校验(Odd)、偶校验(Even)或标记/空格校验(Mark/Space)
波特率:串口通信的速率
起始位:标志一个数据帧的开始,固定为低电平
数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行
校验位:用于数据验证,根据数据位计算得来
停止位:用于数据帧间隔,固定为高电平
- 一个数据帧10位
- 起始位:1bit
- 数据位:8bit(1byte)
- 停止位:1bit
- 一个数据帧11位
- 起始位:1bit
- 数据位:8bit
- 校验位:1bit
- 停止位:1bit
- 实测串口时序
Ⅳ、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)
- 流控:
nCTS
: 清除发送,若是高电平,在当前数据传输结束时阻断下一次的数据发送(判断对方是否准备好接收数据)nRTS
: 发送请求,若是低电平,表明USART准备好接收数据(告诉对方自己是否准备好接收数据)
TXE
和RXNE
是判断发送状态和接收状态的重要标志位
TDR
与RDR
都是通过DR
寄存器来实现其功能
数据帧
起始位侦测
数据采样
- 进行三次数据采样,增加容错
- 采样时钟是波特率的16倍
波特率发生器
发送器和接收器的波特率由波特率寄存器BRR里的DIV确定
计算公式:
波特率 = f P C L K 2 / 1 16 ∗ D I V 波特率 = \frac{f_{PCLK2/1} }{16 * DIV} 波特率=16∗DIVfPCLK2/1
解释:PCLK1或PLCK2的时钟频率除以16倍的DIV
- 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_BaudRate | USART通信波特率,使用公式计算: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(通用同步/异步收发传输器)的数据位长度 宏定义
- USART_WordLength_8b
- 值:
((uint16_t)0x0000)
- 描述:定义了一个8位数据长度的宏。当USART配置为8位数据长度时,每个数据帧包含8个数据位
- 值:
- USART_WordLength_9b
- 值:
((uint16_t)0x1000)
- 描述:定义了一个9位数据长度的宏。当USART配置为9位数据长度时,每个数据帧包含9个数据位
- 值:
宏函数
IS_USART_WORD_LENGTH(LENGTH)
- 描述:这是一个宏函数,用于检查给定的数据位长度是否有效
- 参数:
LENGTH
,代表USART的数据位长度 - 功能:检查
LENGTH
是否等于USART_WordLength_8b
或USART_WordLength_9b
- 返回值:如果
LENGTH
有效,返回1
(真),否则返回0
(假)
表格:
宏定义 值 描述 USART_WordLength_8b 0x0000 8位数据长度 USART_WordLength_9b 0x1000 9位数据长度 宏函数 描述 IS_USART_WORD_LENGTH(LENGTH) 检查LENGTH是否为有效的USART数据位长度 - USART_WordLength_8b
-
3、USART_StopBits
-
类型:
uint16_t
(无符号16位整数) -
用途:指定传输的停止位数量
-
说明:这个参数定义了在数据帧结束后传输的停止位的数量,可以是1位或2位,具体值取决于@ref USART_Stop_Bits枚举
-
@ref USART_Stop_Bits:
-
定义了USART(通用同步/异步收发传输器)的停止位配置 宏定义
- USART_StopBits_1
- 值:
((uint16_t)0x0000)
- 描述:定义了一个1个停止位的宏。在USART通信中,1个停止位是最常见的配置
- 值:
- USART_StopBits_0_5
- 值:
((uint16_t)0x1000)
- 描述:定义了0.5个停止位的宏。这种配置不常见,主要用于某些特定的通信协议
- 值:
- USART_StopBits_2
- 值:
((uint16_t)0x2000)
- 描述:定义了2个停止位的宏。这种配置用于提高数据传输的可靠性,特别是在噪声较大的通信环境中
- 值:
- USART_StopBits_1_5
- 值:
((uint16_t)0x3000)
- 描述:定义了1.5个停止位的宏。这种配置同样不常见,主要用于某些特定的通信协议
- 值:
宏函数
IS_USART_STOPBITS(STOPBITS)
- 描述:这是一个宏函数,用于检查给定的停止位设置是否有效
- 参数:
STOPBITS
,代表USART的停止位设置 - 功能:检查
STOPBITS
是否等于USART_StopBits_1
、USART_StopBits_0_5
、USART_StopBits_2
或USART_StopBits_1_5
中的任一个 - 返回值:如果
STOPBITS
有效,返回1
(真),否则返回0
(假)
表格:
宏定义 值 描述 USART_StopBits_1 0x0000 1个停止位 USART_StopBits_0_5 0x1000 0.5个停止位 USART_StopBits_2 0x2000 2个停止位 USART_StopBits_1_5 0x3000 1.5个停止位 宏函数 描述 IS_USART_STOPBITS(STOPBITS) 检查STOPBITS是否为有效的USART停止位设置 - USART_StopBits_1
-
4、USART_Parity
-
类型:
uint16_t
(无符号16位整数) -
用途:指定奇偶校验模式
-
说明:这个参数决定了是否启用奇偶校验,以及使用哪种类型的校验(奇校验、偶校验或无校验)。当启用校验时,计算出的校验位会被插入到传输数据的最高有效位(MSB)位置。具体值取决于@ref USART_Parity枚举
-
@ref USART_Parity:
-
定义了USART(通用同步/异步收发传输器)的奇偶校验配置 宏定义
- USART_Parity_No
- 值:
((uint16_t)0x0000)
- 描述:定义了一个无奇偶校验的宏。当设置为无奇偶校验时,USART通信不包含校验位
- 值:
- USART_Parity_Even
- 值:
((uint16_t)0x0400)
- 描述:定义了一个偶校验的宏。当设置为偶校验时,USART通信中的数据帧会包含一个校验位,使得数据位加上校验位的总和为偶数
- 值:
- USART_Parity_Odd
- 值:
((uint16_t)0x0600)
- 描述:定义了一个奇校验的宏。当设置为奇校验时,USART通信中的数据帧会包含一个校验位,使得数据位加上校验位的总和为奇数
- 值:
宏函数
IS_USART_PARITY(PARITY)
- 描述:这是一个宏函数,用于检查给定的奇偶校验设置是否有效
- 参数:
PARITY
,代表USART的奇偶校验设置 - 功能:检查
PARITY
是否等于USART_Parity_No
、USART_Parity_Even
或USART_Parity_Odd
中的任一个 - 返回值:如果
PARITY
有效,返回1
(真),否则返回0
(假)
表格:
宏定义 值 描述 USART_Parity_No 0x0000 无奇偶校验 USART_Parity_Even 0x0400 偶校验 USART_Parity_Odd 0x0600 奇校验 宏函数 描述 IS_USART_PARITY(PARITY) 检查PARITY是否为有效的USART奇偶校验设置 - USART_Parity_No
-
5、USART_Mode
-
类型:
uint16_t
(无符号16位整数) -
用途:指定是否启用接收或发送模式
-
说明:这个参数决定了USART是处于接收模式、发送模式,还是两者都启用。具体值取决于@ref USART_Mode枚举
-
@ref USART_Mode:
-
定义了USART(通用同步/异步收发传输器)的工作模式 宏定义
- USART_Mode_Rx
- 值:
((uint16_t)0x0004)
- 描述:定义了一个仅接收模式的宏。当设置为仅接收模式时,USART仅用于接收数据
- 值:
- USART_Mode_Tx
- 值:
((uint16_t)0x0008)
- 描述:定义了一个仅发送模式的宏。当设置为仅发送模式时,USART仅用于发送数据
- 值:
宏函数
IS_USART_MODE(MODE)
- 描述:这是一个宏函数,用于检查给定的工作模式设置是否有效
- 参数:
MODE
,代表USART的工作模式设置 - 功能:检查
MODE
是否为有效的接收模式、发送模式或两者的组合(即接收和发送模式)。它通过与0xFFF3
进行按位与操作来确保只有接收和发送模式位被设置,其他位应为0。同时,也检查MODE
不为0,因为0表示没有启用任何模式 - 返回值:如果
MODE
有效,返回1
(真),否则返回0
(假)
表格:
宏定义 值 描述 USART_Mode_Rx 0x0004 仅接收模式 USART_Mode_Tx 0x0008 仅发送模式 宏函数 描述 IS_USART_MODE(MODE) 检查MODE是否为有效的USART工作模式设置 - USART_Mode_Rx
-
6、USART_HardwareFlowControl
-
类型:
uint16_t
(无符号16位整数) -
用途:指定是否启用硬件流控制模式
-
说明:硬件流控制用于控制数据的传输速率,以防止接收器溢出。这个参数决定了是否启用硬件流控制,如RTS/CTS(请求发送/清除发送)。具体值取决于@ref USART_Hardware_Flow_Control枚举
-
@ref USART_Hardware_Flow_Control:
-
定义了USART(通用同步/异步收发传输器)的硬件流控制配置 宏定义解释
- USART_HardwareFlowControl_None
- 值:
((uint16_t)0x0000)
- 描述:定义了一个无硬件流控制的宏。当设置为无硬件流控制时,USART通信不使用任何硬件流控制信号
- 值:
- USART_HardwareFlowControl_RTS
- 值:
((uint16_t)0x0100)
- 描述:定义了一个仅使用请求发送(RTS)信号的硬件流控制宏。RTS信号用于通知接收设备是否准备好接收数据
- 值:
- USART_HardwareFlowControl_CTS
- 值:
((uint16_t)0x0200)
- 描述:定义了一个仅使用清除发送(CTS)信号的硬件流控制宏。CTS信号用于通知发送设备是否应该开始发送数据
- 值:
- USART_HardwareFlowControl_RTS_CTS
- 值:
((uint16_t)0x0300)
- 描述:定义了一个同时使用RTS和CTS信号的硬件流控制宏。这种配置提供了双向的硬件流控制,以确保数据传输的同步和可靠性
- 值:
宏函数
IS_USART_HARDWARE_FLOW_CONTROL(CONTROL)
- 描述:这是一个宏函数,用于检查给定的硬件流控制设置是否有效
- 参数:
CONTROL
,代表USART的硬件流控制设置 - 功能:检查
CONTROL
是否等于USART_HardwareFlowControl_None
、USART_HardwareFlowControl_RTS
、USART_HardwareFlowControl_CTS
或USART_HardwareFlowControl_RTS_CTS
中的任一个 - 返回值:如果
CONTROL
有效,返回1
(真),否则返回0
(假)
表格:
宏定义 值 描述 USART_HardwareFlowControl_None 0x0000 无硬件流控制 USART_HardwareFlowControl_RTS 0x0100 使用RTS硬件流控制 USART_HardwareFlowControl_CTS 0x0200 使用CTS硬件流控制 USART_HardwareFlowControl_RTS_CTS 0x0300 同时使用RTS和CTS硬件流控制 宏函数 描述 IS_USART_HARDWARE_FLOW_CONTROL(CONTROL) 检查CONTROL是否为有效的USART硬件流控制设置 - USART_HardwareFlowControl_None
-
Ⅶ、串口发送数据
#include "stm32f10x.h" // Device header
#include <stdio.h> //为了移植printf
//USART串口
//TX-->PA9
void Serial_Init(void)
{
//使能GPIO和USART时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//初始化GPIO
GPIO_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);
//配置USART
USART_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);//初始化USATR1
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;
}
可变参数函数,模拟实现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-->PA10
uint8_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);
//初始化发送GPIO
GPIO_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);
//初始化接收GPIO
GPIO_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);
//配置USART
USART_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);
//设置NVIC
NVIC_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;//设置抢占优先级为1
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;//设置响应优先级为1
NVIC_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
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;//转移至状态1
Count = 0;
}
}
else if(RxState == 1)//接收数据
{
Serial_RxPacket[Count] = RxData;
Count++;
if(Count >= 4)
{
RxState = 2;//转移至状态2
Count = 0;//状态清零
}
}
else if(RxState == 2)//等待包尾
{
if(RxData == 0xFE)//接收到包尾
{
RxState = 0;//转移至状态0
Serial_RxPacketFlag = 1;//接收到数据包表标志位
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
2、收发文本数据包
包头:
@
包尾:
换行符
#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);
//初始化发送GPIO
GPIO_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);
//初始化接收GPIO
GPIO_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);
//配置USART
USART_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);
//设置NVIC
NVIC_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;//设置抢占优先级为1
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;//设置响应优先级为1
NVIC_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;//转移至状态1
Count = 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;//转移至状态0
Serial_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