STM32

发布于:2025-08-08 ⋅ 阅读:(12) ⋅ 点赞:(0)

目录

一、通信接口

1.1通信接口(5个)

1.2双工模式

1.3时钟特性

1.4信号传输方式

1.5设备特性

二、串口通信

2.1硬件电路

2.2电平标准

2.3串口参数

2.4串口数据帧整体结构(传输数据最小单位)

2.5串口通信实际波形

三、USART

3.1USART简介

3.2USART六大高级功能

3.3USART框图

3.3.1STM32 USART寄存器精要

3.3.2发送接收控制器—数据寄存器(DR)

3.3.3状态寄存器(SR)

3.4USART工作原理

3.5波特率发生器

3.6硬件数据流控 (Hardware Flow Control)

3.7中断控制

3.8SCLK控制 (Synchronous Clock Control)

3.9TE使能

3.10唤醒单元

3.11USART基本结构

四、数据帧

4.1字节设置

4.2配置停止位

4.3起始位侦测

4.4数据采样

4.5波特率发生器

五、USART初始化

5.1初始化流程

5.2USART库函数

5.3USART初始化代码

5.4发送数据

5.5主函数程序

5.6数据模式

5.7SendByte函数分装

5.7.1发送数组

5.7.2发送数字

5.7.3printf函数分装

5.8串口发送和接收


#USART串口协议#

一、通信接口

  • 通信目的:将一个设备的数据传送到另一个设备,扩展硬件系统

STM32芯片内部集成许多功能模块(eg.定时器计数,PWM输出,AD采集……)电路所配置的寄存器,数据寄存器都在芯片,操作芯片直接读写即可

STM内部芯片没有的功能需要外挂芯片完成,其数据在STM32外部,获取方式是:在俩个设备之间连接一根或多根通讯线,通过通讯线路发送或者接收数据,完成数据交换从而实现控制外挂模块和读取外挂模块数据。

  • 通信方式:设备与设备之间的连接方式

串行 : 一根或几根线,一次传1个比特(bit)。 节省引脚,适合远距离(相对并行),是主流。UART, I2C, SPI, USB, CAN都是串行。

并行: 多根线(如8根, 16根),一次传多个比特(一个字节或字)。 速度快,但引脚占用多,线间干扰大,距离短。STM32内部总线常用,外部用得少了(如老式打印机接口)。

有线 vs 无线:STM32本身通常处理有线协议,无线(如WiFi, BLE)常通过额外模块(如ESP8266, HC-05)用UART/SPI连接STM32。

  • 通信协议:制定通信的规则,通信双方按照协议规则进行数据收发

举个例子:考试的时候想给别人传答案,就可以和对方约定一个通信协议。比如先咳嗽一声,代表通信开始,然后竖一个手指,代表发生a,竖两个手指代表发生b,竖三个手指代表发送c,然后挥一挥手,代表通讯结束。这就是一种通信方式。

通信的目的是进行信息传递。双方约定的规则,就是通信协议。

名称

引脚

双工

时钟

电平

设备

USART

TX、RX

全双工

异步

单端

点对点

I2C

SCL、SDA

半双工

同步

单端

多设备

SPI

SCLK、MOSI、MISO、CS

全双工

同步

单端

多设备

CAN

CAN_H、CAN_L

半双工

异步

差分

多设备

USB

DP、DM

半双工

异步

差分

点对点

以上通信接口STM32F103C8T6都支持,表只列举最典型参数和配置。

1.1通信接口(5个)

  • UART (Universal Asynchronous Receiver/Transmitter): 最基础的点对点串行协议。像两个人面对面聊天

TX (Transmit): 发数据的引脚。STM32的嘴巴。

RX (Receive): 收数据的引脚。STM32的耳朵。

(可选) RTS/CTS: 硬件流控引脚,用于协调发送速度(防止数据淹没对方)。

(uart是通用异步收/发器,usart通用同步/异步收/发器,相较于UART多一个时钟输出,无时钟输入)

  • I2C (Inter-Integrated Circuit): 多设备共享“总线”的低速串行协议。像一个小组讨论,大家共用一条电话线,靠“名字”(地址)区分。

SCL (Serial Clock): 时钟线。由主设备产生,像打拍子指挥节奏。大家共用。

SDA (Serial Data): 数据线。主从设备都通过它收发数据。大家共用。

注意: I2C总线需要上拉电阻(通常4.7KΩ)连接到电源(3.3V),让总线在空闲时保持高电平。

  • SPI (Serial Peripheral Interface): 高速全双工串行协议,通常点对点或点对少量设备。像两个人用两条专用电话线同时说和听。

SCK (Serial Clock): 时钟线。由主设备产生,指挥节奏。

MOSI (Master Out Slave In): 主设备发,从设备收的数据线。

MISO (Master In Slave Out): 主设备收,从设备发的数据线。

NSS / CS (Slave Select / Chip Select): 片选线。由主设备控制,低电平有效。拉低哪条线,就选中哪个从设备进行对话。主设备可以有多个CS引脚连接不同从设备。

  • USB (Universal Serial Bus): 复杂但强大的通用串行总线协议。

DP (Data Positive)

DM (Data Negative)

专用差分信号线对,需要符合USB规范的硬件设计。

  • CAN (Controller Area Network): 主要用于汽车、工业的可靠网络协议。

CAN_H (CAN High)

CAN_L (CAN Low)

专用差分信号线对,需要终端电阻(120Ω)。

1.2双工模式

  • 比喻:对话的方向限制。是只能一方说(单工)?还是能轮流说(半双工)?还是能同时说和听(全双工)?

  • 单工: 数据只能单向流动。例如:只读传感器、广播(电台发送,收音机只能接收)。STM32较少纯粹单工。

  • 半双工: 数据可以双向流动,但同一时间只能一个方向。就像对讲机,说完“Over”才能听。I2C是半双工 (SDA线同一时刻只能一个设备驱动)。CAN也是半双工 (总线竞争)。

  • 全双工:数据可以同时双向流动。就像打电话,能边说边听。UART、SPI是典型全双工 (有独立的TX/RX线或MOSI/MISO线)。注意: SPI虽然是物理全双工,但实际应用中,有时从设备在收到主设备命令前并不知道要发什么数据,所以主设备发的可能是命令,从设备发的可能是数据,看起来像半双工,但硬件上具备同时收发的能力。

1.3时钟特性

  • 比喻:对话的语速或节拍器。

  • 同步通信 : 通信双方共用同一个时钟信号来同步数据的发送和接收。主设备提供时钟(SCK/SCL),像指挥拍子。SPII2C是同步通信。

优点: 速度快,抗干扰相对好(因为有时钟边沿采样)。

缺点: 需要额外的时钟线。时钟频率限制通信距离。

  • 异步通信: 没有共享的时钟线。双方事先约定好一个速度(波特率),依靠数据帧内部的起始位、停止位来同步每个字节。UART是异步通信。

优点: 只需要两根数据线(TX/RX),适合远距离(相对)。

缺点: 需要精确的波特率发生器,双方波特率误差不能太大(通常<3%),速度相对同步通信慢。更容易受干扰(没有时钟边沿约束)。

  • 波特率 (Baud Rate): 衡量异步通信速度的单位,表示每秒传输的符号数(1个符号通常代表1个比特bit)。常用值:9600, 19200, 38400, 115200等。波特率越高,速度越快,但对时钟精度和信号质量要求越高。

  • 时钟频率 (SCK/SCL): 衡量同步通信速度的单位(Hz)。SPI可达几十MHz,I2C标准模式100KHz,快速模式400KHz,高速模式3.4MHz等。

1.4信号传输方式

  • 单端信号

用1根信号线 + 公共地线(GND)传输数据。

逻辑状态由信号线对地(GND)的电压差决定:

逻辑1:信号线电压 > 高电平阈值(如3.3V系统为2.0V)

逻辑0:信号线电压 < 低电平阈值(如0.8V)


通俗比喻:像一个人用嗓门音量大小传递信息:

大喊(高电平) = 1

小声(低电平) = 0

参考点是环境背景噪音(相当于GND)。

优点

缺点

电路简单,成本低(少1根线)

抗干扰能力差

功耗较低

传输距离短(通常<1米)

适合低速通信

地线噪声直接影响信号

  • 差分信号

用2根相位相反的信号线传输数据(无地线依赖):

D+(正向信号线)

D-(反向信号线)

逻辑状态由两根线之间的电压差决定:

逻辑1:D+电压 - D-电压 > +阈值(如+200mV)

逻辑0:D+电压 - D-电压 < -阈值(如-200mV)


通俗比喻:像两个人用反义词对暗号:

A说“高”,B说“低” → 表示1

A说“低”,B说“高” → 表示0

外界干扰同时影响两人(如噪音+10dB),但暗号差值不变。

优点

缺点

超强抗干扰(抑制共模噪声)

电路复杂(多1根线)

传输距离远(可达百米)

功耗较高

高速传输(GHz级)

成本更高

降低电磁辐射(EMI)

需阻抗匹配

关键差异总结

特性

单端信号

差分信号

信号线数

1根 + GND

2根(D+和D-)

抗干扰

弱(依赖GND质量)

极强(抵消共模噪声)

传输距离

短(<1米)

长(可达100米+)

速度

低速(通常<10Mbps)

高速(可达Gbps)

成本

高(多1根线+专用芯片)

噪声辐射

高(电流经地线形成环路)

低(磁场相互抵消)

1.5设备特性

点对点:俩个设备直接传输数据

多设备:需要寻址以确定通信对象

二、串口通信

  • 串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信

  • 单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力

USB转串口模块:芯片型号CH340(将串口协议转换为USB协议),实现串口和电脑通信。

陀螺仪传感器模块:可测量角速度,加速度等姿态参数,左右各四个引脚,一边串口引脚,一边I2C引脚。

蓝牙串口模块:四个角是串口通信引脚,芯片可以和手机互联,实现手机遥控单片机功能。

2.1硬件电路

  • 简单双向串口通信有两根通信线(发送端TX和接收端RX

  • TXRX要交叉连接

  • 当只需单向的数据传输时,可以只接一根通信线

一般串口通信的模块有四个引脚,VCC和GND供电,TX和RX通信且为单端信号,它们的高低电平是相对于GND,因此GND严格上也是通信线。所以串口通信的RX、TX、GND必须连接。如果两个设备都有独立供电,VCC可以不接。

如果其中一个设备没有供电,比如设备1是STM32,设备2是蓝牙串口模块。STM32有独立供电,蓝牙串口没有独立供电,就需要把蓝牙串口的VCC和STM32的VCC接在一起。STM32通过VCC-VCC这根线向右边的子模块供电。供电电压需要注意,是按照子模块要求。

  • 当电平标准不一致时,需要加电平转换芯片

3.3V器件 ↔ 5V器件:

    5V输出到3.3V输入:需分压电阻或电平转换芯片。

    3.3V输出到5V输入:通常可直接连接。

TTL ↔ RS232:必须使用电平转换芯片(如MAX3232)。

2.2电平标准

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

  • TTL电平:+3.3V或+5V表示1,0V表示0

  • RS232电平:-3~-15V表示1,+3~+15V表示0

一般在大型机器使用,由于环境可能恶劣,静电干扰较大,因此电瓶电压比较大,允许波动范围也大。

  • RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)

差分信号抗干扰能力强。其通信距离可达上千米。

2.3串口参数

  • 波特率:串口通信的速率

串口一般异步通信,需要双方确定通信速率(波特率,每秒传输码元的个数,二进制情况下,一个码元为一个比特,此时波特率=比特率)

每位比特(bit)的持续时间 T = 1 / 波特率。

优先选用 11.0592MHz 晶振(可被常用波特率整除)

72MHz系统时钟下,9600波特率误差仅0.14%(推荐)

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

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

若发送数据超过设定位数,高位会被截断。

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

三种方式:无校验,奇校验(数据位+校验位=奇数个1),偶校验

但是若俩个数据发送过程都出错,奇偶校验就检测不出来错误。

串口助手中,数据位为有效载荷,校验位是独立的1位

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

2.4串口数据帧整体结构(传输数据最小单位)

串口发送的字节格式,由串口协议规定。

串口每个字节都装载在一个数据帧,每个数据帧都由起始位,数据位和停止位组成。数据位8个代表一个字节8位。

数据帧结构:

空闲态:

  • 通信未开始时,TX/RX线保持高电平(逻辑1)。

起始位(Start Bit):

  • 1个比特的低电平(0),向接收方宣告“数据开始传输!”

  • 关键作用:实现帧同步(接收方检测到下降沿即启动计时)。

数据位(Data Bits):

  • 5~9个比特(通常选8位,兼容ASCII)

  • 传输顺序:LSB(最低位)先传!
    例如发送字符 'A' (0x41 = 二进制 01000001):
    实际传输顺序为 1→0→0→0→0→0→1→0(从D0到D7)

校验位(Parity Bit):

  • 可选,1个比特,用于检错(不能纠错):

    • 奇校验(Odd):数据位+校验位的“1”总数=奇数

    • 偶校验(Even):数据位+校验位的“1”总数=偶数。

例:0x41 (01000001)有2个“1”(偶数),若用偶校验则校验位=0

停止位(Stop Bit):

  • 1~2个比特的高电平(1) ,表示“本帧结束”

  • 强制拉高,为下一帧起始位的下降沿做准备。

数据位8位,无校验位

数据位9位,有校验位

2.5串口通信实际波形

第一个波形,发送字节数据0x55,波特率9600,每位时间是1/9600,大概104us。没发送数据时为空闲状态-高电平。数据帧开始先发送起始位,产生下降沿代表数据帧开始。数据0x55转为二进制,低位先行(依次发送1010 1010)。这个参数是八位数据,1位停止,无校验。没有校验位,后面的停止位把引脚置回高电平,数据帧完成发送


STM32中,根据字节数据反转高低电平是USART外设自动完成,若软件模拟产生此波形,定时器104us+GPIO_WriteBit置高低电平。TX引脚发送是置高低电平,RX引脚接收为读取高低电平,也可以是USART外设自动完成,若软件模拟,定时调用GPIO_ReadInputDataBit读取每一位+接收使用外部中断(起始位下降沿触发)+对齐采样位采取8次。


其余波形也是如此(+校验位)

右下角俩个波形可以看出:串口停止位可以配置(1/1.5/2位)中间没有空闲状态

总结:串口通信——TX引脚输出定时翻转的高低电平,RX引脚定时读取引脚的高低电平。每个字节的数据加上起始位、停止位、可选的校验位,打包成数据帧依次输出在TX引脚,另一端RX引脚依次接收,就完成字节数据的传递。

三、USART

3.1USART简介

  • USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器

相较于UART模式,多一个时钟输出。

USART=UART+同步通信扩展功能

USART 与 UART 的本质区别

特性

UART

USART

通信模式

仅异步

同步 + 异步

时钟线

同步模式需SCLK引脚

协议支持

基础串行协议

支持LIN、智能卡、IrDA等

硬件复杂度

简单

更复杂(寄存器更多)

STM32资源

部分型号仅有UART

主流型号均有USART

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

  • 自带波特率发生器,最高达4.5Mbits/s

波特率发生器相当于一个分频器。比如APB2总线72MHz,波特率发生器极性分频,得到波特率时钟(通信波特率),在此时钟下进行接收发送波形。波特率常用9600和115200.

  • 可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)

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

  • 支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN

  • STM32F103C8T6 USART资源: USART1(APB2)、 USART2 USART3

3.2USART六大高级功能

1.多处理器通信(地址标记)

  • 用途:一主多从通信(类似I2C寻址)

  • 原理:

发送特殊地址帧唤醒目标从机

机忽略非自身地址的数据帧

  • 配置:USART_CR2 寄存器的 ADD0~3 设置自身地址

2. 硬件流控(RTS/CTS)

  • 引脚:

RTS:输出,指示“本机准备好接收”

CTS:输入,检测“对方是否允许发送”

  • 作用:防止接收缓存溢出(尤其高速传输)

3. LIN总线支持

  • LIN Break检测:自动识别13位低电平起始符

  • 同步场生成:硬件自动发送 0x55 同步字节

  • 配置:USART_CR2 寄存器的 LINEN 使能

4. 智能卡模式(ISO 7816)

  • 支持T=0/T=1协议(SIM卡、金融IC卡)

  • 自动生成ETU(Elementary Time Unit)时钟

  • 硬件校验奇偶错误并重传

5. IrDA红外编码

  • 内置编解码器:将数据转为3/16位脉宽红外信号

  • 支持SIR(115.2kbps)和MIR(1.152Mbps)速率

6. DMA联动

  • 解放CPU:自动搬运大量数据到USART缓存

3.3USART框图

3.3.1STM32 USART寄存器精要

寄存器

作用

关键位域

USART_SR

状态寄存器

RXNE(接收缓存非空), TC(发送完成), PE(校验错)

USART_DR

数据寄存器(读写合一)

(TDR发送+RDR接收)

写入数据启动发送,读取获取数据

USART_BRR

波特率寄存器(16位)

存储 USARTDIV 值

USART_CR1

控制寄存器1

UE(使能), M(字长), PCE(校验使能)

USART_CR2

控制寄存器2

STOP(停止位), CLKEN(同步时钟使能)

3.3.2发送接收控制器—数据寄存器(DR)

两个数据寄存器——发送数据寄存器TDR(Transmit DR)和接收数据寄存器RDR(Receive DR)。两个寄存器占用同一个地址(与51单片机串口的SBUF寄存器相似)。在程序上只表现为一个寄存器——数据寄存器DR。但实际硬件中是分成两个寄存器,一个用于发送TDR,一个用于接收RDR。TDR只写,RDR只读。当进行写操作时,数据就写到TDR,当进行读操作时,数据就从RDR读出。

发送器控制

控制发送移位寄存器工作

负责把CPU准备好的数据通过TX引脚一位一位地发送出去(比如发送一个字节0x55)

工作流程(发快递)=发送数据流程

发送数据流程

发送数据寄存器TDR:类似于快递站“打包台”(临时存放待发送的快递)

发送移位寄存器:快递站的“传送带”(把包裹逐个送出)

关键状态标志位(USART_SR寄存器)

TXE(Transmit Data Register Empty):

  • TXE=1:打包台空着,可以放新快递(CPU可写入新数据)

    • TXE=1:TDR为空(数据已转移到移位寄存器),可写入新数据

    • 写入USART_DR后自动清零

  • TXE=0:打包台被占用(正在发送)

TC(Transmission Complete):

  • TC=1:所有快递已发出(包括最后的包装盒——停止位)

    • TC=1:移位寄存器发送完毕(包括停止位),一帧完成

    • 读SR寄存器 + 写USART_DR可清零

  • TC=0:还在发送中

  • 移位寄存器:像传送带一样,把数据从低位到高位逐个比特推出去

发送数据流程文字描述

在某时刻给TDR写入0x55,在寄存器中二进制存储0101 0101。此时,硬件检测到写入的数据并检查当前移位寄存器是否有数据正在移位。如果没有,0101 0101全部移动到发送移位寄存器,准备发送。

当数据从TDR移动到移位寄存器时,会置一个标志位TXE(TX Empty),发送寄存器空。我们检查这个标志位,如果置1了,我们就可以在TDR写入下一个数据了若TXE=1,数据没有发送,但是数据已经从TDR转移到发送移位寄存器,从而可写入新数据。此时,发送移位寄存器会在发送器控制的驱动下向右移位,一位一位地把数据输出到TX引脚。这里是向右移位的,正好和串口协议规定的低位先行一致。

数据移位完成后,新的数据会再次自动地从TDR转移到发送移位寄存器。如果当前移位寄存器移位还没有完成,TDR的数据就会进行等待,一旦移位完成,就会立刻转移过来。

TDR和移位寄存器的双重缓存,可保证在连续发送数据时,数据帧之间不会有空闲,提高工作效率。简单来说,数据一旦从TDR转移到移位寄存器了,不管有没有移位完成,都立刻把下一个数据放在TDR里等着,一旦移位完成,新的数据就会立刻跟上。


接受控制器

控制接收移位寄存器工作

负责把RX引脚一位一位地接收数据,并组装成完整的字节交给CPU(比如接收0XAA)

工作流程(收快递)=接收数据流程

接收数据流程

接收移位寄存器:快递站的“扫描仪”(逐个检查收到的快递)

接收数据寄存器RDR:快递站的“暂存架”(存放已扫描的完整快递)

关键状态标志位(USART_SR寄存器)

RXNE=1:暂存架上有快递待取(CPU需及时读取)

移位寄存器:像扫描仪一样,从低位到高位逐个比特组装数据

错误处理:

  • 停止位不对 → 标记为"破损快递"(帧错误FE)

  • 暂存架未取又来新快递 → 标记"爆仓"(溢出错误ORE)

数据从RX引脚通向接收移位寄存器,在接收器控制的驱动下一位一位的读取RX电平,先放在最高位,然后往右移,移位八次之后就能接收一个字节。由于串口协议规定低位先行,因此接收移位器从高位往低位方向移动。当一个字节移位完成,一整个字节就会转移到接收数据寄存器RDR。在转移过程中产生标志位RXNE,接收数据寄存器非空。当RXNE=1时,可将数据读取。同样俩个寄存器进行缓存,当数据从移位寄存器转移到RDR时,可直接移位接收下一帧数据。

发送有帧头和帧尾,接收需要剔除它们,电路内部自动执行。


双缓冲机制的优势

为什么需要两个寄存器?

场景

单寄存器方案

双寄存器方案(TDR+RDR)

发送时

必须等全部发完才能写新数据

数据装上传送带后立刻可写下一包

接收时

必须立刻取走否则丢数据

前一包在暂存架时仍能收下一包

效率

高(实现"流水线"作业)

类比:就像快递站有两个工作台:
一个在打包新快递(TDR),另一个在送出已打包的快递(移位寄存器)
互不干扰,效率翻倍!


常见问题:

Q1: 为什么发送时要先检查TXE?

A:就像快递站——只有打包台空着(TXE=1),才能放新快递,否则会覆盖未处理的快递

Q2: 数据为什么要从低位(LSB)开始传?

A:就像写数字"123"——先写个位"3",再十位"2",最后百位"1",接收方反过来组装即可还原

Q3: 移位寄存器怎么知道何时停止?

A:根据配置的"数据位数"(如8位)——就像扫描仪知道快递单号有几位数字。

Q4:为什么发送时要用 TXE 和 TC 两个标志?

TXE=1(打包台空着) 只表示可以放新数据到TDR,但可能还有数据在移位寄存器没发完。

TC=1 (所有快递发送完毕)表示所有数据(包括停止位)已经全部发出。

Q5:接收数据时为什么会丢数据?

原因1:CPU没有及时读取 USART_DR(导致 ORE 溢出错误)。

原因2:波特率不匹配(比如STM32设成115200,但对方发的是9600)。

解决方法:

  • 使用DMA自动接收数据。
  • 确保双方波特率一致。

Q6:发送和接收能同时进行吗?

可以! USART是 全双工 的,发送和接收完全独立(有各自的寄存器和引脚)。


发送 vs 接收控制器对比

功能

发送控制器

接收控制器

核心寄存器

TDR(发送数据寄存器)

RDR(接收数据寄存器)

移位寄存器

把数据逐位推到TX引脚

从RX引脚逐位读取数据

关键标志

TXE(可写新数据)、TC(发送完成)

RXNE(有数据可取)、FE/PE/ORE(错误)

数据顺序

LSB(最低位)先发

LSB(最低位)先收

触发方式

CPU写入 USART_DR 启动发送

检测起始位(下降沿)自动启动接收

  • 发送控制器:把数据从 TDR → 移位寄存器 → TX引脚 逐位发出(LSB先发)。

  • 接收控制器:从RX引脚 → 移位寄存器 → RDR 逐位接收(LSB先收)。

  • 状态寄存器(USART_SR) 就像 仪表盘,告诉你当前状态(能不能发/有没有数据/是否出错)。


3.3.3状态寄存器(SR)

状态寄存器(USART_SR) 就像是USART模块的“工作状态仪表盘”,实时显示发送、接收、错误等各种状态。它的每个标志位都像是一个小灯泡,亮起(=1)时表示某种状态发生。

状态寄存器核心标志位

标志位

名称(英文全称)

作用(通俗解释)

谁负责点亮它?

如何熄灭它?

TXE

Transmit Data Register Empty

发送快递台空啦!

(可以放新数据了)

当TDR数据转移到移位寄存器时

写入新数据到USART_DR自动熄灭

TC

Transmission Complete

所有快递发完啦!

(包括最后的包装盒-停止位)

移位寄存器发完最后一比特时

读SR寄存器 + 写USART_DR

RXNE

Receive Data Register Not Empty

暂存架上有快递!

(快来取数据)

当移位寄存器存满一帧数据到RDR时

读取USART_DR自动熄灭

ORE

Overrun Error

爆仓啦!

(新快递把旧快递挤掉了)

RDR数据未读又收到新数据时

读SR + 读USART_DR

FE

Framing Error

快递包装破损!

(停止位不对)

检测到停止位为低电平时

读SR + 读USART_DR

PE

Parity Error

快递单号对不上!

(校验错误)

奇偶校验失败时

读SR + 读USART_DR

工作状态实时演示

状态寄存器的三大关键作用

通知CPU该干啥

  • 亮TXE灯:提醒CPU"可以发下一个数据了"

  • 亮RXNE灯:提醒CPU"快来取数据"

报告错误情况

  • 亮FE灯:警告"对方发来的数据格式不对"

  • 亮ORE灯:警告"你取数据太慢了!"

控制DMA传输

  • TXE/RXNE标志可直接触发DMA请求,实现"自动搬运数据"

状态寄存器使用避坑指南

TXE vs TC的区别

  • TXE=1:仅表示可以放新数据(可能还有数据在移位寄存器未发完)

  • TC=1:表示所有数据(含停止位)已完全发出

清除标志的玄机

  • TXE:写入DR自动清除

  • TC:需要读SR + 写DR(两步操作!)

  • 错误标志(ORE/FE/PE):需要读SR + 读DR

DMA模式下的特殊行为

  • 启用DMA发送时,TXE标志不会置1(由DMA自动维护)

  • 但TC标志仍会正常置位,可用于判断发送完成

标志位更新时序

TXE置位时刻:刚好在数据从TDR加载到移位寄存器时

TC置位时刻:停止位发送完成后立即发生

RXNE置位时刻:停止位采样正确的瞬间

事件

标志位变化

延迟周期(72MHz系统)

写入USART_DR

TXE立即清零

0

TDR→移位寄存器

TXE置位

1-2

停止位发送完成

TC置位

1

RX引脚采样完成

RXNE置位

1

硬件连接关系

USART_SR ← 发送控制器/接收控制器/错误检测单元
USART_SR → 中断控制器/NVIC
USART_SR ↔DMA控制器(通过TXE/RXNE触发请求)


3.4USART工作原理

1.异步模式(UART模式)

  • 无时钟线,靠起始位/停止位同步

  • 数据帧结构:起始位 + 数据位(8~9) + 校验位 + 停止位

  • 波特率由内部定时器生成(依赖APB总线时钟)

2. 同步模式

  • 有时钟线(SCLK),由主设备(通常是STM32)产生

  • 数据在时钟边沿采样(类似SPI),支持全双工

  • 可配置时钟极性(CPOL)和相位(CPHA)

3. 数据收发引擎

  • 发送器:并行数据 → 移位寄存器 → 按比特串行输出

  • 接收器:采样RX信号 → 移位寄存器 → 数据校验 → 存入缓存


3.5波特率发生器

  • USART模块的“心跳控制器”,决定数据发送和接收的速度节奏,确保通信双方以相同的速率传输数据

  • 定义:每秒传输的符号数(1符号=1比特),单位是bps(比特/秒)

  • 常见值:9600、115200(数值越大速度越快)

  • 关键公式:
    每位持续时间(秒) = 1 / 波特率
    例如:
    115200波特率 → 每位持续 8.68μs

波特率发生器结构

时钟源:来自STM32的APB总线(如APB1=72MHz)

分频器:16位寄存器(USART_BRR)计算分频系数

输出:生成发送和接收所需的精确时钟

计算公式:

USARTDIV = f_PCLK / (16 * 波特率)

f_PCLK1/2:APB总线时钟频率(如72MHz)

USARTDIV:写入USART_BRR的

分频值拆分:

整数部分:USART_BRR[15:4]
例:39 → 0x27

小数部分:USART_BRR[3:0](步长0.0625)
例:0.0625 → 0x1, 0.125 → 0x2

工作流程

1.发送时钟控制

2.接收采样时钟

3次采样抗干扰:在每位中点附近采样3次,取多数值

问题为什么波特率通信不稳定?

1.APB时钟配置错误(可能误用HSI内部时钟)

2.BRR计算未四舍五入(小数部分处理不当)


3.6硬件数据流控 (Hardware Flow Control)

USART通信的“交通警察”,通过nRTS(Request To Send请求发送)和nCTS(Clear To Send清除发送)俩跟信号线,防止数据拥堵丢失

硬件流控核心概念

1. 两根关键信号线

信号线

方向

作用(低电平有效)

等效比喻

nRTS

输出

告诉对方:“我的接收缓冲区有空,可以发数据”

快递仓库的“有空位”指示灯

nCTS

输入

检测对方:“是否允许我发送数据?”

快递员的“绿灯通行”信号

2.工作逻辑

3.完整工作流程

硬件流控的三大核心机制

1. nRTS触发阈值

  • STM32自动控制:当接收缓冲区达到预设阈值时自动拉高/拉低nRTS
  • 阈值配置(通过USART_RTOR寄存器):USART1->RTOR = 0x10; 
  • // 当空闲空间<16字节时拉高nRTS

2. nCTS响应时间

  • 实时检测:发送前检查nCTS,若为高电平则阻塞发送
  • 典型响应延迟:<2个波特周期(115200波特率下约17μs)

3. 错误恢复

错误类型

触发条件

处理方式

CTS超时

nCTS持续高电平>1ms

触发中断,重新初始化通信

RTS冲突

nRTS被意外拉高

检查缓冲区是否溢出


3.7中断控制

  • 通信系统的智能警报器,当事件发生时(数据送达/发送完成/出现错误),立即通知CPU处理。

  • 中断触发条件

中断类型

触发标志位

典型应用场景

比喻解释

TXE

USART_SR.TXE

发送寄存器空,可填充新数据

快递员喊:“箱子空了,快装货!”

TC

USART_SR.TC

一帧数据完全发送完毕

快递站通知:“包裹已全部发出!”

RXNE

USART_SR.RXNE

接收到新数据

收件人收到短信:“快递到货!”

ORE

USART_SR.ORE

数据溢出(旧数据被覆盖)

仓库报警:“货物堆积爆仓了!”

IDLE

USART_SR.IDLE

检测到总线空闲(无数据)

快递员报告:“今天没货送了”

  • 中断优先级:可配置4个抢占级别

  • 发送中断流程

  • 接收中断流程

TXE要数据,TC报完成,RXNE催取件,ORE喊救命


3.8SCLK控制 (Synchronous Clock Control)

SCLK基础概念

1. 同步 vs 异步模式

特性

异步模式(UART)

同步模式(USART+SCLK)

时钟线

需SCLK引脚

速率

较低(通常<1Mbps)

更高(可达SPI级速度)

适用场景

简单设备间通信

需精确时钟同步的设备

2.SCLK引脚作用

  • 主模式:STM32输出时钟信号(驱动从设备)

  • 从模式:STM32接收外部时钟(需外部主设备)

3.工作流程

同步发送时序(主模式)

同步接受时序(从模式)

SCLK三大核心参数:
1. 时钟极性(CPOL) - 空闲状态电平
2. 时钟相位(CPHA) - 数据采样边沿
3. 频率控制(BRR) - 通过波特率寄存器调节

调试口诀:
“SCLK不正常,先查CPOL/CPHA,再量时钟频率”

四种时钟模式(类似SPI)

模式

CPOL

CPHA

数据采样边沿

数据变化边沿

0

0

0

上升沿

下降沿

1

0

1

下降沿

上升沿

2

1

0

下降沿

上升沿

3

1

1

上升沿

下降沿

3.9TE使能

USART发送功能总开关,控制整个发送通道的激活与关闭

TE使能的核心作用

行为

TE=0(关闭)

TE=1(使能)

TX引脚状态

高阻态或保持最后电平

正常输出数据

数据发送

禁止发送(忽略写入DR)

允许发送

移位寄存器操作

冻结

正常工作

中断/DMA触发

不产生TXE/TC中断

正常触发

TE使能的四大关键特性

硬件自动管理空闲状态

TE使能后,TX引脚自动拉高(空闲状态),直到发送第一个起始位。

首次写入DR的同步作用

第一次写入USART_DR会触发:起始位(低电平);后续数据位按LSB-first发出

关闭时的缓冲保护

若TE由1→0时移位寄存器仍在发送:会完成当前帧传输(包括停止位),之后TX引脚进入高阻态

与DMA的联动

即使TE=1,如果DMA未配置,TXE不会自动触发DMA请求


3.10唤醒单元

作用:实现串口挂载多设备

功能:给串口分配地址。串口一般时点对点通信,仅支持俩个设备互相通信。多设备在一条线上可以接都哦个设备,每个设备分配一个地址,想跟某个设备通信,先寻址确定通信对象在进行数据收发。当发送指定地址时,设备唤醒开始工作。没有接收到的地址保持沉默。


3.11USART基本结构

串口数据收发过程

波特率发生器用于产生约定的通信速率。时钟来源是PCLK2或1。经过波特率发生器分频后,产生的时钟通向发送控制器和接收控制器,发送控制器和接收控制器用来控制发送移位和接收移位

之后由发送数据寄存器和发送移位寄存器这两个寄存器的配合,将数据一位一位地移出去,通过GPIO口的复用输出(引脚图),输出到TX引脚,产生串口协议规定的波形。

当数据由数据寄存器转移到移位寄存器时,会置TXE标志位,判断标志位就可以知道是否可以写下一个数据。

接收部分与之类似,RX引脚的波形通过GPIO口输入,在接收控制器的控制下,一位一位地移入接收移位寄存器。由于低位先行,因此数据要从左边开始移进来,移完一帧数据后,数据就会统一转运到接收寄存器,在转移的同时置RXNE标志位,检查标志位就可以知道是否收到数据。同时这个标志位也可以去申请中断,这样就可以在收到数据时直接进入中断函数,之后快速地读取和保存数据。

四、数据帧

4.1字节设置

字长=数据位长度(包含校验位)

9位字长波形:

第一条时序是TX发送或者RX接收的数据帧格式。空闲高电平,起始为零,接着根据写入的数据置1或置0,依次发送位0到位8,最后停止位1,数据帧结束。一般选择8位数据位(一个字节)+1位校验位

第二条时钟是同步时钟输出功能。每个数据位的中间都有一个时钟上升沿,时钟的频率和数据速率一样。接收端可以在时钟上升沿进行采样,就可以精准定位每一位数据。时钟的最后一位可以通过BCL位控制要不要输出。时钟的相位极性可通过配置寄存器配置。

第三条时空闲帧1

第四条时断开帧0

三四俩条时局域网协议使用。


8位字长波形:

一般8位数据位(一个字节)+无校验位


4.2配置停止位

STM32的串口可以配置停止位长度为0.5、1、1.5、2四种。

1个停止位,停止位的时长=数据位的1位时长

1.5个停止位,停止位时长=1.5倍数据位1位时长

2个停止位的,停止位时长=2倍数据位1位时长

0.5个停止位,停止位时长=0.5倍数据位1位时长

一般选择1位停止位


对于串口来说,串口的输出TX比输入RX简单很多。

输出只要定时翻转TX引脚高低电平即可。

输入不仅要保证输入的采样频率和波特率一致,还要保证每次输入采样的位置,正好处于每一位的正中间。只有在每一位的正中间采样,高低电平读进来才是最可靠的。如果采样点过于靠前或靠后,有可能高低电平还正在翻转,电平还不稳定,或者稍有误差,数据容易采样错。

此外,输入还要对噪声有一定的判断能力。

输入RX采样方法:

4.3起始位侦测

当输入电路侦测到一个数据帧的起始位后,就会以波特率的频率连续采样一帧数据。同时从起始位开始采样位置就要对齐位的正中间。

为了实现这一功能,输入对电路采样时钟进行了细分,以波特率的16倍频率进行采样。

最开始空闲状态高电平,采样为1,在某个位置采样到0(出现下降沿)且没有噪音,就为起始位。在起始位进行16次采样,没有噪音位0,为了采集准确,根据手册描述,接收电路还会在下降沿之后的第三次、五次、七次进行一批采样。

在第八次、九次、十次再进行一批采样,且这两批采样都要要求每三位里面至少应该有两个零。

①没有噪声置0,满足情况。

②有一些轻微的噪声,导致起始位中三位里有两个0,另一个是1,符合情况,并且在状态寄存器置NE(Noise Error)噪声标志位。若起始位中三位里有一个零,不符合情况。可猜测下降沿是噪声导致,电路需要重新捕捉下降沿。

若起始位侦测正确,接收状态从空闲变为接收起始位。同时,第八、九、十次采样的位置,正好是起始位的正中间,之后接收数据位时,就都在第八、九、十、次进采样。由此保证采样位置在位的正中间。

4.4数据采样

数据位的时间长度为16。一个数据位有十六个采样时钟,由于起始位侦测已经对齐了采样时钟,因此可直接在第八、九、十、次采样数据位,为保证数据的可靠性,连续采样三次。

没有噪声的理想情况下,这三次全为1或者全为0。

全为1就认为收到了1,全为0就认为收到了0。

如果有噪声导致三次采样不是全为1或者全为0,就按照2:1的规则确定:两次为1就认为收到了1,两次为0就认为收到了0。在这种情况下,噪声标志位NE也会置1。

4.5波特率发生器

  • 发送器和接收器的波特率由波特率寄存器BRR里的DIV确定
  • 计算公式:波特率 = fPCLK2/1 / (16 * DIV)

五、USART初始化

5.1初始化流程

①开启时钟,需要GPIO时钟和USART时钟
②GPIO初始化,把TX配置成复用输出,RX配置成输入
③配置USART,使用结构体
④若只需要发送功能,直接开启USART
⑤若需要接收功能,需要配置中断,(NVIC+ITConfig),再开启USART
初始化完成
发送数据:调用发送函数
接收数据:调用接收函数
获取发送和接受状态:调用标志位函数

5.2USART库函数

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);


④配置同步时钟输出
void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);
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);


⑧发送数据(写DR寄存器)
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);


⑨接收数据(读DR寄存器)
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);


⑩标志位相关函数
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

5.3USART初始化代码

#include "stm32f10x.h"                  // Device header

void serial_init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	GPIO_InitTypeDef GPIO_Initstructure;
	GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AF_PP;//TX使用复用推挽输出 
	GPIO_Initstructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);
	
	USART_InitTypeDef USART_Initstructure;
	USART_Initstructure.USART_BaudRate=9600;//波特率
	USART_Initstructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制
	/*
	#define USART_HardwareFlowControl_None      不使用流控   
	#define USART_HardwareFlowControl_RTS       只用CTS 
	#define USART_HardwareFlowControl_CTS       只用RTS
	#define USART_HardwareFlowControl_RTS_CTS   CTSRTS都使用
	*/
	USART_Initstructure.USART_Mode=USART_Mode_Tx;//USART模式
	/*
	#define USART_Mode_Rx    发送模式
	#define USART_Mode_Tx    接收模式
	*/
	USART_Initstructure.USART_Parity=USART_Parity_No;//校验位
	/*
	#define USART_Parity_No          无校验
	#define USART_Parity_Even        偶校验
	#define USART_Parity_Odd         奇校验
	*/
	USART_Initstructure.USART_StopBits=USART_StopBits_1;//停止位
	/*
	#define USART_StopBits_1             
	#define USART_StopBits_0_5           
	#define USART_StopBits_2             
	#define USART_StopBits_1_5           
	*/
	USART_Initstructure.USART_WordLength=USART_WordLength_8b;//字长
	/*
	#define USART_WordLength_8b   
	#define USART_WordLength_9b   
	*/
	USART_Init(USART1,&USART_Initstructure);
	
	USART_Cmd(USART1 ,ENABLE);
}

5.4发送数据

void serial_sendbyte(uint8_t byte)
{
	USART_SendData(USART1,byte);//等待数据转移到移位寄存器,再进行数据传递,为了防止新发送的数据数据覆盖原先数据,等待标志位
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	//标志位是否手动清除
	/*
TXE:发送数据寄存器空 (Transmit data register empty) 
当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1
寄存器中的TXEIE为1,则产生中断。对USART_DR的写操作,将该位清零。 
0:数据还没有被转移到移位寄存器; 
1:数据已经被转移到移位寄存器。 
注意:单缓冲器传输中使用该位。
	*/
	//不需要手动清除标志位,在下一次的senddata时,标志位会自动清0
	
}

标志位是否手动清零?

TXE 标志位通常不需要(也不应该)手动清除。写入新数据到 USART_DR 寄存器是清除它的唯一且正确的方式,并且这个清除操作是自动发生的。

以下是关键点的解释

1.硬件置位 (Set by Hardware):

  • 当硬件完成将 TDR (发送数据寄存器) 中的数据转移到移位寄存器(准备开始通过 TX 线一位一位地发送出去)时,硬件会自动将 TXE 标志位置为 1

  • 这个动作表示 TDR 现在空了,可以接收新的数据了。

  • 如果此时 TXEIE (TXE 中断使能) 位为 1,这个置位操作还会触发一个中断。

2.清零机制 (Clearing Mechanism):

  • 文档明确说明:“对 USART_DR 的写操作,将该位清零”

  • 这是唯一的清除 TXE 标志位的方式。

  • 当你向 USART_DR (数据寄存器,通常通过写这个寄存器来发送数据) 写入一个新的字节时:

    • 硬件首先将这个新字节加载到 TDR 寄存器中。

    • 然后,硬件自动地、立即地将 TXE 标志位清零 (0)。

  • 你不需要(也无法)通过直接向标志位寄存器写 0 或 1 来手动清除 TXE 标志位。 尝试这样做要么无效,要么可能影响其他标志位。

5.5主函数程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "serial.h"
int main(void)
{	
	
    OLED_Init();
	serial_init();
	serial_sendbyte(0x44);
	while(1)
	{

	}
}

5.6数据模式

  • HEX模式/十六进制模式/二进制模式:以原始数据的形式显示
  • 文本模式/字符模式:以原始数据编码后的形式显示

字符和数据在发送和接收的转换关系

5.7SendByte函数分装

5.7.1发送数组

//发送数组
void Serial_SendArray(uint8_t *Array,uint16_t Length)
{
	uint16_t i;
	for(i=0;i<Length;i++)
	{
		serial_sendbyte(Array[i]);
	}
}

//main函数中的代码编写
	uint8_t  arr[]={0x41,0x42,0x43,0x44};
	Serial_SendArray(arr,4);

5.7.2发送数字

//次方函数
uint32_t  serial_pow(uint32_t x,uint32_t y)
{
	uint32_t  result=1;
	while(y--)
	{
		result *=x;
	}
	return result ;
}

//发送数字
void serial_sendnumber(uint32_t number,uint8_t length)
{
	uint8_t i;
	for(i=0;i<length;i++)
	{
		serial_sendbyte(number/serial_pow(10,length-1-i)%10+0x30);//ASCII码中字符0对应0x30
	}
}

//主函数代码
	serial_sendnumber(12345,5);

5.7.3printf函数分装

	//printf函数移植方法
	printf("num=%d\r\n",1234);//搭配fputc函数
    int fputc(int ch,FILE *f)
    {
    	serial_sendbyte(ch);
	    return ch;
    }
	
    //此方法printf只能有一个,重定向到串口1,串口2无法使用
	
	//若每个串口想使用printf,可使用sprintf
	//sprintf可以把格式化字符传输到一个字符串里
	char string[100];
	sprintf(string "num=%d\r\n",1234);
	serial_sendstring(string);
	
	
	//封装printf函数
	//在serial.c文件添加头文件
	#include "stdarg.h"
	void serial_printf(char*format,...)
	{
		char string[100];
		va_list arg;//定义参数列表变量
		va_start(arg,format);//从format位置开始接收参数表,放在arg里
		vsprintf(string,format,arg);//打印位置string 格式化字符串format,参数表为arg
		serial_sendstring(string);
	}

5.8串口发送和接收

serial.c函数修改不多

①GPIO口加PA10引脚,使用上拉输入

②USART结构体中模式加入接收模式

③接收串口可以是查询或者中断俩种方法

查询方法
serial.c文件中
需要改变的地方
Ⅰ
	GPIO_InitTypeDef GPIO_Initstructure;
	GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AF_PP;//TX使用复用推挽输出 
	GPIO_Initstructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);
	
	GPIO_Initstructure.GPIO_Mode=GPIO_Mode_IPU;//RX使用上拉输入
	GPIO_Initstructure.GPIO_Pin=GPIO_Pin_10;
	GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);

Ⅱ
	USART_Initstructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//USART模式
	/*
	#define USART_Mode_Rx    发送模式
	#define USART_Mode_Tx    接收模式
	*/


uint16_t  serial_getbyte(void)
{
	uint16_t RXdata;
	if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET)
	{
		RXdata=USART_ReceiveData(USART1);
		//是否需要清除标志位-不需要,DR寄存器清除
	}
	
	return RXdata;
}

main.c文件中
int main(void)
{	
	
  OLED_Init();
	serial_init();
	while(1)
	{
		OLED_ShowHexNum(1,1,serial_getbyte(),2);
	}
}


中断方法
在serial.c文件中
添加相关中断函数
	USART_ITConfig(USART1 ,USART_IT_RXNE,ENABLE );
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1 ,ENABLE);
中断函数配置
uint8_t serial_getRxfalg(void)
{
	if(Serial_RXFlag==1)
	{
		Serial_RXFlag=0;
		return 1;
	}
	return 0;
}


uint8_t serial_getRXdata(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);
		}
}


main.c文件中
uint16_t Rxdata;
int main(void)
{	
	
  OLED_Init();
	serial_init();
	OLED_ShowString(1,1,"RXdata:");
	while(1)
	{
		if(serial_getRxfalg()==1)
		{
			Rxdata=serial_getRXdata();
			serial_sendbyte(Rxdata);
		}
		OLED_ShowHexNum(1,8,Rxdata,2);
	}
}


网站公告

今日签到

点亮在社区的每一天
去签到