STM32外部中断与看门狗

STM32外部中断与看门狗

前面说过中断的概念了,但是没有细究,中断除了内部中断(比如运行错误),还能受到外部中断



一 外部中断描述

1.1 外部中断描述

在这里插入图片描述16个中断线如下:
理论上
在这里插入图片描述
对于这16根中断线(EXTIX名)触发中断可以设置上升沿触发,下降沿触发,边沿触发)以及使能
但是控制着16根线的只有7个终端服务函数
在这里插入图片描述具体对应7个终端服务函数

EXTI0_IRQHandler           
EXTI1_IRQHandler
EXTI2_IRQHandler           
EXTI3_IRQHandler           
EXTI4_IRQHandler           
EXTI9_5_IRQHandler         
EXTI15_10_IRQHandler     

在实际代码中外部中断常用的库函数为:

①void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
   //设置IO口与中断线的映射关系

   exp:  GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);

②void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
 //采用结构体初始化中断线:触发方式等

③ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//判断中断线中断状态,是否发生

④void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//清除中断线上的中断标志位

解释一下这里为什么要花这么大的篇幅写这个,类比USART里面自带有中断服务函数USART1_IRQHandler(),外部触发中断因为引脚多但服务函数少。所以定义中断是有限制的。比方说在EXT8和EXT9两根线上想触发中断,但是只有一个中断服务函数(也就意味着会触发同一个中断函数)。如果没有区分这两个中断那没事反正执行的是同一个中断函数,但是如果想让这两个中断执行不同的中断函数,显然是不合理的。因此在设计上要注意这块。尽量设计外部中断分开在7个中断服务函数中。

1.2 代码

EXTI_Init函数其中结构体如下:
typedef struct
{
  uint32_t EXTI_Line;   //指定要配置的中断线           
  EXTIMode_TypeDef EXTI_Mode;   //模式:事件 OR中断
  EXTITrigger_TypeDef EXTI_Trigger;//触发方式:上升沿/下降沿/双沿触发
  FunctionalState EXTI_LineCmd;  //使能 OR失能
}EXTI_InitTypeDef;

很自然而然的结构体初始化,就不细说了
值得注意的是在USART串口中断函数USART1_IRQHandler()这是一个固件库事先定义好名字的但内部未定义函数,外部中断也有和它相似的地方。
外部中断一般配置步骤:

  1.初始化IO口为输入。
              GPIO_Init();
       2.开启IO口复用时钟。
              RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
       3.设置IO口与中断线的映射关系。
               void GPIO_EXTILineConfig();
       4.初始化线上中断,设置触发条件等。
              EXTI_Init();
       5.配置中断分组(NVIC),并使能中断。
              NVIC_Init();
       6. 编写中断服务函数(就体现出上面写的7个中断函数的作用了)。
             EXTIx_IRQHandler();
       7.清除中断标志位(好像该位不能自动回复)
             EXTI_ClearITPendingBit();

在实际代码中:有三个按键可以控制串口实现外部中断(mini),所以mini的代码设计的就是这三个引脚来触发按键实现外部中断
在这里插入图片描述


二 、看门狗实验

简单来说看门狗就是一种定时器,不过主要用于检测系统运行时间(不正常时间就会超,就会触发中断),独立看门狗限制喂狗时间在0-x内,x由相关寄存器决定。喂狗的时间不能过晚。

2.1 独立看门狗概述:

在这里插入图片描述在这里插入图片描述
看门狗功能和四个寄存器有关

键值寄存器IWDG_KR: 0~15位有效,可以取消下面的写保护
预分频寄存器IWDG_PR:0~2位有效。具有写保护功能,要操作先取消写保护
重装载寄存器IWDG_RLR:0~11位有效。具有写保护功能,要操作先取消写保护。
状态寄存器IWDG_SR:0~1位有效

在这里插入图片描述
IWDG_PR和外部低俗时钟分频有关系
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 独立看门狗的设置

看门狗这块设置如下:

void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//取消写保护:0x5555使能
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//设置预分频系数:写PR
void IWDG_SetReload(uint16_t Reload);//设置重装载值:写RLR
void IWDG_ReloadCounter(void);//喂狗:写0xAAAA到KR
void IWDG_Enable(void);//使能看门狗:写0xCCCC到KR

FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);//状态:重装载/预分频 更新
在代码中仅仅需要调用:

 1.取消寄存器写保护:
      IWDG_WriteAccessCmd();
2.设置独立看门狗的预分频系数,确定时钟:
     IWDG_SetPrescaler();
3.设置看门狗重装载值,确定溢出时间:
    IWDG_SetReload();
4.使能看门狗
    IWDG_Enable();
5.应用程序喂狗(不能和上面放在一块):
   IWDG_ReloadCounter();

注意;溢出时间计算:

   Tout=((4×2^prer) ×rlr) /40 (M3)

比方说:预分频是64,重载数值是625,那么根据公式42^4625/40就是1000,也就是1秒

代码中没有按键就意味着喂狗没及时。会重启系统(小灯会重启在灭再亮)

2.3 窗口看门狗

窗口看门狗就是说喂狗时间是一个有上下限的范围内(窗口),你可以通过设定相关寄存器,设定其上限时间(下限固定)。喂狗的时间不能过早也不能过晚。(类似阳台上不断蹦跶的狗,够到窗口才能吃饭。)
在这里插入图片描述
窗口看门狗比较复杂,建议看看这篇博客https://www.cnblogs.com/firege/p/5805947.html

计数器

窗口看门狗的计数器是一个递减计数器,共有7位,也是图中左侧线段最高的一点,其值存在控制寄存器CR的位6:0,即T[6:0],当7个位全部为1时是0X7F,这个是最大值,当递减到T6位变成0时,即从0X40变为0X3F时候,会产生看门狗复位。这个值0X40是看门狗能够递减到的最小值,所以计数器的值只能是:0X40~0X7F之间,实际上用来计数的是T[5:0]。当递减计数器递减到0X40的时候,还不会马上产生复位,如果使能了提前唤醒中断:CFR位9 EWI 置1,则产生提前唤醒中断,如果真进入了这个中断的话,就说明程序肯定是出问题了
。那么在中断服务程序里面我们就需要做最重要的工作,比如保存重要数据,或者报警等,这个中断我们也叫它死前中断。

窗口值

我们知道窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是固定的0X40,上窗口的值可以改变,具体的由配置寄存器CFR的位6:0 W[6:0]设置。其值必须大于0X40,如果小鱼或者等于0X40就是失去了窗口的价值,而且也不能大于计数器的值,所以必须得小于0X7F。那窗口值具体要设置成多大?这个得根据我们需要监控的程序的运行时间来决定。如果我们要监控的程序段A运行的时间为Ta,当执行完这段程序之后就要进入窗口期间进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。

一般计数器的值TR设置成最大0X7F,窗口值为WR,计数器减一个数的时间为T,那么时间:(TR-WR)*T应该稍微大于Ta即可,这样就能做到刚执行完程序段A之后喂狗,起到监控的作用,这样也就可以算出WR的值是多少。
所以实际上我们设置的有两个参数(一个是计数(最大0X7F最小0X40)),另一个是窗口的上限

STM32F的窗口看门狗中有一个7位的递减计数器T[6:0],它会在出现下述2种情况之一时产生看门狗复位(可以不用自己喂狗):
1.当喂狗的时候如果计数器的值大于设定数值W[6:0]时,此设定数值在WWDG_CFR寄存器定义。

2.当计数器的数值从0x40减到0x3F时【此时T6位跳变到0】(窗口下限会自己复位然后喂狗) 。
如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于自己喂狗以避免WWDG复位
在这里插入图片描述

总结:

这里在理一下思路(脑瓜已经乱了)
也就是说我们真正要设置窗口看门狗的其实就两个数值

1是看门狗的上限,也叫窗口 W[6:0]
2是需要定时的一个counter(也就是上限) T[5:0]

之后都是一些概念上的问题:

超时时间(这个超时时间表示运行代码后开启窗口看门狗,开始减数,多久会触发复位(减到0X40))

最小时间: T6设置为1,后几位都设为0。递减计数器再减一次,就产生复位了,我们在设置WDGTB=0.那这减一的时间就等于计数器的周期=1/CNT_CK = Tpclk1 * 4096 * (2^WDGTB) = 1/30 * 4096 *2^0 = 136.53us,这个就是最短的超时时间

最大时间:如果T[5:0]全部装满为1,即63,当他减到0X40变成0X3F时,所需的时间就是最大的超时时间=113.72^5 (2^WDGTB)=136.5364 (2^WDGTB)=8.74* (2^WDGTB)ms。

同理,当WDGTB等于1/2/3时,代入公式即可。

 使能看门狗时钟:
     RCC_APB1PeriphClockCmd();
设置分频系数:
     WWDG_SetPrescaler();
设置上窗口值:
     WWDG_SetWindowValue();
开启提前唤醒中断并分组(可选)WWDG_EnableIT();   
     NVIC_Init();
使能看门狗:
     WWDG_Enable();
喂狗:
    WWDG_SetCounter();
编写中断服务函数
   WWDG_IRQHandler();

代码

在主函数定义的窗口看门狗

WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);   

定义如下

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{ 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //时钟使能
	WWDG_SetPrescaler(fprer);设置IWDG预分频
	WWDG_SetWindowValue(wr);//设置窗口值
	WWDG_Enable(tr);	 //是能看门狗   并设置计数值            
	WWDG_ClearFlag();
	WWDG_NVIC_Init();/、初始化看门狗
	WWDG_EnableIT(); //看门狗中断
} 

可能还需要配置一下喂狗、初始化、重载数值的操作就不细说了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值