FreeRTOS下实现精准us级延时的三种方案与实战避坑指南
1. 项目概述为什么在FreeRTOS下实现us延时是个“技术活”搞嵌入式开发的朋友尤其是玩STM32和FreeRTOS的肯定都遇到过这个需求需要一个精准的微秒us级延时。听起来很简单不就是让CPU空转一会儿吗但在FreeRTOS这个多任务实时操作系统的环境下这事儿就变得微妙起来了。你可能会想直接用HAL_Delay()或者FreeRTOS的vTaskDelay()不就行了但前者依赖SysTick精度通常只到ms级后者是任务调度级的延时最小单位是一个系统节拍tick通常也是1ms。当你需要驱动WS2812B灯带、读取DHT11温湿度传感器、或者实现精密的软件SPI/I2C时序时ms级的延时简直就是“慢动作”us级延时才是刚需。然而在FreeRTOS里粗暴地写一个for循环或者while循环来做空延时你会立刻踩到第一个大坑任务调度。FreeRTOS的心跳SysTick中断会定期触发进行任务切换。如果你的空延时循环执行到一半正好发生了任务切换那么实际的延时时间就会远远超出你的预期因为你的任务可能被挂起去执行其他任务了。这会导致时序完全错乱设备通信失败。所以核心矛盾在于我们需要一段“独占”CPU的时间来执行高精度延时但这段时间又不能影响整个系统的实时性和多任务特性。网上常见的解决方案有几种关闭全局中断、使用调度锁、或者用高精度硬件定时器。每种方法都有其适用的场景和代价。这个项目我们就来深入拆解在STM32平台上基于FreeRTOS实现一个可靠、精准、对系统影响可控的us级延时函数。我们会从原理分析到代码实现再到实测验证和避坑指南让你彻底搞懂背后的门道。2. 核心思路与方案选型关闭中断、调度锁还是硬件定时器要实现us延时本质是让CPU执行一段已知指令周期的空操作。在裸机环境下这很简单计算好CPU主频和循环次数就行。但在RTOS下我们必须考虑如何在这段“空操作”期间避免被系统调度打断。主要有三种思路我们来逐一分析其优劣和适用场景。2.1 方案一关闭全局中断__disable_irq/__enable_irq这是最“霸道”的方案。直接在延时开始前关闭所有中断包括SysTick延时结束后再开启。优点绝对精准在延时期间没有任何中断能打断CPU延时时间高度确定。实现简单代码非常简洁。缺点与风险破坏系统实时性关闭中断期间系统无法响应任何外部事件如按键、串口数据SysTick中断也被暂停导致整个FreeRTOS的时钟节拍“停滞”。任务调度、时间统计、软件定时器全部失效。可能引发故障如果关闭中断时间过长比如几十毫秒可能导致看门狗复位、通信数据丢失等严重问题。需谨慎处理嵌套如果延时函数被中断调用或者自身被嵌套调用中断的开关需要妥善管理。注意这是一个“杀鸡用牛刀”的方案通常只适用于延时时间极短几个微秒到几十微秒且对系统实时性影响可接受的场景。绝对禁止在中断服务程序ISR中使用此方案否则可能导致中断无法嵌套系统死锁。2.2 方案二使用FreeRTOS调度锁vTaskSuspendAll/xTaskResumeAll这是更“文明”的方案。FreeRTOS提供了调度锁APIvTaskSuspendAll()挂起调度器xTaskResumeAll()恢复。优点保持中断响应在调度锁期间中断包括SysTick依然可以发生并被响应。这意味着硬件外设如UART、ADC的中断服务程序可以照常运行。避免任务切换核心目标达成延时循环不会被其他任务抢占。支持嵌套FreeRTOS内部维护了一个调度锁计数器可以安全地嵌套调用。缺点与风险不停止系统节拍SysTick中断依然会触发并累计算“被挂起”的tick数。当调用xTaskResumeAll()恢复调度时如果发现tick计数有更新它会立即进行一次任务切换。这意味着你的延时函数返回后可能马上就会切换到更高优先级的任务而不是紧接着执行你延时后面的代码。这是一个非常关键且容易被忽略的细节影响高优先级任务就绪在调度锁期间即使有更高优先级的任务就绪了也无法被调度。如果锁定时长过长会影响高优先级任务的响应时间。延时可能被“拉长”由于SysTick中断照常发生虽然你的循环计数是准确的但从“任务级”的视角看从调用vTaskSuspendAll()到真正恢复执行中间可能穿插了SysTick中断的处理时间使得感知到的总时间略长于纯循环时间通常可忽略但在极端追求精度时需考虑。这是本项目重点推荐的方案它在精准度和系统影响之间取得了较好的平衡。2.3 方案三使用独立硬件定时器如TIM2, TIM5这是最“优雅”但最复杂的方案。配置一个专用的硬件定时器工作在计数模式然后等待其计数值达到设定值。优点精度最高CPU占用率最低延时由硬件实现不占用CPU进行空循环。CPU可以在此期间执行其他低优先级任务或进入低功耗模式。完全不受调度影响延时是硬件行为与任务调度无关。缺点与风险资源占用需要独占一个硬件定时器资源。实现复杂需要编写定时器初始化、启动、停止、中断可选等代码集成到FreeRTOS中可能需要考虑线程安全。灵活性稍差延时时间通常需要根据定时器预分频和周期进行计算配置动态调整不如软件循环方便。方案选型总结对于大多数需要us延时的场景如驱动单总线器件、模拟时序方案二调度锁是首选。它在保证us级精度的同时最大程度地减少了对系统整体功能的干扰。方案一过于粗暴方案三则大材小用。因此后续的实操我们将围绕FreeRTOS调度锁CPU空循环这一核心方案展开。3. 核心实现基于调度锁的us延时函数详解确定了方案我们来动手实现。这里以STM32F4系列Cortex-M4内核主频168MHz为例使用STM32CubeMX生成的FreeRTOS工程进行说明。3.1 关键代码实现我们创建一个名为bsp_delay_us.c/h的文件来放置我们的延时函数。// bsp_delay_us.h #ifndef __BSP_DELAY_US_H #define __BSP_DELAY_US_H #include main.h #include cmsis_os.h void delay_us(uint32_t us); #endif// bsp_delay_us.c #include bsp_delay_us.h /** * brief 微秒级延时函数基于FreeRTOS调度锁 * param us: 需要延时的微秒数范围建议在 1 ~ 1000*N (N取决于主频和循环开销) * note 此函数通过挂起调度器来防止任务切换保证延时精度。 * 延时期间中断仍可响应但SysTick中断会累计恢复调度时可能引起立即任务切换。 * 禁止在中断服务程序(ISR)中调用 */ void delay_us(uint32_t us) { uint32_t ticks; uint32_t told, tnow, tcnt 0; /* 1. 计算需要等待的CPU周期数 */ /* 假设系统主频为168MHz即每个时钟周期约5.95ns。 一次循环ticks us * (SystemCoreClock / 1000000)的计算结果 表示需要空转的CPU周期总数。 但实际循环体本身while(tcntticks)也有开销需要校准。*/ /* 这里使用一个经验值进行校准。校准方法见后文。*/ ticks us * (SystemCoreClock / 1000000) / 8; // 除以8是一个经验校准系数 /* 2. 挂起FreeRTOS调度器防止任务切换 */ vTaskSuspendAll(); /* 3. 获取当前SysTick计数器的值作为起始点 */ told SysTick-VAL; /* 4. 核心空等待循环 */ while(1) { /* 获取当前的SysTick计数器值 */ tnow SysTick-VAL; /* 计算从上一次读取到当前SysTick计数器走过的周期数 */ /* SysTick是向下计数器所以如果当前值小于之前值说明是正常递减 */ if (tnow ! told) { if (tnow told) { tcnt told - tnow; } /* 如果当前值大于之前值说明SysTick发生了重载从0重新加载为LOAD值*/ else { tcnt told (SysTick-LOAD - tnow); } told tnow; /* 如果累计周期数已经超过目标值则退出循环 */ if (tcnt ticks) { break; } } /* 如果tnow told说明可能发生了SysTick中断并重载 但中断处理很快我们紧接着就读取到了重载后的值。 这种情况在tcnt累计中通过else分支处理这里继续循环即可。*/ } /* 5. 恢复FreeRTOS调度器 */ xTaskResumeAll(); }3.2 代码原理深度解析计算ticks目标周期数SystemCoreClock是系统核心时钟频率如168MHz。us * (SystemCoreClock / 1000000)理论上表示us微秒内对应的CPU时钟周期总数。为什么除以8或其它系数这是校准系数。因为我们的while循环不是单周期指令。读取SysTick-VAL、比较、加减运算、条件跳转都需要消耗时钟周期。ticks计算的是“需要消耗的CPU周期”而循环体本身也在消耗周期。如果不校准实际延时会是理论值的很多倍。系数8是一个在168MHz下针对该特定循环结构的经验值必须通过实际测量进行校准。使用vTaskSuspendAll()和xTaskResumeAll()这对函数包裹了延时核心循环确保了在循环执行期间即使SysTick中断触发了osSystickHandlerFreeRTOS的调度器也不会进行任务切换。这是实现精准延时的关键。基于SysTick计数器的精准计时我们没有使用简单的for(i0; in; i)空循环因为编译器优化级别不同会极大影响其执行时间。我们选择硬件计数器SysTick-VAL作为计时基准。SysTick是一个24位的向下递减计数器与CPU时钟同步精度极高。循环中我们不断读取当前计数器值tnow并与上一次值told比较累加其差值tcnt。这样能准确统计出流逝的CPU周期数不受循环体本身指令数轻微波动的影响。处理了计数器重载tnow told的情况确保周期累计正确。恢复调度后的潜在任务切换正如前面提到的在调度锁期间SysTick中断会累计。xTaskResumeAll()函数内部会检查是否有丢失的tick如果有它会返回pdTRUE并且可能立即引发一次任务调度。这意味着delay_us()函数返回后当前任务可能马上被挂起转而执行另一个就绪的高优先级任务。如果你的后续代码要求严格连续执行需要考虑这个风险。4. 校准、测试与性能优化4.1 如何校准延时函数理论必须联系实际。上面的代码中/8这个系数是假设的你需要在自己的硬件上校准。校准方法使用一个GPIO引脚如PA5。在校准代码中先将引脚拉高调用delay_us(10)再将引脚拉低。用示波器或逻辑分析仪测量这个高电平脉冲的实际宽度。根据测量结果调整计算ticks时的系数。实测宽度 50us 期望宽度 10us。 说明延时长了系数8太小。 新系数 8 * (50 / 10) 40。修改代码为ticks us * (SystemCoreClock / 1000000) / 40;重复步骤2-4直到实测宽度与期望宽度如10us基本吻合。可以多测试几个点如1us, 5us, 50us, 100us观察线性度。校准代码示例void delay_us_calibration(void) { while(1) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); delay_us(10); // 期望产生10us的高电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); osDelay(100); // 延时100ms方便观察波形 } }4.2 不同优化等级下的表现编译器优化等级-O0, -O1, -O2, -O3会严重影响空循环的执行效率。我们的方案基于硬件计数器受优化影响较小但循环体内的比较、累加操作仍可能被优化。建议在最终发布的优化等级通常是-O2或-Os下进行校准和测试确保实际表现符合预期。4.3 更优的实现使用DWT时钟周期计数器对于Cortex-M3/M4/M7等内核有一个更强大的调试组件——数据观察点与跟踪单元其中的CYCCNT寄存器是一个32位的时钟周期计数器它从内核时钟使能后就开始自由递增。它的精度和SysTick一样高但使用起来更简单。启用DWT CYCCNT#define DWT_CR *(volatile uint32_t *)0xE0001000 #define DWT_CYCCNT *(volatile uint32_t *)0xE0001004 #define DEM_CR *(volatile uint32_t *)0xE000EDFC #define DEM_CR_TRCENA (1 24) #define DWT_CR_CYCCNTENA (1 0) static void DWT_Init(void) { /* 使能DWT跟踪模块 */ DEM_CR | DEM_CR_TRCENA; /* 清零CYCCNT计数器并使其能 */ DWT_CYCCNT 0; DWT_CR | DWT_CR_CYCCNTENA; }基于DWT的delay_us函数void delay_us_dwt(uint32_t us) { uint32_t start_tick, end_tick, delay_ticks; /* 计算需要延时的周期数已校准 */ delay_ticks us * (SystemCoreClock / 1000000) / 8; // 同样需要校准系数 vTaskSuspendAll(); // 挂起调度器 start_tick DWT_CYCCNT; // 获取开始周期计数 do { end_tick DWT_CYCCNT; // 获取当前周期计数 /* 处理计数器溢出32位约在168MHz下26秒溢出一次对us延时无影响*/ } while((end_tick - start_tick) delay_ticks); xTaskResumeAll(); // 恢复调度器 }优点代码更简洁无需处理重载直接相减即可。缺点需要确保DWT功能被启用STM32CubeMX默认不启用需手动添加初始化代码。5. 常见问题、避坑指南与实战心得在实际项目中应用这个delay_us函数我踩过不少坑也总结了一些经验。5.1 常见问题排查表问题现象可能原因解决方案延时时间远大于预期如10us变成100us1. 校准系数不正确。2. 编译器优化导致循环被优化掉或改变。3. 在中断服务程序ISR中调用发生了中断嵌套或优先级问题。1.务必使用示波器进行硬件校准。2. 在最终项目使用的优化等级下校准和测试。3.禁止在ISR中调用本函数。ISR中如需短延时考虑使用硬件定时器或纯空循环需关闭中断。延时时间不稳定每次测量有波动1. 系统中断特别是高优先级中断在延时期间发生虽然调度被挂起但中断处理本身消耗了时间。2. 缓存未命中、总线竞争等底层硬件因素。1. 检查系统中其他高优先级中断如USB、DMA。对于极高精度要求可能需要暂时提升延时任务的优先级或调整其他中断优先级。2. 波动在几个CPU周期内是正常的若影响应用需评估是否必须用软件延时可考虑硬件方案如PWM、定时器。调用delay_us后程序偶尔会“跳”到其他任务这是正常现象是xTaskResumeAll()的特性。在调度锁期间积累的SysTick中断在恢复调度时可能导致立即的任务切换。如果后续代码必须连续执行有几种方法1.临时提升当前任务优先级在delay_us前后使用vTaskPrioritySet()临时将任务设为最高优先级延时后再恢复。2.使用临界段用taskENTER_CRITICAL()和taskEXIT_CRITICAL()替代调度锁。这会关闭中断影响更大只适用于极短延时。3.接受并设计在软件架构上允许这种微小切换或确保关键连续操作在更底层如驱动层用更短的时间完成。长时间调用delay_us如100us导致系统卡顿调度锁阻止了其他任务的执行即使它们就绪了。重新评估设计us级延时函数不应用于长时间等待。对于ms级或更长的延时必须使用vTaskDelay()或osDelay()将CPU让给其他任务。本函数仅用于硬件时序要求的短延时。5.2 实操心得与高级技巧分层设计延时策略ns~us级10us用于极精密时序如模拟8080并口。可使用关闭中断的纯循环或硬件定时器。us级10us ~ 几百us用于单总线、软件SPI/I2C等。推荐使用本文的调度锁硬件计数器方案。ms级及以上必须使用FreeRTOS的vTaskDelay()。这是RTOS的协作式延时能让出CPU。为delay_us函数增加超时保护 虽然我们的循环等待的是硬件计数器理论上不会死循环。但为了代码健壮性可以增加一个基于SysTick的毫秒级超时判断。uint32_t start_ms osKernelGetTickCount(); while((end_tick - start_tick) delay_ticks) { if((osKernelGetTickCount() - start_ms) timeout_ms) { // 超时处理例如记录错误日志跳出循环 break; } end_tick DWT_CYCCNT; }考虑CPU频率变化的影响 如果你的系统有动态调频如运行在低功耗模式SystemCoreClock变量可能会变。我们的delay_us函数依赖于这个全局变量来计算ticks。确保在频率改变后更新SystemCoreClock或者更稳妥的方法是将计算ticks所需的“每微秒周期数”作为一个常量在系统初始化时根据当前频率计算好并保存延时函数直接使用这个常量。中断服务程序ISR中的延时再次强调不要在ISR中调用本文的delay_us函数。ISR中如果需要短延时通常的做法是如果延时极短几个周期使用简单的__NOP()空操作指令组合。如果延时稍长且该中断优先级最高可以临时关闭全局中断__disable_irq()使用精简的空循环然后立即开启__enable_irq()。但必须确保关闭时间极短。最佳实践是在ISR中设置标志位或发送通知将需要延时的操作转移到任务中处理任务里可以安全地使用delay_us。实现一个在FreeRTOS下稳定可靠的us延时关键在于理解操作系统调度机制与硬件计时资源的配合。基于调度锁和硬件计数器SysTick或DWT的方案在精度和系统影响之间取得了最佳平衡。记住它是一把精细的手术刀用于切割那些对时序极其敏感的短促操作而非用来进行漫长的等待。正确校准、理解其行为边界特别是恢复调度后的任务切换你就能在复杂的多任务系统中游刃有余地驾驭微秒级的时间尺度。

相关新闻

Google留痕技术:提升搜索霸屏效果的SEO实战指南

Google留痕技术:提升搜索霸屏效果的SEO实战指南

1. 什么是Google留痕?Google留痕指的是通过特定技术手段,在Google搜索结果页面上实现大量内容曝光的行为。简单来说,就是让同一个网站或品牌的相关内容占据搜索结果前几页的多个位置。这种现象在业内被称为"搜索霸屏"或"搜索结…

2026/10/13 12:49:30 阅读更多 →
AI教材生成工具:低查重技术与教育应用实践

AI教材生成工具:低查重技术与教育应用实践

1. AI教材生成工具的核心价值解析当我在教育科技行业深耕十年后,第一次接触到AI教材生成工具时,立刻意识到这将是改变传统教材编写模式的革命性技术。这类工具通过自然语言处理和机器学习算法,能够根据教学大纲和知识点体系,自动生…

2026/10/8 16:03:38 阅读更多 →
如何快速实现Atom编辑器中文汉化:完整简体中文菜单解决方案

如何快速实现Atom编辑器中文汉化:完整简体中文菜单解决方案

如何快速实现Atom编辑器中文汉化:完整简体中文菜单解决方案 【免费下载链接】atom-simplified-chinese-menu Atom 的简体中文汉化扩展,目前最全的汉化包。包含菜单汉化、右键菜单汉化以及设置汉化 项目地址: https://gitcode.com/gh_mirrors/at/atom-simplified-c…

2026/10/7 9:13:19 阅读更多 →

最新新闻

健康管理平台PRD:状态机、字段字典与接口契约实战解析

健康管理平台PRD:状态机、字段字典与接口契约实战解析

简介:这是一份传智健康管理系统的产品需求文档,面向产品经理、需求分析师及系统设计人员。文档围绕数据结构管理展开,详细定义健康评估指标的关键字段——序号、指标名称、参考值、单位、针对性别,并明确用户(病人&…

2026/10/13 15:19:55 阅读更多 →
软件测试全流程解析:从测试分类到缺陷管理,系统化落地指南

软件测试全流程解析:从测试分类到缺陷管理,系统化落地指南

入行这么多年,被问得最多的一个问题不是"这个bug怎么提",而是"软件测试到底怎么做才算是系统的、规范的"。很多刚入行的朋友拿着一堆测试理论,却分不清冒烟测试和回归测试的应用场景,也理不清从需求评审到测试…

2026/10/13 15:19:55 阅读更多 →
Spring Boot优雅关闭实战:从SIGTERM到Bean销毁的完整链路

Spring Boot优雅关闭实战:从SIGTERM到Bean销毁的完整链路

“Spring Boot 应用关闭”这六个字,放在一起看像个没什么技术含量的话题,但只要你经历过一次线上事故,就会意识到它值得单独拉出来做一次专项分析。我之前接手过一套内部订单系统,团队发现每次发版期间总会出现“下单成功但支付记…

2026/10/13 15:19:55 阅读更多 →
STM32 FOC库2.0全量资源解析:从电机驱动到调试避坑指南

STM32 FOC库2.0全量资源解析:从电机驱动到调试避坑指南

简介:面向STM32开发者与电机控制工程师的FOC库2.0完整版,提供磁场定向控制所需的算法实现、硬件驱动与工程模板,适用于BLDC、PMSM及ACIM的高性能驱动开发。压缩包共246个文件,主要包含c/h源码、icf链接脚本、gpj/ewp等IDE工程文件…

2026/10/13 15:19:54 阅读更多 →
SpringBoot+微信小程序文旅项目:从架构到部署的全栈实战指南

SpringBoot+微信小程序文旅项目:从架构到部署的全栈实战指南

很多人做毕设或者练手项目的时候,一看是"基于SpringBoot的文化旅游小程序",第一反应是"又一个老掉牙的选题"。但说实话,我见过太多同类项目翻车,要么代码能跑但接口乱成一团,要么论文写得像产品说…

2026/10/13 15:19:54 阅读更多 →
Java实现基于机器学习的图书推荐系统:协同过滤与矩阵分解实战

Java实现基于机器学习的图书推荐系统:协同过滤与矩阵分解实战

简介:这份资源是一套基于机器学习的图书推荐系统完整源码,面向计算机与软件工程专业学生、Java Web开发者及机器学习入门实践者,可用于课程设计、毕业设计或推荐算法学习。系统涵盖图书管理、读书会管理以及科技、人文、历史、中小学等多类别…

2026/10/13 15:18:53 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/12 21:05:09 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →