STM32 9位SPI驱动LCD:原理、配置与调试避坑指南
1. 项目缘起当8位SPI遇上“指令数据”的LCD最近在做一个基于STM32的便携式设备主控是STM32F103显示部分选了一块小巧的1.8寸TFT LCD控制器是常见的ILI9341。为了节省IO口自然选择了SPI接口。前期用标准8位SPI驱动初始化、清屏都挺顺利但一到实际显示文字和图片麻烦就来了。屏幕总是花屏或者显示的位置完全不对。查了半天数据手册和代码才发现根源在于ILI9341这类LCD控制器的一个关键通信特性它的大部分操作都需要先发送一个8位的“指令”Command再跟上一个或多个8位的“数据”Data。在标准的8位SPI模式下我发送的每一个字节都会被屏幕当成数据来处理。当我试图发送指令0x2C写显存指令时屏幕会错误地将其解释为要写入显存的第一个数据字节。这直接导致了后续的数据流全部错位显示自然就乱套了。这个问题在驱动ST7735、SSD1306部分模式等同样采用“指令/数据”架构的LCD时也会遇到。解决这个问题的核心就是让MCU能明确地告诉LCD“我接下来发的是命令”还是“我接下来发的是数据”。硬件上这类屏幕通常会提供一个独立的“DC”Data/Command引脚电平高低代表数据类型。而软件上一种高效且优雅的解决方案就是使用SPI的“9位数据帧”模式。9位SPI顾名思义就是在每个时钟周期内传输9个比特位而不是常见的8个。多出来的这第9位通常用作标志位。在驱动LCD的场景下我们可以约定当第9位为0时表示当前传输的8位数据是“指令”当第9位为1时表示是“数据”。这样我们就能将指令和数据的标识信息与数据本身打包在同一个SPI事务中发送出去无需频繁操作额外的GPIODC引脚通信效率更高时序也更紧凑。STM32的SPI外设恰好支持这种模式这便是我这次折腾“STM32使用9bit SPI驱动LCD”的全部起因。2. 理解SPI的9位数据帧模式硬件如何支持在深入代码之前我们必须先搞清楚STM32的SPI外设是如何实现9位传输的。这对于后续的配置和排错至关重要。很多朋友第一次接触时会疑惑SPI不是通常说“数据寄存器是16位的吗”这和9位模式有什么关系实际上STM32的SPI数据寄存器SPI_DR确实是一个16位的寄存器。在常见的8位数据帧模式下我们只使用其低8位[7:0]来存放要发送或接收的数据。当我们将SPI配置为9位数据帧时情况发生了变化。此时数据帧长度被设定为16位但这16位被赋予了新的结构含义低8位[7:0]这8位用来存放我们实际要发送的“有效数据”也就是LCD的指令码如0x2A或者数据值如颜色值0x00F8。高8位中的特定一位通常是[8]位这1位被用作“帧格式位”或“标志位”。在LCD驱动语境下我们将其定义为“指令/数据选择位”。例如我们约定[8]0代表指令[8]1代表数据。高8位的其他位[15:9]这些位在9位帧格式下是“无效位”或“保留位”发送时通常被硬件置为0接收时也应被忽略。所以从物理传输上看STM32的SPI在9位模式下每次通信实际上是在MOSI线上依次移出16个比特。但这16个比特被我们“解读”为1个标志位 8个有效数据位 7个填充位。接收方LCD如果也是类似的9位SPI控制器它可以只关注前9个比特。但更常见的情况是LCD的SPI接口是标准的8位输入它只关心8个数据位。这时STM32发出的16位数据流中只有中间的8个“有效数据位”会被LCD正确锁存而最前面的那个“标志位”和后面的“填充位”在时钟边沿到来时LCD可能已经错过了对它们的采样取决于LCD控制器的设计或者直接忽略。因此“9位SPI”更像是一种主机STM32端的协议封装技巧它利用16位传输的灵活性将控制信息标志位和数据打包在一起发送而从设备LCD可能依然按照标准的8位序列来接收数据部分。理解这一点后配置的关键就明确了我们需要正确设置SPI的“数据帧格式”为16位并确保在发送时将“标志位”和“有效数据”正确组合成一个16位的值写入SPI_DR寄存器。3. STM32 CubeMX配置与关键代码实现我使用的是STM32F103C8T6和HAL库开发环境是STM32CubeIDE。以下配置过程具有通用性。3.1 CubeMX图形化配置SPI外设选择根据你的硬件连接选择一个SPI外设例如SPI1。配置为“全双工主模式”Full-Duplex Master。基础参数时钟分频根据你的LCD控制器手册和MCU主频设置。ILI9341的SPI时钟最高通常支持几十MHz初期调试可以设低一些如PCLK/8。时钟极性与相位这必须严格匹配你的LCD控制器。ILI9341通常使用CPOL0 CPHA0模式0或CPOL1 CPHA1模式3。请查阅你的LCD数据手册“Serial Interface”部分。我使用的是模式0。核心数据帧格式在“Data Size”选项中选择“16 Bits”。这是实现9位通信的关键一步。CubeMX和HAL库层面没有直接的“9 Bits”选项我们通过选择16位并在软件中构造包含标志位的16位数据来实现。其他设置片选NSS设置为“软件控制”Software NSS Management。我们将用另一个GPIO如PA4手动控制片选信号。硬件流控制禁用。CRC计算禁用。GPIO配置除了SPI的SCK、MOSI引脚别忘了配置一个GPIO作为片选CS一个作为复位RST还有一个作为背光控制。那个关键的“DC”引脚在这里不需要了因为其功能已被整合到9位数据帧中。3.2 驱动代码编写构造16位数据帧配置完成后生成代码。核心在于发送函数的编写。我们需要定义两个宏用于快速构造包含指令/数据标志位的16位数据。// 定义指令和数据的标志位在16位数据中的位置 // 假设我们使用 bit8 作为标志位0指令 1数据 #define LCD_CMD_FLAG (0x00 8) // 标志位为0 指令 #define LCD_DATA_FLAG (0x01 8) // 标志位为1 数据 // 发送一个字节的命令 void LCD_Write_Cmd(uint8_t cmd) { uint16_t data_to_send LCD_CMD_FLAG | cmd; // 组合标志位(0) 8位命令 HAL_SPI_Transmit(hspi1, (uint8_t*)data_to_send, 1, HAL_MAX_DELAY); } // 发送一个字节的数据 void LCD_Write_Data(uint8_t dat) { uint16_t data_to_send LCD_DATA_FLAG | dat; // 组合标志位(1) 8位数据 HAL_SPI_Transmit(hspi1, (uint8_t*)data_to_send, 1, HAL_MAX_DELAY); } // 发送多个字节的数据常用于发送颜色数组 void LCD_Write_Data_Buffer(uint8_t *pData, uint32_t len) { // 注意这里需要将每个字节数据都加上 DATA_FLAG for(uint32_t i0; ilen; i) { uint16_t data_to_send LCD_DATA_FLAG | pData[i]; HAL_SPI_Transmit(hspi1, (uint8_t*)data_to_send, 1, HAL_MAX_DELAY); } }关键点解析LCD_CMD_FLAG被定义为(0x00 8)即0x0000。与8位命令cmd例如0x2A进行按位或操作后得到16位数0x002A。其二进制为0000 0000 0010 1010。bit8为0低8位是命令。LCD_DATA_FLAG被定义为(0x01 8)即0x0100。与8位数据dat例如0xF8进行按位或操作后得到0x01F8二进制0000 0001 1111 1000。bit8为1低8位是数据。HAL_SPI_Transmit的第三个参数是DataSize单位是“数据项”的数量。由于我们在CubeMX中配置了数据帧为16位2字节所以这里传入1代表发送1个16位的数据项。函数内部会知道每个数据项是2字节。3.3 初始化序列与基本绘图函数有了基础的读写函数LCD的初始化就是按照数据手册的指令序列调用LCD_Write_Cmd和LCD_Write_Data。例如设置显示区域SET_COLUMN_ADDRESS, 0x2A和SET_PAGE_ADDRESS, 0x2B然后发送写显存指令MEMORY_WRITE, 0x2C之后连续调用LCD_Write_Data发送颜色数据。一个简单的画点函数示例如下void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color) { // 1. 设置光标位置 LCD_Write_Cmd(0x2A); // 列地址设置 LCD_Write_Data(x 8); LCD_Write_Data(x 0xFF); LCD_Write_Data((x1) 8); // 结束列地址单点所以是x1 LCD_Write_Data((x1) 0xFF); LCD_Write_Cmd(0x2B); // 行地址设置 LCD_Write_Data(y 8); LCD_Write_Data(y 0xFF); LCD_Write_Data((y1) 8); LCD_Write_Data((y1) 0xFF); // 2. 发送写显存指令 LCD_Write_Cmd(0x2C); // 写显存 // 3. 发送颜色数据16位色如RGB565 LCD_Write_Data(color 8); // 高字节 LCD_Write_Data(color 0xFF); // 低字节 }注意这里LCD_Write_Data发送的是颜色值的高8位和低8位它们都带有DATA_FLAG。对于LCD控制器它接收到写显存指令0x2C后会预期接下来是所有要写入的数据流。我们发送的每个16位SPI帧中bit81数据标志低8位是真实的颜色字节LCD控制器会正确识别并存入显存。4. 调试中的关键陷阱与波形分析理论很美好但实际调试时我遇到了几个典型的坑。用逻辑分析仪抓取SPI波形是必不可少的调试手段。4.1 陷阱一数据位序MSB/LSB不匹配这是最隐蔽的问题之一。STM32的SPI可以配置数据帧从最高位MSB还是最低位LSB开始发送。而你的LCD控制器也有相应的要求。如果两者不匹配你发送的指令0x2C二进制0010 1100可能被LCD解读为完全不同的值例如0x34如果LSB先发。排查与解决仔细核对STM32的SPI配置和LCD数据手册。在CubeMX中SPI的“First Bit”选项通常选择“MSB First”。使用逻辑分析仪抓取初始化阶段的波形。发送一个简单的命令如软复位命令0x01。观察MOSI线上最先出现的是高位0还是低位1。0x01的MSB是0LSB是1很容易区分。如果发现不匹配修改CubeMX中的“First Bit”设置或者查阅LCD手册看是否可以通过指令配置其位序。4.2 陷阱二16位数据帧的构造错误逻辑分析仪显示我发送的16位数据是0x012C发送命令0x2C。但我期望的波形是先发标志位0bit8再发8位命令0x2C。然而分析仪解码显示我发送的16位序列是0000 0001 0010 1100。这不对0x012C的二进制是0000 0001 0010 1100这意味着标志位bit8是1而低8位是0x2C。LCD会把0x2C当成数据而不是命令根因我错误地构造了16位数据。我的宏定义是#define LCD_CMD_FLAG (0 8)这没错。但在调用时我写成了uint16_t data cmd | (1 8)手误将命令标志写成了数据标志。或者是宏定义和函数实现中位域的理解出现了偏差。解决仔细检查LCD_Write_Cmd和LCD_Write_Data函数中data_to_send的构造逻辑。确保按位或运算的优先级和意图。使用逻辑分析仪验证发送出的16位数值是否符合预期发送命令时bit8应为0发送数据时bit8应为1。4.3 陷阱三SPI时钟极性与相位CPOL/CPHA即使数据内容正确如果时钟极性和相位不对LCD也会在错误的时钟边沿采样数据导致读取的值不稳定或完全错误。症状可能是屏幕初始化部分成功能复位、背光亮但无法正常显示内容或者显示杂乱无章的条纹。排查黄金法则以LCD数据手册为准。找到“Serial Interface”章节的时序图。看时序图关键点CPOL时钟极性看SCK线在空闲状态没有数据传输时是高电平CPOL1还是低电平CPOL0。CPHA时钟相位看数据是在SCK的第一个边沿上升沿或下降沿被采样还是在第二个边沿被采样。通常数据在SCK的边沿保持稳定在相反的边沿变化。用逻辑分析仪抓取SPI的CS、SCK、MOSI三线波形与LCD手册的时序图严格对比。调整CubeMX中的“Clock Polarity”和“Clock Phase”选项直到波形匹配。4.4 陷阱四片选CS信号时序片选信号CS或NSS的时序也容易被忽略。有些LCD要求CS在每笔SPI传输一个命令或一个数据之间都需要有一个从低到高再到低的跳变而有些则允许在一次连续传输如发送大量像素数据期间保持低电平。操作要点在LCD_Write_Cmd和LCD_Write_Data函数中在调用HAL_SPI_Transmit前后手动控制CS引脚拉低和拉高。对于连续发送大量数据的操作如填充整屏颜色可以在开始前拉低CS全部发送完毕后再拉高CS以提高传输效率。同样参考LCD数据手册的时序图确认CS信号的有效电平和建立/保持时间要求。5. 性能优化与DMA应用思考当驱动分辨率较高的LCD如320x240进行全屏刷新或绘制复杂图形时频繁调用HAL_SPI_Transmit会导致CPU被大量占用在等待SPI发送完成上。这时使用DMA直接存储器访问来搬运显示数据到SPI外设是必然的选择。然而在9位SPI模式下使用DMA会带来一个独特的挑战数据预处理。DMA通常是从一个内存缓冲区src直接搬运数据到外设数据寄存器dst。我们的src缓冲区里存放的通常是纯像素数据RGB565格式每个像素2字节。但SPI外设需要的是“带有数据标志位bit81的16位帧”。因此我们不能简单地把像素数据缓冲区直接丢给DMA。有两个主流解决方案方案一CPU预处理缓冲区在启动DMA传输前先用CPU遍历整个像素数据缓冲区将每个像素的2个字节分别与LCD_DATA_FLAG组合生成一个新的、大小为两倍的16位缓冲区然后将这个新缓冲区的地址交给DMA。这种方法简单可靠但需要额外的内存双倍缓冲区并且CPU仍然需要执行预处理工作只是省去了等待SPI发送的时间。方案二使用SPI的硬件CRC或TI模式“曲线救国”高级技巧这是一种更硬核的优化但依赖特定型号SPI外设的支持和更底层的寄存器操作。有些STM32的SPI支持在16位模式下通过配置“帧格式”寄存器将特定的位如bit8固定为某个值。或者可以利用SPI的“TI模式”Motorola SPI的一种变体的帧头特性来模拟标志位。这种方法需要对SPI外设寄存器有深入理解且通用性较差不推荐初学者尝试。对于大多数应用方案一CPU预处理DMA传输是平衡性能和复杂度的最佳实践。它虽然消耗一些CPU时间和内存但相比纯CPU轮询发送全屏刷新的帧率提升是数量级的。6. 与8位DC引脚模式的对比与选型建议最后我们来对比一下“9位SPI”模式和传统的“8位SPI独立DC引脚”模式。特性9位SPI模式8位SPI DC引脚模式GPIO占用节省1个GPIO。无需独立的DC引脚。多占用1个GPIO作为DC。通信效率理论上稍高。指令/数据标志与数据在同一SPI事务中发送无GPIO操作延迟。每次发送数据前需先设置DC引脚电平引入微小延迟。代码复杂度稍高。需要理解9位数据帧构造DMA使用更复杂。简单直观。读写函数直接控制DC引脚电平。兼容性较低。依赖MCU的SPI支持16位/帧格式且从设备LCD需能忽略或适应多出的位。极高。任何支持SPI的MCU和LCD都适用是行业最通用做法。调试难度较高。需用逻辑分析仪解码16位帧以验证标志位。较低。DC引脚电平在逻辑分析仪上清晰可见。选型建议首选8位SPIDC引脚模式如果你是初学者或者项目对GPIO数量不敏感或者未来可能更换不同型号的LCD屏幕强烈建议使用这种最通用、最易调试的方案。它的库和示例代码也最丰富。考虑9位SPI模式仅当你的项目IO口真的非常紧张寸土寸金并且你使用的STM32型号SPI外设支持16位数据帧格式同时你愿意为节省这一个IO口付出额外的学习和调试成本。在批量生产的低成本产品中这1个IO口可能意味着可以选用更小封装的MCU从而节省成本和PCB面积。我这次选择9位SPI更多是出于技术探索和挑战的目的。实际走通整个流程后对SPI协议和STM32外设的理解确实加深了不少。但下次在新项目中如果IO不是问题我大概率会回归简单可靠的“8位SPIDC引脚”方案。把时间花在实现更酷的功能上而不是调试通信底层往往是更明智的选择。

相关新闻

ESP32 Arduino环境手动部署指南:离线安装与SDK配置详解

ESP32 Arduino环境手动部署指南:离线安装与SDK配置详解

1. 为什么我们还在为ESP32的Arduino环境安装发愁?如果你最近想玩ESP32,并且打算用最新的Arduino IDE 2.0.4来开发,大概率会在第一步“安装开发板支持”这里卡住。浏览器里搜到的教程,十有八九会告诉你,需要去GitHub下载…

2026/10/19 22:56:20 阅读更多 →
2026数字人直播硬件选型实战:从入门到商用的GPU服务器/工作站配置全指南

2026数字人直播硬件选型实战:从入门到商用的GPU服务器/工作站配置全指南

一、数字人直播,正在重写直播行业的底层逻辑 如果你最近打开抖音或淘宝直播间,大概率已经遇到过"数字人主播"——它们724小时不下播,中英文切换自如,表情动作自然流畅,甚至能实时响应用户弹幕互动。 这不是…

2026/10/19 16:10:54 阅读更多 →
【AI】最强 Coding Agent,但用法不对也白搭

【AI】最强 Coding Agent,但用法不对也白搭

本文为技术观点整理稿,汇总了全网热度较高的 10 篇 Claude 相关技术文章的核心观点,涵盖 Claude Code 实战、MCP 协议、Skills 技能体系、提示词工程等主题。适合想系统了解 Claude 生态的开发者收藏。 目录前言一、Claude Code:最强 Coding …

2026/10/19 20:39:59 阅读更多 →

最新新闻

context-mode:上下文感知的自动模式切换引擎实践

context-mode:上下文感知的自动模式切换引擎实践

最早让我决定做一个 context-mode 项目,是因为一个特别具体的痛点:同一套应用,放在办公室、通勤路上、家里、深夜加班这些不同场景里,使用者的操作习惯和真实需求完全不一样。白天在公司网络下打开后台,你可能希望默认…

2026/10/20 20:59:49 阅读更多 →
AI检测率太高怎么办?一套有效降低AI率的文本改写优化方法

AI检测率太高怎么办?一套有效降低AI率的文本改写优化方法

不知道你有没有遇到过这种尴尬:用AI工具写了一版内容,读起来通顺、逻辑也完整,结果放进检测工具里一查,AI概率直接飙到百分之八九十。改了半天也不知道从哪里下手,只能一边吐槽检测器“不靠谱”,一边重新手…

2026/10/20 20:59:48 阅读更多 →
图结构在智能体系统中的应用:任务编排、记忆检索与多智能体协作

图结构在智能体系统中的应用:任务编排、记忆检索与多智能体协作

1. 图结构在智能体系统里到底解决了什么问题第一次把图结构塞进智能体系统的时候,我其实是带着怀疑的。毕竟那会儿大家都在卷提示词工程,谁有空去折腾数据结构。但做完两个项目之后我改主意了——图不是锦上添花,它解决的是智能体系统里最要命…

2026/10/20 20:59:48 阅读更多 →
基于图卷积神经网络的基因-疾病关联预测实战解析

基于图卷积神经网络的基因-疾病关联预测实战解析

做生信的人对“基因疾病关联”这个词不会陌生。从单基因病的位点筛查,到复杂疾病的多基因风险评分,我们一直在跟“哪个基因通过什么机制影响了哪种疾病”这个问题打交道。但传统做法要么靠体外实验一点一点验证,要么靠统计关联从海量样本里硬…

2026/10/20 20:59:48 阅读更多 →
Git分支与合并实战:从commit整理到冲突解决的协作指南

Git分支与合并实战:从commit整理到冲突解决的协作指南

1. 分支纠结现场:为什么大家的git乱成一锅粥1.1 一个真实困扰:代码怎么又“丢”了上个月某天下午,A同学在公司群里发了一句“我改的代码怎么没了”,紧接着截图里是一堆红色的冲突标记。那一刻我就知道,这不是代码丢了&…

2026/10/20 20:59:48 阅读更多 →
鸿蒙ArkTS生鲜超市实战项目解析与避坑指南

鸿蒙ArkTS生鲜超市实战项目解析与避坑指南

简介:本资源是一套基于华为鸿蒙操作系统(HarmonyOS)开发的生鲜超市行业应用实战项目,面向Android开发者转型鸿蒙生态、高校学生学习分布式应用开发及企业级HarmonyOS项目实践者。项目聚焦线上线下融合购物场景,完整呈现…

2026/10/20 20:58:45 阅读更多 →

日新闻

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实现详解

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

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

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

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

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

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

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在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 阅读更多 →