RT-Thread+FreeModbus+EasyFlash卡死排查:CmBacktrace实战
1. 问题现场还原与整体排查思路1.1 这个卡死问题到底卡在哪先说清楚这个项目背景。在嵌入式开发里RT-Thread 作为一款国产实时操作系统配合 FreeModbus 协议栈做从机通信再用 EasyFlash 做参数掉电存储这套组合在工业网关、数据采集终端、智能仪表里非常常见。问题出在三者交汇的地方FreeModbus 在中断或高优先级线程里收到一帧写寄存器命令回调里直接调用 EasyFlash 的ef_set_env去保存参数结果程序就卡死了串口没响应看门狗复位后依然复现。这种卡死最恶心的地方在于——它不一定是必现的。有时候跑几个小时才卡一次有时候一上电就卡。用调试器打断点发现程序停在某个while循环里出不来或者干脆 HardFault 之后进了死循环。更麻烦的是一旦卡死连 RT-Thread 的list_thread命令都敲不出来因为串口 shell 线程也被挂住了。我接手这个问题的第一反应是先别急着改代码先让系统自己把死之前发生了什么说出来。这就是引入 CmBacktrace 的动机。CmBacktrace 是 RT-Thread 生态里一款专门做 Cortex-M 系列 MCU 错误追踪的组件它能在 HardFault 或断言失败时自动回溯函数调用栈把出错时的现场信息打印出来甚至能定位到具体是哪一行代码触发的。没有它你面对的就是一个黑盒有了它至少能看到尸体躺在哪。1.2 为什么选择 CmBacktrace 而不是手动加打印有人会问为什么不直接在 EasyFlash 调用前后加rt_kprintf打印我试过效果很差。原因有三点第一卡死往往发生在中断上下文或者调度器临界区这时候rt_kprintf本身可能就不安全打印到一半就卡住了你看到的日志是残缺的反而误导判断。第二EasyFlash 操作 Flash 的时间是不确定的擦除一个扇区可能几十毫秒如果在这期间发生总线冲突或者看门狗喂狗失败打印根本来不及输出。第三也是最关键的——卡死的根因往往不是 EasyFlash 本身而是调用时机不对导致的资源竞争。比如 FreeModbus 的回调运行在 Modbus 线程里而 EasyFlash 的 GC垃圾回收可能被另一个线程触发两者同时操作同一块 Flash 区域就会死锁。这种问题靠打印是看不出来的必须靠调用栈回溯。CmBacktrace 的优势在于它是事后分析工具。系统崩溃的瞬间它把栈里的返回地址、寄存器状态全部 dump 出来你离线用 addr2line 工具一解析就能还原出完整的调用链。这比在代码里到处埋打印点高效得多而且对运行时性能几乎无影响。1.3 整体解决路径的拆解我把整个排查和解决过程分成四个阶段后面每个阶段都会展开讲第一阶段让崩溃可见。移植 CmBacktrace配置好栈回溯和日志输出确保任何 HardFault 都能打印出调用栈。第二阶段复现并抓取现场。构造稳定的复现条件抓取崩溃日志用工具解析出出错函数。第三阶段定位根因。结合 RT-Thread 的线程状态、FreeModbus 的回调机制、EasyFlash 的锁机制分析出真正的冲突点。第四阶段修复与验证。调整调用方式加入必要的同步保护长时间跑稳定性测试。这个路径的核心逻辑是先观测再假设后验证。很多工程师一上来就猜是不是栈溢出了是不是中断优先级配错了然后盲目改参数结果问题依旧。CmBacktrace 的价值就是帮你把猜变成看。提示在移植 CmBacktrace 之前务必确认你的工程已经开启了 RT-Thread 的组件自动初始化机制否则需要手动调用初始化函数容易漏掉导致回溯功能不生效。2. CmBacktrace 移植与配置的核心细节2.1 移植前的环境确认清单CmBacktrace 不是拿来就能用的它对工程环境有几点硬性要求我踩过坑这里列个清单让你对照检查检查项要求不满足的后果编译器支持 GCC 或 ARMCC需保留调试符号无法解析函数名只能看到地址优化等级建议 -O0 或 -O1避免 -O2 以上函数被内联调用栈失真栈对齐8 字节对齐回溯时读取栈数据错位串口输出有一个可用的阻塞式输出接口崩溃日志打印不全中断向量HardFault_Handler 未被占用需要手动挂接 CmBacktrace 的处理函数特别强调优化等级这一条。我一开始用 -O2 编译回溯出来的调用栈少了两层怎么都对不上代码逻辑。后来降到 -O1栈帧完整了问题立刻清晰。原因是高优化等级下编译器会把小函数内联返回地址被优化掉回溯自然就断了。调试阶段用 -O0量产再切回 -O2这是嵌入式调试的常规操作。2.2 移植步骤与关键配置项CmBacktrace 的移植其实不复杂但有几个配置项必须理解含义不能照抄。我按实际操作顺序说第一步把 CmBacktrace 源码加入工程。核心文件是cmb_backtrace.c、cmb_fault.c、cmb_cfg.h。其中cmb_cfg.h是配置总入口所有开关都在这里。第二步配置cmb_cfg.h里的关键宏。我列几个最关键的/* 使能 HardFault 处理 */ #define CMB_FAULT_HANDLER_ENABLE 1 /* 使能断言处理 */ #define CMB_ASSERT_ENABLE 1 /* 打印方式使用 RT-Thread 的 rt_kprintf */ #define CMB_PRINTF rt_kprintf /* 栈回溯深度默认 16可根据实际栈大小调整 */ #define CMB_BACKTRACE_DEPTH 16 /* 使用地址转函数名功能需要 addr2line 工具配合 */ #define CMB_USING_ADDR2LINE 1这里CMB_BACKTRACE_DEPTH的设置有个经验值取你最大线程栈深度除以 4 再留一倍余量。比如主线程栈 2048 字节深度设 16 就够如果设太小深层调用看不到设太大回溯时读取越界栈数据可能触发二次异常。第三步挂接 HardFault 处理函数。在cmb_fault.c里CmBacktrace 已经实现了HardFault_Handler你只需要在启动文件里把默认的弱定义覆盖掉即可。如果是 RT-Thread 工程注意不要和 RT-Thread 自己的异常处理冲突通常把 CmBacktrace 的处理函数放在最前面。第四步配置 addr2line 工具路径。CmBacktrace 打印出来的是地址需要配合addr2line命令解析成函数名和行号。在cmb_cfg.h里指定工具链路径#define CMB_ADDR2LINE_PATH C:/toolchain/bin/arm-none-eabi-addr2line.exe这个路径必须指向你实际使用的工具链路径里有空格或中文会导致解析失败这是很多人第一次用会忽略的细节。2.3 让日志真正可读的三个技巧移植完能打印地址只是第一步让日志真正可读还需要几个技巧技巧一保留 .elf 或 .axf 文件。addr2line 解析依赖调试符号文件每次编译后把 elf 文件按版本归档否则事后拿到地址也解析不出函数名。我习惯在编译脚本里自动把 elf 复制到带时间戳的目录。技巧二开启 CmBacktrace 的栈扫描功能。除了返回地址回溯它还支持扫描整个栈空间找出所有可能是返回地址的值。这个功能在栈被破坏时特别有用因为常规回溯可能因为栈帧损坏而中断栈扫描能捞回更多线索。技巧三把崩溃日志重定向到非易失存储。如果崩溃后系统立即复位串口日志可能来不及保存。可以在 CmBacktrace 的输出回调里把日志同时写入 Flash 的保留区域下次启动时读出来。这个改动不大但对现场问题定位帮助极大。注意CmBacktrace 的回溯过程本身会占用一定栈空间如果崩溃时栈已经耗尽回溯可能失败。建议在cmb_cfg.h里开启CMB_USING_STACK_CHECK回溯前先检查栈指针是否在合法范围内。3. 从崩溃日志到根因定位的完整实操3.1 构造稳定复现条件问题不是必现的直接等它自己崩效率太低。我的做法是构造一个高频触发场景用 Modbus 主站工具以 10ms 间隔连续写多个保持寄存器每个写操作都触发 EasyFlash 保存。同时后台跑一个线程每隔 500ms 调用一次ef_get_env读取参数。这样读写并发冲突概率大幅提升。实测下来平均 3 到 5 分钟就能复现一次卡死。复现频率提上来之后抓日志就轻松多了。这里有个心得复现条件要尽量贴近真实业务但频率可以人为放大。真实场景可能一天写一次参数你等一周也等不到崩溃把频率放大到每秒几十次问题本质不变但暴露速度快了几个数量级。3.2 崩溃日志的解读方法抓到崩溃日志后CmBacktrace 会输出类似这样的内容 CmBacktrace Firmware name: app_firmware Firmware version: 1.0.0 Fault exception: HardFault Current thread: modbus Fault address: 0x0800A3C4 Call stack: 0x0800A3C4 0x0800B120 0x0800C458 0x0800D2A0 0x0800E1F4 拿到这些地址后用 addr2line 批量解析arm-none-eabi-addr2line -e app_firmware.elf -f -C 0x0800A3C4 0x0800B120 0x0800C458 0x0800D2A0 0x0800E1F4输出会告诉你每个地址对应的函数名和行号。我第一次解析出来的调用链是这样的ef_set_env ef_env_set ef_save_env modbus_write_registers_callback看到这个链条问题就清楚了一半Modbus 的写寄存器回调里直接调用了 EasyFlash 的保存函数。而 EasyFlash 的保存操作会触发 Flash 擦写这个过程是阻塞的且可能触发 GC。3.3 根因分析三个层面的冲突光看到调用链还不够要理解为什么会卡死。我结合 RT-Thread 的调度机制和 EasyFlash 的内部实现分析出三个层面的冲突第一层线程上下文冲突。FreeModbus 的回调运行在 Modbus 线程里而 EasyFlash 的 GC 操作可能被其他线程比如空闲线程或定时器线程触发。两个线程同时操作 Flash如果没有互斥保护就会一个在擦除、一个在写入硬件层面直接冲突。第二层临界区嵌套。EasyFlash 内部会调用rt_hw_interrupt_disable关中断来保护 Flash 操作。如果 Modbus 回调本身已经在某个临界区里再嵌套关中断可能导致中断状态恢复错误进而让调度器失效。第三层看门狗超时。Flash 擦除一个扇区在有些 MCU 上要几十毫秒如果 Modbus 线程优先级很高长时间占用 CPU 不让出看门狗喂狗线程得不到调度直接复位。复位后如果参数还没写完下次启动读到脏数据又触发异常形成死循环。这三层冲突叠加就表现为卡死。CmBacktrace 帮我们确认了第一层的调用链后两层需要结合 RT-Thread 的线程状态和 EasyFlash 的源码进一步分析。3.4 用 list_thread 辅助验证在崩溃前如果能敲出list_thread命令可以看到各线程的状态。我抓到的关键信息是Modbus 线程处于suspend状态而 EasyFlash 的 GC 线程处于ready但一直没被调度。这说明 Modbus 线程在等一个永远不会到来的信号量而 GC 线程在等一个被占用的互斥量典型的死锁。这个验证很关键它把卡死这个模糊描述变成了两个线程互相等待的精确描述。有了这个结论修复方向就明确了要么让 EasyFlash 操作不在 Modbus 回调里同步执行要么给 Flash 操作加统一的互斥保护。提示list_thread命令在系统卡死时可能敲不出来可以提前在空闲线程里加一个心跳打印或者用硬件定时器定期输出线程状态到备用串口。4. 修复方案与稳定性验证4.1 方案选型三种修复思路的对比定位到根因后修复方案有三条路我逐一分析并做了取舍方案做法优点缺点方案A异步化Modbus 回调只发消息另起线程做 EasyFlash 保存彻底解耦不阻塞通信需要消息队列增加内存开销方案B加互斥锁所有 EasyFlash 操作统一加互斥量改动小实现快锁粒度不好控制仍可能阻塞方案C降低频率参数攒够一批再统一保存减少 Flash 操作次数掉电可能丢数据我最终选了方案A为主、方案C为辅的组合。理由是这样Modbus 通信对实时性要求高回调里绝对不能做耗时操作异步化是根本解法同时参数保存不需要每次都写攒一批再写既减少 Flash 磨损又降低冲突概率。4.2 异步化的具体实现异步化的核心是引入一个消息队列和一个专门的存储线程。Modbus 回调里只做一件事把要保存的参数打包成消息投递到队列然后立即返回。存储线程从队列取消息调用 EasyFlash 保存。关键代码结构大致是这样/* 定义消息结构 */ struct save_msg { char key[16]; char value[32]; }; /* 消息队列 */ static struct rt_messagequeue save_mq; static char mq_pool[512]; /* 存储线程入口 */ static void storage_thread_entry(void *param) { struct save_msg msg; while (1) { if (rt_mq_recv(save_mq, msg, sizeof(msg), RT_WAITING_FOREVER) RT_EOK) { ef_set_env(msg.key, msg.value); ef_save_env(); } } } /* Modbus 回调里只投递消息 */ static void modbus_write_callback(uint16_t addr, uint16_t value) { struct save_msg msg; rt_snprintf(msg.key, sizeof(msg.key), reg_%d, addr); rt_snprintf(msg.value, sizeof(msg.value), %d, value); rt_mq_send(save_mq, msg, sizeof(msg)); }这个改动的精髓在于把写 Flash这个耗时动作从通信路径上摘出去。Modbus 回调的执行时间从几十毫秒降到几微秒通信实时性得到保证Flash 操作在独立线程里串行执行不会和其他线程冲突。4.3 参数攒批与掉电保护异步化之后还要考虑掉电丢数据的问题。如果参数刚投递到队列还没写 Flash 就掉电了数据就丢了。我的做法是加一个脏标记机制参数变更时置位标记存储线程每隔固定时间比如 1 秒检查标记有变更才写 Flash。同时利用 EasyFlash 的 ENV 机制它本身支持掉电保护写入过程中掉电不会破坏已有数据。攒批的另一个好处是减少 Flash 擦写次数。Flash 寿命通常按擦写次数算比如 10 万次。如果每次 Modbus 写都保存一天写一万次十天就把扇区写坏了。攒批之后一天最多写几千次寿命延长一个数量级。4.4 长时间稳定性验证修复完成后我做了三轮验证第一轮高频压力测试。用主站工具以 5ms 间隔连续写寄存器连续跑 72 小时观察是否还有卡死。这一轮主要验证异步化是否彻底解决了冲突。第二轮掉电测试。在参数写入过程中随机断电重启后检查参数是否完整。这一轮验证掉电保护机制。第三轮边界测试。把消息队列填满看系统如何表现。如果队列满了投递失败需要有降级策略比如直接丢弃或者阻塞等待。我选择的是丢弃并记录日志因为参数保存不是关键路径丢一次下次变更还会再存。三轮测试跑下来系统稳定没有再出现卡死。CmBacktrace 也一直保留在工程里作为长期监控手段。后来偶尔出现其他异常它都能第一时间给出调用栈省了大量排查时间。注意异步化之后Modbus 回调返回成功不代表参数已经落盘。如果业务上要求写成功即持久化需要在协议层做额外确认比如读回校验。这个取舍要根据实际业务需求决定。5. 常见问题与排查技巧实录5.1 CmBacktrace 移植常见问题速查现象可能原因解决办法崩溃时无任何输出HardFault_Handler 未挂接检查启动文件确认处理函数被覆盖输出只有地址无函数名未配置 addr2line 或 elf 文件不匹配确认工具路径和 elf 版本一致调用栈层数明显偏少优化等级过高导致内联调试阶段降到 -O0 或 -O1回溯时二次崩溃栈已损坏或深度设置过大减小回溯深度开启栈检查日志打印一半中断输出接口非阻塞或缓冲区不足改用阻塞式输出增大缓冲5.2 我踩过的三个坑坑一忘了关看门狗。第一次调试时崩溃日志还没打印完看门狗就复位了日志残缺。后来在调试阶段先关掉看门狗或者把喂狗时间临时调长确保日志完整输出。坑二addr2line 路径带空格。工具链装在Program Files目录下路径里有空格CmBacktrace 调用时解析失败。解决办法是把工具链装到无空格路径或者用短路径名。坑三多版本 elf 混淆。改了几次代码elf 文件覆盖了事后拿旧日志解析函数名对不上。后来养成习惯每次编译自动归档 elf文件名带时间戳和 git 提交号。5.3 独家避坑技巧分享几个文档里不会写、但实际很有用的技巧技巧一在 CmBacktrace 输出里加上线程名和 tick 计数。默认输出只有调用栈加上当前线程名和系统 tick能判断崩溃发生在哪个阶段、系统跑了多久对分析时序相关问题帮助很大。技巧二用断言代替裸奔。在 EasyFlash 调用前后加RT_ASSERT检查关键条件比如 Flash 是否忙、互斥量是否已持有。断言失败时 CmBacktrace 会自动回溯比 HardFault 更容易定位。技巧三保留一个最小复现工程。把问题剥离到一个只包含 RT-Thread、FreeModbus、EasyFlash 的最小工程里去掉所有业务代码。这样排查时干扰最少也方便把问题反馈给组件维护者。技巧四定期做栈使用率统计。RT-Thread 有list_thread可以看每个线程的栈使用峰值定期检查把栈快满的线程及时扩容能从源头避免栈溢出导致的崩溃。这套组合拳打下来这个卡死问题算是彻底解决了。回头看CmBacktrace 的价值不只是解决了这一个问题更重要的是它改变了我的调试习惯——从猜问题变成看问题。嵌入式开发最怕的就是黑盒有了调用栈回溯再复杂的崩溃也能一层层剥开。后来我在其他项目里也一直保留这个组件它就像给系统装了个黑匣子平时不占资源出事时能救命。

相关新闻

Oppia CI 测试套件配置指南:解读 core/tests/ci-test-suite-configs 的注册机制与运行链路

Oppia CI 测试套件配置指南:解读 core/tests/ci-test-suite-configs 的注册机制与运行链路

教育后端前端 【免费下载链接】oppia A free, online learning platform to make quality education accessible for all. 项目地址: https://gitcode.com/gh_mirrors/op/oppia 点击查看 免费下载 导读:core/tests/ci-test-suite-configs 是 Oppia 仓库…

2026/10/16 18:49:15 阅读更多 →
iPhoneMirror协议原理:QuickTime私有USB Screen Capture协议逆向解析(H.264/HEVC全链路)

iPhoneMirror协议原理:QuickTime私有USB Screen Capture协议逆向解析(H.264/HEVC全链路)

【免费下载链接】iPhoneMirror Local Windows iPhone/iPad mirroring over USB and AirPlay with D3D11 preview, multi-device sessions, OBS output, and a standalone driver manager. 项目地址: https://gitcode.com/gh_mirrors/ip/iPhoneMirror 点击查看 免费下…

2026/10/16 19:40:28 阅读更多 →
cangjie_stdx 字符串池化缓存指南:使用 string_intern 的 intern 机制降低临时字符串内存开销

cangjie_stdx 字符串池化缓存指南:使用 string_intern 的 intern 机制降低临时字符串内存开销

标准库网络密码学并发编程 【免费下载链接】cangjie_stdx 仓颉编程语言提供了 stdx 模块,该模块提供了网络、安全等领域的通用能力。 项目地址: https://gitcode.com/Cangjie/cangjie_stdx 点击查看 免费下载 导读 string_intern 是仓颉标准扩展库&…

2026/10/15 18:01:15 阅读更多 →

最新新闻

惯性导航解算算法实现:从IMU数据到ECEF位置的六步闭环

惯性导航解算算法实现:从IMU数据到ECEF位置的六步闭环

简介:本资源是一套完整的惯性导航解算算法实现工程,面向导航制导、智能无人系统、机器人定位等方向的本科生、研究生及嵌入式开发者,聚焦于INS核心姿态解算、加速度积分与卡尔曼滤波校正等关键环节,解决无GPS环境下自主定位与姿态…

2026/10/17 0:31:59 阅读更多 →
Kube-OVN 安装避坑指南:内核适配、网卡识别与版本兼容三重校验

Kube-OVN 安装避坑指南:内核适配、网卡识别与版本兼容三重校验

简介:本资源是一份面向Kubernetes运维工程师、云原生网络架构师及容器平台开发者的Kube-OVN深度技术文档,系统解析这一CNCF沙盒项目的网络设计哲学与工程实践。文档覆盖其三大核心优势:依托OVN/OVS实现的子网管理、VPC多租户、跨集群互联等丰…

2026/10/17 0:31:59 阅读更多 →
35岁后端转大模型:从零到求职的全路径实战规划

35岁后端转大模型:从零到求职的全路径实战规划

最近有个老同事约我吃饭,聊到一个特别现实的问题:35岁,传统后端开发干了十来年,薪资到顶,业务需求也在收缩,要不要all in大模型?他说自己把网上关于“35岁程序员转行大模型”的文章翻了个遍&…

2026/10/17 0:30:58 阅读更多 →
用户画像构建实战:从标签体系设计到计算存储的完整方案

用户画像构建实战:从标签体系设计到计算存储的完整方案

1. 用户画像构建的整体思路与方案选型用户画像这个词,这几年被提得很多,但真正落地做过的团队都知道,它不是一个“建张表、打几个标签”就完事的活儿。我前后参与过三个不同量级的画像项目,从早期几十万用户的小型推荐系统&#x…

2026/10/17 0:30:58 阅读更多 →
AI工具平权时代,真正拉开差距的是这四种稀缺能力

AI工具平权时代,真正拉开差距的是这四种稀缺能力

最近一段时间,我身边几乎所有人都在讨论AI工具。聊天群里天天有人分享新出的提示词,短视频上不断刷到"三分钟用AI做出爆款",公司内部更夸张,连搞行政的同事都在用AI写周报。一个很现实的问题摆在每个人面前:…

2026/10/17 0:30:58 阅读更多 →
2020春招后端与算法岗面试全攻略:线上笔试、手撕代码与项目深挖

2020春招后端与算法岗面试全攻略:线上笔试、手撕代码与项目深挖

2020年刚开年那阵子,身边准备春招的朋友普遍都有个感受:往年学长学姐留下的面经套路,突然就失效了。线下宣讲、现场笔试、群面大战这些经典环节被彻底重排,大部分流程都搬到了线上,一轮接一轮的视频面、电话面&#xf…

2026/10/17 0:30:58 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 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/16 21:54:38 阅读更多 →
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/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →