STM32F407标准库6路串口DMA中断配置实战

简介:这份资源面向使用STM32F407进行多串口通信开发的嵌入式工程师与学生,基于标准外设库实现6路USART的完整配置,并配套DMA发送与中断接收机制,可解决多设备并发通信、模块化数据转发等场景下的串口资源调度问题。压缩包共115个文件,以50个.c与50个.h源码文件为核心,另含hex烧录文件、Keil工程文件(uvprojx、uvoptx)、批处理脚本及说明文档,整体约552KB,工程结构完整、可直接编译参考。目前已有3893人学习下载,热度较高。代码覆盖串口初始化、GPIO与时钟配置、DMA通道映射、中断服务例程及多串口并行运行时的资源冲突处理,读者可据此掌握DMA减轻CPU负载、中断回调区分数据来源的编程思路,并借助工程文件快速搭建自己的多串口通信框架。

1. 从一块吃灰的 F407 板子说起:6 路串口到底难在哪

手头这块 STM32F407ZGT6 最小系统板在抽屉里躺了大半年,最近被一个多串口采集的活儿翻了出来——上位机要同时接 6 个传感器模块,每个模块走一路 UART,波特率还不一样,有的 9600,有的 115200。第一反应是“F407 有 6 个 USART/UART,硬件够用”,结果真动手才发现,标准库下把 6 路全开起来、还要 DMA 发送加中断接收,坑比想象中密得多。串口这东西看着简单,配置错一个时钟位、DMA 通道选错一个映射,表现就是“发出去没反应”或者“收几个字节就卡死”,没有示波器根本不知道死在哪。这篇笔记就是记录我从零把 6 路串口跑通的全过程,包括时钟怎么算、DMA 流怎么分、中断优先级怎么排,以及装坏了怎么救回来。适合正在用标准库做多串口项目、被 DMA 和中断绕晕的开发者,尤其是从 HAL 库转过来、对寄存器配置还不太熟的人。

2. 环境与版本先列清:标准库、器件手册、工具链一个都不能少

2.1 硬件与固件库版本对照

动手之前先把家底列清楚,不然后面出问题都不知道该怀疑谁。我用的是 STM32F407ZGT6,属于 F4 系列里外设比较全的型号,6 个串口分别是 USART1、USART2、USART3、UART4、UART5、USART6。标准库用的是 ST 官方那套STM32F4xx_DSP_StdPeriph_Lib_V1.8.0,这个版本对 F407 的支持最稳,网上很多 V1.9.0 的包其实是给 F429 用的,直接拿来编译 F407 的工程偶尔会报寄存器定义对不上。工具链我用的 Keil MDK 5.38 加 ARMCC V5 编译器,如果你用 GCC 或者新版 AC6,标准库里的core_cm4.h可能需要小改,这个后面避坑章节细说。

项目型号/版本说明
MCUSTM32F407ZGT66 路串口全支持
标准库STM32F4xx_DSP_StdPeriph_Lib_V1.8.0F407 适配最稳
编译器ARMCC V5 / Keil MDK 5.38AC6 需改 core 头文件
调试器ST-Link V2SWD 四线接法
串口工具任意 USB-TTL建议 CH340 或 CP2102

这里要特别提醒一句:标准库和 HAL 库的工程结构完全不同,标准库没有 CubeMX 自动生成的那套初始化代码,所有外设时钟、GPIO 复用、NVIC 都得自己写。好处是可控,坏处是漏一行就白屏。我一般会先建一个干净的模板工程,把system_stm32f4xx.c、startup_stm32f40_41xxx.s、stm32f4xx_conf.h这几个关键文件确认到位,再往里加串口代码。

2.2 工程目录与关键文件确认

标准库工程的目录结构建议这样组织,后面加 6 路串口才不会乱:

Project/ ├── CMSIS/ # 内核相关 │ ├── core_cm4.h │ └── system_stm32f4xx.c ├── FWlib/ # 标准外设库 │ ├── inc/ │ └── src/ │ ├── stm32f4xx_usart.c │ ├── stm32f4xx_dma.c │ ├── stm32f4xx_gpio.c │ └── stm32f4xx_rcc.c ├── User/ │ ├── main.c │ ├── usart_config.c # 6 路串口配置集中放这 │ └── stm32f4xx_it.c # 中断服务函数 └── Output/

stm32f4xx_conf.h里要把用到的外设头文件都放开,否则编译时RCC_APB1PeriphClockCmd这类函数会报未定义。常见做法是把#include "stm32f4xx_usart.h"、"stm32f4xx_dma.h"、"stm32f4xx_gpio.h"、"stm32f4xx_rcc.h"这几行的注释去掉。这一步看着琐碎,但漏一个后面就是几十行报错,血泪经验。

3. 六路串口初始化:时钟、GPIO、DMA 流一次配到位

3.1 先搞清楚 6 个串口挂在哪条总线上

F407 的串口不是全挂在同一个时钟域,这是第一个容易翻车的地方。USART1 和 USART6 挂在 APB2,USART2、USART3、UART4、UART5 挂在 APB1。APB1 最高 42MHz,APB2 最高 84MHz,算波特率的时候分频系数不一样,如果统一按 84MHz 算,APB1 上的串口波特率会差一倍,表现就是乱码。我一般会在配置函数开头就把时钟使能写全:

// 使能 6 路串口时钟,注意 APB1 和 APB2 分开 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_USART6, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 | RCC_APB1Periph_USART3 | RCC_APB1Periph_UART4 | RCC_APB1Periph_UART5, ENABLE); // GPIO 时钟:USART1/6 在 GPIOA/GPIOG,其余分散在 GPIOA/GPIOB/GPIOC/GPIOD RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOG, ENABLE);

逻辑说明:RCC_APB2PeriphClockCmd管高速外设,RCC_APB1PeriphClockCmd管低速外设,两者不能混。参数里用|把多路串口拼起来一次使能,比一行一行写清爽。GPIO 时钟走 AHB1,这个别写成 APB,否则引脚没输出。

3.2 GPIO 复用配置:AF7 是串口的统一答案

6 路串口的引脚分布比较散,我按板子实际走线选了一组:USART1 用 PA9/PA10,USART2 用 PA2/PA3,USART3 用 PB10/PB11,UART4 用 PC10/PC11,UART5 用 PC12/PD2,USART6 用 PG14/PG9。配置的时候统一用复用功能 AF7,因为 F4 系列里 USART1/2/3/6 和 UART4/5 的复用编号都是 7,这点比 F1 系列省心。

GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 复用模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉,防止悬空误触发 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 以 USART1 的 PA9/PA10 为例 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

参数说明:GPIO_PuPd_UP上拉在接收脚上很有用,模块没上电时不会读到随机电平。GPIO_PinAFConfig这行最容易漏,漏了引脚就是普通 IO,串口一点反应没有。其余 5 路照这个模板改引脚和 AF 编号即可,注意 UART5 的 RX 在 PD2,PD 口也要使能时钟。

3.3 串口参数与 DMA 发送通道分配

波特率我按模块需求分别设成 9600、115200 等,数据位 8、停止位 1、无校验。关键是 DMA 发送的通道分配,F407 的 DMA1 和 DMA2 各有 8 个流,每个流能映射不同请求,串口发送请求的对应关系必须查手册,不能随便挑:

串口DMA 控制器流通道方向
USART1DMA2Stream7Channel4发送
USART2DMA1Stream6Channel4发送
USART3DMA1Stream3Channel4发送
UART4DMA1Stream4Channel4发送
UART5DMA1Stream7Channel4发送
USART6DMA2Stream6Channel5发送

这张表是我对着参考手册一页页翻出来的,网上有些帖子把 USART6 写成 Channel4,实际是 Channel5,照抄就发不出去。配置 DMA 的时候还要开USART_DMAReq_Tx,并且记得在发送函数里判断 DMA 传输完成标志,否则连续发会丢数据。

DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA2_Stream7); DMA_InitStructure.DMA_Channel = DMA_Channel_4; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)tx_buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = len; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_Init(DMA2_Stream7, &DMA_InitStructure); DMA_Cmd(DMA2_Stream7, ENABLE); USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

逻辑说明:DMA_DIR_MemoryToPeripheral表示内存到外设,发送方向。DMA_Mode_Normal是单次传输,发完就停,适合不定长数据;如果要循环发送才用Circular。DMA_PeripheralBaseAddr填串口数据寄存器地址,这个别填错,填成别的寄存器数据就发到奇怪的地方去了。

3.4 中断接收配置与 NVIC 优先级

接收我用中断方式,每路串口开USART_IT_RXNE,在中断里把数据存进各自的环形缓冲区。6 路串口的中断优先级要排一下,避免高频率的那路把低频率的挤掉。我一般把波特率最高、数据量最大的 USART1 设成抢占优先级 1,其余依次 2 到 6。

NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE);

参数说明:NVIC_IRQChannelPreemptionPriority是抢占优先级,数值越小越优先。SubPriority是子优先级,同抢占级下才比较。中断服务函数里记得先判断USART_GetITStatus再读USART_ReceiveData,读完自动清标志,不用手动清。

4. 避坑与排查:6 路串口最容易翻车的 5 个地方

4.1 现象:某一路串口完全没输出,其他路正常

原因:九成是 GPIO 复用没配或者时钟没使能。UART5 的 TX 在 PC12、RX 在 PD2,PD 口时钟经常被忘掉;USART6 的 TX 在 PG14,GPIOG 时钟也容易漏。解决:拿万用表量引脚电压,空闲时 TX 应该是高电平,如果是 0 或者浮空,回去查RCC_AHB1PeriphClockCmd和GPIO_PinAFConfig这两行。

4.2 现象:DMA 发送只能发一次,第二次没反应

原因:DMA_Mode_Normal模式下传输完成后流会自动关闭,第二次发送前没有重新使能。解决:在每次发送函数开头加DMA_Cmd(stream, DISABLE)再重新配置DMA_BufferSize和DMA_Cmd(stream, ENABLE),或者干脆用DMA_Mode_Circular配合双缓冲。我一般封装一个uart_dma_send(),里面统一处理重装。

4.3 现象:接收数据偶尔丢字节,尤其是高波特率

原因:中断里处理太慢,或者没开USART_IT_ORE溢出中断,数据寄存器被覆盖了都不知道。解决:中断服务函数里只做“读数据进缓冲区”这一件事,别在里面做解析和打印。另外把USART_IT_ORE也开上,溢出时清标志,能救回不少数据。

4.4 现象:编译报错core_cm4.h里__ASM未定义

原因:用 AC6 编译器编标准库 V1.8.0 时,老的汇编语法不兼容。解决:要么切回 ARMCC V5,要么把core_cm4.h里__ASM改成__asm,并加上-Wno-armcc-compat之类的编译选项。我一般直接锁 V5,省事。

4.5 现象:6 路全开之后系统跑飞,进 HardFault

原因:DMA 流冲突或者中断优先级配置超出范围。F407 的 NVIC 优先级分组默认是 4 位抢占 0 位子优先级,如果NVIC_PriorityGroupConfig没设对,写进去的优先级可能越界。解决:在main开头加NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2),然后检查 6 路 DMA 流有没有重复用同一个。

5. 装完怎么验证:用回环加示波器把 6 路一次跑通

配置写完只是纸面功夫,真正跑通得靠验证。我的习惯是分三步走,别一上来就接 6 个模块,那样出问题根本定位不到哪一路。

第一步,单路回环自测。把 USART1 的 TX 和 RX 用杜邦线短接,发一串0x55,看接收缓冲区是不是原样回来。这一步能验证 GPIO、波特率、中断接收是否正常。代码里加个简单的计数:

uint8_t test_buf[] = {0x55, 0xAA, 0x01, 0x02}; uart_dma_send(USART1, test_buf, sizeof(test_buf)); HAL_Delay(10); // 标准库用自己写的延时 if (rx1_count == sizeof(test_buf)) { // 回环成功 }

第二步,6 路同时发不同数据,用逻辑分析仪或者示波器抓 TX 引脚。重点看两件事:波形是不是干净的方波,波特率对不对。9600 的位宽约 104us,115200 约 8.7us,拿示波器一量就知道分频算错没有。我一般会把 6 路 TX 分别接到逻辑分析仪的 6 个通道,一次抓完,比一路一路测快得多。

第三步,压力测试。让 6 路同时以最高波特率连续发 1KB 数据,跑十分钟,看有没有丢包或者死机。这一步最容易暴露 DMA 流冲突和中断优先级问题。如果某一路开始丢数据,回去查它的 DMA 流是不是和别的外设共用了。

验证步骤工具通过标准
单路回环杜邦线收发一致
6 路波形逻辑分析仪波特率误差 < 2%
压力测试串口助手十分钟无丢包

从那以后我每次配多路串口,都强制先跑一遍单路回环再上整机,这个习惯帮我省了至少三次通宵查线的时间。希望这套流程能帮到你,少走点我踩过的弯路。

本文还有配套的精品资源,点击获取

相关新闻

电商大数据规模到底有多大?从业务场景到技术选型的完整拆解

电商大数据规模到底有多大?从业务场景到技术选型的完整拆解

电商行业的数据规模到底有多大&#xff0c;这个问题几乎每个做数据相关工作的朋友都问过我。不管是刚入行的数据分析师想了解行业天花板&#xff0c;还是做技术选型时拿不准该用什么量级的方案&#xff0c;又或者是产品经理在规划数据看板时想搞清楚“我们这点数据算大还是算小…

2026/10/20 20:54:23 阅读更多 →
AI爬虫技能实战:从反爬识别到合规数据采集

AI爬虫技能实战:从反爬识别到合规数据采集

做数据采集的人&#xff0c;几乎都逃不过“反爬”这两个字。就在上个月&#xff0c;我给自己那个只会聊天的AI助手——代号“小龙虾”——加了一套爬虫技能&#xff0c;让它能自己看网页、提取数据、清洗入库。整个过程踩了不少坑&#xff0c;但也整理出了一套相对完整的思路。…

2026/10/20 20:53:19 阅读更多 →
TransNeXt聚合注意力在医学图像分割中的原理与实战

TransNeXt聚合注意力在医学图像分割中的原理与实战

1. 从一张病理切片说起&#xff1a;为什么传统卷积网络在医学图像上总差那么一口气第一次接触医学图像分割&#xff0c;是帮一个做病理分析的朋友处理一批肝脏切片。那批数据里&#xff0c;肿瘤区域和正常组织的边界模糊得像水墨画晕开的边缘&#xff0c;用当时主流的卷积网络跑…

2026/10/20 20:53:19 阅读更多 →

最新新闻

AI平台选型指南:从通用对话到开源自部署的实战策略

AI平台选型指南:从通用对话到开源自部署的实战策略

1. 主流AI平台的全景地图与选型逻辑1.1 为什么现在聊“AI平台”比聊“AI模型”更实际过去一年我接触了不少团队&#xff0c;从几个人的小工作室到上百人的产品线&#xff0c;大家问得最多的问题早就不是“哪个模型最强”&#xff0c;而是“我该把活儿交给哪个平台”。这个转变很…

2026/10/20 21:33:02 阅读更多 →
Win11 25H2下WPS频繁未响应:一个从证据到方向的完整排查记录

Win11 25H2下WPS频繁未响应:一个从证据到方向的完整排查记录

先说结论&#xff1a;我遇到的这个“Win11 25H2 WPS 频繁未响应”问题&#xff0c;直到现在还没有一个确定的根因。但是经过几天反复测试和收集证据&#xff0c;基本可以锁定它并不是WPS软件自身单独惹的祸&#xff0c;而是系统底层和当前环境里某个驱动层组件有兼容性冲突。这…

2026/10/20 21:33:02 阅读更多 →
MCP / Agent / Skill 技术生态分类汇总:用 TaoToken 统一 Key 打通三类工具链

MCP / Agent / Skill 技术生态分类汇总:用 TaoToken 统一 Key 打通三类工具链

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 21:33:02 阅读更多 →
Claude账号防封全攻略:避开风控红线,让账号长期稳定

Claude账号防封全攻略:避开风控红线,让账号长期稳定

说来有点丢人&#xff0c;我在刚接触 Claude 的头两个月里&#xff0c;就亲眼看着身边三个朋友先后被提示账号异常&#xff0c;其中一个甚至用了不到三天就进小黑屋。那时候大家的第一反应都是"平台是不是疯了"&#xff0c;但后来我对照着官方使用条款和自己的操作记…

2026/10/20 21:33:02 阅读更多 →
AI漫剧工业化生产流水线:人机协作边界与六层技术栈实战

AI漫剧工业化生产流水线:人机协作边界与六层技术栈实战

1. 项目概述&#xff1a;这不是“白嫖教程”&#xff0c;而是一套可落地的AI漫剧工业化生产流水线“AI漫剧制作全教程”这个标题&#xff0c;乍看是知识付费圈常见的流量钩子&#xff0c;但真正拆开来看&#xff0c;它背后指向的是一整套正在快速成型的数字内容工业化新范式。我…

2026/10/20 21:33:01 阅读更多 →
FPGA开发者必看:SRIO协议从IP配置到数据收发的完整调试指南

FPGA开发者必看:SRIO协议从IP配置到数据收发的完整调试指南

简介&#xff1a;面向FPGA与嵌入式系统开发者&#xff0c;这套Xilinx SRIO使用例程围绕Serial RapidIO高速串行互连协议在Spartan6系列中的实际部署&#xff0c;系统覆盖硬核配置、端口速率选择、测试平台搭建与仿真验证&#xff0c;解决高带宽低延迟场景下的接口设计与调试难题…

2026/10/20 21:31:57 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →