概念先知道
- 看门狗(WDG):像“监工”——程序必须周期性“喂狗”(清零计数器);如果程序卡死没喂,看门狗就复位系统。
- 计数器/比较值:看门狗时钟持续计数,计到比较值(
comp_val)还没喂狗就触发中断或复位。 - 时钟源:看门狗可以用不同时钟(BCLK/32K/1K/XTAL),例程遍历它们校验实际走时。
例程功能简介
本页对应博流官方 SDK 的 wdg_clksource_check 例程(examples/peripherals/wdg/wdg_clksource_check),演示看门狗定时器与时钟源验证:
- 看门狗时钟 = 时钟源 /(分频 + 1),例程遍历 BCLK、32K、1K、XTAL 四种时钟源;
- 对每种时钟源:配置 → 清零计数器 → 启动 → 延时 200ms → 读取计数器值 → 停止,重复 10 次取计数;
- 通过计数差值可以校验看门狗实际走时是否与理论频率一致。
- 同族例程(
examples/peripherals/wdg/):wdg_int(中断模式)、wdg_reset(复位模式)。
操作步骤
本页不需要额外接线。在终端进入 SDK 的看门狗例程目录(前提:已按快速开始(Linux)或Windows搭建好环境):
cd examples/peripherals/wdg/wdg_clksource_check执行编译命令。Ai-M62(BL616)与 Ai-M61(BL618)同属一个系列,统一填写引脚最少的 bl616 即可:
make CHIP=bl616 BOARD=bl616dk用 USB 线连接开发板,按住 BOOT 键(Ai-M61-32S-Kit 为 IO2)不放、短按 EN/RST 进入下载模式,然后执行烧录(把串口号换成实际值):
make flash CHIP=bl616 COMX=/dev/ttyUSB0打开串口助手(波特率 2000000)。例程依次用 BCLK/32K/1K/XTAL 四种时钟源启动看门狗,每次延时 200ms 后读取计数器值并打印 Delay 200ms, div = x, test x times, cnt: xxx,最后打印 case success.。
代码执行流程
例程从启动到运行的完整流程如下(图中的循环箭头表示反复执行):
例程调用的 API 介绍
bflb_device_get_by_name("watchdog0")
获取看门狗外设的设备句柄,BL616/BL618 上名称为 "watchdog0"。
参数:
name:外设名称,固定"watchdog0"
返回值:struct bflb_device_s * 设备句柄(获取失败为 NULL)
bflb_wdg_init(wdt, config)
初始化看门狗。struct bflb_wdg_config_s 中:
clock_source:时钟源,WDG_CLKSRC_BCLK/WDG_CLKSRC_32K/WDG_CLKSRC_1K/WDG_CLKSRC_XTALclock_div:分频值,计数时钟 = 时钟源 /(div + 1)comp_val:比较值,例程0xffffmode:WDG_MODE_INTERRUPT中断模式(超时先产生中断)
参数:
wdt:看门狗设备句柄config:配置结构体指针
返回值:成功返回 0;失败返回负值错误码
完整代码
以下为 wdg_clksource_check/main.c 完整源码,与官方示例(examples/peripherals/wdg/wdg_clksource_check)一致;点灯引脚已适配 Ai-M61/62-32S-Kit 板载 RGB 灯,默认折叠,点击展开:
📜 点击展开 wdg_clksource_check/main.c 完整代码
#include "bflb_mtimer.h"
#include "bflb_wdg.h"
#include "board.h"
#include <assert.h>
#if !defined(BL702L)
uint8_t wdg_clk_src_type[] = {
WDG_CLKSRC_BCLK,
WDG_CLKSRC_32K,
WDG_CLKSRC_1K,
WDG_CLKSRC_XTAL,
};
#else
uint8_t wdg_clk_src_type[] = {
WDG_CLKSRC_32K,
WDG_CLKSRC_1K,
WDG_CLKSRC_XTAL,
};
#endif
int main(void)
{
uint32_t i = 0;
uint32_t j = 0;
uint32_t cnt = 0;
board_init();
printf("Timer clksource check\n");
struct bflb_device_s *wdt;
wdt = bflb_device_get_by_name("watchdog0");
assert(wdt != NULL);
/* watchdog clk = clock_source/(div + 1)*/
struct bflb_wdg_config_s cfg;
cfg.clock_source = WDG_CLKSRC_32K;
cfg.clock_div = 0;
cfg.comp_val = 0xffff;
cfg.mode = WDG_MODE_INTERRUPT;
for (i = 0; i < sizeof(wdg_clk_src_type) / sizeof(wdg_clk_src_type[0]); i++) {
cnt = 0;
if (wdg_clk_src_type[i] == WDG_CLKSRC_XTAL) {
printf("Watchdog Src Clk is XTAL\r\n");
cfg.clock_div = 199;
} else if (wdg_clk_src_type[i] == WDG_CLKSRC_32K) {
printf("Watchdog Src Clk is 32K\r\n");
cfg.clock_div = 1;
} else if (wdg_clk_src_type[i] == WDG_CLKSRC_1K) {
printf("Watchdog Src Clk is 1K\r\n");
cfg.clock_div = 1;
}
#if !defined(BL702L)
else if (wdg_clk_src_type[i] == WDG_CLKSRC_BCLK) {
printf("Watchdog Src Clk is BCLK\r\n");
cfg.clock_div = 249;
}
#endif
else {
printf("Other clock, not test.\r\n");
continue;
}
cfg.clock_source = wdg_clk_src_type[i];
bflb_wdg_init(wdt, &cfg);
for (j = 0; j < 10; j++) {
bflb_wdg_reset_countervalue(wdt);
bflb_wdg_start(wdt);
bflb_mtimer_delay_ms(200);
cnt = bflb_wdg_get_countervalue(wdt);
bflb_wdg_stop(wdt);
bflb_mtimer_delay_ms(10);
printf("Delay 200ms, div = %lu, test %lu times, cnt: %lu\r\n", cfg.clock_div + 1, j, cnt);
}
}
printf("case success.\r\n");
while (1) {
bflb_mtimer_delay_ms(1500);
}
}FAQ
程序反复复位
看门狗启动后没有及时喂狗就会复位。例程是验证用途(启停模式),实际项目要在主循环或空闲任务中周期性调用 bflb_wdg_reset_countervalue 喂狗。
计数器值与理论值不符
计数 = 时钟源频率 /(div + 1)× 时间。先确认对应时钟源实际频率(如 XTAL=40MHz、32K=32768Hz),再核对 clock_div 配置。
如何让看门狗真正复位系统
把 mode 改为复位模式(如 WDG_MODE_RESET,具体枚举见 bflb_wdg.h),并配置合适的 comp_val 超时时间。
遇到问题?
如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

