看门狗很棒,但当您的程序或系统无法轻松适应时,它也会给您带来麻烦。当您的代码(通常)看起来像这样时,效果最好:
Watchdog_init();
hardware_init();
subsystem1_init();
subsystem2_init();
subsystem3_init();
...
subsystemN_init();
forever {
Watchdog_tickle();
subsystem1_work();
subsystem2_work();
subsystem3_work();
...
subsystemN_work();
}
您通常可以以这样的方式设计您的程序,这样就可以正常工作,而且通常它是非常简单的(但并非完全)。
但在像你这样的情况下,这并不好用。您最终必须设计和创建(或可能使用库)一个框架,该框架具有必须满足的各种条件,以控制看门狗是否/何时被宠爱。不过,这可能非常棘手。此代码的复杂性本身可能会引入其自身的错误。除了看门狗框架之外,您完全可以编写一个完美的应用程序,您的项目可能会重置很多,或者您的所有代码可能都是坏的,只是不断地抚摸看门狗,导致它永远不会重置。
更改上述代码以处理更复杂情况的一个好方法是更改subsystemX_work 函数以跟上状态。这可以通过函数中的静态变量或使用函数指针而不是函数来完成,并更改执行的实际函数以反映该子系统的当前状态。每个子系统都成为一个状态机。
另一种使用快速咬人的看门狗解决长时间有意等待的方法是将长时间运行的函数分解为更短的部分。而不是:
slow_device_init();
Watchdog_tickle();
你可以这样做:
slow_device_init_begin();
Watchdog_tickle();
slow_device_init_finish();
Watchdog_tickle();
然后通过执行以下操作扩展它以延长看门狗计时器:
slow_device_init_begin();
for ( i = SLOW_DEV_TRIES; i ; i--) {
Watchdog_tickle();
if (slow_device_init_done()) {
break;
}
}
Watchdog_tickle();
即使它仍然可以变得越来越复杂。通常,您最终不得不创建一个看门狗代表,它只检查要满足的条件,并根据这些条件是否宠爱看门狗。这开始变得非常复杂。它可以通过为每个子系统创建一个对象来实现,该对象具有一些方法/函数来调用以测试子系统的健康状况。健康方法可能非常复杂,甚至可能随着子系统状态的变化而变化,尽管它应该尽可能简单,以便尽可能容易地验证代码是否正确,并且因为子系统的工作需要改变您衡量健康的方式。
如果您可以确保某些代码定期运行,那么您可以为每个子系统设置一个整数,作为子系统的本地看门狗。一些代码(可能在定时器中断处理程序中,但不一定)将递减并测试每个子系统的变量。如果任何子系统的值为 0,则不会触发看门狗。
Watchdog_periodic() {
for_each subsustem in subsystem_list { // not C, but you get the idea
if ( 0 > --(subsystem->count_down) ) {
// Do something that causes a reset. This could be returning and not petting
// the hardware watchdog, doing a while(1);, or something else
}
}
Watchdog_tickle();
}
然后,每个子系统可以通过将其 count_down 设置为正值来在不同的时间段内对自己的 count_down 进行痒痒。
您还应该注意到,这实际上只是一个软件看门狗,尽管它可能会利用硬件看门狗来进行实际的重置。
您还应该注意,看门狗框架越复杂,出现错误的机会就越大,其他代码中的错误也就越容易导致其无法正常工作。例如指针错误,例如:
int x;
fscanf(input, "%i", x); // Passed uninitialized x rather than address of x
可能会导致设置某些子系统的 count_down 值,这最终可能会阻止看门狗在应该咬人时停止。