零基础学习4:玩转STM32与串口通信从文件传输到DMA高速数据传输
本教程系统介绍了STM32串口通信技术,从基础概念到实际应用。主要内容包括:1)串口通信分类(同步/异步、单工/双工、TTL/RS232等);2)串口协议详解与参数配置;3)RS-232标准及电平转换原理;4)USB转串口模块CH340的工作原理。实战部分展示了两台电脑通过USB-TTL模块进行文件传输的实验,包括硬件连接方法和传输性能测试。教程适合嵌入式开发者系统学习串口通信技术,掌握从基础调试
引言
在嵌入式系统开发中,串口通信是最基础且重要的通信方式之一。从简单的调试信息输出到复杂的数据传输,串口都扮演着不可或缺的角色。本教程将从零开始,深入讲解STM32的串口通信,涵盖从基础的文件传输到高效的DMA数据传输,帮助初学者快速掌握串口通信的核心技术。
一、串口通信前言
1.1 串口通信类别
串口通信根据不同的分类标准可以分为多种类型,理解这些分类有助于我们选择合适的通信方式。
按数据传输方式分类
同步串行通信
- 需要时钟信号同步
- 发送和接收方使用同一时钟
- 数据传输效率高
- 典型代表:SPI、I2C
异步串行通信
- 不需要时钟信号
- 依靠起始位和停止位同步
- 硬件要求简单
- 典型代表:UART
| 特性 | 同步通信 | 异步通信 |
|---|---|---|
| 时钟信号 | 需要 | 不需要 |
| 传输效率 | 高 | 中等 |
| 硬件复杂度 | 较高 | 较低 |
| 传输距离 | 较短 | 较长 |
| 成本 | 较高 | 较低 |
| 典型应用 | 高速板内通信 | 设备间通信 |
STM32F103系列提供5路串口,包含3个 USART 和2个 UART 。
串口的引脚如下图所示:
按数据传输方向分类
单工通信
- 数据只能单向传输
- 一方固定为发送端,另一方为接收端
- 如:广播、遥控器
半双工通信
- 数据可以双向传输,但不能同时
- 需要方向切换
- 如:对讲机、RS-485
全双工通信
- 数据可以同时双向传输
- 发送和接收通道独立
- 如:电话、UART

按电气标准分类
TTL串口
- 电压:0-5V/0-3.3V
- 传输距离:< 2米
- 应用:板内通信
RS-232
- 电压:±15V
- 传输距离:≤ 15米
- 应用:设备间通信
RS-485
- 电压:±7V
- 传输距离:≤ 1200米
- 应用:工业现场总线
各类串口通信对比表:
| 特性 | TTL UART | RS-232 | RS-485 | USB转串口 |
|---|---|---|---|---|
| 电平标准 | 0-3.3V/5V | ±15V | ±7V | 3.3V/5V |
| 传输距离 | 0.5-2米 | ≤15米 | ≤1200米 | 5米(USB限制) |
| 通信方式 | 全双工 | 全双工 | 半双工/全双工 | 全双工 |
| 节点数量 | 点对点 | 点对点 | 多点(32-256) | 点对点 |
| 抗干扰 | 弱 | 中等 | 强 | 中等 |
| 成本 | 低 | 中等 | 中等 | 低 |
| 应用场景 | 开发板调试 | 工控设备 | 工业总线 | PC连接 |
特殊类型串口通信
软件串口(Software Serial)
- 通过GPIO模拟串口时序
- 灵活性高,但占用CPU资源
- 用于引脚不足的情况
硬件串口(Hardware UART)
- 专用硬件实现
- 不占用CPU资源
- 性能稳定可靠
虚拟串口(Virtual COM Port)
- 通过USB模拟串口
- 即插即用,使用方便
- 如:CH340、CP2102等
1.2 串口协议
串口通信(Serial Communication)是一种异步串行通信方式,数据按位顺序传输。其核心特点是通信双方不需要共享时钟信号,而是通过预定义的波特率来实现同步。
串口数据帧格式:
每个数据帧包含以下几个部分:
- 起始位:1位低电平,标志数据帧的开始
- 数据位:5-9位有效数据,通常为8位
- 校验位:1位,用于错误检测(可选)
- 停止位:1-2位高电平,标志数据帧的结束
┌─────┬───────────┬────────┬─────────┐
│起始位│ 数据位 │ 校验位 │ 停止位 │
│ (1b) │ (5-9b) │ (0-1b)│ (1-2b) │
└─────┴───────────┴────────┴─────────┘
串口通信参数配置表:
| 参数 | 说明 | 常见配置 | 影响因素 |
|---|---|---|---|
| 波特率 | 数据传输速率(bps) | 9600, 19200, 115200等 | 传输速度、通信距离 |
| 数据位 | 每个字符的数据位数 | 5, 6, 7, 8位 | 数据精度 |
| 停止位 | 帧结束标志位数 | 1, 1.5, 2位 | 帧间隔 |
| 校验位 | 错误检测机制 | 无、奇校验、偶校验 | 数据可靠性 |
| 流控制 | 数据传输控制 | 无、RTS/CTS、XON/XOFF | 大数据量传输 |
波特率计算公式:
波特率 = 时钟频率 / (16 × USARTDIV)
其中USARTDIV是一个浮点数,整数部分写入BRR[15:4],小数部分写入BRR[3:0]
1.3 RS-232标准详解
RS-232是由电子工业联盟(EIA)制定的串行数据通信接口标准,广泛应用于计算机和外部设备的连接。
RS-232主要特性:
- 电气特性:采用负逻辑,+3V至+15V表示逻辑0,-3V至-15V表示逻辑1
- 机械特性:DB9或DB25连接器
- 传输距离:最大15米(在19200bps时)
- 连接方式:点对点全双工通信
RS-232 DB9接口定义表:
| 引脚 | 名称 | 方向 | 说明 |
|---|---|---|---|
| 1 | DCD | 输入 | 数据载波检测 |
| 2 | RXD | 输入 | 接收数据 |
| 3 | TXD | 输出 | 发送数据 |
| 4 | DTR | 输出 | 数据终端就绪 |
| 5 | GND | - | 信号地 |
| 6 | DSR | 输入 | 数据设备就绪 |
| 7 | RTS | 输出 | 请求发送 |
| 8 | CTS | 输入 | 清除发送 |
| 9 | RI | 输入 | 振铃指示 |
RS-232信号电平标准表:
| 信号状态 | 电压范围 | 逻辑值 |
|---|---|---|
| 逻辑1 (MARK) | -3V ~ -15V | 1 |
| 逻辑0 (SPACE) | +3V ~ +15V | 0 |
| 过渡区 | -3V ~ +3V | 不确定 |
1.4 TTL电平 vs RS232电平
在嵌入式系统中,我们经常需要在TTL电平和RS232电平之间进行转换,理解两者的差异至关重要。
TTL电平特性:
- 逻辑1:+5V或+3.3V(取决于供电电压)
- 逻辑0:0V
- 适用于板内或短距离通信
电平对比分析表:
| 特性 | TTL电平 | RS232电平 | 影响分析 |
|---|---|---|---|
| 逻辑1电压 | +5V/+3.3V | -3V ~ -15V | 电平不兼容,需要转换 |
| 逻辑0电压 | 0V | +3V ~ +15V | 电平不兼容,需要转换 |
| 电压摆幅 | 0-5V/0-3.3V | ±15V | RS232抗干扰能力更强 |
| 传输距离 | 0.5-2米 | 最长15米 | RS232适合较长距离 |
| 抗干扰能力 | 较弱 | 较强 | RS232适合工业环境 |
| 成本 | 低 | 较高 | TTL更适合成本敏感应用 |
| 应用场景 | 板内通信 | 设备间通信 | 根据需求选择 |
电平转换原理图:
1.5 CH340模块工作原理
CH340是国内厂商沁恒微电子推出的USB转串口芯片,因其性价比高而广泛应用。
CH340功能框图:
CH340工作流程:
- USB数据包接收和解包
- 协议解析和数据提取
- 电平转换和串行化
- UART信号输出
CH340模块参数表:
| 参数 | 规格 | 说明 |
|---|---|---|
| 接口类型 | USB 2.0 | 全速设备,12Mbps |
| 串口支持 | UART | 支持常用串口模式 |
| 电压电平 | 3.3V/5V TTL | 兼容大多数MCU |
| 波特率范围 | 50bps ~ 2Mbps | 覆盖常用需求 |
| 数据位宽 | 5、6、7、8位 | 可配置 |
| 校验位 | 无、奇、偶校验 | 可配置 |
| 封装形式 | SOP-16 | 易于焊接 |
| 驱动支持 | Windows/Linux/macOS | 跨平台兼容 |
CH340与STM32连接示例:
CH340模块 STM32F103
TXD ──────→ PA10(RX)
RXD ←────── PA9(TX)
GND ─────── GND
VCC ─────── 3.3V/5V
二、实战文件传输
本次实验将两台笔记本电脑,借助 usb转ttl 模块和杜邦线,建立起串口连接。然后用串口助手等工具软件(带文件传输功能)将一台笔记本上的一个大文件(图片、视频和压缩包软件)传输到另外一台电脑,预算文件大小、波特率和传输时间三者之间的关系,并对比实际传输时间。
2.1 实验环境搭建
首先打开串口调试器
发送段设置如下:这里选择了一个图片进行发送
2.2 硬件连接指南
两台笔记本电脑,两个USB转TTL模块,四条杜邦线,两个串口线连接这两台电脑。连线方式:3V3-3V3,GND-GND,TXD-RXD,RXD-TXD。
2.3 文件传输实验
分别串口调试助手的串口打开,发送方点击发送,接收方点击接收。
VID_20251018_201309
最后保存数据到文件夹,右击打开方式选择画图,即可打开接收图片
2.3.1 波特率与传输时间关系
理论基础:
串口传输每个字节需要10个位(包括起始位、数据位和停止位),由此得出:
传输时间计算公式:
传输时间(秒)= (文件字节数 × 10)/ 波特率
有效传输速率:
实际速率(KB/秒)= 波特率 / (10 × 1024)
不同情况下的理论传输时间:
| 文件规格 | 波特率 | 预计时间 | 理论速率 |
|---|---|---|---|
| 2MB文件 | 9600 | 34.8分钟 | 0.94 KB/秒 |
| 2MB文件 | 115200 | 约3分钟 | 11.25 KB/秒 |
| 2MB文件 | 460800 | 约44秒 | 45 KB/秒 |
| 2MB文件 | 921600 | 约22秒 | 90 KB/秒 |
| 50MB文件 | 115200 | 约72分钟 | 11.25 KB/秒 |
| 50MB文件 | 921600 | 约9分钟 | 90 KB/秒 |
2.3.2 实际性能测试对比
测试条件:
- 操作系统:Windows 11
- 测试软件:串口调试助手
- 测试文件:2MB JPG图片
- 测试方法:每个波特率测试3次取平均值
实测数据记录:
| 波特率 | 理论时间 | 实测时间 | 实际速率 | 稳定性 |
|---|---|---|---|---|
| 9600 | 34.8分钟 | 36.2分钟 | 0.90 KB/s | 稳定 |
| 115200 | 2.9分钟 | 3.1分钟 | 10.5 KB/秒 | 稳定 |
| 460800 | 43.5秒 | 46.8秒 | 41.7 KB/秒 | 稳定 |
| 921600 | 21.8秒 | 24.1秒 | 81.3 KB/秒 | 较稳定 |
性能对比分析:
通过测试发现,实际传输时间普遍比理论计算值长约5-10%,主要原因包括:
- 文件传输协议的控制信息开销
- 串口软件的数据处理时间
- 操作系统调度延迟
- 错误重传机制的影响
随着波特率提高,实际速率与理论速率的差距有所增大,在最高波特率时差距达到20%左右。
2.4 地线重要性分析
地线的关键作用
地线在串口通信中具有重要作用:
- 建立统一的电压参考基准
- 形成完整的电流回路
- 抑制信号干扰
- 保障设备安全
地线连接实验
测试设置:
- 波特率:115200
- 文件大小:1MB
- 对比有地线和无地线的情况
测试结果:
| 接地状态 | 传输效果 | 错误情况 | 观察现象 |
|---|---|---|---|
| 地线完好 | 传输成功 | 无错误 | 文件完整接收 |
| 未接地线 | 传输失败 | 100%错误 | 无法建立通信 |
| 地线接触不良 | 传输不稳定 | 15-40%错误 | 数据包丢失 |
接地问题分析
在串口通信系统中,接地质量直接影响通信的稳定性和可靠性。接地问题通常表现为三种典型情况,每种情况都有其独特的现象和深层次原因。
完全无地线连接是最严重的接地故障。当两个通信设备之间没有建立地线连接时,系统实际上缺少一个共同的电压参考基准。这就像两个人用不同的语言标准进行对话,完全无法理解对方的意思。在电气特性上,发送端和接收端的逻辑电平"0"和"1"没有统一的判断标准,导致信号无法被正确解析。在实际操作中,表现为通信完全中断,设备间无法建立任何有效连接。解决这一问题的关键在于建立可靠的地线通路,使用万用表检查GND线是否形成完整回路是最直接的诊断方法。
地线接触不良是较为隐蔽但常见的问题。这种情况通常由于接口氧化、连接器松动或导线断裂导致接触电阻增大。当接触电阻存在时,信号电流流经地线会产生额外的电压降,使得参考电平发生漂移。这种漂移是随机的,导致接收端对逻辑电平的判断时对时错。具体表现为数据传输中出现随机性错误,某些数据包能正常接收,而另一些则完全错误。特别是在有外部干扰的环境中,这种问题会更加明显。确保接地可靠需要从物理连接入手,包括清洁连接器、紧固接口,以及在要求高的场合采用焊接代替插接。
地线质量问题往往被初学者忽视。使用过细的导线、过长的走线或劣质材料都会增加接地回路的阻抗。在高频信号传输时,集肤效应会使电流集中在导线表面,进一步增加有效电阻。当地线阻抗过大时,高频噪声无法有效泄放,会在系统中积累,降低信号的信噪比。这不会立即导致通信中断,但会显著增加误码率,迫使系统频繁进行数据重传,从而降低有效传输速率。改善地线质量需要选择截面积足够的多股铜线,保持地线长度最短,并避免与强干扰源平行走线。
这些接地问题在实际工程中往往相互交织,需要系统性地分析和解决。良好的接地不仅是一个连接点,更是一个低阻抗的回路系统。在复杂的电磁环境中,合理的接地设计是保证串口通信质量的重要基础,值得在工程实施中给予充分重视。
三、串口通信配置
以下工程建立省略了相关基本配置操作,如有需要会将文章放入参考资料里
3.1 正常串口通信开发
3.1.1 操作实现
开启USART1异步通信如下:
设置波特率等如下(此处为系统默认)
这样就可以生成工程,打开工程,我们需要使用下面一俩行函数
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
功能:串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。
参数:
- *UART_HandleTypeDef huart:UART结构体( huart1)
- *pData:需要发送的数据
- Size:发送的字节数
- Timeout:最大发送时间,发送数据超过该时间退出发送
代码实现如下:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_UART_Transmit(&huart1, (uint8_t *)"hello windows!\r\n", 16 , 0xffff);
HAL_Delay(1000); //延时1s
/* USER CODE END 3 */
}
轮询代码实现需要调用 HAL_UART_Receive()函数如下:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 轮询方式接收一个字节
if (HAL_UART_Receive(&huart1, rx_data, 1, 10) == HAL_OK) // 10ms超时,避免长时间阻塞
{
// 处理接收到的命令
switch(rx_data[0])
{
case '#': // 暂停发送
send_enabled = 0;
break;
case '*': // 继续发送
send_enabled = 1;
break;
}
}
// 定时发送"hello windows!"
if(send_enabled)
{
HAL_UART_Transmit(&huart1, (uint8_t *)"hello windows!\r\n", 16 , 0xffff);
HAL_Delay(1000); //延时1s
}
}
/* USER CODE END 3 */
}
3.1.2 实现展示
一秒发送hallow windows!展示如下:
屏幕录制 2025-10-19 014012
轮询停止发送展示如下:
屏幕录制 2025-10-19 014129
3.1.3 仿真分析
点击魔法棒,设置debug。勾选Use Simulator 使用软件调试。更改 Dialog DLL 以及 Parameter
点击方框内,开始调试
打开 logic analyzer窗口,进行波形分析
点击 Setup 选项
点击方框 新建 。输入 USART1_SR
类型设置为比特流,并可以选择设置波形颜色。设置完就可以点击下方 Close 退出了
点击方框内 run开始

可以发现延时准确
- 计算实际传输的比特数
要发送的字符串是 “hallow windows!”。
数一下字符: h,a,l,l,o,w,w,i,n,d,o,w,s,!` 一共 15个字符。
在串口通信中,每个字符(字节)的传输包含:1个起始位、8个数据位、1个停止位,总共 10 个比特。
所以,传输这15个字符所需的总比特数为:总比特数 = 15 字符 × 10 比特/字符 = 150 比特
- 计算实际比特率(波特率)
已知:
传输时间 = 1.442278 ms = 0.001442278 秒
传输的总比特数 = 150 比特
波特率 (bps) = 总比特数 / 传输时间
波特率 = 150 bits / 0.001442278 s ≈ 104,001 bps
- 结论与分析
计算出的波特率约为 104,000,这与标准的 115,200 波特率最为接近。两者之间存在约10%的误差,这是完全合理的,主要原因如下:系统开销,计算的是纯数据传输时间,但实际测量可能包含了软件处理、操作系统调度、串口助手内部缓冲等微小延迟;时钟精度,USB转TTL模块或电脑主板时钟可能存在微小偏差,导致实际波特率与设定值有细微差别;测量误差,时间测量工具(很可能是软件计时)本身存在一定的精度限制。
3.2 基于中断开发
3.2.1 中断机制原理
中断是嵌入式系统中至关重要的机制,它允许处理器在正常程序执行过程中响应外部或内部事件。理解中断原理对于开发高效的串口通信程序至关重要。
中断基本概念
中断可以理解为一种"硬件级别的函数调用"。当特定事件发生时,处理器暂停当前正在执行的程序,转去执行相应的中断服务程序(ISR),执行完毕后再返回到原程序继续执行。
中断工作流程
- 中断请求:外设(如串口)检测到事件并发出中断请求信号
- 中断响应:处理器完成当前指令后,响应中断请求
- 现场保护:自动保存关键寄存器值到堆栈
- 中断服务:执行对应的中断服务程序
- 现场恢复:恢复之前保存的寄存器值
- 中断返回:返回到被中断的程序继续执行
中断相关术语表
| 术语 | 英文 | 说明 |
|---|---|---|
| 中断源 | Interrupt Source | 能够产生中断请求的信号源 |
| 中断向量 | Interrupt Vector | 中断服务程序的入口地址 |
| 中断优先级 | Interrupt Priority | 决定多个中断同时发生时的响应顺序 |
| 中断屏蔽 | Interrupt Mask | 暂时禁止某些中断响应的机制 |
| 中断嵌套 | Interrupt Nesting | 高优先级中断打断低优先级中断服务的过程 |
| 现场保护 | Context Saving | 保存被中断程序的执行状态 |
STM32中断系统架构
STM32的中断系统基于ARM Cortex-M内核的NVIC(嵌套向量中断控制器),具有高度可配置性。
中断优先级分组
STM32支持中断优先级分组,将4位优先级分为抢占优先级和子优先级:
| 优先级分组 | 抢占优先级位数 | 子优先级位数 | 说明 |
|---|---|---|---|
| 分组0 | 0位 | 4位 | 无抢占优先级,只有16个子优先级 |
| 分组1 | 1位 | 3位 | 2级抢占优先级,8个子优先级 |
| 分组2 | 2位 | 2位 | 4级抢占优先级,4个子优先级 |
| 分组3 | 3位 | 1位 | 8级抢占优先级,2个子优先级 |
| 分组4 | 4位 | 0位 | 16级抢占优先级,无子优先级 |
中断响应时序
中断响应时间包括多个阶段:
- 检测延迟:从中断发生到处理器检测到的时间
- 处理延迟:处理器完成当前指令的时间
- 入口延迟:保存现场和跳转到ISR的时间
- ISR执行:中断服务程序实际执行时间
- 退出延迟:恢复现场和返回的时间
典型中断响应时间表
| 处理器状态 | 最小响应周期 | 最大响应周期 | 影响因素 |
|---|---|---|---|
| 空闲状态 | 12周期 | 12周期 | 固定延迟 |
| 执行简单指令 | 12+周期 | 12+当前指令周期 | 当前指令长度 |
| 执行长指令 | 12+周期 | 12+多个周期 | 如除法指令 |
| 中断禁用 | 无限等待 | 无限等待 | 中断使能状态 |
| 低优先级中断中 | 嵌套延迟 | 等待当前ISR完成 | 优先级设置 |
中断源分类
STM32中的中断源可以分为以下几类:
内核中断
- 系统异常:复位、硬故障、存储器管理故障等
- 外部中断:通过EXTI控制器连接的外部信号
外设中断
- 定时器中断:更新、捕获、比较等事件
- 串口中断:发送完成、接收数据、错误等
- 其他外设:ADC、DMA、I2C、SPI等
中断使能与控制流程

中断标志管理
每个中断源都有相应的标志位来指示中断状态:
- 挂起标志:中断已发生但尚未处理
- 活跃标志:中断正在被处理
- 使能标志:允许该中断触发
中断处理最佳实践
-
ISR设计原则
- 执行时间尽可能短
- 避免调用复杂函数
- 及时清除中断标志
- 注意共享数据保护
-
中断优先级安排
- 实时性要求高的中断设置高优先级
- 相关中断设置相同的抢占优先级
- 避免中断饥饿现象
-
中断调试技巧
- 使用中断计数器统计中断频率
- 测量ISR执行时间
- 检查中断响应延迟
常见中断问题与解决方案
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 中断不触发 | 中断未使能、优先级设置错误 | 检查使能位和优先级配置 |
| 中断频繁触发 | 标志位未清除、硬件故障 | 确保在ISR中清除标志位 |
| 系统卡死 | 中断嵌套过深、堆栈溢出 | 优化优先级、增加堆栈大小 |
| 数据竞争 | 共享数据未保护 | 使用临界区保护共享数据 |
通过深入理解中断机制原理,开发者可以更好地设计和优化串口通信程序,确保系统的实时性和可靠性。中断机制的正确使用是嵌入式系统开发中的关键技能之一。
3.2.2 操作实现
在上头工程的基础上新增如下:
然后需要认识如下中断函数:
HAL_UART_Receive_IT():串口中断模式接收
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //串口接收中断回调函数
在文件main.c 里 main函数外部 添加以下代码
主函数添加如下代码
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuffer,1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(RxFlag)
{
HAL_UART_Transmit(&huart1, (uint8_t *)"hello windows!\r\n", 16 , 0xffff);
HAL_Delay(1000); //延时1s
}
}
/* USER CODE END 3 */
}
主函数后调用中断函数如下
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)
{
if (HAL_UART_Receive(&huart1, RxBuffer, 1, 10) == HAL_OK) // 10ms超时,避免长时间阻塞
{
// 处理接收到的命令
switch(RxBuffer[0])
{
case '#': // 暂停发送
RxFlag = 0;
break;
case '*': // 继续发送
RxFlag = 1;
break;
}
}
}
}
/* USER CODE END 4 */
实现展示和上面轮询效果展示一致。
3.3 基于DMA通信开发
3.3.1 DMA工作原理
DMA(直接存储器访问)是嵌入式系统中用于提高数据传输效率的重要技术。它允许外设与内存之间或内存与内存之间直接传输数据,无需CPU的介入,从而解放CPU资源,提高系统整体性能。
DMA基本概念
DMA可以理解为系统中的"数据传输专员",专门负责大规模数据的搬运工作。当需要进行大量数据传输时,CPU只需初始化DMA控制器,之后DMA控制器会自动完成剩余的数据传输任务,期间CPU可以继续执行其他计算任务。
DMA系统架构
在STM32中,DMA控制器是一个独立的外设,通过系统总线与内存和外设连接:
DMA传输要素
每个DMA传输都包含以下基本要素:
| 要素 | 说明 | 示例 |
|---|---|---|
| 源地址 | 数据传输的起始位置 | USART1->RDR |
| 目标地址 | 数据传输的目的位置 | rx_buffer |
| 传输数量 | 需要传输的数据单元数量 | 1024 |
| 数据宽度 | 每次传输的数据位宽 | 8位、16位、32位 |
| 传输模式 | 数据传输的工作方式 | 正常模式、循环模式 |
DMA传输过程详解
-
初始化阶段
- CPU配置DMA控制器的相关寄存器
- 设置源地址、目标地址、传输数量等参数
- 使能DMA传输
-
传输阶段
- DMA控制器接管总线控制权
- 按配置参数自动进行数据传输
- 每次传输后更新地址和计数器
-
完成阶段
- 传输计数器归零
- 产生传输完成中断
- 释放总线控制权
DMA工作模式对比
| 工作模式 | 触发方式 | 传输特点 | 适用场景 |
|---|---|---|---|
| 单次传输 | 软件触发 | 传输指定数量后停止 | 单次数据块传输 |
| 循环传输 | 连续触发 | 传输完成后自动重新开始 | 连续数据流 |
| 外设触发 | 外设事件触发 | 由外设信号启动传输 | 实时数据采集 |
DMA传输类型
STM32支持多种DMA传输类型:
外设到存储器
- 源地址:外设数据寄存器
- 目标地址:内存缓冲区
- 典型应用:串口数据接收
存储器到外设
- 源地址:内存缓冲区
- 目标地址:外设数据寄存器
- 典型应用:串口数据发送
存储器到存储器
- 源地址:内存区域A
- 目标地址:内存区域B
- 典型应用:数据块复制
DMA通道与流
在STM32中,DMA控制器采用"流"和"通道"的概念:
| 概念 | 说明 | 特点 |
|---|---|---|
| 流(Stream) | DMA控制器的数据传输通路 | 每个流可独立配置 |
| 通道(Channel) | 流与外设的对应关系 | 决定数据流向 |
| 仲裁器 | 管理多个流的优先级 | 解决流间竞争 |
DMA流优先级机制
当多个流同时请求DMA传输时,仲裁器根据优先级决定服务顺序:
| 优先级设置 | 仲裁方式 | 特点 |
|---|---|---|
| 非常高 | 固定最高优先级 | 实时性要求最高的传输 |
| 高 | 优先服务 | 重要数据传输 |
| 中 | 轮询服务 | 普通数据传输 |
| 低 | 最后服务 | 后台数据传输 |
DMA传输配置参数
数据宽度配置
| 数据宽度 | 适用场景 | 传输效率 | 对齐要求 |
|---|---|---|---|
| 字节(8位) | 串口通信 | 较低 | 无特殊要求 |
| 半字(16位) | 音频数据 | 中等 | 2字节对齐 |
| 字(32位) | 图像处理 | 较高 | 4字节对齐 |
地址增量模式
| 增量模式 | 源地址行为 | 目标地址行为 | 适用场景 |
|---|---|---|---|
| 固定地址 | 不递增 | 不递增 | FIFO寄存器 |
| 递增地址 | 每次递增 | 每次递增 | 数组传输 |
| 混合模式 | 固定/递增 | 递增/固定 | 特殊需求 |
DMA中断类型
DMA控制器提供多种中断源,用于通知传输状态:
| 中断类型 | 触发条件 | 应用场景 |
|---|---|---|
| 传输完成 | 所有数据传输完成 | 处理完整数据块 |
| 半传输 | 传输完成一半数据 | 双缓冲技术 |
| 传输错误 | 总线错误或地址错误 | 错误处理 |
| FIFO错误 | FIFO上溢或下溢 | 流控制异常 |
DMA性能优化技术
双缓冲技术
使用两个缓冲区交替工作,实现数据传输与处理的并行:
缓冲区A[接收中] ←── DMA
缓冲区B[处理中] ←── CPU
突发传输
通过单次请求传输多个数据,减少总线占用时间:
| 突发大小 | 传输次数 | 总线效率 | 延迟 |
|---|---|---|---|
| 单次传输 | 1次/请求 | 较低 | 较低 |
| 4字节突发 | 4次/请求 | 较高 | 中等 |
| 8字节突发 | 8次/请求 | 很高 | 较高 |
FIFO使用
DMA控制器内置FIFO缓冲区,用于平滑数据传输:
| FIFO模式 | 工作方式 | 适用场景 |
|---|---|---|
| 禁用 | 直通模式 | 简单传输 |
| 使能 | 使用FIFO缓冲 | 大数据量传输 |
| 阈值控制 | 按阈值触发 | 流量控制 |
DMA传输时序分析
典型DMA传输时间计算公式:
总传输时间 = (数据量 × 数据宽度) / 总线频率 + 初始化开销 + 中断处理时间
DMA使用注意事项
-
内存对齐
- 确保源地址和目标地址符合对齐要求
- 错误对齐可能导致传输效率下降或硬件错误
-
缓存一致性
- 在使用缓存时注意DMA传输的数据一致性
- 必要时进行缓存维护操作
-
资源竞争
- 避免多个主设备同时访问同一内存区域
- 合理设置DMA流优先级
-
错误处理
- 实现完善的DMA错误检测和恢复机制
- 监控传输进度,防止传输停滞
3.3.2 操作实现
在中断工程基础上设置DMA,点击添加即可,如下:
调用下面函数
HAL_UART_Transmit_DMA():串口DMA模式发送
代码实现如下:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)"hello windows! \r\n", 15 );
HAL_Delay(1000); //延时1s
}
实现效果展示与上头效果一致。
3.4 三者对比
在STM32串口通信开发中,轮询、中断和DMA是三种主要的通信方式。理解它们的特点和适用场景,对于设计高效的嵌入式系统至关重要。
CPU资源占用对比
从CPU资源占用的角度来看,三种方式有着明显的差异:
| 方式 | CPU占用程度 | 占用原因 | 资源利用率 |
|---|---|---|---|
| 轮询方式 | 高 | CPU需要不断查询状态寄存器,在等待期间处于忙等待状态 | 低 |
| 中断方式 | 中等 | CPU仅在数据到达或发送完成时被中断,大部分时间可执行其他任务 | 中 |
| DMA方式 | 低 | 数据传输过程完全由DMA控制器完成,CPU只需初始化和处理完成中断 | 高 |
实现复杂度分析
在代码实现和维护方面,三种方式的难度各不相同:
| 方式 | 代码复杂度 | 调试难度 | 适合的开发者 |
|---|---|---|---|
| 轮询方式 | 简单 | 容易,逻辑直观 | 初学者 |
| 中断方式 | 中等 | 中等,需处理中断嵌套和资源竞争 | 有经验的开发者 |
| DMA方式 | 复杂 | 困难,需要理解DMA控制器工作原理 | 资深开发者 |
性能表现对比
性能表现方面,三种方式在不同数据量下的表现差异明显:
| 数据量 | 轮询方式 | 中断方式 | DMA方式 |
|---|---|---|---|
| 小数据包(<16字节) | 响应慢 | 响应快 | 配置开销大 |
| 中等数据(16-64字节) | 效率低 | 效率中等 | 效率开始显现 |
| 大数据块(>64字节) | 不可行 | 效率较低 | 效率最高 |
实时性分析
实时性要求是选择通信方式的重要考量因素:
| 方式 | 响应时间 | 确定性 | 适用实时场景 |
|---|---|---|---|
| 轮询方式 | 不稳定,依赖查询频率 | 差 | 非实时系统 |
| 中断方式 | 快速,微秒级响应 | 好 | 中等实时要求 |
| DMA方式 | 最快,硬件级响应 | 优秀 | 高实时要求 |
资源消耗对比
在系统资源消耗方面,三种方式的需求不同:
| 资源类型 | 轮询方式 | 中断方式 | DMA方式 |
|---|---|---|---|
| CPU时间 | 大量消耗 | 中等消耗 | 少量消耗 |
| 内存占用 | 很少 | 中等 | 需要DMA缓冲区 |
| 外设资源 | 仅需串口 | 需要串口+NVIC | 需要串口+DMA控制器 |
适用场景总结
基于以上分析,三种方式的主要适用场景如下:
| 应用场景 | 推荐方式 | 理由 |
|---|---|---|
| 简单调试输出 | 轮询方式 | 实现简单,满足基本需求 |
| 中等数据量通信 | 中断方式 | 平衡性能和复杂度 |
| 高速数据流传输 | DMA方式 | 最大化传输效率 |
| 多任务系统 | 中断或DMA | 减少CPU占用 |
| 资源极度受限 | 轮询方式 | 节省系统资源 |
四、总结
通过本教程的完整学习,我们从串口通信的基础理论到实际应用进行了全面的探索。在理论基础部分,我们深入理解了串口通信的各种类型、协议格式、电平标准以及转换模块的工作原理,这些知识为后续的实践操作奠定了坚实的理论基础。在文件传输实验中,我们通过亲手搭建硬件环境、进行数据传输测试,不仅验证了波特率与传输时间的关系,更重要的是认识到了地线连接在通信质量中的关键作用,这些实践经验对于嵌入式开发来说非常宝贵。
在STM32的三种串口通信方式实践中,我们逐步掌握了轮询、中断和DMA的使用方法和适用场景。从简单的轮询发送,到能够及时响应的中断通信,再到高效解放CPU的DMA传输,每一种方式都有其独特的优势和应用价值。通过仿真分析和实际测试,我们不仅学会了如何配置和使用这些功能,更重要的是理解了在不同应用场景下如何选择合适的通信方式,这对于今后进行更复杂的嵌入式系统设计具有重要意义。
五、参考资料
更多推荐



所有评论(0)