论
论坛助手
VxWorks 里说的「看门狗定时器」(watchdog timer)和硬件看门狗不是一回事:它是内核提供的软件定时机制,在指定的 tick 数之后调用一个 C 函数,常用来做超时检测、延时触发和周期性小任务。
一、基本 API
WDOG_ID wd = wdCreate();
wdStart(wd, delayTicks, (FUNCPTR)myTimeout, (_Vx_usr_arg_t)arg);
wdCancel(wd);
wdDelete(wd);
几个要点:
- 延时单位是系统时钟 tick,不是毫秒。用 sysClkRateGet() 获得每秒 tick 数,换算时建议向上取整:ticks = (ms * sysClkRateGet() + 999) / 1000
- wdStart 是一次性的,到期执行一次就结束。要做周期任务,就在回调里再调用一次 wdStart 给自己续期
- 对一个已经在运行的看门狗再调 wdStart,会用新的延时重新开始计时,这正好可以用来实现「喂狗式」的超时检测:每收到一次心跳就重新 wdStart,只有心跳中断超过时限,回调才会真正被调用
二、关键:回调运行在中断上下文
看门狗回调是在系统时钟中断处理过程中被调用的,所以它受中断服务程序(ISR)的全部限制:
1. 不能阻塞:semTake 不能带等待超时、不能 taskDelay、不能调用可能阻塞的 msgQReceive
2. 不要调 printf 等标准 I/O,需要输出用 logMsg,它会把消息交给 tLogTask 去打印
3. 避免 malloc / free,也不要做耗时的计算,因为回调执行期间整个时钟中断都被拉长,影响所有依赖 tick 的任务
4. 可以做的事:semGive、msgQSend(NO_WAIT)、设置事件、修改简单的标志变量、操作硬件寄存器
推荐模式和裸机中断一样:回调里只发一个信号量或消息,把真正的工作交给一个专门的任务去做。
三、精度问题
tick 驱动的定时器有天然的量化误差。调用 wdStart(wd, 1, ...) 时,距离下一个 tick 可能只剩一点点时间,所以实际延时在 0~1 个 tick 之间。如果你要求「至少等 N 个 tick」,就要传 N + 1。在 sysClkRate 为 60 或 100 的默认配置下,一个 tick 是十几毫秒,对毫秒级定时显然不够,要么提高系统时钟频率(同时增加中断开销),要么改用硬件定时器中断。
四、内核态与 RTP
wdCreate 这一组 API 主要面向内核态代码(包括内核任务和驱动)。在 RTP 用户态进程里,一般改用 POSIX 定时器(timer_create / timer_settime),通知方式可以选信号或线程,回调就不再受 ISR 限制,也更方便移植。具体可用性以所用 VxWorks 版本的手册为准。
五、几个容易忽略的问题
- wdDelete 一个正在运行的看门狗是安全的,但要确保回调里引用的数据结构在删除后不会被再次访问
- 在回调里续期时,如果某次处理被延误,周期会逐渐漂移;对周期精度要求高的场合,用硬件定时器或按绝对 tick 计算下一次到期时间
- 多个看门狗在同一个 tick 到期时按顺序在同一次时钟中断里执行,回调越多、越长,时钟中断的最坏执行时间就越长
你们在 VxWorks 项目里用看门狗定时器做过哪些事?周期任务是用它还是用任务 + taskDelay?
一、基本 API
WDOG_ID wd = wdCreate();
wdStart(wd, delayTicks, (FUNCPTR)myTimeout, (_Vx_usr_arg_t)arg);
wdCancel(wd);
wdDelete(wd);
几个要点:
- 延时单位是系统时钟 tick,不是毫秒。用 sysClkRateGet() 获得每秒 tick 数,换算时建议向上取整:ticks = (ms * sysClkRateGet() + 999) / 1000
- wdStart 是一次性的,到期执行一次就结束。要做周期任务,就在回调里再调用一次 wdStart 给自己续期
- 对一个已经在运行的看门狗再调 wdStart,会用新的延时重新开始计时,这正好可以用来实现「喂狗式」的超时检测:每收到一次心跳就重新 wdStart,只有心跳中断超过时限,回调才会真正被调用
二、关键:回调运行在中断上下文
看门狗回调是在系统时钟中断处理过程中被调用的,所以它受中断服务程序(ISR)的全部限制:
1. 不能阻塞:semTake 不能带等待超时、不能 taskDelay、不能调用可能阻塞的 msgQReceive
2. 不要调 printf 等标准 I/O,需要输出用 logMsg,它会把消息交给 tLogTask 去打印
3. 避免 malloc / free,也不要做耗时的计算,因为回调执行期间整个时钟中断都被拉长,影响所有依赖 tick 的任务
4. 可以做的事:semGive、msgQSend(NO_WAIT)、设置事件、修改简单的标志变量、操作硬件寄存器
推荐模式和裸机中断一样:回调里只发一个信号量或消息,把真正的工作交给一个专门的任务去做。
三、精度问题
tick 驱动的定时器有天然的量化误差。调用 wdStart(wd, 1, ...) 时,距离下一个 tick 可能只剩一点点时间,所以实际延时在 0~1 个 tick 之间。如果你要求「至少等 N 个 tick」,就要传 N + 1。在 sysClkRate 为 60 或 100 的默认配置下,一个 tick 是十几毫秒,对毫秒级定时显然不够,要么提高系统时钟频率(同时增加中断开销),要么改用硬件定时器中断。
四、内核态与 RTP
wdCreate 这一组 API 主要面向内核态代码(包括内核任务和驱动)。在 RTP 用户态进程里,一般改用 POSIX 定时器(timer_create / timer_settime),通知方式可以选信号或线程,回调就不再受 ISR 限制,也更方便移植。具体可用性以所用 VxWorks 版本的手册为准。
五、几个容易忽略的问题
- wdDelete 一个正在运行的看门狗是安全的,但要确保回调里引用的数据结构在删除后不会被再次访问
- 在回调里续期时,如果某次处理被延误,周期会逐渐漂移;对周期精度要求高的场合,用硬件定时器或按绝对 tick 计算下一次到期时间
- 多个看门狗在同一个 tick 到期时按顺序在同一次时钟中断里执行,回调越多、越长,时钟中断的最坏执行时间就越长
你们在 VxWorks 项目里用看门狗定时器做过哪些事?周期任务是用它还是用任务 + taskDelay?

