一 本节介绍
📝本节我们将学习看门狗定时器,全称 Watchdog Timer(WDT)的基本用法,包括启动看门狗、定期喂狗、安全停止,以及有控制地验证超时复位。
教程同时适用于以下两款开发板:
- 立创·庐山派K230-CanMV开发板
- 立创·庐山派Lite-K230D-CanMV开发板
1.1 学习目标
🏆学习目标
1️⃣ 理解 WDT 的工作流程以及“喂狗”的真实含义。
2️⃣ 掌握 WDT()、feed()、stop() 和 close() 的常用方法。
3️⃣ 知道为什么不能在无条件执行的定时回调中盲目喂狗。
4️⃣ 能先运行安全喂狗测试,再按需进行真实的超时复位测试。
5️⃣ 能运行一份通过 get_board_info() 自动适配两款开发板的完整例程。
1.2 重点提示
⚠️创建 WDT 对象后会立即开始倒计时
看门狗不是普通计时器。执行 WDT(1, timeout) 后,硬件看门狗会立即启动;如果没有在超时前调用 feed() 或 stop(),开发板将自动复位,CanMV IDE 与开发板的连接也会暂时中断。
IMPORTANT
完整例程默认设置 TEST_RESET = False,只演示正常喂狗并在结束时安全停止 WDT。只有确认安全模式运行正常、代码尚未设置为开机自启动且重要数据已经保存后,才把它改成 True 验证真实复位。
运行脚本不是烧录
MicroPython 是解释性语言。在 CanMV 开发环境中点击运行按钮时,准确说法是“运行脚本”或“执行程序”。只有把 .img 固件镜像写入 TF 卡时,才称为“烧录固件”。
1.3 本节效果
安全模式下,程序每隔 1 s 喂狗一次,共喂狗 5 次,然后调用 stop() 停止 WDT,开发板不会复位。
复位测试模式下,程序先正常喂狗 3 次,随后故意停止喂狗。经过约一个看门狗超时周期后,开发板自动复位,IDE 连接会短暂断开。
二 软硬件准备
| 名称 | 数量 | 说明 |
|---|---|---|
| 立创·庐山派K230-CanMV开发板或立创·庐山派Lite-K230D-CanMV开发板 | 1 | 二选一,本教程同时适配 |
| TF 卡 | 1 | 已写入与板卡型号匹配的 CanMV MicroPython 固件 |
| Type-C 数据线 | 1 | 需要支持数据传输,不能只支持充电 |
| 电脑 | 1 | 用于连接开发板、运行脚本并查看终端输出 |
| 外接模块 | 0 | WDT 是片上资源,不需要外部接线 |
固件要求:建议使用 CanMV v1.8 或更新版本,并确保固件镜像与开发板型号匹配。本文的 stop()/close() 说明以 CanMV v1.8 源码为基准。
开发环境:可以使用与当前固件配套的 CanMV IDE K230、CanMV IDE Web,或 VS Code 配合 CanMV 扩展。
三 双板兼容说明
| 项目 | 立创·庐山派K230-CanMV开发板 | 立创·庐山派Lite-K230D-CanMV开发板 |
|---|---|---|
| 是否支持本节实验 | 支持 | 支持 |
| 主控 | K230 | K230D |
| WDT API | machine.WDT | machine.WDT |
| 外部接线 | 不需要 | 不需要 |
| 本例使用 GPIO | 不使用 | 不使用 |
| 复位后的现象 | 系统重新启动,IDE 短暂断开 | 系统重新启动,IDE 短暂断开 |
| 板卡适配方式 | get_board_info() 自动识别并打印板卡名称 | get_board_info() 自动识别并打印板卡名称 |
IMPORTANT
两款开发板的 WDT Python API 相同,因此看门狗逻辑不需要区分引脚。完整例程保留 get_board_info(),用于确认当前固件正确识别了哪一款庐山派。
四 基础知识与名词解释
4.1 什么是看门狗
可以把 WDT 理解成设备内部的一名“安全员”。程序启动 WDT 后,安全员开始倒计时;健康的程序必须定期报告“关键任务仍然正常”,也就是调用 feed() 喂狗。如果程序卡死、死锁或关键任务失去响应,喂狗停止,WDT 超时后便通过硬件复位让系统重新启动。
| 名词 | 全称 | 说明 |
|---|---|---|
| WDT | Watchdog Timer,看门狗定时器 | 在软件失去响应时触发系统复位 |
| 超时时间 | Timeout | 两次有效喂狗之间允许的最长时间 |
| 喂狗 | Feed/Kick | 重新开始 WDT 倒计时 |
| 故障恢复 | Fault Recovery | 通过复位等方式使系统从不可恢复状态重新启动 |
| 启动循环 | Boot Loop | 开机脚本反复启动 WDT、超时、复位,导致系统无法稳定进入工作状态 |
4.2 WDT 的工作流程
- 创建 WDT 对象并设置超时时间,倒计时立即开始。
- 程序完成关键健康检查后调用
feed()。 - 每次喂狗都会重新开始倒计时。
- 如果在超时时间内没有再次喂狗,WDT 触发系统复位。
- 如果程序准备正常退出,应在退出前调用
stop()或close()。
4.3 喂狗位置决定了 WDT 是否真正有效
最常见的错误是“只要主循环还能跑就喂狗”:
while True:
wdt.feed()2
如果传感器采集、网络连接或数据保存已经失效,但上述循环仍能执行,WDT 就永远不会复位系统。这种写法只能证明喂狗代码仍在运行,不能证明产品功能健康。
工程中应当在所有关键任务都通过健康检查后再喂狗,例如:
- 传感器数据仍在更新,而不是一直返回旧值。
- 通信任务没有长期阻塞,关键连接仍可恢复。
- 数据处理流水线在规定时间内完成一轮。
- 多线程程序中的每个关键线程都更新了自己的健康标志。
不要用独立 Timer 无条件喂狗
如果定时器回调始终喂狗,即使主业务已经死锁,WDT 也可能永远不会超时。正确方法是由健康监控逻辑汇总各任务状态,只有整个系统满足健康条件时才调用 feed()。
4.4 当前 CanMV v1.8 的 WDT 资源模型
当前源码虽然接受 id 参数,但 Python 绑定只维护一个全局 WDT 占用状态。同一时刻只能有一个有效 WDT 对象;在它停止之前再次创建 WDT,会出现 WDT is already in use。
因此,本教程沿用官方例程的 WDT(1, timeout) 写法,但不要把 WDT(0) 和 WDT(1) 当成两个可以由 Python 独立同时运行的看门狗。
4.5 WDT 不等于异常处理
WDT 是最后一道恢复手段,不应该替代正常的软件设计:
| 故障类型 | 首选处理 | WDT 的角色 |
|---|---|---|
| 可预期的通信超时 | 超时返回、重连和退避重试 | 多次恢复失败且系统失去响应时兜底 |
| 参数错误 | 启动时校验并拒绝运行 | 不应依赖复位掩盖配置错误 |
| 可捕获的软件异常 | try/except/finally 记录并清理资源 | 异常处理自身失效时兜底 |
| 死循环、死锁、系统无响应 | 健康监控停止喂狗 | 超时后自动复位 |
4.6 超时时间如何选择
超时时间必须大于系统最坏情况下完成一次健康检查和喂狗所需的时间,还要为文件系统、网络重连、垃圾回收和高负载任务保留余量。
本教程要求喂狗间隔小于超时时间的一半。正式产品还应测量最坏执行时间,而不是只依据平均时间设置。超时时间过短容易误复位;超时时间过长则会延迟故障恢复。
五 常用 API 说明
5.1 创建 WDT 对象
WDT 类位于 machine 模块中:
from machine import WDT
wdt = WDT(1, 5)2
3
CanMV v1.8 的构造形式为:
WDT(id=1, timeout=5, *, auto_close=True)| 参数 | 说明 |
|---|---|
id | 整数参数,默认值为 1;本教程固定使用官方例程中的 1 |
timeout | 正整数,单位为秒;创建后硬件可能根据支持档位调整实际超时时间 |
auto_close | 关键字参数;当前 v1.8 源码解析该参数但没有依据其值切换行为,本教程不依赖它 |
不要用 id 创建多个独立 WDT
当前 v1.8 Python 绑定同一时刻只允许一个 WDT 对象。第二次创建会抛出 ValueError: WDT is already in use。需要统一由一个健康监控模块管理看门狗。
5.2 feed() 方法
wdt.feed()feed() 重新开始 WDT 倒计时。只有确认关键任务都健康时才应该调用它。WDT 已停止后再次喂狗,会抛出 OSError: watchdog is closed。
5.3 stop() 与 close() 方法
wdt.stop()
# 或
wdt.close()2
3
在 CanMV v1.8 源码中,stop() 和 close() 指向相同的资源释放实现,都会停止 WDT 并释放全局占用状态。本教程统一使用语义更直观的 stop()。
stop() 可以重复调用而不会重复关闭硬件,但工程代码仍建议只在统一的清理路径调用一次。
5.4 最小安全示例
from machine import WDT
import time
wdt = None
try:
wdt = WDT(1, 5)
wdt.feed()
time.sleep(1)
wdt.feed()
finally:
if wdt is not None:
wdt.stop()2
3
4
5
6
7
8
9
10
11
12
该示例会在 finally 中停止 WDT,不会故意触发系统复位。完整的可配置测试程序见第七节。
六 操作步骤
6.1 首先运行安全模式
- 确认 TF 卡固件与实际板卡型号匹配。
- 使用支持数据传输的 Type-C 数据线连接电脑。
- 在 CanMV 开发环境中新建脚本,复制第七节完整代码。
- 保持
TEST_RESET = False。 - 运行脚本,确认终端依次输出 5 次喂狗信息。
- 确认最后输出“WDT 已停止”,开发板没有复位。
6.2 再进行真实复位测试
⚠️复位测试会中断 IDE 连接
进行下面的操作前,请保存重要文件和代码。不要先把复位测试脚本设置为 main.py 开机自启动,否则配置错误可能造成启动循环,使 IDE 难以重新连接。
- 把
TEST_RESET改为True。 - 保持
WDT_TIMEOUT_S = 5和RESET_AFTER_FEED_COUNT = 3。 - 再次运行脚本。
- 观察程序正常喂狗 3 次后停止喂狗。
- 等待开发板复位,并观察 IDE 短暂断开后重新连接。
- 验证完成后立即把
TEST_RESET改回False。
七 代码例程
# 立创·庐山派-K230-CanMV开发板资料与相关扩展板软硬件资料官网全部开源
# 开发板官网:www.lckfb.com
# 技术支持常驻论坛,任何技术问题欢迎随时交流学习
# 立创论坛:www.jlc-bbs.com/lckfb
# 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
# 不靠卖板赚钱,以培养中国工程师为己任
# 编写者:LCKFB-YZH
from machine import WDT
import os
import time
# ==================== 用户可修改参数 ====================
# 当前 CanMV 教程与官方例程统一使用 WDT1
WDT_ID = 1
# 看门狗超时时间,单位:s
WDT_TIMEOUT_S = 5
# 正常喂狗间隔,单位:ms;建议明显小于超时时间
FEED_INTERVAL_MS = 1000
# 安全模式下完成多少次喂狗后正常退出
SAFE_FEED_COUNT = 5
# False:安全喂狗并停止 WDT;True:故意停止喂狗并等待复位
TEST_RESET = False
# 复位测试模式下,完成多少次正常喂狗后开始模拟故障
RESET_AFTER_FEED_COUNT = 3
# 等待 WDT 复位时的主循环休眠时间,单位:ms
RESET_WAIT_INTERVAL_MS = 100
# ======================================================
def get_board_info():
"""自动识别庐山派型号,返回本例需要的板卡信息。"""
board_id = os.uname()[-1]
if board_id == "k230_canmv_lckfb":
return {
"board_name": "立创·庐山派K230-CanMV开发板",
}
return {
"board_name": "立创·庐山派Lite-K230D-CanMV开发板",
}
def validate_parameters():
"""在启动 WDT 前检查参数,避免配置错误造成意外复位。"""
if WDT_TIMEOUT_S <= 0:
raise ValueError("WDT_TIMEOUT_S 必须为正整数")
if FEED_INTERVAL_MS <= 0:
raise ValueError("FEED_INTERVAL_MS 必须为正整数")
if FEED_INTERVAL_MS * 2 >= WDT_TIMEOUT_S * 1000:
raise ValueError("喂狗间隔必须小于 WDT 超时时间的一半")
if SAFE_FEED_COUNT <= 0:
raise ValueError("SAFE_FEED_COUNT 必须为正整数")
if RESET_AFTER_FEED_COUNT <= 0:
raise ValueError("RESET_AFTER_FEED_COUNT 必须为正整数")
BOARD = get_board_info()
wdt = None
try:
# 必须在创建 WDT 之前完成参数校验
validate_parameters()
print("当前板卡:{}".format(BOARD["board_name"]))
print("运行模式:{}".format("复位测试" if TEST_RESET else "安全喂狗"))
# 创建后 WDT 立即开始倒计时
wdt = WDT(WDT_ID, WDT_TIMEOUT_S)
print("WDT 已启动:{}".format(wdt))
feed_count = 0
while True:
# 允许用户在 CanMV 开发环境中停止脚本
os.exitpoint()
if TEST_RESET and feed_count >= RESET_AFTER_FEED_COUNT:
print("故障模拟开始:停止喂狗,等待 WDT 复位")
# 不再调用 feed();如果用户主动停止脚本,finally 会停止 WDT
while True:
os.exitpoint()
time.sleep_ms(RESET_WAIT_INTERVAL_MS)
# 实际项目应在所有关键任务健康时才执行这一行
wdt.feed()
feed_count += 1
print("第 {} 次喂狗完成".format(feed_count))
if not TEST_RESET and feed_count >= SAFE_FEED_COUNT:
print("安全模式测试完成")
break
time.sleep_ms(FEED_INTERVAL_MS)
except KeyboardInterrupt:
print("用户停止运行")
except Exception as exc:
print("WDT 示例运行异常:{}".format(exc))
finally:
# 真实 WDT 复位发生时,系统会直接重启,不会执行到这里
if wdt is not None:
try:
wdt.stop()
print("WDT 已停止")
except Exception as cleanup_exc:
print("WDT 停止异常:{}".format(cleanup_exc))
print("程序结束")2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
八 代码说明
8.1 为什么参数校验必须早于创建 WDT
WDT() 构造函数会立即启动硬件倒计时。如果先创建 WDT,再检查喂狗间隔是否合理,一旦后续校验或初始化失败,程序可能在异常路径中被复位。
因此完整例程先执行:
validate_parameters()只有全部参数通过检查后,才创建 WDT 对象。
8.2 安全模式与复位测试模式
TEST_RESET 是本例最重要的安全开关:
| 值 | 行为 | 适用场景 |
|---|---|---|
False | 定期喂狗,达到次数后正常退出并停止 WDT | 首次学习、日常调试 |
True | 喂狗数次后停止喂狗,等待硬件复位 | 有控制的故障恢复验证 |
安全模式退出时会进入 finally,调用 wdt.stop()。复位测试模式如果正常触发硬件复位,CPU 会直接重新启动,因此不会执行原脚本的 finally。
8.3 为什么使用两层循环
外层循环负责正常喂狗。进入故障模拟后,程序转入内层循环,只保留 os.exitpoint() 和短暂休眠,不再调用 feed()。
这样既能真实验证 WDT 超时,又允许用户在等待期间主动停止脚本;用户主动停止时会进入 finally 并关闭 WDT,避免不必要的复位。
8.4 喂狗周期的安全余量
代码要求:
FEED_INTERVAL_MS * 2 < WDT_TIMEOUT_S * 1000这表示喂狗间隔必须小于超时时间的一半,为短时系统负载波动保留基础余量。正式项目还要测量最坏执行时间,并为文件系统、网络和多任务竞争留出额外裕量。
8.5 退出清理
os.exitpoint()让开发环境可以中止脚本。try/except/finally同时覆盖正常结束、用户停止和软件异常。finally中调用wdt.stop(),不依赖对象回收时机。- 如果 WDT 已停止,再调用
feed()会报错,因此业务代码应统一管理 WDT 生命周期。
8.6 常改参数
| 参数 | 作用 | 建议 |
|---|---|---|
WDT_TIMEOUT_S | WDT 超时时间 | 根据最坏任务执行时间设置,不要只看平均值 |
FEED_INTERVAL_MS | 正常喂狗间隔 | 小于超时时间的一半,并留出充分裕量 |
SAFE_FEED_COUNT | 安全演示次数 | 正整数,通常无需改动 |
TEST_RESET | 是否进行真实复位 | 默认保持 False |
RESET_AFTER_FEED_COUNT | 复位测试前的正常喂狗次数 | 建议至少为 2,便于观察正常阶段 |
九 实际运行效果
9.1 安全模式
当前板卡:立创·庐山派Lite-K230D-CanMV开发板
运行模式:安全喂狗
WDT 已启动:WDT: timeout=5s
第 1 次喂狗完成
第 2 次喂狗完成
第 3 次喂狗完成
第 4 次喂狗完成
第 5 次喂狗完成
安全模式测试完成
WDT 已停止
程序结束2
3
4
5
6
7
8
9
10
11
9.2 复位测试模式
当前板卡:立创·庐山派Lite-K230D-CanMV开发板
运行模式:复位测试
WDT 已启动:WDT: timeout=5s
第 1 次喂狗完成
第 2 次喂狗完成
第 3 次喂狗完成
故障模拟开始:停止喂狗,等待 WDT 复位2
3
4
5
6
7
随后终端停止输出,IDE 与开发板的连接短暂断开,开发板重新启动。标准版与 Lite-K230D 的 WDT 行为相同,只有第一行板卡名称不同。
十 常见问题
10.1 为什么运行脚本后 IDE 突然断开?
现象:终端停止输出,IDE 暂时无法连接开发板。
原因:WDT 已启动但没有及时喂狗,超时后触发了系统复位。
解决方法:
- 首次运行保持
TEST_RESET = False。 - 检查
FEED_INTERVAL_MS是否明显小于超时时间。 - 等待开发板完成重新启动后再次连接。
- 不要在调试完成前把复位测试脚本设置为开机自启动。
10.2 开发板为什么不断重启?
现象:开发板刚启动不久就再次复位,IDE 很难连接。
原因:开机自启动脚本启动了 WDT,但在系统完成初始化前就超时,形成启动循环。
解决方法:
- 优先取消或重命名有问题的开机自启动脚本。
- 无法进入开发环境时,可将 TF 卡连接电脑,备份后移除问题脚本。
- 必要时重新写入与板卡匹配的固件镜像。
- 恢复后先用较长超时和安全模式验证,再逐步收紧参数。
10.3 提示 WDT is already in use?
当前固件同一时刻只允许一个 WDT 对象。检查代码、导入模块和后台任务是否已经创建 WDT,并把看门狗管理集中到一个模块。不要尝试通过更换 id 同时创建多个对象。
10.4 提示 watchdog is closed?
说明代码在 stop() 或 close() 之后又调用了 feed()。停止 WDT 后应结束当前监控流程;如果确实要重新开始,应重新创建新的 WDT 对象。
10.5 明明定期喂狗,为什么仍会复位?
常见原因包括:
- 某次循环执行时间超过超时时间。
- 文件、网络或外设调用发生了长时间阻塞。
- 喂狗代码位于可能被跳过的条件分支。
- 超时时间对应的硬件实际档位与预期存在差异。
应增加时间裕量,记录每轮任务耗时,并确保所有关键路径都能在最坏时间内回到健康检查点。
10.6 多线程项目应该由哪个线程喂狗?
建议只由一个健康监控线程或主线程持有 WDT。其他关键线程更新各自的心跳状态,监控者确认所有心跳都在允许时间内更新后再统一喂狗。
不要让每个线程各自创建 WDT,也不要让某个独立线程无条件喂狗,否则其他关键线程即使已经死锁,系统仍可能被错误地判定为健康。
10.7 stop() 在旧固件上不存在怎么办?
本文以 CanMV v1.8 源码为基准。旧固件或旧资料可能只有 feed(),没有公开的 stop()/close()。请升级到与板卡匹配的较新固件后再运行完整例程;在无法确认停止接口的固件上,不要随意启动 WDT 测试。
十一 总结
本节完成了 WDT 的安全喂狗和可选超时复位测试。核心要点如下:
- 两款庐山派使用相同的
machine.WDTAPI,不需要外部接线。 - 创建 WDT 对象后倒计时立即开始,参数校验必须放在构造函数之前。
- 当前 CanMV v1.8 同一时刻只允许一个 WDT 对象,本教程固定使用
WDT(1, timeout)。 - 只有所有关键任务都健康时才应该喂狗,不能用独立定时器无条件喂狗。
stop()和close()在 v1.8 中指向相同的停止实现,受控退出时应显式调用。- 真实复位测试会导致 IDE 短暂断开,不能未经验证就设置为开机自启动。
- WDT 是系统失去响应时的最后防线,不能替代超时、重试、异常处理和资源清理。
后续可以把 WDT 与线程心跳、网络重连状态和传感器数据新鲜度结合,构建真正反映产品健康状态的监控策略。