RTOS中如何使用看門狗 ---- 以RT-thread爲例

  • When given the choice between being right or being kind, choose kind.
    當你要在正確和善良之間做選擇的時候,選擇善良。

一、 在RTOS使用看門狗的策略

在由單片機構成的微型計算機系統中,由於單片機的工作常常會受到來自外界電磁場的干擾,造成程序的跑飛,而陷入死循環,程序的正常運行被打斷,由單片機控制的系統無法繼續工作,會造成整個系統的陷入停滯狀態,發生不可預料的後果,所以出於對單片機運行狀態進行實時監測的考慮,便產生了一種專門用於監測單片機程序運行狀態的芯片,俗稱“看門狗”(watchdog)。”
看門狗通常是一個定時器,定時器定時到預定時間就會產生復位信號讓單片機復位。要想避免看門狗復位單片機,要及時“餵狗”(恢復定時器初始值),也就是說只要程序能正常運行,就能及時餵狗,避免復位。反之,若程序跑飛,則無法及時餵狗,導致單片機能夠復位,解決了程序跑飛的問題。

1.1、回顧裸機中看門狗的使用

通常在裸機中編程的時候,一般都是一個大循環,採用時間片的方式去執行各種形式的任務。通常選擇一個固定的時間片(比如每5ms)給看門狗餵狗,當然遇到一些可能會操作比較久的任務時,會追加一些額外的餵狗操作。

1.2、RTOS中使用看門狗

查看了網上很多關於如何在RTOS中使用看門狗的策略,其實每種策略都有其使用場景,下面主要提到的幾種方式。

  • 1、建立一個看門狗的定時任務,並將該任務定義爲最低優先級。
    這種方式需要保證看門狗定時器的溢出時間一般要足夠長,且單片機不是經常滿負荷運行。(保證CPU的使用權不是一直被高優先級的線程搶佔)
  • 2、建立一個看門狗的定時任務,並將該任務定義爲最高優先級。
    這種方式保證了餵狗的及時性,但是如果只有低優先級的任務死了(經歷少,倒是沒遇到過),這種方式下的看門狗就起不到作用。
  • 3、多任務監測實現思路
    將看門狗“餵狗”置於最高優先級,每個任務(或者某幾個重要的任務)定時向看門狗任務法消息,如果看門狗任務在一定時間內收全其他任務發來的消息才餵狗。這保證了能夠監測儘量多的任務。
二、RT-thread&STM32 中使用看門狗

使用STM32CubeMX來配置STM32的內部看門狗,超時時間爲1000ms。
在這裏插入圖片描述
我們定義一個線程每200ms喂一次狗,優先級爲RT_THREAD_PRIORITY_MAX-2。(這裏只是舉例,任務多了得仔細考慮如何餵狗)

extern IWDG_HandleTypeDef hiwdg;
/* 200ms 喂一次看門狗 */
static void iwdg_control(void *parameter)
{  
    int i = 0;
	while(1)
    {
        rt_thread_mdelay(200);
        i++;
       /* Refresh IWDG: reload counter */
       HAL_IWDG_Refresh(&hiwdg);

       rt_kprintf("第%d次餵狗\n",i);
    }
}

static rt_thread_t iwdg_tid = RT_NULL;
int iwdg_init(void)
{

    /* 創建電機線程*/
    iwdg_tid = rt_thread_create("iwdg_thread",          // 線程名字
                            iwdg_control,	            // 線程入口函數  
							RT_NULL,		            // 線程入口參數
                            512,	                    // 堆棧大小,
                            RT_THREAD_PRIORITY_MAX-2,   // 線程優先級
							5);	                        // 時間片長度
    
    /* 如果獲得線程控制塊,啓動這個線程 */
    if (iwdg_tid != RT_NULL)
        rt_thread_startup(iwdg_tid);  
    return 0;
}
INIT_DEVICE_EXPORT(iwdg_init); // 自動初始化

效果如下:
在這裏插入圖片描述
接下來屏蔽餵狗操作,可以看到看門狗起作用了,單片機不斷復位。

extern IWDG_HandleTypeDef hiwdg;
/* 200ms 喂一次看門狗 */
static void iwdg_control(void *parameter)
{  
    int i = 0;
	while(1)
    {
        rt_thread_mdelay(200);
        i++;
        rt_kprintf("第%d次200ms\n",i);
    }
}

static rt_thread_t iwdg_tid = RT_NULL;
int iwdg_init(void)
{

    /* 創建電機線程*/
    iwdg_tid = rt_thread_create("iwdg_thread",          // 線程名字
                            iwdg_control,	            // 線程入口函數  
							RT_NULL,		            // 線程入口參數
                            512,	                    // 堆棧大小,
                            RT_THREAD_PRIORITY_MAX-2,   // 線程優先級
							5);	                        // 時間片長度
    
    /* 如果獲得線程控制塊,啓動這個線程 */
    if (iwdg_tid != RT_NULL)
        rt_thread_startup(iwdg_tid);  
    
    return 0;
}

INIT_DEVICE_EXPORT(iwdg_init); // 自動初始化

可以看到每5次200ms,單片機就會重啓。
在這裏插入圖片描述

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章