STM32CubeMX學習筆記(12)——WWDG視窗看門狗使用

語言: CN / TW / HK

一、WWDG簡介

看門狗其實就是一個定時器,從功能上說它可以讓微控制器在程式發生意外(程式進入死迴圈或跑飛)的時候,能重新回覆到系統剛上電狀態,以保障系統出問題的時候可以重啟一次。說的複雜一點,看門狗就是能讓程式出問題是能重新啟動系統。

STM32 有兩個看門狗,一個是獨立看門狗,一個是視窗看門狗。我們知道獨立看門狗的工作原理就是一個遞減計數器不斷的往下遞減計數,當減到 0 之前如果沒有喂狗的話,產生復位。視窗看門狗跟獨立看門狗一樣,也是一個遞減計數器不斷的往下遞減計數,當減到一個固定值 0X40 時還不喂狗的話,產生復位,這個值叫視窗的下限,是固定的值,不能改變。這個是跟獨立看門狗類似的地方,不同的地方是視窗看門狗的計數器的值在減到某一個數之前喂狗的話也會產生復位,這個值叫視窗的上限,上限值由使用者獨立設定。視窗看門狗計數器的值必須在上視窗和下視窗之間才可以喂狗,這就是視窗看門狗中視窗兩個字的含義。

二、WWDG應用場景

**WWDG 一般被用來監測,由外部干擾或不可預見的邏輯條件造成的應用程式背離正常的執行序列而產生的軟體故障。**比如一個程式段正常執行的時間是 50ms,在執行完這個段程式之後緊接著進行喂狗,如果在規定的時間視窗內還沒有喂狗,那就說明我們監控的程式出故障了,跑飛了,那麼就會產生系統復位,讓程式重新執行。

三、新建工程

1. 開啟 STM32CubeMX 軟體,點選“新建工程”

2. 選擇 MCU 和封裝

3. 配置時鐘
RCC 設定,選擇 HSE(外部高速時鐘) 為 Crystal/Ceramic Resonator(晶振/陶瓷諧振器)

選擇 Clock Configuration,配置系統時鐘 SYSCLK 為 72MHz
修改 HCLK 的值為 72 後,輸入回車,軟體會自動修改所有配置





4. 配置除錯模式
非常重要的一步,否則會造成第一次燒錄程式後續無法識別偵錯程式
SYS 設定,選擇 Debug 為 Serial Wire



四、WWDG

4.1 引數配置

System Core 中選擇 WWDG 設定,並勾選 Activated 啟用

WWDG counter clock prescaler 預分頻器值設為 8
WWDG window value 上視窗值設為 90
WWDG free-running downcounter value 計數器值設為 127





超時時間 Twwdg = Tpclk1 x 4096 x 2^wdgtb x (T[5:0] + 1) (ms)


由圖知 Tpclk1 為 36 MHz,當 prv 取 WWDG_Prescaler_8,即 wdgtb為3
即最小超時值為 910us,最大超時值為 58.25ms。



  • 1 是計數器的初始值
  • 2 是我們設定的上視窗值
  • 3 是下視窗值(0x3F)
    視窗看門狗計數器的值只有在 23 之間(上視窗和下視窗之間)才可以喂狗

看門狗中斷 Early wakeup interrupt 提前喚醒中斷,選擇 Enable 使能

4.2 配置NVIC

使能WWDG中斷

4.3 生成程式碼

輸入專案名和專案路徑

選擇應用的 IDE 開發環境 MDK-ARM V5

每個外設生成獨立的 ’.c/.h’ 檔案
不勾:所有初始化程式碼都生成在 main.c
勾選:初始化程式碼生成在對應的外設檔案。 如 GPIO 初始化程式碼生成在 gpio.c 中。

點選 GENERATE CODE 生成程式碼









4.4 修改中斷回撥函式

開啟 stm32f1xx_it.c 中斷服務函式檔案,找到 WWDG 中斷的服務函式 WWDG_IRQHandler()
中斷服務函式裡面就呼叫了串列埠中斷處理函式 HAL_WWDG_IRQHandler()


開啟 stm32f1xx_hal_wwdg.c 檔案,找到視窗看門狗中斷處理函式原型 HAL_WWDG_IRQHandler(),其主要作用就是判斷產生中斷,清除中斷標識位,然後呼叫中斷回撥函式 HAL_WWDG_EarlyWakeupCallback()

/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
這個函式不應該被改變,如果需要使用回撥函式,請重新在使用者檔案中實現該函式。


HAL_WWDG_EarlyWakeupCallback() 按照官方提示我們應該再次定義該函式,__weak 是一個弱化標識,帶有這個的函式就是一個弱化函式,就是你可以在其他地方寫一個名稱和引數都一模一樣的函式,編譯器就會忽略這一個函式,而去執行你寫的那個函式;而 UNUSED(hwwdg) ,這就是一個防報錯的定義,當傳進來的視窗看門狗沒有做任何處理的時候,編譯器也不會報出警告。其實我們在開發的時候已經不需要去理會中斷服務函數了,只需要找到這個中斷回撥函式並將其重寫即可而這個回撥函式還有一點非常便利的地方這裡沒有體現出來,就是當同時有多箇中斷使能的時候,STM32CubeMX會自動地將幾個中斷的服務函式規整到一起並呼叫一個回撥函式,也就是無論幾個中斷,我們只需要重寫一個回撥函並判斷傳進來的定時器號即可。

接下來我們就在 stm32f1xx_it.c 這個檔案的最下面新增 HAL_WWDG_EarlyWakeupCallback()

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
   
   
    if(huart->Instance == USART1)
    {
   
   
        HAL_UART_Transmit(&huart1, (uint8_t *)Buffer, 1, 0xffff);
        HAL_UART_Receive_IT(&huart1, (uint8_t *)Buffer, 1);
    }
}
/* USER CODE END 1 */

4.5 新增列印函式

在 while 迴圈中 1 秒列印一條語句

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
   
   
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_USART1_UART_Init();
  MX_WWDG_Init();
  /* USER CODE BEGIN 2 */
  printf("\n\r***** WWDG Test Start *****\n\r");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
   
   
    printf("\n\r Running...\n\r");
    HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

4.6 檢視列印

串列埠列印功能檢視 STM32CubeMX學習筆記(6)——USART串列埠使用

當去掉 stm32f1xx_it.c 中 HAL_WWDG_EarlyWakeupCallbackHAL_WWDG_Refresh(hwwdg);,也就是不喂狗時,系統約 59 毫秒重啟一次。

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
   
   
//    HAL_WWDG_Refresh(hwwdg);
}

4.7 HAL庫與標準庫程式碼比較

STM32CubeMX 使用 HAL 庫生成的程式碼:

/**
  * @brief WWDG Initialization Function
  * @param None
  * @retval None
  */
static void MX_WWDG_Init(void)
{
   
   
  /* USER CODE BEGIN WWDG_Init 0 */

  /* USER CODE END WWDG_Init 0 */

  /* USER CODE BEGIN WWDG_Init 1 */

  /* USER CODE END WWDG_Init 1 */
  hwwdg.Instance = WWDG;
  hwwdg.Init.Prescaler = WWDG_PRESCALER_8;
  hwwdg.Init.Window = 90;
  hwwdg.Init.Counter = 127;
  hwwdg.Init.EWIMode = WWDG_EWI_ENABLE;
  if (HAL_WWDG_Init(&hwwdg) != HAL_OK)
  {
   
   
    Error_Handler();
  }
  /* USER CODE BEGIN WWDG_Init 2 */

  /* USER CODE END WWDG_Init 2 */
}

HAL_WWDG_Refresh(hwwdg);

使用 STM32 標準庫的程式碼:

WWDG_Config(0X7F, 0X5F, WWDG_Prescaler_8);

// WWDG 中斷優先順序初始化
static void WWDG_NVIC_Config(void)
{
   
   
  NVIC_InitTypeDef NVIC_InitStructure; 
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 
  NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

/* WWDG 配置函式
 * tr :遞減計時器的值, 取值範圍為:0x7f~0x40
 * wr :視窗值,取值範圍為:0x7f~0x40
 * prv:預分頻器值,取值可以是
 *      @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1(36MHZ)/4096)/1
 *      @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1(36mhz)/4096)/2
 *      @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1(36mhz)/4096)/4
 *      @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1(36mhz)/4096)/8
 */
void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
{
   
   	
	// 開啟 WWDG 時鐘
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	
	// 設定遞減計數器的值
	WWDG_SetCounter( tr );
	
	// 設定預分頻器的值
	WWDG_SetPrescaler( prv );
	
	// 設定上視窗值
	WWDG_SetWindowValue( wr );
	
	// 設定計數器的值,使能WWDG
	WWDG_Enable(WWDG_CNT);	
	
	// 清除提前喚醒中斷標誌位
	WWDG_ClearFlag();	
	// 配置WWDG中斷優先順序
	WWDG_NVIC_Config();	
	// 開WWDG 中斷
	WWDG_EnableIT();
}

WWDG_SetCounter( WWDG_CNT );

MX_WWDG_Init(); 對應 WWDG_Config(0X7F, 0X5F, WWDG_Prescaler_8);
HAL_WWDG_Refresh(hwwdg); 對應 WWDG_SetCounter(WWDG_CNT);

五、注意事項

使用者程式碼要加在 USER CODE BEGIN NUSER CODE END N 之間,否則下次使用 STM32CubeMX 重新生成程式碼後,會被刪除。


• 由 Leung 寫於 2021 年 1 月 29 日

• 參考:STM32CubeMX系列教程15:看門狗(WDG)
    【STM32】HAL庫 STM32CubeMX教程五----看門狗(獨立看門狗,視窗看門狗)