STM32 学习 —— 个人学习笔记9-1(USART串口协议 串口发送及接收数据)

发布时间:2026/7/4 12:35:57

STM32 学习 —— 个人学习笔记9-1(USART串口协议  串口发送及接收数据) 声明文中内容为观看 BiliBili 视频【STM32入门教程-2023版 细致讲解 中文字幕】后学习并扩展总结。本文章为个人学习使用版面观感若有不适请谅解文中知识仅代表个人观点若出现错误欢迎各位批评指正。一、USART 串口协议1.1 通信接口在嵌入式系统与电子设备互联领域通信的核心目的是实现不同设备间的数据传输与交互进而扩展硬件系统的功能边界、提升系统集成度使单一设备能够通过数据交互协同完成复杂任务。为保障通信过程的有序性、准确性与兼容性通信双方需遵循统一的通信协议该协议作为数据收发的标准化规则明确了数据传输的格式、时序、电平标准及交互逻辑是实现设备间可靠通信的基础。目前嵌入式系统中常用的通信方式各具特色其核心引脚配置、双工模式、时钟机制、电平类型及设备互联方式如下通用同步异步收发传输器USART采用TX、RX引脚支持全双工异步通信为单端电平、点对点设备互联集成电路总线I2C以SCL、SDA为核心引脚半双工同步传输单端电平且支持多设备互联串行外设接口SPI包含SCLK、MOSI、MISO、CS引脚全双工同步传输单端电平可实现多设备互联控制器局域网CAN通过CAN_H、CAN_L差分引脚半双工异步通信支持多设备互联通用串行总线USB以DP、DM为差分引脚半双工异步传输适用于点对点设备互联详见下附表格。名称引脚双工时钟电平设备USARTTX、RX全双工异步单端点对点I2CSCL、SDA半双工同步单端多设备SPISCLK、MOSI、MISO、CS全双工同步单端多设备CANCAN_H、CAN_L半双工异步差分多设备USBDP、DM半双工异步差分点对点综上不同通信方式基于其引脚配置、双工模式、时钟机制、电平类型及设备互联能力的差异形成了各自的应用优势与适用场景在实际系统设计中需结合数据传输速率、传输距离、设备数量及抗干扰需求选择合适的通信方式与对应协议以实现硬件系统的高效、可靠互联。1.2 串口通信在嵌入式系统与电子设备互联领域串口作为应用最为广泛的通信接口之一具备成本低廉、操作便捷、通信线路简洁的核心优势其仅需少量通信线路即可实现两个设备间的双向数据交互无需复杂的硬件配置有效降低了系统设计与实现成本。在单片机应用系统中串口是核心通信接口之一其可实现单片机与单片机、单片机与上位机如计算机、单片机与各类功能模块如传感器模块、显示模块、通信模块等之间的可靠通信。这一功能有效打破了单一单片机的功能局限极大地拓展了单片机系统的应用范围增强了单片机系统的硬件扩展能力与数据交互能力为单片机系统实现复杂功能、接入多设备互联网络提供了重要支撑。此外串口的广泛应用进一步推动了嵌入式系统向小型化、低成本、高兼容性方向发展在智能控制、数据采集、工业自动化等诸多领域发挥着不可替代的作用。1.3 硬件电路在嵌入式系统与外设互联场景中UART通用异步收发传输器作为典型的串行通信接口其物理层连接与通信模式设计直接影响数据传输的可靠性与效率。针对设备间的简单双向串口通信其核心连接规范可归纳为通信链路包含发送端Transmit, TX与接收端Receive, RX两根核心信号线为实现双向数据交互需遵循TX 与 RX 交叉连接的原则 —— 即设备 1 的 TX 引脚需与设备 2 的 RX 引脚直连设备 1 的 RX 引脚则与设备 2 的 TX 引脚直连以此构建完整的双向传输通道同时为保障电平参考一致两设备的接地端Ground, GND必须共地连接若需由一方为另一方供电可额外接入电源端VCC。在通信模式层面UART 支持灵活的传输配置当应用场景仅需单向数据传输如传感器向主控节点上报数据时可仅保留单根通信线仅连接发送端与对应接收端以简化硬件布线并降低功耗而在双向交互场景如主控与外设的指令应答中则需完整保留 TX/RX 交叉链路实现全双工数据交换。此外不同设备间的电平标准差异如 3.3V CMOS 与 5V TTL、RS-232 与 TTL 电平会直接导致信号识别失效因此在电平标准不兼容的场景下必须引入电平转换芯片如 MAX3232、SP3232 等进行电平匹配以保障通信的稳定性与兼容性。1.4 电平标准在串行通信体系中电平标准是实现数字逻辑与物理电信号映射的核心规范它明确定义了二进制数据 “1” 和 “0” 在传输线缆上的电压表示方式是保障设备间信号可靠识别与传输的基础。不同电平标准通过差异化的电压区间、信号形式及抗干扰设计适配了多样化的通信场景与距离需求。串口通信领域常用的电平标准主要包括三类1、TTL 电平Transistor-Transistor Logic作为嵌入式系统与板级通信的主流电平标准其逻辑定义为3.3 V 或 5 V 对应逻辑 “1”0 V 对应逻辑 “0”。该标准具有功耗低、响应速度快、电路结构简单等优势广泛应用于微控制器、传感器等短距离板级设备间的通信但抗共模干扰能力较弱传输距离通常限制在 1 米以内。2、RS-232 电平作为早期计算机与外设通信的经典标准采用负逻辑定义-3 V ~ -15 V 表示逻辑 “1”3 V ~ 15 V 表示逻辑 “0”。通过正负电压的极性差异提升了抗干扰能力传输距离可达 15 米但由于单端信号传输的特性其抗共模干扰能力仍有限且电平幅值较高需专用芯片实现与 TTL 电平的转换。3、RS-485 电平基于差分信号传输的工业级电平标准其逻辑由两线间的电压差决定2 V ~ 6 V 压差对应逻辑 “1”-2 V ~ -6 V 压差对应逻辑 “0”。差分结构使其具备极强的抗共模干扰能力可支持最长 1200 米的远距离传输同时允许多节点总线连接因此成为工业现场、楼宇自动化等长距离、强干扰环境下的首选串口通信电平标准。不同电平标准的电气特性差异决定了其应用边界TTL 电平适用于板级高密度互联RS-232 适用于中短距离点对点通信RS-485 则面向长距离、多节点的工业级场景。当设备间电平标准不兼容时需通过专用电平转换芯片如 MAX3232、MAX485实现信号电平的匹配以保障通信链路的稳定性与兼容性。1.5 串口通信核心参数定义串口通信UART/USART是一种异步、点对点的串行数据传输协议其通信行为由一组关键参数定义直接决定数据帧的格式与传输速率波特率Baud Rate波特率是衡量串口通信速率的核心指标定义为单位时间内传输的码元数量单位bit/s它决定了每位数据的持续时间 T b 1/BB 为波特率。常见标准波特率包括 9600、19200、38400、115200 bit/s 等通信双方必须配置为相同波特率以实现同步采样。起始位Start Bit起始位是数据帧的同步标志位固定为低电平逻辑 0用于通知接收方新数据帧的开始触发接收端的采样时序逻辑。数据位Data Bits数据位是帧的有效载荷部分通常为 8 位或 9 位支持多字节 / 地址模式遵循低位先行LSB First原则即最低有效位D0最先传输最高有效位D7/D8最后传输。逻辑 1 对应高电平逻辑 0 对应低电平。校验位Parity Bit校验位是可选的差错检测位根据数据位计算生成奇校验 / 偶校验用于验证传输过程中数据的完整性。在 9 位数据帧模式下第 9 位可复用为校验位如 RB8/TB8实现多机通信中的地址 / 数据区分。停止位Stop Bit停止位是数据帧的结束标志位固定为高电平逻辑 1用于帧间间隔与电平复位常见长度为 1 位或 2 位为接收端提供足够的时序恢复时间。1.6 串口数据帧时序结构串口数据帧的时序结构 1.5 部分所述参数按固定顺序组合而成典型帧格式如下8 位数据位帧10 位帧结构空闲态 → 起始位(1位) → 数据位(D0~D7, 8位) → 停止位(1位) → 空闲态总长度1起始 8数据 1停止 10 位时序特征起始位触发接收数据位按 LSB 到 MSB 顺序传输停止位结束帧并恢复空闲电平。9 位数据位帧11 位帧结构支持多机通信空闲态 → 起始位(1位) → 数据位(D0~D8, 9位) → 停止位(1位) → 空闲态总长度1起始 9数据 / 校验 1停止 11 位时序特征第 9 位D8可作为校验位RB8/TB8或地址标记位在多机通信中用于区分地址帧与数据帧增强协议扩展性。1.7 USART 简介USARTUniversal Synchronous/Asynchronous Receiver/Transmitter通用同步 / 异步收发器是嵌入式微控制器中广泛应用的串行通信外设作为实现设备间全双工串行数据交互的核心硬件模块其兼具同步通信与异步通信的双重特性能够适配不同场景下的串行数据传输需求是嵌入式系统中数据通信的基础核心组件之一。在硬件实现层面USART 作为 STM32 系列微控制器如 STM32F103C8T6内部集成的专用外设具备独立的硬件时序生成与解析能力无需占用 CPU 核心的大量运算资源发送数据时CPU 仅需将待传输的字节数据写入数据寄存器USART 外设即可自动按照预设的通信协议生成标准数据帧时序并通过 TX发送引脚完成数据输出接收数据时外设可自动检测 RX接收引脚的电平变化解析串行数据帧时序将逐位传输的串行数据拼接为完整的字节数据后存入数据寄存器等待 CPU 读取这一硬件化的处理方式大幅提升了串行通信的效率降低了 CPU 的负载。从性能与配置特性来看STM32 内置的 USART 外设搭载了独立的波特率发生器可灵活配置通信速率最高传输速率可达 4.5 Mbits/s能够满足中高速串行通信场景的需求在数据帧格式方面USART 支持高度可配置化设计数据位长度可选择 8 位或 9 位停止位长度可配置为 0.5 位、1 位、1.5 位或 2 位校验位支持无校验、奇校验与偶校验三种模式可适配不同通信协议对帧格式的差异化要求。除基础的异步串行通信功能外STM32 的 USART 外设还具备丰富的扩展特性支持同步通信模式可通过同步时钟引脚CLK实现主从设备间的同步数据传输集成硬件流控制功能CTS/RTS能够有效避免数据传输过程中的溢出或丢失支持 DMA直接存储器访问传输可实现数据在 USART 数据寄存器与内存间的无 CPU 干预传输进一步提升通信效率此外还兼容智能卡协议、IrDA红外数据协会红外通信、LIN本地互联网络等专用通信标准拓展了其在工业控制、汽车电子等领域的应用场景。针对 STM32F103C8T6 这款主流微控制器其集成的 USART 资源包含 USART1、USART2、USART3 三路独立外设各路 USART 均可独立配置通信参数支持多通道并行通信满足多设备互联的应用需求。USART 凭借其高可靠性、灵活配置性与低 CPU 占用率的特性成为 STM32 系列微控制器实现串口通信、外设互联、上位机交互等功能的核心外设广泛应用于工业自动化、物联网、智能硬件等领域。1.8 USART基本结构通用同步异步收发器Universal Synchronous Asynchronous Receiver Transmitter, USART是嵌入式系统中实现串行数据通信的核心外设其硬件架构可划分为时钟与波特率生成模块、发送控制通路、接收控制通路、数据缓冲与移位寄存器及接口控制模块五大部分各模块协同完成同步 / 异步串行数据的帧编码、传输与解码。1时钟与波特率生成模块该模块以外设时钟PCLK2/PCLK1为输入通过可编程分频与计数逻辑生成精确的波特率时钟为发送与接收通路提供同步时序基准。核心功能根据用户配置的波特率参数将系统外设时钟分频为符合通信标准的比特率时钟确保收发双方时序对齐。控制关系生成的波特率时钟分别送入发送控制器与接收控制器作为数据移位与采样的时间基准。2发送控制通路发送通路负责将并行数据转换为符合通信协议的串行比特流由发送控制器、发送数据寄存器Transmit Data Register, TDR与发送移位寄存器构成。发送数据寄存器TDR作为 CPU 与发送硬件之间的并行数据缓冲CPU 通过写操作将待发送数据载入 TDR。发送移位寄存器在发送控制器的时序驱动下将 TDR 中的并行数据逐位转换为串行比特流并添加起始位、校验位与停止位等协议帧头帧尾。发送控制器依据波特率时钟与通信模式同步 / 异步控制数据加载、移位输出与帧格式生成同时管理发送完成标志与中断请求。3接收控制通路接收通路实现串行比特流到并行数据的解码与缓冲由接收控制器、接收移位寄存器与接收数据寄存器Receive Data Register, RDR构成。接收移位寄存器在接收控制器的采样时序控制下对 RX 引脚输入的串行比特流进行过采样与同步逐位接收并拼接为完整并行数据。接收数据寄存器RDR作为接收硬件与 CPU 之间的并行数据缓冲存储已完成拼接的有效数据等待 CPU 读取。接收控制器负责检测起始位、同步时钟、校验位验证与停止位检测控制移位寄存器的数据加载与向 RDR 的转移同时管理接收完成标志与错误状态如帧错误、溢出错误、校验错误。4接口与控制模块GPIO 接口实现 USART 硬件引脚与芯片外部物理链路的连接TX 引脚用于发送串行数据RX 引脚用于接收串行数据GPIO 的复用功能配置决定引脚的通信角色。开关控制模块作为全局控制逻辑负责 USART 外设的使能 / 禁用、收发通路的单独开关、中断使能与 DMA 请求控制是系统软件配置与硬件行为的交互接口。5模块协同工作机制发送流程CPU 写入 TDR → 发送控制器将 TDR 数据载入发送移位寄存器 → 波特率时钟驱动移位寄存器逐位输出至 TX 引脚 → 完成发送后触发状态标志。接收流程RX 引脚检测到起始位 → 接收控制器启动采样与移位 → 接收移位寄存器拼接为并行数据 → 数据载入 RDR → 触发接收完成标志等待 CPU 读取。该架构通过双缓冲机制数据寄存器 移位寄存器实现了全双工通信有效提升了数据传输的吞吐量与可靠性。1.9 字长配置与帧基本结构数据帧以起始位作为传输唤醒与同步标识通常为低电平逻辑用于通知接收方后续数据的到来。数据位段长度可配置为 8 位或 9 位当未设置 M 位时数据位为 8 位位 0 至位 7对应标准字节传输当设置 M 位时数据位扩展为 9 位位 0 至位 8可用于多模态数据或地址 / 数据复用传输。在数据位之后可选择性插入奇偶校验位通过奇校验或偶校验机制实现传输差错检测提升通信可靠性。帧尾以停止位结束停止位为高电平逻辑用于标识一帧数据的结束并为下一次传输提供空闲间隔。此外通信链路中存在空闲帧与断开帧两种特殊状态空闲帧表现为持续高电平代表无数据传输的链路空闲状态断开帧则以持续低电平后跟随停止位的形式标识物理链路的断开或异常状态。1.10 停止位配置与时序适配停止位作为帧结束的标识其长度可配置为 0.5 位、1 位、1.5 位或 2 位以适配不同时钟频率与收发设备时序差异1 位停止位为最基础配置提供最小的帧间隔适用于高速、同步精度较高的通信场景1.5 位与 2 位停止位通过延长帧尾高电平时长为低速设备或时钟偏差较大的收发双方提供更充裕的时序恢复窗口降低帧同步丢失风险0.5 位停止位为极简配置可最小化帧间开销适用于极高速、时序高度同步的专用通信场景。停止位长度的配置由 LBCLLast Bit Clock Length位控制该位直接决定最后一位数据位之后的时钟脉冲数量从而精准定义停止位的时序宽度。这种可配置的帧结构设计使异步串行通信能够在传输效率与时序容错性之间实现动态平衡满足多样化嵌入式与工业通信场景的需求。1.11 起始位侦测机制在异步串行通信系统中起始位侦测是实现帧同步的核心环节其本质是通过多采样点的统计判决在噪声与时钟偏差干扰下可靠识别数据帧的起始标志。系统在空闲状态下持续监测接收信号线的电平变化当检测到下降沿跳变由高电平至低电平时即触发起始位侦测流程进入 “起始位” 接收状态。为应对收发端时钟频率偏差与信号噪声系统采用过采样策略以 16 倍于波特率的采样时钟对接收信号进行逐位采样每一位数据对应 16 个采样点。在起始位判定阶段系统将 16 个采样点划分为若干组进行统计判决首先在下降沿后对前若干采样点进行初步电平确认随后将后续采样点分为多组每组 3 个采样点要求每组中至少出现 2 个低电平采样值以此作为判定当前低电平为有效起始位的核心条件。这种多采样点的多数表决机制能够有效滤除瞬时噪声干扰并容忍约 6/16 至 7/16 的时钟相位偏差确保在波特率误差范围内仍可稳定识别起始位为后续数据位、校验位与停止位的可靠接收奠定同步基础。1.12 数据采样机制在高速串行数据传输的噪声检测场景中数据采样是实现信号可靠判决的核心环节其采样时序与位周期的匹配直接决定了噪声容限与数据恢复精度。如下图所示系统采用16 倍于数据位速率的过采样时钟将单个数据位的时间长度划分为 16 个等间隔采样点。为规避信号跳变沿的瞬时噪声干扰采样窗口被精确限定在数据位的稳定区间内以第 1 个数据位为例其有效采样区间为第 8 至第 10 个采样时钟沿覆盖了数据位中部的稳定电平阶段而数据位的前后沿区域分别对应前 7 个与后 6 个采样点则被排除在有效采样之外以避免跳变噪声引入的判决误差。这种居中过采样策略通过将采样窗口锚定在数据位的稳态平台区最大化了对信号抖动与信道噪声的容忍能力一方面16 倍过采样率提供了精细的时间分辨率可捕捉信号电平的微小波动另一方面限定采样窗口于稳态区间规避了上升 / 下降沿的亚稳态风险确保采样结果能够真实反映数据位的逻辑电平。从时序分配来看单个数据位的有效采样区间占比为3 16 \frac{3}{16}163​​剩余13 16 \frac{13}{16}1613​的时间窗口用于隔离跳变噪声这种设计在噪声抑制与采样效率之间实现了优化平衡为后续的噪声分析与数据恢复提供了可靠的原始样本。1.13 波特比率寄存器USART_BRR波特比率寄存器是通用同步 / 异步收发器USART中负责波特率配置的核心寄存器其地址偏移为 0x08复位值为 0x0000。该寄存器的 32 位结构中位 31 至 16 为硬件强制置 0 的保留位位 15 至 4 为 DIV_Mantissa [11:0]用于定义 USART 分频器除法因子USARTDIV的整数部分位 3 至 0 为 DIV_Fraction [3:0]用于定义 USARTDIV 的小数部分且所有有效位域均支持读写操作。在模块运行逻辑中发送器TE与接收器RE的使能状态直接影响波特率计数器当 TE 或 RE 任一被使能时计数器正常计数以驱动波特率生成若二者均被禁止则计数器停止计数以降低功耗并避免无效时序干扰。波特率的生成严格遵循公式波特率 f P C L K 2 / 1 16 × DIV \text{波特率} \frac{f_{PCLK2/1}}{16 \times \text{DIV}}波特率16×DIVfPCLK2/1​​其中 fPCLK2 为 APB2 总线时钟频率DIV 由 USART_BRR 中 DIV_Mantissa 与 DIV_Fraction 共同构成通过对该寄存器的精准配置可实现 USART 收发链路波特率的精确调控以适配不同串行通信场景的速率需求。二、串口发送数据 及 串口发送接收数据2.1 串口发送数据的实现首先按下图接线方式搭建面包板电路连接 OLED 显示屏并将 USB 转串口的 TXD 和 RXD 分别与 PA2 和 PA3 连接然后将 DAP-Link / ST-Link 连接到 STM32 最小系统板上为使 OLED 显示屏的 VCC 和 GND 正确连接正负极请先连接对应正负极跳线或直接使用 GPIO 口进行供电。直接复制先前演示的已有文件目录重命名并双击后缀名为 .uvprojx 的文件打开工程文件并对 main.c 进行修改工程中所使用的全部头文件其详细内容已放于文末。#include stm32f10x.h // Device header #include Serial.h #include OLED.h int main(void) { OLED_Init(); Serial_Init(); Serial_SendByte(0x41); uint8_t MyArray[] {0x42, 0x43, 0x44, 0x45}; Serial_SendArray(MyArray, 4); Serial_SendString(\r\nNum1); Serial_SendNumber(111, 3); printf(\r\nNum2%d, 222); char String[100]; sprintf(String, \r\nNum3%d, 333); Serial_SendString(String); Serial_printf(\r\nNum4%d, 444); Serial_printf(\r\n); while (1) { } }打开串口助手串口助手软件 请在【江协科技】视频下方下载按下 STM32 开发板上的复位按键后系统将发送数据可在串口助手软件中查看数据输出结果。注波特率、数据位、停止位、校验位等信息可根据自身需求更改但务必与代码中设置保持一致。2.2 串口发送 接收数据的实现首先按下图接线方式搭建面包板电路连接 OLED 显示屏并将 USB 转串口的 TXD 和 RXD 分别与 PA2 和 PA3 连接然后将 DAP-Link / ST-Link 连接到 STM32 最小系统板上为使 OLED 显示屏的 VCC 和 GND 正确连接正负极请先连接对应正负极跳线或直接使用 GPIO 口进行供电。直接复制先前演示的已有文件目录重命名并双击后缀名为 .uvprojx 的文件打开工程文件并对 main.c 进行修改工程中所使用的全部头文件其详细内容已放于文末。#include stm32f10x.h // Device header #include Serial_Receive.h #include OLED.h uint8_t RxData; int main(void) { OLED_Init(); Serial_Init(); OLED_ShowString(1, 1, RxData:); while (1) { // 查询方法 // if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) SET){ // RxData USART_ReceiveData(USART2); // OLED_ShowHexNum(1, 1, RxData, 2); // } // 中断方法 if(Serial_GetRxFlag() 1){ RxData Serial_GetRxData(); Serial_SendByte(RxData); OLED_ShowHexNum(1, 8, RxData, 2); } } }三、演示代码关联的头文件与源文件说明OLED 相关头文件请从 STM32 学习 —— 个人学习笔记4OLED 显示屏及调试工具 文末查看此处不重复展示。Serial.c#include stm32f10x.h // Device header #include stdio.h #include stdarg.h void Serial_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate 9600; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Tx; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_Init(USART2, USART_InitStructure); USART_Cmd(USART2, ENABLE); } void Serial_SendByte(uint8_t Byte){ USART_SendData(USART2, Byte); while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) RESET); } void Serial_SendArray(uint8_t *Array, uint16_t Length){ uint16_t i; for(i0; iLength; i){ Serial_SendByte(Array[i]); } } void Serial_SendString(char *String){ uint8_t i; for(i0; String[i] ! \0; i){ Serial_SendByte(String[i]); } } 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(i0; iLength; i){ Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 0x30); } } int fputc(int ch, FILE *f){ Serial_SendByte(ch); return ch; } void Serial_printf(char *format, ...){ char String[100]; va_list arg; va_start(arg, format); vsprintf(String, format, arg); va_end(arg); Serial_SendString(String); }Serial.h#ifndef __SERIAL_H #define __SERIAL_H #include stdio.h void Serial_Init(void); void Serial_SendByte(uint8_t Byte); void Serial_SendArray(uint8_t *Array, uint16_t Length); void Serial_SendString(char *String); void Serial_SendNumber(uint32_t Number, uint8_t Length); int fputc(int ch, FILE *f); void Serial_printf(char *format, ...); #endifSerial_Receive.c#include stm32f10x.h // Device header #include stdio.h #include stdarg.h uint8_t Serial_RxData; uint8_t Serial_RxFlag; void Serial_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate 9600; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Tx | USART_Mode_Rx; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_Init(USART2, USART_InitStructure); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; NVIC_Init(NVIC_InitStructure); USART_Cmd(USART2, ENABLE); } void Serial_SendByte(uint8_t Byte){ USART_SendData(USART2, Byte); while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) RESET); } void Serial_SendArray(uint8_t *Array, uint16_t Length){ uint16_t i; for(i0; iLength; i){ Serial_SendByte(Array[i]); } } void Serial_SendString(char *String){ uint8_t i; for(i0; String[i] ! \0; i){ Serial_SendByte(String[i]); } } 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(i0; iLength; i){ Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 0x30); } } int fputc(int ch, FILE *f){ Serial_SendByte(ch); return ch; } void Serial_printf(char *format, ...){ char String[100]; va_list arg; va_start(arg, format); vsprintf(String, format, arg); va_end(arg); Serial_SendString(String); } uint8_t Serial_GetRxFlag(void){ if(Serial_RxFlag1){ Serial_RxFlag 0; return 1; } return 0; } uint8_t Serial_GetRxData(void){ return Serial_RxData; } void USART2_IRQHandler(void){ if(USART_GetITStatus(USART2, USART_IT_RXNE) SET){ Serial_RxData USART_ReceiveData(USART2); Serial_RxFlag 1; USART_ClearITPendingBit(USART2, USART_IT_RXNE); } }Serial_Receive.h#ifndef __SERIAL_RECEIVE_H #define __SERIAL_RECEIVE_H #include stdio.h void Serial_Init(void); void Serial_SendByte(uint8_t Byte); void Serial_SendArray(uint8_t *Array, uint16_t Length); void Serial_SendString(char *String); void Serial_SendNumber(uint32_t Number, uint8_t Length); int fputc(int ch, FILE *f); void Serial_printf(char *format, ...); uint8_t Serial_GetRxFlag(void); uint8_t Serial_GetRxData(void); #endif文中部分知识参考B 站 —— 江协科技百度百科

相关新闻