PCA9685 16路PWM调光:从寄存器到伽马校正的实战指南
简介这份资源围绕STM32F103C8T6驱动PCA9685实现PWM调光展开面向正在学习嵌入式外设通信与LED亮度控制的开发者尤其适合想通过I2C总线掌握12位PWM调节的入门到中级学习者。压缩包共213个文件约6.68MB包含37个c源文件、38个h头文件、38个o目标文件与37个crf编译记录另有uvprojx、uvoptx工程配置、hex烧录文件、sct分散加载及map映射文件完整保留了Keil工程结构与编译中间产物便于直接打开复现。资源中涉及I2C初始化、PCA9685工作模式与PWM频率设置、各通道占空比写入等关键环节并延伸至灯板LED阵列的亮度与颜色渐变控制思路。目前已有1279人学习下载可作为调光系统搭建与排错参考。1. 从一次调光翻车说起PCA9685 到底能解决什么问题如果你手头有一块 PCA9685多半是因为遇到了同一个问题单片机的硬件 PWM 通道不够用了。我最早接触这颗芯片是想给一组 LED 做呼吸灯阵列结果发现主控能拿出来的 PWM 引脚只有三四个而灯有十六路。当时第一反应是用软件延时模拟 PWM写完跑起来才发现主循环被占得死死的串口响应都卡了调光还一抖一抖的典型的翻车现场。PCA9685 就是冲着这个场景来的。它是一颗 16 通道、12 位分辨率的 PWM 驱动芯片通过 I2C 总线控制理论上一条 I2C 总线可以挂 62 片也就是接近一千路 PWM。它内部有独立的振荡器自己产生 PWM 波形主控只负责通过 I2C 写寄存器告诉它「哪一路、占空比多少」写完就可以去干别的事。这一点对调灯特别关键调光是个持续输出的活儿交给专用芯片扛主控才腾得出手。这篇笔记面向的是已经会点单片机、想用 PCA9685 做 LED 调光或者调亮度的人。我会从寄存器层面讲清楚它为什么能调、怎么接线、代码怎么写、参数怎么设最后把我在实际调试里踩过的坑一条条摆出来。看完你应该能自己搭出一套稳定的多路调光方案而不是停留在「抄个库能亮就行」的阶段。2. PCA9685 调光的底层逻辑12 位分辨率是怎么落到亮度上的2.1 从 I2C 写寄存器到引脚输出波形PCA9685 的调光本质是它内部给每一路都维护了一对寄存器ON 寄存器和 OFF 寄存器各 12 位。芯片内部有一个 12 位的计数器从 0 数到 4095 然后归零循环往复。每一路输出在计数器等于 ON 值时拉高等于 OFF 值时拉低。所以占空比就是 (OFF - ON) / 4096。这里有个容易忽略的点ON 和 OFF 都是 12 位但寄存器是分两个字节存的低 8 位在 LEDn_ON_L高 4 位在 LEDn_ON_H 的低四位。写的时候要先写低字节再写高字节因为芯片内部有个影子寄存器机制高字节写入的那一刻才真正生效。如果你顺序写反了会出现短暂的错误占空比灯会闪一下。我一般封装成一个函数把顺序固定死。调光时最常用的模式是 ON 固定为 0只改 OFF。这样占空比从 0 到 4095 线性变化对应亮度从全灭到全亮。但要注意LED 的亮度和占空比并不是线性关系人眼对亮度的感知近似对数所以如果你直接线性写 OFF 值低亮度段会感觉变化很慢高亮度段又跳得厉害。后面讲伽马校正会专门说这个。2.2 频率、分辨率与 LED 驱动的三角关系PCA9685 的 PWM 频率由内部振荡器和 PRESCALE 寄存器决定。公式是prescale round(osc_clock / (4096 * freq)) - 1osc_clock 典型值是 25MHz。比如你要 1000Hz 的 PWM 频率prescale round(25000000 / (4096 * 1000)) - 1 round(6.1) - 1 5。频率选多少取决于你驱动的是什么。普通 LED 调光200Hz 到 1000Hz 都行太低会看到闪烁太高则分辨率会受影响。因为 prescale 是整数频率和分辨率是绑死的频率越高每个周期内的计数步数越少实际可用的占空比档位就越少。比如你把频率拉到 5000Hzprescale 会很小12 位分辨率名存实亡低亮度段基本没法细调。我一般给 LED 调光用 1000Hz 左右兼顾无闪烁和分辨率。如果是驱动舵机那是另一套逻辑舵机要 50Hzprescale 会大很多这里不展开。下面是一段初始化频率的代码基于常见的 I2C 读写封装# 假设 i2c 是一个已初始化的 I2C 对象地址 0x40 PCA9685_ADDR 0x40 MODE1 0x00 PRESCALE 0xFE def set_pwm_freq(freq_hz): # 计算 prescaleosc 取 25MHz prescale_val int(round(25000000.0 / (4096 * freq_hz)) - 1) old_mode i2c.read_byte_data(PCA9685_ADDR, MODE1) # 进入睡眠模式才能改 prescale i2c.write_byte_data(PCA9685_ADDR, MODE1, (old_mode 0x7F) | 0x10) i2c.write_byte_data(PCA9685_ADDR, PRESCALE, prescale_val) # 唤醒 i2c.write_byte_data(PCA9685_ADDR, MODE1, old_mode) # 等待振荡器稳定典型 500us time.sleep(0.005) # 重启 PWM 输出 i2c.write_byte_data(PCA9685_ADDR, MODE1, old_mode | 0x80)这段代码里有两个关键动作改 prescale 前必须让芯片进入 sleepMODE1 的 bit4 置 1否则 prescale 写不进去改完之后要等振荡器稳定再通过 RESTART 位MODE1 的 bit7重启。很多人只写了前半段结果频率没生效灯还是默认频率在闪查半天查不出来。2.3 亮度曲线为什么你的灯低亮度段像没反应前面说了人眼感知非线性。如果你直接把 0 到 4095 线性映射到亮度低亮度段比如 OFF 值 0 到 500人眼几乎看不出变化而到了高亮度段稍微动一点就感觉亮很多。解决办法是做伽马校正把目标亮度值先做一次幂运算再写入 OFF 寄存器。常用公式是off_value int(4095 * (brightness / 4095) ** gamma)gamma 一般取 2.2 到 2.8 之间。我实测 2.5 左右对普通 LED 比较舒服。这个运算可以在主控里做也可以预先算好一张查找表存起来运行时直接查表省去浮点运算。如果你用的是资源紧张的单片机强烈建议用查找表。# 预生成伽马查找表gamma2.5 GAMMA 2.5 gamma_table [int(4095 * ((i / 4095.0) ** GAMMA)) for i in range(4096)] def set_brightness(channel, brightness): # brightness 范围 0-4095 off_val gamma_table[brightness] # 写 ON 为 0OFF 为 off_val base 0x06 4 * channel i2c.write_byte_data(PCA9685_ADDR, base, 0) # ON_L i2c.write_byte_data(PCA9685_ADDR, base 1, 0) # ON_H i2c.write_byte_data(PCA9685_ADDR, base 2, off_val 0xFF) # OFF_L i2c.write_byte_data(PCA9685_ADDR, base 3, off_val 8) # OFF_H注意这里写寄存器的顺序先写 ON_L、ON_H再写 OFF_L、OFF_H。因为 OFF_H 写入时才生效所以把 OFF_H 放最后保证一次更新是原子的。如果你先写了 OFF_H 再写 OFF_L中间会有一个瞬间占空比错误灯会闪。3. 从零搭一套 16 路调光接线、地址与最小验证3.1 硬件连接与 I2C 地址配置PCA9685 模块通常引出 VCC、GND、SCL、SDA 四根控制线以及 V 和 16 路输出。这里有个大坑VCC 是芯片逻辑供电一般 3.3V 或 5VV 是 LED 的驱动电源可以独立供电电压范围看模块上的稳压和电容耐压。如果你用 12V 灯带V 接 12V但 VCC 必须接 3.3V 或 5V千万别把 12V 灌到 VCC 上芯片会直接烧。I2C 地址由模块上的 A0 到 A5 六个焊盘决定默认全不接是 0x40。如果你要挂多片就通过焊接不同组合来改地址。地址范围是 0x40 到 0x7F共 62 个可用地址。注意 0x70 到 0x7F 这一段和某些 I2C 设备冲突实际用的时候尽量避开。接线时 SCL 和 SDA 要接上拉电阻一般 4.7k 到 10k。很多模块已经自带上拉如果你挂多片或者线拉得长可能需要额外加。我遇到过 SDA 被拉死的情况最后查出来是某一片模块的上拉和主控的上拉叠加阻值太小波形上升沿太陡导致振铃。后来把模块上的上拉拆了只留主控端一组就稳了。3.2 最小验证让第 0 路亮起来在写复杂逻辑之前先做最小验证让第 0 路输出一个固定占空比确认硬件和 I2C 通路没问题。import time PCA9685_ADDR 0x40 MODE1 0x00 LED0_ON_L 0x06 def init_chip(): # 复位 MODE1关闭 sleep开启 auto-increment i2c.write_byte_data(PCA9685_ADDR, MODE1, 0x00) time.sleep(0.005) # 设置 prescale 为 1000Hz 对应的值 set_pwm_freq(1000) def set_channel(channel, on, off): base LED0_ON_L 4 * channel i2c.write_byte_data(PCA9685_ADDR, base, on 0xFF) i2c.write_byte_data(PCA9685_ADDR, base 1, on 8) i2c.write_byte_data(PCA9685_ADDR, base 2, off 0xFF) i2c.write_byte_data(PCA9685_ADDR, base 3, off 8) init_chip() # 第 0 路ON0OFF2048即 50% 占空比 set_channel(0, 0, 2048)跑完这段第 0 路应该以一半亮度亮起。如果没亮先量 V 有没有电压再量 SCL/SDA 有没有波形。我一般会先用 I2C 扫描工具确认地址能不能扫到扫不到就是接线或上拉问题扫到了但不亮就是 V 或输出通道问题。这个排查顺序能省很多时间。3.3 多路同步与相位设置16 路同时调光时如果所有通道的 ON 都设为 0它们会在同一个时刻一起拉高瞬间电流很大电源会被拉出一个坑灯会闪。解决办法是给不同通道设置不同的 ON 相位错开开启时刻。比如 16 路均分 4096 个计数每路 ON 值间隔 256for ch in range(16): on_val ch * 256 off_val on_val 2048 # 保持 50% 占空比 if off_val 4095: off_val - 4096 set_channel(ch, on_val, off_val)注意 OFF 值超过 4095 时要回绕。这种相位错开的方式对电源友好尤其是驱动大功率 LED 时能明显减少闪烁和电源纹波。代价是每一路的实际开启时刻不同如果你要做严格的同步闪烁就不能这么干得另想办法。4. 避坑与排查调光不亮、闪烁、发热的 5 个真实原因4.1 灯不亮但 I2C 能扫到地址现象I2C 扫描工具能看到 0x40但所有通道都没输出。原因最常见的是 MODE1 的 sleep 位没清掉芯片还在睡眠PWM 输出关闭。其次是 prescale 没设置芯片用默认值但默认值也能输出只是频率不对不至于完全不亮。还有一种可能是输出通道的 ON 和 OFF 都写成了 0占空比为 0自然不亮。解决先读回 MODE1 寄存器确认 bit4 是 0。再读回某一通道的 OFF 寄存器确认不是 0。如果 MODE1 的 bit4 是 1重新写一次唤醒序列注意唤醒后要等 500us 再写通道值。4.2 低亮度段闪烁或抖动现象占空比设得很低时灯不是稳定微亮而是一闪一闪的。原因PWM 频率太低比如低于 200Hz人眼能感知到闪烁。另一个原因是电源纹波太大低占空比时驱动电流小电源进入非连续工作模式输出不稳。解决把频率提到 1000Hz 以上。如果是电源问题在 V 端并一个大电容比如 1000uF 电解加 0.1uF 陶瓷。我一般会在 V 和 GND 之间直接并一个 2200uF 的低阻电容低亮度抖动基本就没了。4.3 多路同时亮时电源被拉垮现象单独亮一路正常16 路一起亮时整体变暗甚至主控复位。原因所有通道同相位开启瞬间电流是单路的 16 倍电源和走线扛不住。另外 V 和 VCC 如果共用一根细线压降会直接影响到芯片逻辑供电。解决用相位错开的方式设置 ON 值把开启时刻分散开。V 和 VCC 分开走线V 用粗线VCC 单独从主控取。如果电流实在大考虑分组供电每片 PCA9685 带一部分灯。4.4 芯片发热明显现象没接负载或者只接了小负载PCA9685 芯片就烫手。原因输出通道的驱动能力有限每路持续电流一般不超过 25mA峰值 100mA。如果你直接驱动大功率 LED 没加三极管或 MOS芯片内部输出级会过流发热。另一个原因是 VCC 电压过高比如接了 5V 但芯片是 3.3V 版本。解决大功率负载必须外加驱动管PCA9685 只负责出 PWM 信号。确认 VCC 电压和芯片规格匹配。如果只是微温那是正常的烫到摸不住就是有问题。4.5 调光曲线不线性低亮度跳变现象从 0 往上调前 20% 亮度几乎没变化然后突然亮起来。原因没有做伽马校正直接线性写 OFF 值。人眼感知非线性低占空比段的变化看不出来。解决用前面说的伽马查找表把亮度值先做幂运算再写入。gamma 取 2.2 到 2.8根据实际灯珠和观感微调。如果主控资源够也可以用浮点实时算但查找表更稳。5. 进阶技巧用查找表与相位错开把调光做稳5.1 预生成伽马表并固化到 Flash如果你的主控是单片机每次上电都算一遍伽马表太浪费。我一般会在开发阶段用脚本生成一张 4096 项的查找表直接以数组形式写进代码固化到 Flash 里。运行时只做一次查表速度快且不占 RAM。生成脚本可以这样写GAMMA 2.5 table [int(4095 * ((i / 4095.0) ** GAMMA)) for i in range(4096)] # 输出成 C 数组 print(const uint16_t gamma_table[4096] {) for i in range(0, 4096, 8): print( , .join(str(v) for v in table[i:i8]) ,) print(};)生成的数组直接贴进单片机工程调光时off_val gamma_table[brightness]就行。注意表是 4096 项每项 2 字节一共 8KB对大多数单片机来说可以接受。如果 Flash 紧张可以降到 1024 项中间做线性插值精度也够用。5.2 相位错开的参数怎么定相位错开的核心是让 16 路的 ON 值均匀分布在 0 到 4095 之间。间隔就是 4096 / 16 256。但如果你只用了 8 路间隔可以取 512让开启时刻更分散。实际调的时候我会先按均分设一遍然后用示波器看 V 上的电流波形。如果还有明显的尖峰就把间隔再调大或者把相邻通道的 ON 值错开更多。这个没有固定公式跟你的电源和走线关系很大得实测。另外相位错开会影响占空比的精确性。因为 OFF 值要跟着 ON 值偏移回绕处理要小心。我一般会写一个辅助函数输入目标占空比和相位偏移自动算出 ON 和 OFFdef set_channel_phase(channel, duty, phase_offset): # duty 范围 0-4095 on_val phase_offset off_val on_val duty if off_val 4095: off_val - 4096 set_channel(channel, on_val, off_val)这样调用时只需要关心占空比和相位不容易出错。5.3 用示波器验证调光线性度调光做完了怎么确认它真的按预期工作我一般会做两件事一是用示波器看输出引脚的波形确认频率和占空比跟设定值一致二是用照度计或者手机的光传感器测不同亮度设定下的实际光照画一条曲线看是不是接近伽马曲线。如果没有示波器也可以用逻辑分析仪抓 I2C 波形确认寄存器写入的值正确。最土的办法是拿手机慢动作录像拍灯看有没有闪烁。这些手段结合起来基本能定位大部分问题。我自己的习惯是每次改完调光参数先跑一遍从 0 到 4095 的扫描用眼睛看一遍有没有跳变或者闪烁再用示波器抽几个点确认。这个流程走下来后面批量生产或者长期运行就很少出玄学问题。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

达梦数据库认证机制深度解析:从disql登录到用户权限的七步链路

达梦数据库认证机制深度解析:从disql登录到用户权限的七步链路

1. 为什么达梦数据库的认证练习不是“背命令”,而是必须亲手拆解的底层逻辑课“达梦数据库认证练习”这八个字,放在今天的技术圈里,听起来像一份标准考纲、一套应试题库,甚至有人直接把它等同于“把dmctl、disql这些命令敲熟就行”…

2026/10/15 4:19:48 阅读更多 →
MCP协议中context-mode的本质与SQLite FTS5全文检索精度关系

MCP协议中context-mode的本质与SQLite FTS5全文检索精度关系

1. “context-mode”不是功能开关,而是MCP协议里的一套上下文协商机制你第一次在日志里看到context-mode: full或者在HTTP头里撞见X-MCP-Context-Mode: incremental,大概率会下意识把它当成某个软件里的“高级模式开关”——就像Photoshop的“GPU加速开启…

2026/10/15 4:19:48 阅读更多 →
Spring Boot健身会所运营平台开发实战:从选题到排坑全解析

Spring Boot健身会所运营平台开发实战:从选题到排坑全解析

选毕设题目的时候,我最怕的就是那种“看起来很高大上,实际做起来全是坑”的题目。健身房运营平台这个方向,乍看是个传统管理系统,真上手了才发现它夹着会员、课程、私教、储值、场地好几条业务线,每一条都涉及状态流转…

2026/10/15 4:19:48 阅读更多 →

最新新闻

火山引擎智能数据洞察平台v2.0工程实践深度解析

火山引擎智能数据洞察平台v2.0工程实践深度解析

简介:本资源是火山引擎官方发布的《智能数据洞察平台v2.0》核心介绍PPT,面向企业数据平台建设者、BI工程师、数据分析负责人及数字化转型决策者,系统解析该平台在跨源融合、自助建模、AI增强分析与嵌入式BI等关键场景下的技术架构与落地能力。…

2026/10/15 4:59:06 阅读更多 →
基于SpringBoot+Vue的校园体育资源共享与运动爱好者交流平台设计与实现

基于SpringBoot+Vue的校园体育资源共享与运动爱好者交流平台设计与实现

选题背景与意义 随着我国高等教育事业的持续发展和“健康中国”战略的深入推进,高校体育教育逐渐从传统的课堂教学模式向多元化、个性化、信息化方向转型。校园体育资源作为高校育人体系的重要组成部分,不仅承载着增强学生体质、培养健康生活方式的功能&…

2026/10/15 4:59:06 阅读更多 →
金融方面的证书有哪些含金量高的?按岗位分赛道的选择思路

金融方面的证书有哪些含金量高的?按岗位分赛道的选择思路

金融领域的证书很多,宣传口径也很杂。有人把从业资格和CFA放在一张表里比,有人把培训结业证说成"国家认可",还有人暗示考下某个证就能进投行。这些说法往往忽略了一个前提:证书的含金量,取决于它本身的制度性…

2026/10/15 4:59:06 阅读更多 →
剑侠世界4:无限定档10.15公测!开服福利奖励攻略

剑侠世界4:无限定档10.15公测!开服福利奖励攻略

剑侠世界4:无限于10月15日全平台公测,预下载也已经正式开启。10 月 14 日 10 点起全平台开放预下载,同步开启服务器预创角。PC 端玩家预创角成功后,还能进入独立试玩场景,提前熟悉各武器的技能手感和外观效果。要注意首…

2026/10/15 4:59:06 阅读更多 →
xtu C语言基础-试除法判断素数

xtu C语言基础-试除法判断素数

//试除法判断素数 int is_prime(int n){if(n<2) return 0; if(n2) return 1;if(n%20) return 0; //除2以外所有偶数都不是素数//排除了偶数之后只用遍历奇数for(int i3;i*i<n;i2){ //i*i可以避免浮点数运算if(n%i0) return 0;}return 1; }

2026/10/15 4:59:06 阅读更多 →
静态路由实现全网可达:从路由表原理到配置与排错

静态路由实现全网可达:从路由表原理到配置与排错

做网络项目最烦的是什么&#xff1f;设备连好线、接口全亮&#xff0c;结果PC之间互相ping不通&#xff0c;而且怎么查都看不出问题。干这行久了你就明白&#xff0c;八成是路由表没配周全——数据包走到中间某台路由器&#xff0c;转发表里没有目标网段&#xff0c;报文直接被…

2026/10/15 4:58:06 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时&#xff0c;网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上&#xff0c;依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里&#xff0c;扩缩容到底难在哪做过大模型推理服务部署的人&#xff0c;大概都经历过这样的场景&#xff1a;一个团队共用一套推理集群&#xff0c;A 业务跑的是 7B 的小模型&#xff0c;B 业务跑的是 72B 的大模型&#xff0c;C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子&#xff1a;一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减&#xff0c;为了把启动时间压进两秒以内&#xff0c;我手贱地把一串自认为“没用”的 systemd 服务给 disable 了&#xff0c;其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →