Bog*_*ogi 6 c embedded watchdog
我是嵌入式系统编程的新手,虽然我在学习期间完成了课程,但实际编程还是有点远.
问题在于:我必须在NXP LPC2103微控制器(基于ARM 7)上编写一个小型系统,而不需要操作系统.它有一个看门狗定时器,需要定期更新.该系统具有嵌入了TCP/IP堆栈的GPRS调制解调器,并且初始化这需要比看门狗需要超时的时间更长的时间.当我调用初始化函数时,系统重置.
我和一位经验更丰富的同事交谈过,他建议我退出并重新进入同一个初始化函数,从主函数开始,我将看门狗定时器咬了很久,直到函数完成执行.这个想法听起来不错,但我还想听听其他一些经历.此外,参考(书籍或网站)也可能有用,因为我找不到任何具体的内容.
我不想从初始化函数调用看门狗定时器,我没有发现这个好.
我不想从初始化函数调用看门狗定时器,我没有发现这个好.
对于这种情况可能有点过头了,但是我用于长时间运行操作的一般技术是让你可能想要执行其他工作的是让长时间运行的函数接受将定期调用的回调函数指针.我通常使用的模式是有一个回调原型,可能看起来像:
int (callback_t*)(void* progress, void* context);
Run Code Online (Sandbox Code Playgroud)
长时间运行的函数将定期调用回调,其中一些信息指示它的进度(如何表示该进度表示它取决于特定函数的详细信息)以及原始调用者传入的上下文值以及回调指针(再次 - 该参数的含义以及它的解释方式完全取决于回调).一般来说,回调函数的返回值可能用于指示"长时间运行的东西"应该取消或以其他方式改变行为.
这样,您的初始化函数可以使用带有上下文值的回调指针,并且只是定期调用它.显然,在你的情况下,那些回调必须经常发生,以保持看门狗的快乐.
int watchdog_callback( void* progress, void* context)
{
kick_the_watchdog();
return 0; // zero means 'keep going...'
}
void init_modem( callback_t pCallback, void* callback_context)
{
// do some stuff
pCallback( 0, callback_context);
// do some other stuff
pCallback( 1, callback_context);
while (waiting_for_modem()) {
// do work...
pCallback( 2, callback_context);
}
}
Run Code Online (Sandbox Code Playgroud)
关于这种模式的一个好处是它可以在不同的情况下使用 - 你可能有一个读取或写入大量数据的函数.回调模式可能用于显示进度的某些内容.
请注意,如果您发现自己有其他长时间运行的函数,则watchdog_callback()可以使用相同的函数来处理阻止看门狗重置的问题.但是,如果您发现自己需要经常为监视程序依赖此类事物,那么您可能需要考虑您的任务如何进行交互并将其分解得更多或使用更加复杂的监视程序方案来管理监视程序通过自己的任务,其他任务与之交互,以保持监视程序计时器间接满意.
一般来说,我采用了两种方法来应对这种情况.
第一个就像你的同事建议的那样:在作为主循环的一部分调用的状态机中实现初始化例程,然后停止调用初始化例程并开始调用主例程.
这是一个简单而干净的功能,但在涉及特殊的长过程(例如启动低频振荡器)时可能会有点尴尬.
如果你有一个'systick'或等效的中断,还有另一种选择,例如每1 ms触发一次中断.在这种情况下,您可以考虑每隔50次中断调用看门狗(例如),但限制看门狗进给的次数等于初始化程序完成的最大允许时间.然后通常需要(如果你有,我认为应该是一个窗口看门狗)在初始化结束时有一个短的同步循环,以确保在达到最小窗口时间之前没有馈送看门狗,但这很难实现.
这是一个非常干净的解决方案(因为它不会将初始化例程转换为不必要的状态机)并处理初始化例程挂起的问题.但是,强制执行ISR中看门狗呼叫的限制非常重要.
两者都有其优点和缺点,但是针对不同的要求采用不同的方法是有用的.我倾向于选择后一种解决方案,其中我有一些低频振荡器(可能需要一段时间才能启动),因为它避免了过度复杂的初始化程序,这可能是他们自己的复杂程度!
我相信其他人也会提供其他替代想法......