本帖最后由 春娇霹雳娃 于 2023-8-16 17:35 编辑
#申请原创# @21小跑堂
本实验基于MM32F0040实现IWDG和WWDG工程开发工作。
1.开发板简介
MM32F0040使用高性能的 Arm® Cortex-M0 为内核的 32 位微控制器,最高工作频率可达 72MHz,内置高速存储器,其硬件外观如下图所示:
电路图如下:
2.功能描述
2.1 IWDG
IWDG(Independent Watch Dog),为检测和解决由软件错误所引起的故障而设计。独立看门狗(IWDG)适用于需要看门狗作为一个处于主程序之外,能够完全独立工作,适用于对时间精度要求低的需求场景中。IWDG分为两种工作模式:
- 硬件独立看门狗
- 软件独立看门狗(默认为软件独立看门狗模式)
功能框图如下:
本质:可理解为一个12位递减计数器,当计数器的值从装载的值一直递减到零时,向系统触发复位信号,即IWDG_RESET。在计数器递减到零之前,重新装置计数器内的值,则不会产生复位信号,重置计数器值的操作即为“喂狗”。
“喂狗” 分为两种方式:
2.2 WWDG
WWDG(Window Watchdog Timer)窗口看门狗,一种七位向下计数的timer,计数范围0x7F~0x3F(计数到0x3F将发出复位请求)。喂狗操作:通过更新计数器WWDG_CR[T]计数值,避免计数器向下计数到0x3F,实现“喂狗”操作。
有上下限的喂狗(IWDG只有下限)
- 上限:寄存器WWDG_CFGR[W]配置值,如果计数值大于此配置值时“喂狗”,则WWDG向CPU发出复位请求(提前“喂狗”)
- 下限:0x3F(不可修改),如果计数值计数到0x3F,则WWDG向CPU发出复位请求(没有“喂狗”)
作用:
- 当程序运行偏离了正常的程序路径,能够及时发出复位请求
- 程序运行偏离了正常的程序路径,提前执行了“喂狗”操作,也能及时发出复位请求
WWDG功能框图如下:
WWDG使用范围:
1.用于程序执行时间精度要求较高的场景
- 通过APB时钟分频作为计数器时钟来源,计数时钟可精确计算
- 具有上下限的喂狗窗口范围,避免过早喂狗使喂狗失效
2.喂狗时间范围极小
- 当APB1时钟频率为60MHz时,最晚30毫秒内就需要喂狗一次
3.能否在低功耗状态下使用
- WWDG的计数时钟来源于APB时钟的分频
- 如果APB时钟关闭,WWDG则无法继续计数,因此WWDG无法在低功耗状态下使用。
3.寄存器配置
3.1 IWDG
iwdg 受访问保护的寄存器有:
- IWDG_PR
- IWDG_CR
- IWDG_IGEN
- IWDG_RLR
上述四个寄存器受访问保护。若要修改其中任一寄存器,须先对 IWDG_KR寄存器写入解锁值( 0x5555),写入后四个寄存器将同时被解除访问保护。当IWDG_KR被写入除0x5555外的值时,上述四个寄存器将同时都被锁定。如重装载操作(即“喂狗”)也会对上述四个寄存器启动访问保护功能。
预分频系数设置:
IWDG 实现思路:
- 开启LSI时钟
- 设置IWDG预分频系数
- 设置IWDG重载值
- IWDG溢出配置
- 更新IWDG重载值
- 使能IWDG
2. 更新重载值
- 方法一:通过IWDG_KG直接重载初定值
- 方法二: 重新设定重载值
3. 中断配置
- 使能IWDG中断
- 失能IWDG中断(仅能在初始化阶段使用)
- 配置IWDG中断触发值
- 获取IWDG中断状态
- 清除IWDG中断
3.2 WWDG
WWDG实现思路:
1.启动WWDG
- 开启WWDG的RCC时钟
- 初始化WWDG,包括配置时基和重装载窗口值
- 使能WWDG,计数器开始计数
- 使能WWDG_INT_EW中断(可选)
2.喂狗
- 在规定时间内重装载计数值“喂狗”,提前或超时重装载计数值将产生复位请求
3.中断
- 使能WWDG_INT_EW中断后,计数器计数到0x40产生中断
4.复位
- WWDG产生复位请求后,CPU响应复位请求产生复位,复位后RCC_CSR[WWDGRSTF]置位
- MCU复位后,可通过查看RCC_CSR[WWDGRSTF]标志位确定是否为窗口看门狗复位
4.软件实现
4.1 IWDG
启动检测,若为独立看门口复位,则通过UART输出本次启动为独立看门口复位,若非独立看门狗复位,则通过UART输出本次启动为正常启动或其他复位。开启时钟LSI , 配置IWDG的预分频系数为 32,重载值为 0x1F,初始化独立看门狗功能。在主函数中循环喂狗10次后停止喂狗。停止喂狗,则等待计数器溢出,独立看门狗触发复位信号。
主函数:int main(void){
uint32_t i = 0;
BOARD_Init();
printf("iwdg_basic example.\r\n");
app_iwdg_init();
for(i = 0; i < 10; i++){
/* Reload the IWDG counter. */
IWDG_DoReload(BOARD_IWDG_PORT);
printf("Feed dog count: %u\r\n", (unsigned)(i+1) );
app_soft_delay(200);}
/* Waiting for MCU reset. */
while(1){}}
配置IWDG
/* IWDG. */
#define BOARD_IWDG_PORT IWDG
#define BOARD_IWDG_RELOAD 0x7ff //0x3ff
#define BOARD_IWDG_PRESCALER IWDG_Prescaler_32
初始化:
void IWDG_Init(IWDG_Type * IWDGx, IWDG_Init_Type * init)
{
if ( NULL != init )
{
IWDGx->KR = IWDG_KEY_UNLOCK;
IWDGx->PR = init->Prescaler;
IWDGx->KR = IWDG_KEY_UNLOCK;
IWDGx->RLR = init->Relaod;
IWDG_DoReload(IWDGx);
}
}
使能IWDG
void IWDG_Start(IWDG_Type * IWDGx)
{
IWDGx->KR = IWDG_KEY_ENABLE;
}
重载IWDG
void IWDG_DoReload(IWDG_Type * IWDGx)
{
IWDGx->KR = IWDG_KEY_RELOAD;
}
开启中断
void IWDG_EnableInterrupts(IWDG_Type * IWDGx, uint32_t interrupts, bool enable)
{
if( (true == enable ) && (IWDG_INT_ALMOST_TIMEOUT == interrupts) )
{
IWDGx->CR |= IWDG_CR_IRQSEL_MASK;
}
else
{
/* if IWDG_EnableInterrupts interrupt was enabled, only MCU reset can close it. */
}
}
4.2 WWDG
1.初始化WWDG_Init():
- 配置计数器的计数时基(分频系数)TimeBase
- 配置“喂狗”重装载窗口值(喂狗上限)ReloadWindow
2.使能WWDG_Enable():
- 使能WWDG,使计数器开始计数
- 使能WWDG后,只有复位才能关闭WWDG。
3.重装载计数值WWDG_Reload():
- 重装载计数值,实现“喂狗”操作
- 重装载计数值后,计数器从新的计数值开始向下计数
4.中断
- 提前唤醒中断WWDG_INT_EW,当计数器计数到0x40时发出,通知CPU即将发出复位请求。
- 同使能WWDG一样,使能提前唤醒中断WWDG_INT_EW后只有复位才能关闭此中断。
初始化:void WWDG_Init(WWDG_Type * WWDGx, WWDG_Init_Type * init)
{
if (NULL != init)
{
WWDGx->CFGR = WWDG_CFGR_WDGTB(init->Prescaler)
| WWDG_CFGR_W(init->UpperLimit);
}
}
使能WWDG
void WWDG_Start(WWDG_Type * WWDGx)
{
WWDGx->CR |= WWDG_CR_WDGA_MASK;
}
重载WWDG
void WWDG_Reload(WWDG_Type * WWDGx, uint32_t value)
{
if (value > WWDG_LOWER_LIMIT)
{
WWDGx->CR = (WWDGx->CR & ~WWDG_CR_T_MASK) | WWDG_CR_T(value);
}
}
中断唤醒
void WWDG_EnableInterrupts(WWDG_Type * WWDGx, uint32_t interrupts, bool enable)
{
if ( (true == enable) && (WWDG_INT_ALMOST_TIMEOUT == interrupts) )
{
WWDGx->CFGR |= WWDG_CFGR_EWI_MASK;
}
else
{
/* if WWDG_INT_ALMOST_TIMEOUT interrupt is enabled, only MCU reset can close it. */
}
}
配置中断/* WWDG */
#define BOARD_WWDG_PORT WWDG
#define BOARD_WWDG_IRQn WWDG_IWDG_IRQn
#define BOARD_WWDG_IRQHandler WWDG_IWDG_IRQHandler
#define BOARD_WWDG_UPPER_LIMIT 0x7fu
#define BOARD_WWDG_RELOAD_TIMES 100u
#define BOARD_WWDG_RELOAD_VALUE 0x7fu
#define BOARD_WWDG_PRESCALER WWDG_Prescaler_8
开启时钟
/* WWDG. */
RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_WWDG, true);
RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_WWDG);
主函数:
int main(void)
{
BOARD_Init();
printf("\r\nwwdg_basic example.\r\n");
/* Setup WWDG. */
app_wwdg_init();
while (1)
{
putchar('.');
app_soft_delay(100);
}
}
5.实验现象
iwdg_basic
wwdg_basic
6.附件
原理图:
Mini-F0040_SCH.pdf
(314.04 KB)
工程文件:
mini-f0040_iwdg_basic_mdk.zip
(510.03 KB)
mini-f0040_wwdg_basic_mdk.zip
(510.23 KB)
|
对比介绍IWDG和WWDG两种单片机外设,原理介绍清晰,实现过程较好,值得借鉴