2. VxWorks看门狗API:wdCreate、wdStart、wdCancel、wdDelete函数详解与参数说明
好,咱们进入正题。看门狗定时器(Watchdog Timer)在嵌入式系统里,说白了就是一个「保命符」。系统跑飞了?死锁了?任务卡死了?看门狗会帮你把系统拉回来。VxWorks 提供了一套简洁的 API 来管理看门狗,今天我就把这四个核心函数掰开揉碎讲清楚。
2.1 wdCreate —— 创建看门狗定时器
这个函数用来创建一个看门狗定时器对象。原型很简单:
WDOG_ID wdCreate(void)
返回一个 WDOG_ID 类型的句柄。如果创建失败,返回 NULL。
参数说明: 无参数。
注意事项:
- 每个看门狗定时器会占用系统资源(内存、定时器槽位)。
- 创建的数量受系统配置限制,默认通常支持几十个。
- 创建成功后,看门狗处于「未启动」状态。
我的经验: 我个人习惯在系统初始化阶段就把所有看门狗一次性创建好。别在任务运行中频繁创建删除,容易造成内存碎片。我曾经在一个项目中,因为动态创建看门狗导致系统运行几天后莫名其妙挂掉,查了两天才发现是内存碎片惹的祸。
2.2 wdStart —— 启动看门狗定时器
创建完看门狗,得让它跑起来。wdStart 就是干这个的:
STATUS wdStart
(
WDOG_ID wdogId, /* 看门狗ID */
int delay, /* 延迟时间,单位:tick */
FUNCPTR routine, /* 超时回调函数 */
int parameter /* 传给回调函数的参数 */
)
参数详解:
| 参数 | 说明 | 典型值/注意事项 |
|---|---|---|
| wdogId | 由 wdCreate 返回的句柄 | 必须有效,否则返回 ERROR |
| delay | 超时时间(tick数) | 最小为 1 tick。0 表示立即触发 |
| routine | 超时后执行的回调函数 | 在系统时钟中断上下文中执行! |
| parameter | 传递给回调函数的参数 | 通常传一个整数或指针 |
⚠️ 重要警告: 回调函数是在中断上下文中执行的!这意味着:
- 不能调用可能阻塞的函数(如 semTake、taskDelay)
- 不能进行浮点运算(除非使能了浮点中断支持)
- 执行时间要尽可能短,否则会影响系统实时性
2.3 wdCancel —— 取消看门狗定时器
有时候看门狗启动了,但条件满足了,不需要它再触发。这时候用 wdCancel:
STATUS wdCancel
(
WDOG_ID wdogId /* 看门狗ID */
)
返回值:
- OK:取消成功
- ERROR:取消失败(比如看门狗已经触发过了)
使用场景:
- 任务正常完成,不需要看门狗干预了
- 重新设置超时时间前,先取消旧的
- 系统进入休眠/低功耗模式前
避坑指南: 我曾经在项目中遇到一个问题:看门狗已经触发了,但代码还在调用 wdCancel。结果返回 ERROR,但程序没检查返回值,继续往下走,导致逻辑混乱。记住:一定要检查 wdCancel 的返回值! 如果返回 ERROR,说明看门狗已经触发或不存在,需要做相应处理。
2.4 wdDelete —— 删除看门狗定时器
看门狗不用了,记得删除,释放资源:
STATUS wdDelete
(
WDOG_ID wdogId /* 看门狗ID */
)
注意事项:
- 删除前,看门狗必须处于「未启动」状态
- 如果看门狗正在运行,需要先调用 wdCancel
- 删除后,WDOG_ID 变为无效,不能再使用
我的习惯: 我一般会在删除前先调用 wdCancel,即使我知道它可能已经停止了。为什么?因为安全。你想想看,如果某个任务意外重启了看门狗,而你直接删除,系统可能会崩溃。先取消再删除,双重保险。
2.5 完整使用示例
光说不练假把式。我给你写一个完整的示例,展示这四个函数怎么配合使用:
/* 看门狗回调函数 */
void myWatchdogRoutine(int param)
{
/* 注意:这是在中断上下文中! */
logMsg("Watchdog timeout! param=%d\n", param, 0,0,0,0,0);
/* 这里可以做紧急处理,比如重启任务 */
taskRestart((int)param);
}
/* 某个任务中使用看门狗 */
void myTask(void)
{
WDOG_ID wdId;
int myTaskId = taskIdSelf();
/* 1. 创建看门狗 */
wdId = wdCreate();
if (wdId == NULL)
{
logMsg("wdCreate failed!\n", 0,0,0,0,0,0);
return;
}
/* 2. 启动看门狗,5秒超时(假设系统tick=100Hz) */
if (wdStart(wdId, 500, myWatchdogRoutine, myTaskId) != OK)
{
logMsg("wdStart failed!\n", 0,0,0,0,0,0);
wdDelete(wdId);
return;
}
/* 3. 执行主要工作 */
while (1)
{
/* 做一些需要监控的操作 */
if (workDone())
{
/* 工作完成,取消看门狗 */
wdCancel(wdId);
break;
}
taskDelay(1); /* 让出CPU */
}
/* 4. 清理 */
wdDelete(wdId);
}
核心要点总结:
- 创建 → 启动 → 取消/触发 → 删除,这是标准生命周期
- 回调函数在中断上下文,别干重活
- 一定要检查返回值,尤其是 wdCancel 和 wdStart
- 删除前先取消,养成好习惯
好了,这四个函数就讲完了。说白了,看门狗 API 本身不复杂,复杂的是怎么用好它。下一章我会讲看门狗在系统可靠性设计中的实战技巧,包括多级看门狗、喂狗策略这些。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。