串口
目录
[3.5.编写代码(默认PA9 PA10)](#3.5.编写代码(默认PA9 PA10))
[3.6.编写代码(重映射PB6 PB7)](#3.6.编写代码(重映射PB6 PB7))
一、通信协议
1.1.串口的概念
通信接口,用来传输数据

Tx:Transmit 数据发送引脚
Rx:Receive 数据接收引脚
1.2.串口的通信协议
1.2.1.通信协议的概念
甲与乙两人之间交流需要使用相同的语言
串口发送方与接收方要使用相同数据格式
这种数据格式也被称为通信协议
1.2.2.传输流程
数据通过导线以高低电平变化的形式传输:
- 空闲状态:串口未传送数据时,线路保持高电平
- 起始信号:空闲状态下,发送方拉低电平启动数据传输
- 接收数据:接收方检测到空闲状态下的低电平后开始接收数据
- 数据传输:高电平表示1,低电平表示0,以字节为单位逐位传输
- 终止信号:发送方恢复高电平结束数据传输

**注:**串口传输是低位先行(LSB First)
**示例1:**通过串口发送十进制数字27
27的原码:0001 1011
低位先行:发送时的顺序为1101 1000

**示例2:**发送字符串"Hello"
ASCII码值:H=0x48 e=0x65 l=0x6c o=0x6f

1.2.3.串口数据帧格式

- 起始位:1位
- 数据位:8~9位
- 校验位:检测数据传输过程中是否出错(数据位的最后一位可以作为校验位)
- 停止位:0.5,1,1.5,2位
八位无校验(常用):

数据位长度:1字节
八位有校验:

数据位长度:不足1字节
九位无校验:

数据位长度:多余1字节
九位有校验(常用):

数据位长度:1字节
1.2.4.校验位的使用方式
**奇校验:**要求数据位有奇数个1
**偶校验:**要求数据位有偶数个1
**示例:**假设采用九位有校验的数据帧格式,校验方式为奇校验

发送方发送85(0101 0101):

**注:**为了确保数据位有奇数个1,发送方需通过校验位补1
接收方:

**注:**检验数据位中是否有奇数个1
- 有奇数个1:传输数据成功
- 无奇数个1:传输数据出错
二、USART模块的使用方法
2.1.USART模块简介

USART模块类似于人的嘴巴与耳朵的结合体
既能通过嘴巴发送信息,又能通过耳朵接收信息
2.2.USART的基本用法

2.2.1.发送数据
向发送数据寄存器写入数据,USART模块将数据以数据帧格式从Tx引脚发送给对侧
**示例:**向发送数据寄存器写入100(0110 0100)
发送数据寄存器存放:
Tx引脚输出:
2.2.2.接收数据
Rx引脚接收对侧发送的数据帧,USART模块将数据解析出来,存入接收数据寄存器
**示例:**从接收数据寄存器读取88(0101 1000)
接收数据寄存器存放:
Rx引脚接收:
2.3.移位寄存器和串并转换

2.3.1.并行传输
多个bit位同时进行传输操作
示例:
- 通过USART模块发送数据时,8位数据同时写入发送数据寄存器
- 通过USART模块接收数据时,8位数据同时存入接收数据寄存器
2.3.2.串行传输
逐个bit位按序进行传输操作
示例:
- 通过Tx引脚以数据帧格式传输时,每个bit位按顺序依次发送
- 通过Rx引脚接收数据时,逐个bit位检测高低电平的变化
2.3.3.并行转串行

2.3.4.串行转并行

2.4.数据帧格式的设置方法
2.4.1.数据帧格式

2.4.2.参数设置方法

通过电路控制数据传输时波形(数据帧)的格式
参数设置:
- 数据位:8、9
- 停止位:0.5、1、1.5、2
- 校验方式:奇、偶、无
2.5.波特率的设置方法

**波特率:**每秒钟最多传输多少位
**常用的波特率:**9600、115200、921600
**示例:**输入时钟频率为72MHz,通过电路,产生115200的波特率

将波特率寄存器的值设置为x,即分频器的分配系数为x
列出方程:72MHz ÷ x ÷ 16 = 115200,解得x的值等于39.0625
将x的值以二进制的形式(0000 0010 0111 0001)存入波特率寄存器
2.6.编程接口
2.6.1.USART编程接口
cpp
void USART_Init(USARTTypeDef* USARTx, USART_InitTypeDef* USART_InistStruct);
解析:
- 参数1:设置串口名称
- 参数2:初始化的参数结构体地址
作用: 初始化串口,配置串口的各种参数
- 串口的波特率
- 串口的数据位长度
- 串口的停止位长度
- 串口的校验方式
- 串口的数据收发方向
**补充:**USART_InitTypeDef结构(串口参数菜单)
cpp
typedef struct USART_InitTypeDef
{
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
}USART_InitTypeDef;
分析:
**1.USART_BaudRate:**波特率
**2.USART_WordLength:**数据位长度
- USART_WordLength_8b
- USART_WordLength_9b
**3.USART_StopBits:**停止位长度
- USART_StopBits_0_5
- USART_StopBits_1
- USART_StopBits_1_5
- USART_StopBits_2
**4.USART_Parity:**校验方式
- USART_Parity_No
- USART_Parity_Even
- USART_Parity_Odd
**5.USART_Mode:**数据收发方向
- USART_Mode_Tx
- USART_Mode_Rx
- USART_Mode_Tx | USART_Mode_Rx
2.6.2.设置USART实验
**实验内容:**设置USART1 波特率115200 数据位8位 停止位1位 无校验
编码部分:
2.6.2.1.开启USART1模块时钟
cpp
RCC_APB2PerihClockCmd(RCC_APB2Periph_USART1, ENABLE);
2.6.2.2.USART结构的前置声明
cpp
USART_InitTypeDef USART_InitStruct;
2.6.2.3.串口初始化
cpp
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为双向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
/*调用初始化函数*/
USART_Init(USART1,&USART_InitStruct);
三、为串口初始化IO引脚
3.1.USART模块引脚

- Tx:数据发送引脚
- Rx:数据接收引脚
- CTS:硬件流控
- RTS:硬件流控
- CK:同步模式的时钟线
3.2.引脚分布表
数据手册3.Table 5 引脚分布表(封装为LQFP48)
|--------|-----------------|----------|----------------|-------------------------------------------------|--------------------------------|
| 编号 | 名称 | 电压范围 | 主功能(复位后默认) | 复用功能 ||
| 编号 | 名称 | 电压范围 | 主功能(复位后默认) | 默认 | 重映射 |
| 1 | VBAT | | VBAT | | |
| 2 | PC13-TEMPER-RTC | | PC13 | TAMPER-RTC | |
| 3 | PC14-OSC32_IN | | PC14 | OSC32_IN | |
| 4 | PC15- OSC32_OUT | | PC15 | OSC32_OUT | |
| 5 | OSC_IN | | OSC_IN | PD0 | |
| 6 | OSC_OUT | | OSC_OUT | PD1 | |
| 7 | NRST | | NRST | | |
| 8 | VSSA | | VSSA | | |
| 9 | VDDA | | VDDA | | |
| 10 | PA0-WKUP | | PA0 | WKUP USART2_CTS ADC12_IN0 TIM2_CH1_ ETR | |
| 11 | PA1 | | PA1 | USART2_RTS ADC12_IN1 TIM2_CH2 | |
| 12 | PA2 | | PA2 | USART2_TX ADC12_IN2 TIM2_CH3 | |
| 13 | PA3 | | PA3 | USART2_RX ADC12_IN3 TIM2_CH4 | |
| 14 | PA4 | | PA4 | SPI1_NSS USART2_CK ADC12_IN4 | |
| 15 | PA5 | | PA5 | SPI1_SCK ADC12_IN5 | |
| 16 | PA6 | | PA6 | SPI1_MISO ADC12_IN6 TIM3_CH1 | TIM1_BKIN |
| 17 | PA7 | | PA7 | SPI1_MOSI ADC12_IN7 TIM3_CH2 | TIM1_CH1N |
| 18 | PB0 | | PB0 | ADC12_IN8 TIM3_CH3 | TIM1_CH2N |
| 19 | PB1 | | PB1 | ADC12_IN9 TIM3_CH4 | TIM1_CH3N |
| 20 | PB2 | | PB2/BOOT1 | | |
| 21 | PB10 | FT | PB10 | I2C2_SCL USART3_TX | TIM2_CH3 |
| 22 | PB11 | FT | PB11 | I2C2_SDA USART3_RX | TIM2_CH4 |
| 23 | VSS_1 | | VSS_1 | | |
| 24 | VDD_1 | | VDD_1 | | |
| 25 | PB12 | FT | PB12 | SPI2_NSS I2C2_SMBAl USART3_CK TIM1_BKIN | |
| 26 | PB13 | FT | PB13 | SPI2_SCK USART3_CTS TIM1_CH1N | |
| 27 | PB14 | FT | PB14 | SPI2_MISO USART3_RTS TIM1_CH2N | |
| 28 | PB15 | FT | PB15 | SPI2_MOSI TIM1_CH3N | |
| 29 | PA8 | FT | PA8 | USART1_CK TIM1_CH1 MCO | |
| 30 | PA9 | FT | PA9 | USART1_TX TIM1_CH2 | |
| 31 | PA10 | FT | PA10 | USART1_RX TIM1_CH3 | |
| 32 | PA11 | FT | PA11 | USART1_CTS CANRX USBDM TIM1_CH4 | |
| 33 | PA12 | FT | PA12 | USART1_RTS CANTX USBDP TIM1_ETR | |
| 34 | PA13 | FT | JTMS SWDIO | | PA13 |
| 35 | VSS_2 | | VSS_2 | | |
| 36 | VDD_2 | | VDD_2 | | |
| 37 | PA14 | FT | JTCK SWCLK | | PA14 |
| 38 | PA15 | FT | JTDI | | TIM2_CH1_ ETR . SPI1_NSS |
| 39 | PB3 | FT | JTDO | | TIM2_CH2 PB3 TRACESWO SPI1_SCK |
| 40 | PB4 | FT | JNTRST | | TIM3_CH1 PB4 SPI1_MISO |
| 41 | PB5 | | PB5 | I2C1_SMBAl | TIM3_CH2 SPI1_MOSI |
| 42 | PB6 | FT | PB6 | I2C1_SCL TIM4_CH1 | USART1_TX |
| 43 | PB7 | FT | PB7 | I2C1_SDA TIM4_CH2 | USART1_RX |
| 44 | BOOT0 | | BOOT0 | | |
| 45 | PB8 | FT | PB8 | TIM4_CH3 | I2C1_SCL CANRX |
| 46 | PB9 | FT | PB9 | TIM4_CH4 | I2C1_SDA CANTX |
| 47 | VSS_3 | | VSS_3 | | |
| 48 | VDD_3 | | VDD_3 | | |
根据IO引脚分布表,找到USART1模块默认发送引脚为PA9,接收引脚为PA10
当这些引脚不可用时,芯片还为USART1模块提供了备用引脚
发送引脚PB6,接收引脚PB7,通过使能重映射,可以切换为备用的引脚

3.3.重映射表
参考手册8.3 复用功能I/O和调试配置(AFIO)
3.4.IO配置表
参考手册8.1.11 外设的GPIO配置

3.4.1.全双工模式

数据传输方向为双向,能同时进行
3.4.2.半双工模式

数据传输方向为双向,不能同时进行
3.4.3.同步模式

在标准的串口基础上添加CK线
在两个设备之间传输时钟信号,使两个设备同步
3.4.4.硬件流量控制

在标准的串口基础上添加CTS和RTS两个引脚
这两个引脚交叉连接
注:
Rx引脚配置全双工模式时,GPIO优先选择输入上拉模式:
- 当通信线路断开,Rx引脚会处于悬空状态,上拉电阻可以为Rx引脚提供稳定的高电平
- 避免外界电磁波干扰,确保信号的完整性
- 使串口引脚保持在空闲状态(高电平),降低断线对系统的影响
3.5.编写代码(默认PA9 PA10)
3.5.1.GPIO结构前置声明
cpp
/*前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
3.5.2.配置发送端Tx对应的PA9引脚
cpp
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*选择PA9引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
3.5.3.配置接收端Rx对应的PA10引脚
cpp
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*选择PA10引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
/*设置输入上拉模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
/*初始化引脚*/
GPIO_Init(GPIOA, &GPIO_InitStruct);
3.6.编写代码(重映射PB6 PB7)

3.6.1.开启AFIO模块时钟
cpp
/*使能AFIO模块的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
**注:**AFIO作为芯片的片上外设,核心功能是实现引脚复用选择
3.6.2.使能重映射
cpp
/*使能USART1的重映射*/
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
3.6.3.GPIO结构的前置声明
cpp
/*前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
3.6.4.配置发送端Tx对应的PB6重映射引脚
cpp
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB6引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
3.6.5.配置接收端Rx对应的PB7重映射引脚
cpp
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB7引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
/*设置输入上拉模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
/*初始化引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
四、发送数据
4.1.回顾串口数据发送的过程

- 通过CPU将要发送的数据写入发送数据寄存器
- 发送数据寄存器将数据并行传输到移位寄存器
- 移位寄存器将数据串行输出
4.2.TxE标志位

**TxE(Transmit Data Register Empty ):**发送数据寄存器空标志位
**功能:**检测发送数据寄存器(TDR)是否有数据,避免数据发送过程中出现覆盖
状态指示:
- 当TDR为空时:TxE = 1
- 当TDR非空时:TxE = 0
4.3.TC标志位

**TC(Transmit Complete):**发送完成标志位
**功能:**检测TDR和移位寄存器是否有数据,判断数据发送是否完成
状态指示:
- 当TDR和移位寄存器都为空时:TC = 1
- 当TDR或移位寄存器不为空时:TC = 0
4.4.编程接口
4.4.1.编程接口1
cpp
void USART_Cmd(USARTTypeDef* USARTx, FunctiomalState NewState);
解析:
- 参数1:串口名称
- 参数2:使能标志 ENABLE(使能)DISABLE(禁止)
**作用:**控制USART模块的使能和禁止(总开关)

示例:
使能USART1:
cpp
USART_Cmd(USART1,ENABLE);
禁止USART1:
cpp
USART_Cmd(USART1,DISABLE);
4.4.2.编程接口2
cpp
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
解析:
- 参数1:串口名称
- 参数2:要查询的标志位名称
**返回值:**RESET(表示0)SET(表示1)
作用: 查询USART标志位的值
标志位:
- TXE:USART_FLAG_TXE
- TC:USART_FLAG_TC
- RXNE:USART_FLAG_RXNE
- PE:USART_FLAG_PE
示例:
判断发送数据寄存器是否为空:
cpp
if ((USART_GetFlagStatus(USART1, USART_FLAG_TXE)) == SET)
{
//......
}
判断数据发送是否完成:
cpp
if ((USART_GetFlagStatus(USART1, USART_FLAG_TC)) == SET)
{
//......
}
4.4.3.编程接口3
cpp
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
解析:
- 参数1:串口名称
- 参数2:要发送的数据
**作用:**把要发送的数据写入到发送数据寄存器里
**注:**发送数据的类型为无符号16位的整型,因为发送的数据可能是9位,8位整型无法接收
示例:
发送字节0x01:
cpp
USART_SendData(USART1, 0x01);
4.5.串口发送多字节数据函数
cpp
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size);
|------------------------|--------------|
| 参数 | 含义 |
| USART_TypeDef* USARTx | 串口名称 |
| uint8_t* pData | 发送数据的数组首元素地址 |
| uint16_t Size | 发送数据的字节数量 |
| 返回值 | void |
代码实现:
cpp
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size)
{
for (uint32_t i = 0; i < Size; i++)
{
/*等待发送数据寄存器为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TXE)) == RESET);
/*为空后将数据写入发送数据寄存器*/
USART_SendData(USARTx, pData[i]);
}
/*等待数组中所有数据发送完成,移位寄存器和数据寄存器都为空*/
while ((USART_GetFlagStatus(USART1, USART_FLAG_TC)) == RESET);
}
解析:
- for循环将数据以字节为单位依次发送,循环次数为发送数据的字节数量
- while循环等待发送数据寄存器为空,为空后将数据写入发送数据寄存器
- while循环等待数组中所有数据发送完成,移位寄存器和数据寄存器都为空
4.6.串口发送数据实验
4.6.1.接线方式

**注:**串口USB的TXD和RXD与芯片上Tx端对应的PB6引脚和Rx端对应的PB7引脚交叉连接:
- 串口USB的TXD接芯片的PB7引脚
- 串口USB的RXD接芯片的PB6引脚
4.6.2.代码编写
cpp
#include "stm32f10x.h"
//声明串口发送多字节数据函数
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size);
int main(void)
{
//初始化GPIO
/*开启AFIO模块的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*使能USART1的重映射*/
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
/*GPIO结构前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
//配置发送端Tx对应的PB6重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB6引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PB6引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//配置接收端Rx对应的PB7重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB7引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
/*设置输入上拉模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
/*初始化PB7引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//初始化串口
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构前置声明*/
USART_InitTypeDef USART_InitStruct;
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为双向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
//创建要发送数据的数组
uint8_t bytesToSend[] = {1,2,3,4,5};
//调用串口发送多字节数据函数
My_USART_SendBytes(USART1,bytesToSend,5);
while(1)
{
}
}
//创建串口发送多字节数据函数
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size)
{
for (uint32_t i = 0; i < Size; i++)
{
/*等待发送数据寄存器为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TXE)) == RESET);
/*为空后将数据写入发送数据寄存器*/
USART_SendData(USARTx, pData[i]);
}
/*等待数组中所有数据发送完成,移位寄存器和数据寄存器都为空*/
while ((USART_GetFlagStatus(USART1, USART_FLAG_TC)) == RESET);
}
4.6.3.配置串口助手



五、格式化打印字符串
5.1.给工程重命名
将模板工程template拷贝一份,重命名为新的工程名字
5.2.整理之前的代码
将IO引脚初始化与串口初始化代码封装为一个函数
cpp
#include "stm32f10x.h"
//声明串口发送多字节数据函数
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size);
//声明初始化函数
void My_USART_Init(void);
int main(void)
{
//调用初始化函数
My_USART_Init();
//创建要发送数据的数组
uint8_t bytesToSend[] = {1,2,3,4,5};
//调用串口发送多字节数据函数
My_USART_SendBytes(USART1,bytesToSend,5);
while(1)
{
}
}
//创建串口发送多字节数据函数
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size)
{
for (uint32_t i = 0; i < Size; i++)
{
/*等待发送数据寄存器为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TXE)) == RESET);
/*为空后将数据写入发送数据寄存器*/
USART_SendData(USARTx, pData[i]);
}
/*等待数组中所有数据发送完成,移位寄存器和数据寄存器都为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TC)) == RESET);
}
//创建初始化函数
void My_USART_Init(void)
{
//初始化GPIO
/*开启AFIO模块的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*使能USART1的重映射*/
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
/*GPIO结构前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
//配置发送端Tx对应的PB6重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB6引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PB6引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//配置接收端Rx对应的PB7重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB7引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
/*设置输入上拉模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
/*初始化PB7引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//初始化串口
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构前置声明*/
USART_InitTypeDef USART_InitStruct;
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为双向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
5.3.给代码添加注释
cpp
#include "stm32f10x.h"
//声明串口发送多字节数据函数
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size);
//声明初始化函数
void My_USART_Init(void);
int main(void)
{
//调用初始化函数
My_USART_Init();
//创建要发送数据的数组
uint8_t bytesToSend[] = {1,2,3,4,5};
//调用串口发送多字节数据函数
My_USART_SendBytes(USART1,bytesToSend,5);
while(1)
{
}
}
//创建串口发送多字节数据函数
//
//@简介:通过串口发送多个字节
//@参数 USARTx:填写串口的名称
//@参数 pData:要发送的数据
//@参数 Size:要发送数据的数量,单位是字节
//
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size)
{
for (uint32_t i = 0; i < Size; i++)
{
/*等待发送数据寄存器为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TXE)) == RESET);
/*为空后将数据写入发送数据寄存器*/
USART_SendData(USARTx, pData[i]);
}
/*等待数组中所有数据发送完成,移位寄存器和数据寄存器都为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TC)) == RESET);
}
//创建初始化函数
//
//@简介:对USART1初始化
//@格式:PB6 - Tx,PB7 - Rx
// 115200,8,1,None,双向
//
void My_USART_Init(void)
{
//#1:初始化GPIO
/*开启AFIO模块的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*使能USART1的重映射*/
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
/*GPIO结构前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
//配置发送端Tx对应的PB6重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB6引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PB6引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//配置接收端Rx对应的PB7重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB7引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
/*设置输入上拉模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
/*初始化PB7引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//#2:初始化串口
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构前置声明*/
USART_InitTypeDef USART_InitStruct;
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为双向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
5.4.格式化字符串编程原理
生成格式化字符串
通过fputc输出到标准输出流
重写fputc把数据发送到串口

5.5.重写fputc函数
cpp
#include <stdio.h>
int fputc(int ch, FILE* f)
{
/*等待发送数据寄存器为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TXE)) == RESET);
/*为空后将数据写入发送数据寄存器*/
USART_SendData(USARTx, (uint8_t)ch);
return ch;
}
注: fputc函数需包含<stdio.h>头文件,只需要在主函数中调用printf函数,写入要发送的字符串就可以将字符串发送至串口,串口的接收设置要改为ASCII

5.6.格式化时间字符串
5.6.1.时间获取函数
cpp
/*delay初始化*/
Delay_Init();
uint32_t currentTick = GetTick();
**注:**GetTick函数需包含"delay.h"头文件,Delay函数需要初始化
cpp
/*计算毫秒*/
uint32_t miliseconds = currentTick % 1000;
currentTick /= 1000;
/*计算秒钟*/
uint32_t seconds = currentTick % 60;
currentTick /= 60;
/*计算分钟*/
uint32_t minutes = currentTick % 60;
currentTick /= 60;
/*计算时钟*/
uint32_t hour = currentTick;
**解析:**时间获取函数会返回一个数值,需要经过计算才能获取具体时间,假设数值为29,430,125

5.6.2.代码编写
cpp
#include "stm32f10x.h"
#include <stdio.h>
#include "delay.h"
//声明串口发送多字节数据函数
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size);
//声明初始化函数
void My_USART_Init(void);
int main(void)
{
/*delay初始化*/
Delay_Init();
//调用初始化函数
My_USART_Init();
while(1)
{
uint32_t currentTick = GetTick();
/*计算毫秒*/
uint32_t miliseconds = currentTick % 1000;
currentTick /= 1000;
/*计算秒钟*/
uint32_t seconds = currentTick % 60;
currentTick /= 60;
/*计算分钟*/
uint32_t minutes = currentTick % 60;
currentTick /= 60;
/*计算时钟*/
uint32_t hour = currentTick;
printf("%02u:%02u:%02u.%03u:",hour,minutes,seconds,miliseconds);
Delay(100);
}
}
//创建串口发送多字节数据函数
//
//@简介:通过串口发送多个字节
//@参数 USARTx:填写串口的名称
//@参数 pData:要发送的数据
//@参数 Size:要发送数据的数量,单位是字节
//
void My_USART_SendBytes(USART_TypeDef* USARTx, uint8_t* pData, uint16_t Size)
{
for (uint32_t i = 0; i < Size; i++)
{
/*等待发送数据寄存器为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TXE)) == RESET);
/*为空后将数据写入发送数据寄存器*/
USART_SendData(USARTx, pData[i]);
}
/*等待数组中所有数据发送完成,移位寄存器和数据寄存器都为空*/
while ((USART_GetFlagStatus(USARTx, USART_FLAG_TC)) == RESET);
}
//创建初始化函数
//
//@简介:对USART1初始化
//@格式:PB6 - Tx,PB7 - Rx
// 115200,8,1,None,双向
//
void My_USART_Init(void)
{
//#1:初始化GPIO
/*开启AFIO模块的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*使能USART1的重映射*/
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
/*GPIO结构前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
//配置发送端Tx对应的PB6重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB6引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PB6引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//配置接收端Rx对应的PB7重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB7引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
/*设置输入上拉模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
/*初始化PB7引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//#2:初始化串口
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构前置声明*/
USART_InitTypeDef USART_InitStruct;
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为双向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
int fputc(int ch, FILE* f)
{
/*等待发送数据寄存器为空*/
while ((USART_GetFlagStatus(USART1, USART_FLAG_TXE)) == RESET);
/*为空后将数据写入发送数据寄存器*/
USART_SendData(USART1, (uint8_t)ch);
return ch;
}
六、串口接收数据
6.1.回顾数据接收过程

6.2.RxNE标志位

**RxNE(Receive Data Register Not Empty):**接收数据寄存器非空标志位
**功能:**检测接收数据寄存器(RDR)是否有数据,有数据时就可以读取数据
状态指示:
- 当RDR为空时:RxNE = 0
- 当RDR非空时:RxNE = 1
6.3.接收代码的编写方法
6.3.1.编程接口
cpp
uint16_t USART_ReceiveData(USARTTypeDef* USARTx);
**注:**返回值为16位是为了方式数据位为9位且没有校验位时不够用
**作用:**从接收数据寄存器读取数据
示例:
cpp
//#1:等待接收数据寄存器非空
while (USART_GetFlagStatus(USARTx,USART_FLAG_RXNE) == RESET);
//#2:接收数据
uint8_t byteRcvd = USART_ReceiveData(USARTx);
//#3:处理数据
//...
6.4.使用串口控制LED
**实验内容:**通过串口控制板载LED,发送0时点亮,发送1时熄灭
cpp
#include "stm32f10x.h"
//声明初始化函数
void My_USART_Init(void);
//声明板载LED初始化函数
void My_OnBoardLED_Init(void);
int main(void)
{
/*调用初始化函数*/
My_USART_Init();
/*调用板载LED初始化函数*/
My_OnBoardLED_Init();
while(1)
{
/*等待接收数据寄存器非空*/
while (USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == RESET);
/*接收数据*/
uint8_t byteRcvd = USART_ReceiveData(USART1);
/*处理数据*/
if(byteRcvd == '0')
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);//写0亮灯
}
else if(byteRcvd == '1')
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);//写1灭灯
}
}
}
//创建初始化函数
//
//@简介:对USART1初始化
//@格式:PB6 - Tx,PB7 - Rx
// 115200,8,1,None,双向
//
void My_USART_Init(void)
{
//#1:初始化GPIO
/*开启AFIO模块的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*使能USART1的重映射*/
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
/*GPIO结构前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
//配置发送端Tx对应的PB6重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB6引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PB6引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//配置接收端Rx对应的PB7重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB7引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
/*设置输入上拉模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
/*初始化PB7引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//#2:初始化串口
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构前置声明*/
USART_InitTypeDef USART_InitStruct;
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为双向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
//创建板载LED初始化函数
void My_OnBoardLED_Init(void)
{
/*开启GPIOC的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
/*GPIO结构前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PC13引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
/*设置通用输出开漏模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
/*最大输出速度为2MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
/*初始化PC13引脚*/
GPIO_Init(GPIOC,&GPIO_InitStruct);
/*写1熄灭*/
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}
6.5.错误标志位

6.5.1.PE标志位
**PE(Parity Error):**奇偶校验错标志位
**功能:**检测接收到的数据是否有校验错误
状态指示:
- 无校验错误:PE = 0
- 有校验错误:PE = 1

6.5.2.FE标志位
**FE(Frame Error):**帧格式错误标志位
**功能:**检测接收到的数据帧是否有效
状态指示:
- 数据帧有效:FE = 0
- 数据帧无效:FE = 1

6.5.3.NE标志位
**NE(Noise Error):**噪声错标志位
**功能:**检测接收数据中是否接收到噪声
状态指示:
- 无噪声:NE = 0
- 有噪声:NE = 1

多次采样,如果三次都为高电平则为高电平
如果三次都为低电平则为低电平,当三次中
既出现高电平有出现高电平时,就有噪声错
6.5.4.ORE标志位
**ORE(Over Run Error):**过载错标志位
**功能:**检测由于过载造成了数据丢失
状态指示:
- 无过载错:ORE = 0
- 有过载错:ORE = 1

Rx端对侧发送数据的速度比接收数据的速度快
数据读取太慢导致了中间字节数据的丢失
七、封装常用功能
7.1.为什么要封装串口的常用功能
将重复代码封装成函数
使用代码时可直接调用
极大地简化编程的过程
7.2.复制串口的初始化代码
cpp
#include "stm32f10x.h"
void My_USART_Init(void);
int main(void)
{
My_USART_Init();
while(1)
{
}
}
void My_USART_Init(void)
{
//#1:初始化GPIO
/*开启AFIO模块的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*使能USART1的重映射*/
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
/*GPIO结构前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
//配置发送端Tx对应的PB6重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB6引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PB6引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//配置接收端Rx对应的PB7重映射引脚
/*开启GPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*选择PB7引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
/*设置输入上拉模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
/*初始化PB7引脚*/
GPIO_Init(GPIOB, &GPIO_InitStruct);
//#2:初始化串口
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构前置声明*/
USART_InitTypeDef USART_InitStruct;
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为双向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
7.3.MyLib文件夹简介
存放底层驱动函数代码的头文件与源文件,方便调用
与串口功能相关的函数都存放在usart.h中,可以直接
在源文件中包含usart.h头文件进行函数调用

**注:**调用前要初始化串口
7.4.串口发送相关的函数
cpp
void My_USART_SendByte(...);//发送一个字节
void My_USART_SendBytes(...);//发送多个字节
void My_USART_SendChar(...);//发送一个字符
void My_USART_SendString(...);//发送字符串
void My_USART_Printf(...);//发送格式化字符串
7.4.1.发送一个字节
cpp
#include "stm32f10x.h"
#include "usart.h"
void My_USART_Init(void);
int main(void)
{
My_USART_Init();
My_USART_SendByte(USART1,0x5a);
while(1)
{
}
}
**注:**调用函数时需包含头文件"usart.h",接收数据模式为HEX模式
7.4.2.发送多个字节
cpp
#include "stm32f10x.h"
#include "usart.h"
void My_USART_Init(void);
int main(void)
{
My_USART_Init();
uint8_t byteArray[]={1,2,3,4,5};
My_USART_SendBytes(USART1,byteArray,5);
while(1)
{
}
}
**注:**接收数据模式为HEX模式
7.4.3.发送一个字符
cpp
#include "stm32f10x.h"
#include "usart.h"
void My_USART_Init(void);
int main(void)
{
My_USART_Init();
My_USART_SendChar(USART1,'a');
while(1)
{
}
}
**注:**接收数据模式为ASCII模式
7.4.4.发送字符串
cpp
#include "stm32f10x.h"
#include "usart.h"
void My_USART_Init(void);
int main(void)
{
My_USART_Init();
My_USART_SendString(USART1,"Hello World.\r\n");
while(1)
{
}
}
**注:**接收数据模式为ASCII模式
7.4.5.发送格式化字符串
cpp
#include "stm32f10x.h"
#include "usart.h"
void My_USART_Init(void);
int main(void)
{
My_USART_Init();
const char* strName = "Tom";
My_USART_Printf(USART1,"Hi,%s!Nice to meet you!\r\n",strName);
while(1)
{
}
}
**注:**接收数据模式为ASCII模式
7.5.串口接收相关的函数
cpp
uint8_t My_USART_ReceiveByte(...);//接收一个字节
uint16_t My_USART_ReceiveBytes(...);//接收多个字节
int My_USART_ReceiveLine(...);//接收一行字符串
7.5.1.接收一个字节
cpp
#include "stm32f10x.h"
#include "usart.h"
void My_USART_Init(void);
int main(void)
{
My_USART_Init();
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
while(1)
{
char c = My_USART_ReceiveByte(USART1);
if(c == '0')
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}
else if(c == '1')
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
}
}
}
**注:**接收数据模式为ASCII模式
7.5.2.接收一行字符串
cpp
#include "stm32f10x.h"
#include "usart.h"
void My_USART_Init(void);
int main(void)
{
My_USART_Init();
while(1)
{
char buffer[100];
if(My_USART_ReceiveLine(USART1,buffer,100,LINE_SEPERATOR_CRLF,-1) == 0)
{
My_USART_SendString(USART1,buffer);
}
}
}
**注:**接收数据模式为ASCII模式,发送数据也为ASCII模式

