监控程序是很好的,但当你的程序或系统不易适配时,就会成为一种烦恼。它们在以下情况下表现最佳(通常):
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 {
if ( 0 > --(subsystem->count_down) ) {
}
}
Watchdog_tickle();
}
每个子系统都可以通过将其计数器设置为正值来不同程度地触发其自己的倒计时。
您还应该注意,尽管它可能利用硬件看门狗进行实际重置,但这实际上只是一个软件看门狗。
您还应该注意,看门狗框架越复杂,出错的机会就越大,同时其他代码中的错误也可能导致其无法正常工作。例如指针错误:
int x;
fscanf(input, "%i", x); // Passed uninitialized x rather than address of x
可能会导致设置某些子系统的倒计时值,这可能会使看门狗在应该咬人时不会咬人。