陈拓 2022/07/02-2022/07/02
此示例演示如何使用任务看门狗计时器Task Watchdog Timer (TWDT)的以下功能:
https://gitee.com/EspressifSystems/esp-idf/tree/master/examples/system/task_watchdog
《用乐鑫国内Gitee镜像搭建ESP32开发环境》
https://zhuanlan.zhihu.com/p/348106034
https://blog.csdn.net/chentuo2000/article/details/113424934?spm=1001.2014.3001.5501
将官方例子项目复制到ESP-IDF开发工具之外:
cd ~/esp
cp -r ~/esp/esp-idf/examples/system/task_watchdog ~/esp/
cd ~/esp/task_watchdog
tree
get_idf
idf.py set-target esp32
idf.py menuconfig
1) 将闪存设置为4MB
2) 在任务看门狗超时时调用紧急处理程序
保存,退出。
idf.py build
查看USB转串口的COM口号:
烧写:
idf.py -p /dev/ttyS3 -b 115200 flash
idf.py monitor -p /dev/ttyS3
当示例正常运行时,将观察到以下输出:
用户可以注释掉esp_task_wdt_reset()或esp_task_wdt_reset_user()调用以测试触发TWDT,
//CHECK_ERROR_CODE(esp_task_wdt_reset(), ESP_OK);
这将导致以下输出:
看门狗被触发。
因为TWDT超时时间为3秒:
#define TWDT_TIMEOUT_S 3 // TWDT超时时间
延时为10秒:
vTaskDelay(pdMS_TO_TICKS(10000)); // 延时10秒
在10秒延时期间,看门狗有3次触发,之后程序会继续执行:
如果你希望任务看门狗触发之后进行重启。
void esp_task_wdt_isr_user_handler(void)
{
esp_restart();
}
这样在看门狗触发时程序会重新启动:
/* Task_Watchdog Examples
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#define TWDT_TIMEOUT_S 3 // TWDT超时时间
#define TASK_RESET_PERIOD_S 2 // 任务重置周期时间
/*
* 宏,用于检查TWDT的输出,如果检测到返回错误码则触发中止程序执行。
*/
#define CHECK_ERROR_CODE(returned, expected) ({ \
if(returned != expected){ \
printf("TWDT ERROR\n"); \
abort(); \
} \
})
static TaskHandle_t task_handles[portNUM_PROCESSORS];
// 回调由app_main()创建的用户任务
void reset_task(void *arg)
{
// 为TWDT添加任务,并检查dwt状态看是否添加
CHECK_ERROR_CODE(esp_task_wdt_add(NULL), ESP_OK);
CHECK_ERROR_CODE(esp_task_wdt_status(NULL), ESP_OK);
while(1){
// 每2秒重置一次看门狗
//CHECK_ERROR_CODE(esp_task_wdt_reset(), ESP_OK); // 喂狗。注释此行以测试触发TWDT超时
vTaskDelay(pdMS_TO_TICKS(TASK_RESET_PERIOD_S * 1000));
}
}
void esp_task_wdt_isr_user_handler(void)
{
esp_restart();
}
void app_main(void)
{
printf("Initialize TWDT\n");
// 初始化或者重新初始化TWDT
CHECK_ERROR_CODE(esp_task_wdt_init(TWDT_TIMEOUT_S, false), ESP_OK);
// 如果启动时未订阅空闲任务,则将其订阅到TWDT
#ifndef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(0));
#endif
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 && !CONFIG_FREERTOS_UNICORE
esp_task_wdt_add(xTaskGetIdleTaskHandleForCPU(1));
#endif
// 创建用户任务并添加到看门狗
for(int i = 0; i < portNUM_PROCESSORS; i++){
xTaskCreatePinnedToCore(reset_task, "reset task", 1024, NULL, 10, &task_handles[i], i);
}
printf("Delay for 10 seconds\n");
vTaskDelay(pdMS_TO_TICKS(10000)); // 延时10秒
printf("Unsubscribing and deleting tasks\n");
// 从任务看门狗中删除并取消订阅用户任务,然后取消订阅空闲任务
for(int i = 0; i < portNUM_PROCESSORS; i++){
vTaskDelete(task_handles[i]); // 首先删除用户任务(防止重置未订阅的任务)
CHECK_ERROR_CODE(esp_task_wdt_delete(task_handles[i]), ESP_OK); // 从TWDT取消订阅任务
CHECK_ERROR_CODE(esp_task_wdt_status(task_handles[i]), ESP_ERR_NOT_FOUND); // 确认任务已取消订阅
// 取消订阅空闲任务
CHECK_ERROR_CODE(esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(i)), ESP_OK); // 从TWDT取消订阅空闲任务
CHECK_ERROR_CODE(esp_task_wdt_status(xTaskGetIdleTaskHandleForCPU(i)), ESP_ERR_NOT_FOUND); // 确认空闲任务已取消订阅
}
// 在所有任务取消订阅后取消TWDT
CHECK_ERROR_CODE(esp_task_wdt_deinit(), ESP_OK);
CHECK_ERROR_CODE(esp_task_wdt_status(NULL), ESP_ERR_INVALID_STATE); //Confirm TWDT has been deinitialized 确认TWDT已解除初始化
printf("Complete\n");
}