STM32定时器主从模式:精确控制脉冲个数的步进电机方案

简介:这份资源面向STM32嵌入式开发者与运动控制方向的学习者,聚焦F103与F407两款芯片的定时器主从模式,解决步进电机精准脉冲个数输出的实际问题。内容基于HAL/LL库函数实现,涵盖主从定时器协同、TRGO触发、预分频与比较寄存器配置等关键环节,适合具备一定定时器基础、希望深入掌握PWM同步输出与电机精确定位的中级开发者。压缩包共264个文件,以c与h源码为主,辅以工程编译产物如o、d、crf、axf、hex及Keil工程文件uvprojx、uvoptx,整体约1.85MB,结构完整可直接编译验证。目前已有8229人学习下载,热度较高。读者可从中获得F103与F407两套独立示例工程,对照理解主从定时器同步机制与脉冲计数控制逻辑,并借助map、lst等文件分析资源占用与汇编细节,为步进电机驱动与自动化项目提供可复用的参考方案。

1. 定时器主从模式:让STM32输出精确到个数的脉冲

做步进电机控制的朋友大概率遇到过这个场景:想让电机走一个精确的角度,比如丝杆滑台移动 50mm,算下来需要发 2000 个脉冲,一个不多一个不少。用软件循环翻转 IO 吧,中断一多就丢脉冲;用 PWM 连续输出吧,又不知道什么时候该停。STM32 的定时器主从模式就是专门解决这个问题的——一个定时器负责输出 PWM 波形,另一个定时器负责数脉冲个数,数够了自动关断。这套方案在 F103 和 F407 上都适用,前者是经典入门款,后者主频高、定时器资源更丰富。本文基于一份 F103/F407 双平台的工程源码,把主从模式的配置流程、寄存器逻辑和实际调试中踩过的坑拆开讲清楚,适合正在做步进电机、伺服驱动器或者任何需要定量脉冲输出的开发者。

2. 主从模式架构:谁当主、谁当从、门控怎么走

2.1 主从定时器的角色划分

STM32 的定时器主从模式,本质上是把两个(或多个)定时器通过内部触发线 ITR 连接起来,让一个定时器的输出事件去控制另一个定时器的启停或时钟。在这个项目里,角色划分很明确:

  • 主定时器(Master):负责输出 PWM 波形,同时它的更新事件或比较事件作为触发输出(TRGO),送给从定时器。
  • 从定时器(Slave):工作在从模式,接收主定时器的触发信号,对脉冲进行计数。当计数值达到预设的脉冲个数时,产生中断,在中断里关闭主定时器的 PWM 输出。

以 F103 为例,常见搭配是 TIM1 做主定时器输出 PWM,TIM2 或 TIM3 做从定时器计数。F407 上因为定时器更多,可以用 TIM8 做主、TIM3 做从,或者反过来,具体看引脚分配和通道需求。

这里有个容易混淆的点:主从模式里的“主”和“从”是触发关系,不是主频高低的关系。从定时器完全可以用一个更高频率的时钟来计数,只要触发信号接对了就行。

2.2 内部触发连接与 TRGO 选择

主定时器要把自己的某个事件“广播”出去,靠的是 TRGO 配置。在 HAL 库里对应的是HAL_TIMEx_MasterConfigSynchronization()函数,关键参数是MasterOutputTrigger。可选的事件源包括:

TRGO 源含义适用场景
RESET更新事件触发每次溢出都发一个触发
ENABLE使能时触发只在启动时发一次
UPDATE更新事件最常用,配合 PWM 模式
COMPARE_PULSE比较脉冲OC1REF 作为触发
COMPARE_OC1REFOC1 比较需要精确对齐时用
COMPARE_OC2REFOC2 比较同上,通道 2
COMPARE_OC3REFOC3 比较同上,通道 3
COMPARE_OC4REFOC4 比较同上,通道 4

这个项目里,主定时器配置为 PWM 模式,TRGO 选TIM_TRGO_UPDATE,也就是每次计数器溢出(一个 PWM 周期结束)时发出一个触发脉冲。从定时器收到这个脉冲,计数值加一。

从定时器的触发输入选择,对应的是TIM_SlaveConfigTypeDef结构体里的InputTrigger字段。F103 的 TIM2 可以选 ITR0 到 ITR3,分别对应不同的内部触发源。具体哪个 ITR 对应哪个定时器,必须查参考手册的“TIMx 内部触发连接”表,这个不能猜。

2.3 从定时器的门控模式与计数逻辑

从定时器的工作模式选的是“门控模式”(Gated Mode)还是“触发模式”(Trigger Mode),直接决定了计数行为。这个项目用的是门控模式,从定时器的计数器只在主定时器输出高电平(或有效电平)时才计数。但更常见的做法是外部时钟模式——把主定时器的 TRGO 当作从定时器的时钟源,每来一个触发脉冲,从定时器计数值加一。

在 HAL 库里配置从定时器:

TIM_SlaveConfigTypeDef sSlaveConfig = {0}; sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; // 外部时钟模式1 sSlaveConfig.InputTrigger = TIM_TS_ITR0; // 触发源选ITR0 sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1; sSlaveConfig.TriggerFilter = 0; HAL_TIM_SlaveConfigSynchro(&htim2, &sSlaveConfig);

SlaveMode选TIM_SLAVEMODE_EXTERNAL1表示从定时器把选定的触发输入当作外部时钟来用。InputTrigger选TIM_TS_ITR0,在 F103 上 TIM2 的 ITR0 对应的是 TIM1 的 TRGO。TriggerPolarity选上升沿,因为主定时器的更新事件在计数器溢出时产生,对应一个上升沿脉冲。

从定时器的自动重装载值(ARR)设成需要的脉冲个数减一。比如要发 2000 个脉冲,ARR 就设 1999。当从定时器计数到 ARR 时产生更新中断,在中断回调里关掉主定时器的 PWM 输出。

注意:从定时器的 CNT 寄存器在外部时钟模式下,每个触发脉冲加一,不是每个系统时钟加一。所以从定时器的预分频器(PSC)要设成 0,否则会漏计脉冲。

3. 工程落地:从 CubeMX 配置到中断回调的完整链路

3.1 时钟树与定时器参数计算

F103 和 F407 的时钟树差异较大,配置前先确认总线频率。F103 通常跑 72MHz,APB1 定时器时钟 72MHz,APB2 定时器时钟也是 72MHz。F407 跑 168MHz 时,APB1 定时器时钟 84MHz,APB2 定时器时钟 168MHz。

主定时器输出 PWM 的频率和占空比由 PSC 和 ARR 决定:

// 主定时器 TIM1 配置:输出 10kHz PWM,占空比 50% htim1.Instance = TIM1; htim1.Init.Prescaler = 72 - 1; // 72MHz / 72 = 1MHz 计数频率 htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 100 - 1; // 1MHz / 100 = 10kHz PWM 频率 htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

PSC 设 71,计数频率就是 1MHz。ARR 设 99,PWM 周期就是 100 个计数,频率 10kHz。占空比通过比较寄存器 CCR 设置,比如 CCR 设 50,占空比就是 50%。

从定时器的 ARR 决定脉冲个数:

// 从定时器 TIM2 配置:计数 2000 个脉冲 htim2.Instance = TIM2; htim2.Init.Prescaler = 0; // 不分频,每个触发脉冲计一次 htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 2000 - 1; // 2000 个脉冲后溢出 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

这里AutoReloadPreload建议关掉,因为从定时器的 ARR 在运行中不需要修改,关掉可以减少一个影子寄存器的延迟。

3.2 主从联动的启动顺序

启动顺序很关键,搞反了会丢脉冲。正确的流程是:

  1. 先启动从定时器,让它进入等待触发状态。
  2. 再启动主定时器,开始输出 PWM。
  3. 主定时器第一个更新事件到来时,从定时器开始计数。

代码里这样写:

// 先启动从定时器,开启中断 HAL_TIM_Base_Start_IT(&htim2); // 再启动主定时器 PWM 输出 HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

如果反过来先启动主定时器,从定时器还没准备好,前几个脉冲就丢了。这个坑我在第一次调试时踩过,电机实际走的步数比预期少了几步,查了半天才发现是启动顺序的问题。

3.3 中断回调里关断 PWM

从定时器计数到 ARR 时触发更新中断,在回调函数里关掉主定时器的 PWM 输出:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { // 从定时器计数完成,关断主定时器 PWM HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1); // 可选:关闭从定时器,等待下次启动 HAL_TIM_Base_Stop_IT(&htim2); // 置标志位,通知主循环脉冲发送完成 g_pulse_done_flag = 1; } }

HAL_TIM_PWM_Stop()会关闭主定时器的 PWM 输出,同时停止计数器。HAL_TIM_Base_Stop_IT()关闭从定时器的中断。置一个全局标志位,主循环里检测到这个标志就可以执行下一步动作,比如改变电机方向、发送下一组脉冲。

注意:在中断里调用HAL_TIM_PWM_Stop()会关闭定时器,如果下次还要发脉冲,需要重新调用HAL_TIM_PWM_Start()。如果频繁启停,建议用__HAL_TIM_SET_COUNTER()复位计数器,而不是完全关闭定时器。

4. 避坑与排查:主从模式调试中的五个血泪教训

4.1 脉冲个数总是少几个

现象:设了 2000 个脉冲,实际只发了 1997 个左右,每次少的数量还不固定。

原因:启动顺序不对。先启动了主定时器,从定时器还没进入等待状态,前几个 PWM 周期没有被计数。另外,如果从定时器的中断优先级低于其他中断,中断响应延迟也可能导致最后一个脉冲被漏掉。

解决:严格按“先从后主”的顺序启动。从定时器的中断优先级设到最高,或者至少高于可能打断它的其他中断。如果还是少,可以在关断 PWM 后读一下从定时器的 CNT 寄存器,确认实际计数值。

4.2 从定时器完全不计数

现象:主定时器 PWM 正常输出,但从定时器的 CNT 一直是 0。

原因:ITR 选错了。F103 和 F407 的内部触发连接表不一样,同一个 ITR 编号对应的主定时器不同。比如 F103 的 TIM2_ITR0 对应 TIM1,但 F407 的 TIM2_ITR0 对应 TIM1,TIM3_ITR0 对应 TIM2。选错了就收不到触发信号。

解决:查对应芯片参考手册的“TIMx 内部触发连接”表,确认 ITR 编号。用示波器测主定时器 TRGO 对应的引脚(如果有引出的话),或者直接在调试器里看从定时器的 CNT 寄存器有没有变化。

4.3 PWM 频率不对

现象:设了 10kHz,实际测出来是 5kHz 或者 20kHz。

原因:时钟树配置错了。F103 和 F407 的 APB1、APB2 定时器时钟倍频关系不同。F103 的 APB1 定时器时钟在 APB1 预分频不为 1 时是 APB1 时钟的 2 倍。F407 同理,但总线频率不同。

解决:在 CubeMX 里确认时钟树,看定时器时钟输入频率是多少。然后按PWM频率 = 定时器时钟 / ((PSC+1) * (ARR+1))重新计算 PSC 和 ARR。

4.4 中断里关断 PWM 后电机还在走

现象:中断回调里调用了HAL_TIM_PWM_Stop(),但电机还多走了几步才停。

原因:HAL_TIM_PWM_Stop()关闭的是 PWM 输出使能位,但定时器计数器可能还在跑,当前 PWM 周期可能还没结束。另外,步进电机驱动器本身有响应延迟,收到停止信号后还会走几个脉冲。

解决:在关断 PWM 后,把主定时器的计数器也复位,确保当前周期立即结束。对于电机驱动器的延迟,可以在软件里提前几个脉冲关断,或者选带使能端的驱动器,直接拉低使能信号。

4.5 F407 上从定时器计数频率上不去

现象:F103 上跑得好好的配置,移植到 F407 上从定时器计数频率明显偏低。

原因:F407 的定时器时钟频率更高,从定时器在外部时钟模式下,触发信号的频率不能超过从定时器时钟频率的一半。如果主定时器 PWM 频率太高,从定时器可能来不及响应。

解决:降低主定时器 PWM 频率,或者换一个时钟频率更高的从定时器。F407 的 TIM2 和 TIM5 是 32 位定时器,时钟频率也高,适合做高速计数。

5. 二次开发:把主从模式封装成可复用的脉冲输出模块

5.1 封装思路与接口设计

原始工程里主从模式的配置散落在 main.c 和回调函数里,改一个参数要翻好几个地方。二次开发的第一步就是把它封装成一个独立的模块,对外只暴露几个简单的接口。

我一般会这样设计:

// pulse_gen.h typedef struct { TIM_HandleTypeDef *master_tim; // 主定时器句柄 uint32_t master_channel; // 主定时器通道 TIM_HandleTypeDef *slave_tim; // 从定时器句柄 uint32_t pulse_count; // 当前设定的脉冲个数 volatile uint8_t is_busy; // 忙标志 volatile uint8_t is_done; // 完成标志 } PulseGen_HandleTypeDef; // 初始化主从定时器联动 void PulseGen_Init(PulseGen_HandleTypeDef *hpg, TIM_HandleTypeDef *master, uint32_t ch, TIM_HandleTypeDef *slave); // 发送指定个数的脉冲,非阻塞 void PulseGen_Start(PulseGen_HandleTypeDef *hpg, uint32_t count); // 查询是否发送完成 uint8_t PulseGen_IsDone(PulseGen_HandleTypeDef *hpg); // 紧急停止 void PulseGen_Stop(PulseGen_HandleTypeDef *hpg);

PulseGen_Start()里做三件事:设置从定时器的 ARR 为count - 1,复位从定时器 CNT,按“先从后主”的顺序启动。PulseGen_IsDone()返回完成标志,主循环轮询或者用回调通知。

5.2 动态修改脉冲个数的技巧

有些场景需要在运行中动态调整脉冲个数,比如根据传感器反馈实时修正。直接改 ARR 寄存器有风险,因为从定时器可能正在计数。安全的做法是:

void PulseGen_UpdateCount(PulseGen_HandleTypeDef *hpg, uint32_t new_count) { // 只在空闲时允许修改 if (hpg->is_busy) { return; } // 关闭从定时器,修改 ARR,重新使能 __HAL_TIM_DISABLE(hpg->slave_tim); __HAL_TIM_SET_AUTORELOAD(hpg->slave_tim, new_count - 1); __HAL_TIM_SET_COUNTER(hpg->slave_tim, 0); __HAL_TIM_ENABLE(hpg->slave_tim); hpg->pulse_count = new_count; }

__HAL_TIM_DISABLE()和__HAL_TIM_ENABLE()是寄存器级操作,比 HAL 库的HAL_TIM_Base_Stop()和HAL_TIM_Base_Start()更轻量,不会触发多余的回调。

5.3 用 DMA 突发模式进一步降低 CPU 占用

如果脉冲个数很多(比如几万个),每次都在中断里处理会增加 CPU 负担。F407 的定时器支持 DMA 突发模式,可以把从定时器的更新事件映射到 DMA 请求,每计满一定个数才触发一次中断。

配置方法是在从定时器的 DMA/中断使能寄存器里打开更新 DMA 请求,然后配置 DMA 通道,设置传输长度。这样 CPU 只在 DMA 传输完成时才介入,中间过程完全不占 CPU。

这个技巧在需要连续发送大量脉冲的场景下特别有用,比如多轴联动的步进电机控制。不过 F103 的 DMA 资源有限,用之前先确认 DMA 通道有没有被其他外设占用。

5.4 验证方法:用逻辑分析仪抓波形

改完代码怎么验证?最直接的办法是用逻辑分析仪抓主定时器 PWM 输出引脚和从定时器的 CNT 寄存器(通过调试器实时查看)。逻辑分析仪上数一下实际脉冲个数,和设定值对比。

如果没有逻辑分析仪,可以用另一个定时器做输入捕获,测量脉冲个数和频率。或者简单点,在中断回调里翻转一个 IO,用示波器看这个 IO 的翻转次数。

我自己的习惯是:每次改完主从模式的配置,先用示波器确认 PWM 频率和占空比正确,再用调试器单步跟一遍启动流程,确认从定时器的 CNT 在第一个触发脉冲后变成 1。这两步过了,基本就不会有大问题。从那以后我每次调定时器主从模式,都强制走一遍“先示波器后调试器”的流程,省得后面返工。希望帮到你。

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

相关新闻

离线环境NTP部署实战:从依赖解析到多级时间树搭建

离线环境NTP部署实战:从依赖解析到多级时间树搭建

1. 为什么离线环境里NTP不是“可有可无”,而是系统稳定性的命脉在某高校实验室的边缘计算节点集群里,我接手过一个典型场景:6台物理服务器全部部署在封闭机房,网络策略严格限制——仅允许内网通信,外网出口被完全关闭。…

2026/10/20 4:40:47 阅读更多 →
提示工程架构师视角:大模型在传统场景的工程化落地方法

提示工程架构师视角:大模型在传统场景的工程化落地方法

那段时间,我几乎每星期都要跟人解释一遍:提示工程不是“跟AI聊天”,也不是谁都能随便写几段话让别人去“抄作业”的工作。真正干这一行之后才明白,提示工程的核心是一整套“怎么让大模型稳定输出、不跑偏、可复用”的工程方法。更…

2026/10/20 4:40:46 阅读更多 →
麒麟V10上搭建UE5.3与Vscode开发环境实战指南

麒麟V10上搭建UE5.3与Vscode开发环境实战指南

麒麟V10系统布置UE5.3和Vscode开发环境,这个活儿我前前后后折腾了几周,踩了不少坑,期间还重装过两遍系统,把UE从源码编译到打包出成果物整个链路摸了一遍。这篇东西不打算写成那种照搬官方文档的流水账,就按我实际操作…

2026/10/20 4:40:46 阅读更多 →

最新新闻

视觉模型重塑时间序列分析:从离散Token到连续视觉的范式转换

视觉模型重塑时间序列分析:从离散Token到连续视觉的范式转换

1. 从离散Token到连续视觉:时间序列分析的新思路拆解时间序列分析这个领域,做的人多,但真正让人眼前一亮的突破少。传统方法从统计模型一路走到深度学习,Transformer架构进来之后,大家发现一个尴尬的事实:文…

2026/10/20 5:21:04 阅读更多 →
向AI提交创作需求:关键信息清单助你生成优质博客

向AI提交创作需求:关键信息清单助你生成优质博客

抱歉,我还没有收到您的项目标题和相关描述。麻烦您将以下信息发给我,我立刻开始创作:项目标题: [在这里填写标题] 项目正文: [零散描述也可以] 关键词: [关键词1, 关键词2, ...] 摘要描述: [一句话简介]收到后我会直接输出一篇完整的、可直接…

2026/10/20 5:21:04 阅读更多 →
PyTorch nn.DataParallel原理与实战:多卡训练的底层基石

PyTorch nn.DataParallel原理与实战:多卡训练的底层基石

1. 为什么今天还要深挖nn.DataParallel?它真过时了吗?在 PyTorch 生态里,提到多卡训练,很多人第一反应是DistributedDataParallel(简称 DDP),社区文档、新教程、论文复现代码几乎清一色推荐它。…

2026/10/20 5:21:04 阅读更多 →
OpenCode接入Qwen模型实战:从选型配置到避坑指南

OpenCode接入Qwen模型实战:从选型配置到避坑指南

最近在折腾终端里的 AI 编程 Agent 工具 OpenCode,有一件事绕不开:模型配置。OpenCode 这类工具默认的模型接入方式对国内开发者不算友好,网络、计费、可用性都有门槛。好在这类工具大多支持自定义模型接入,而这几年国产开源模型里…

2026/10/20 5:21:04 阅读更多 →
榜单第一不等于实战能打:从Argon看大模型代码能力评价误区

榜单第一不等于实战能打:从Argon看大模型代码能力评价误区

开篇想聊个最近在圈子里传得挺开的事:某头部厂商放出了新的旗舰模型Argon,官方口径是“榜单18项第一”,从通用问答到复杂推理再到多模态理解,几乎把所有权威评测的榜首都揽了一遍。可等开发者们真把它拖到真实的代码仓库里跑任务&…

2026/10/20 5:21:04 阅读更多 →
智能支持员实战:从意图识别到多轮诊断的AI排障系统搭建

智能支持员实战:从意图识别到多轮诊断的AI排障系统搭建

做了这么多年技术支持,我对一件事特别有感触:真正占时间的不是那些疑难杂症,而是每天反复出现的“老三样”——服务起不来、配置不生效、报错信息看不懂。团队决定做“智能支持员”这个项目的时候,我的第一反应不是“又要上机器人…

2026/10/20 5:20:04 阅读更多 →

日新闻

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/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

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

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

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

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

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →