目录:
问题场景:
学习使用窗口看门狗配置函数发现一个很奇怪的现象,窗口看门狗的使能函数语句要在上面才能进入提前唤醒中断服务函数中,这是为啥呀,那使能函数要在哪句语句的上面和下面?有顺序吗?-------小盆友你是否有很多问号?
问题原因查找
网上查找原因没有发现相关的说明,查看某原,某火发现窗口看门狗的使能函数都是写着上面的:
某原标准库,STM32F10X:
某原寄存器,STM32F103X:
某原寄存器,STM32F407x:
某火标准库,STM32F10X:
我采用的是:stm32f407x板子,寄存器版和库函数版验证,
窗口看门狗使用stm32103x或者stm32407x板子,库函数或寄存器都差不多,
问题是窗口看门狗的使能函数语句放在哪里,还是哪些语句影响到了窗口
看门狗进入提前唤醒中断,采用最本源的办法验证。
自己,STM32F407X,寄存器版:error表示使能函数不能放到这里。
自己,STM32F407X,库函数版:error表示使能函数不能放到这里
测试验证:
查看stm32f407中文编程参考手册:
窗口看门狗复位条件:
①当递减计数器值小于 0x40 时复位(如果看门狗已激活)
②在窗口之外重载递减计数器时复位(如果看门狗已激活)
为啥不能使能窗口看门狗语句在其他语句完成下面,经过验证,如果清除过窗口期值后使能语句在开启提前唤醒中断语句下面会发生立即进入窗口看门狗中断服务函数,明明已经清除提前唤醒中断标志,但是使能后还是会立即进入中断服务函数,造成刷新计数值不在窗口期(设置窗口值到0x3f)导致复位,即满足复位条件②。
在不清除窗口期值时,可以将正常进入提前唤醒中断喂狗,不会造成复位,但是库函数语句是先进入清空窗口期值,然后填入新的窗口期值。
int main()
{
NVIC_SetPriorityGrouping(5);
uart1_init(115200);
printf("窗口看门狗初始化前\r\n");
Wwdg_Init();
printf("窗口看门狗初始化后\r\n");
while(1)
{
}
}
/****************************
函数名称:Wwdg_Init
函数功能:窗口看门狗初始化
返回值:void
形参: void
****************************/
void Wwdg_Init(void)
{
RCC->APB1ENR |= (1<<11);//打开窗口看门狗时钟
WWDG->CR &= ~(0X7F<<0);//清除计数值,设置计数值
WWDG->CR |= (0X7F<<0);
WWDG->CFR |= (3<<7);//设置分频
// WWDG->CFR &= ~(0X7F<<0);//清除窗口期值,设置窗口期值
WWDG->CFR |= (0X6F<<0);//递减64个数,最短12ms
NVIC_SetPriority(WWDG_IRQn,NVIC_EncodePriority(5,2,2)); //设置窗口看门狗占先和次级优先级
NVIC_EnableIRQ(WWDG_IRQn);//使能窗口看门狗的NVIC中断
WWDG->SR &= ~(1<<0);//清除提前唤醒中断标志
WWDG->CFR |= (1<<9);//提前唤醒中断
WWDG->CR |= (1<<7);//使能窗口看门狗
}
void WWDG_IRQHandler(void)
{
WWDG->SR &= ~(1<<0);//清除提前唤醒中断标志
WWDG->CR |= (0X7F<<0);
}
原因分析:
当你清除窗口期值时:
你先开启中断使能后使能看门狗,当执行到开启窗口看门狗使能立即跳转到中断服务函数,不会管你下面有没有语句,清除中断唤醒标志无效。
你先使能看门狗后开启中断使能,当执行到开启窗口看门狗使能会继续执行下面的语句,清除中断唤醒标志有效,直到计数到0x40才会跳转到中断刷新技数值。
想当然的认为,那我就使能看门狗在清除中断唤醒标志和中断使能之间,这样清除中断唤醒标志有效,但现实猛朝你脸上来一脚。
位 0 EWIF: 提前唤醒中断标志 (Early wakeup interrupt flag)
当计数器值达到 0x40 时此位由硬件置 1。它必须由软件通过写入 0 来清零。写入 1 不起作
用。如果不使能中断,此位也会被置 1。意思是说你前一脚刚将清除中断唤醒标志,后一脚硬件已经将中断唤醒标志置1。草,嗯嗯--可真会玩呢。
当你初始化不清除窗口期值直接赋值时:
上述情况不存在
解决方案:
库函数版总结:
寄存器版总结:
代码:
int main()
{
NVIC_SetPriorityGrouping(5);
uart1_init(115200);
printf("窗口看门狗初始化前\r\n");
Wwdg_Init();
printf("窗口看门狗初始化后\r\n");
while(1)
{
}
}
/****************************
函数名称:Wwdg_Init
函数功能:窗口看门狗初始化
返回值:void
形参: void
****************************/
void Wwdg_Init(void)
{
RCC->APB1ENR |= (1<<11);//打开窗口看门狗时钟
WWDG->CR &= ~(0X7F<<0);//清除计数值,设置计数值
WWDG->CR |= (0X7F<<0);
WWDG->CFR |= (3<<7);//设置分频
WWDG->CFR &= ~(0X7F<<0);//清除窗口期值,设置窗口期值
WWDG->CFR |= (0X6F<<0);//递减64个数,最短12ms
NVIC_SetPriority(WWDG_IRQn,NVIC_EncodePriority(5,2,2)); //设置窗口看门狗占先和次级优先级
NVIC_EnableIRQ(WWDG_IRQn);//使能窗口看门狗的NVIC中断
WWDG->CR |= (1<<7);//使能窗口看门狗
printf("11--CR=%#x--SR=%#x\r\n",WWDG->CR,WWDG->SR);
WWDG->SR &= ~(1<<0);//清除提前唤醒中断标志
WWDG->CFR |= (1<<9);//提前唤醒中断
printf("22--CR=%#x--SR=%#x\r\n",WWDG->CR,WWDG->SR);
}
///****************************
//函数名称:Wwdg_Init
//函数功能:窗口看门狗初始化
//返回值:void
//形参:u8 wr 窗口值
//
//形参必须介于 0x7f 和 0x40 之间
//****************************/
//void Wwdg_Init(u8 wr)
//{
// NVIC_InitTypeDef NVIC_InitStructure;
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); //使能窗口看门狗时钟
//
// WWDG_SetCounter(0x7f);//设置计数值
//
// WWDG_SetPrescaler(WWDG_Prescaler_8); //设置分频值
// WWDG_SetWindowValue(wr); //设置窗口值
//
//
// NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn; //窗口看门狗中断
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; //抢占优先级为2
// NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02; //子优先级为2
// NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能窗口看门狗
// NVIC_Init(&NVIC_InitStructure);
//
// WWDG_Enable(WWDG_CNT); //开启看门狗
//
// WWDG_ClearFlag();//清除提前唤醒中断标志位
// WWDG_EnableIT();//开启提前唤醒中断
//
//}
void WWDG_IRQHandler(void)
{
printf("33--CR=%#x--SR=%#x\r\n",WWDG->CR,WWDG->SR);
WWDG->SR &= ~(1<<0);//清除提前唤醒中断标志
printf("44--CR=%#x\r\n",WWDG->CR);
WWDG->CR |= (0X7F<<0);
printf("55--CR=%#x\r\n",WWDG->CR);
}
结尾:
以上是我见解,欢迎在评论区给出自己不同意见。如果对你有帮助的话,麻烦点个赞再走。