STM32学习笔记5---外部中断、看门狗

外部中断与看门狗

外部中断**

外部中断的代码主要在stm32f10x_exti.h 和 stm32f10x_exti.c 文件中。

STM32的每个IO口都可以作为外部中断的输入口,F103支持19个中断/事件请求。

线0~15对应外部IO口。

线16:连接到PVD输出。

线17:连接到RTC闹钟时间。

线18:连接到唤醒USB事件。

GPIO与中断线的映射关系是:每个IO口的16根线都和外部中断的16根线相连接,从而将16个中断线与每个IO口相对应。设置函数为GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);GPIOE.2 与 EXTI2 中断线连接了。

外部中断线的初始化:

typedef struct		//需要定义的初始化参数结构体
{
 uint32_t EXTI_Line; //中断线标号
 EXTIMode_TypeDef EXTI_Mode;  //中断模式
 EXTITrigger_TypeDef EXTI_Trigger;    //触发方式
 FunctionalState EXTI_LineCmd; //使能
}EXTI_InitTypeDef;

中断模式有EXTI_Mode_Interrupt 和事件 EXTI_Mode_Event。
触发方式有三种下降沿触发 EXTI_Trigger_Falling,上升沿触发 EXTI_Trigger_Rising,或者任意电平(上升沿和下降沿)触发
EXTI_Trigger_Rising_Falling。

初始化完成之后要设置NVIC的中断优先级,之后就是写中断服务函数,外部中断函数定义只有6个。

EXTI0_IRQHandler
EXPORT EXTI1_IRQHandler
EXPORT EXTI2_IRQHandler
EXPORT EXTI3_IRQHandler
EXPORT EXTI4_IRQHandler
EXPORT EXTI9_5_IRQHandler
EXPORT EXTI15_10_IRQHandler
中断线0-4每个对应一个中断函数,中断线5-9共用EXTI9_5_IRQHandler ,中断线 10-15 共用中断函数 EXTI15_10_IRQHandler。

EXTI_GetITStatus(uint32_t EXTI_Line);//用于判断某个中断线上的中断是否发生
EXTI_ClearITPendingBit(uint32_t EXTI_Line);//用于清除某个线上的中断标志位。

使用 IO 口外部中断的一般步骤:
1)初始化 IO 口为输入。
2)开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。
3)初始化线上中断,设置触发条件等。
4)配置中断分组(NVIC),并使能中断。
5)编写中断服务函数。
通过以上几个步骤的设置,我们就可以正常使用外部中断了。

实例:

void EXTIX_Init(void)
{
 EXTI_InitTypeDef EXTI_InitStructure;
 NVIC_InitTypeDef NVIC_InitStructure;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能 AFIO 时钟
 KEY_Init();//初始化OI口对应 io 模式
 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5//GPIOC.5 中断初始化配置
 EXTI_InitStructure.EXTI_Line=EXTI_Line5;
 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
 EXTI_Init(&EXTI_InitStructure);//根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器

 NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//使能按键所在的外部中断通道
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2 
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级 
 1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道 
 NVIC_Init(&NVIC_InitStructure); //根据 NVIC_InitStruct 中指定的参数初始化外设 NVIC 寄存器
}

看门狗WDG

独立看门狗:独立看门狗由40KHz的低速时钟来驱动,时钟不是很精确但是看门狗的要求不高,所以可以用40KHz来估算。

几个关键寄存器:IWDG_KR、IWDGPR 和 IWDGRLR 寄存器。

IWDG_KR为只写寄存器,软件必须在一定的时间间隔写入0xAAAA,否则计数器为零时看门狗会产生复位,写入0xCCCC,启动软件看门狗,写入 0x5555表示允许访问IWDG_PR 和 IWDG_RLR 寄存器;

预分频寄存器(IWDG_PR),该寄存器用来设置看门狗时钟的分频系数;最低为4,最高为256

重装载寄存器(IWDG_RLR),当IWDG_KR被写入0xAAAA时,该寄存器的值会送入到计时器中。

递减计数器计数到末尾会产生一个复位信号。

配置独立看门狗:

库函数文件在stm32f10x_iwdg.h 和stm32f10x_iwdg.c 中

1)取消寄存器写保护(向 IWDGKR 写入-0X5555IWDG_WriteAccessCm(IWDG_WriteAccess_Enable);

2)设置独立看门狗的预分频系数和重装载值
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler); //设置 IWDG 预分频值
void IWDG_SetReload(uint16_t Reload); //设置 IWDG 重装载值

喂狗时间计算公式为Tout=((4×2^prer) ×rlr) /40;
Tout 为看门狗溢出时间(单位为 ms);
prer 为看门狗时钟预分频值(IWDG_PR 值),范围为 0~7;
rlr 为看门狗的重装载值(IWDG_RLR 的值);

3)重载计数值喂狗(向 IWDG_KR 写入 0XAAAA)库函数里面重载计数值的函数IWDGReloadCounter(); //按照 IWDG 重装载寄存器的值重装载 IWDG 计数器

  1. 启动看门狗(向 IWDG_KR 写入 0XCCCC),库函数里面启动独立看门狗的函数是:IWDG_Enable(); //使能 IWDG

实例

void IWDG_Init(u8 prer,u16 rlr) 
{IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对寄存器 IWDG_PR和IWDG_RLR 的写操作
 IWDGSetPrescaler(prer); //设置 IWDG 预分频值:设置 IWDG 预分频值
 IWDG_SetReload(rlr); //设置 IWDG 重装载值
 IWDG_ReloadCounter(); //按照 IWDG 重装载寄寄存器的值重装载 IWDG 计数器
 IWDG_Enable(); //使能 IWDG
}
void IWDG_Feed(void)//喂独立看门狗
{
    IWDG->KR=0XAAAA;//reload
} 

窗口看门狗

窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。

WWDG->CR 的6~0位(T[6:0])为窗口看门狗的递减计数器,如果在递减计数器变成0x40之前没有被刷新,则会产生一个MCU复位信号。另外,如果递减计数器达到窗口配置寄存器(WWDG->CFR)数值之前,递减计数器被刷新,也会产生一个复位信号。所以很明显的可以发现0x40是下窗口,配置寄存器是上窗口。只有在这段时间内刷新计时器才不会产生复位信号。

WWDG_CR:第七位(WDGA)为看门狗激活位,剩下的七位是递减计数器。

WWDG_CFR:第九位中断标志位,该位置1则当计数器值位0x40是产生中断。此中断只能由硬件复位后清除。位8和位7可以设置时钟的预分频系数1/2/4/8,后7位用来设置与计数器进行比较的值。

WWDG_SR:只有位0有效,当计数器值位0x40时此位由硬件置1,必须通过软件写0来清除。

窗口看门狗的超时公式如下: Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk Twwdg:WWDG 超时时间(单位为 ms)
Fpclk1:APB1 的时钟频率(单位为 Khz)
WDGTB:WWDG 的预分频系数
T[5:0]:窗口看门狗的计数器低 6 位

递减计数器达到0x40后在超时时间内刷新计时器是可以避免产生复位。

窗口看门狗使用方法:

1)使能 WWDG 时钟
RCCAPB1PeriphClockCmd(RCCAPB1PeriphWWDG, ENABLE);//使能,WWDG使用的是 PCLK1 的时钟

2)设置窗口值和分频系数
设置窗口值的函数是:void WWDG_SetWindowValue(uint8_t WindowValue);
设置分频数的函数是:void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);

3)开启 WWDG 中断并分组:WWDGEnableIT(); //开启窗口看门狗并设置NVIC。

4)设置计数器初始值并使能看门狗void WWDG_Enable(uint8_t Counter

5)编写中断服务函数:函数中要喂狗并要将状态寄存器清空。//个人感觉配置寄存器中的中断位是通过查询查询状态位来产生中断的。

实例:

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{ 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); 
// WWDG 时钟使能
WWDG_SetPrescaler(fprer);设置 WWDG 预分频值
WWDG_SetWindowValue(wr);//设置窗口值
WWDG_Enable(tr); //使能看门狗 , 设置 counter . 
WWDG_ClearFlag();
WWDG_NVIC_Init();//初始化窗口看门狗 NVIC
WWDG_EnableIT(); //开启窗口看门狗中断
} 
//重设置 WWDG 计数器的值
void WWDG_Set_Counter(u8 cnt)
{
 WWDG_Enable(cnt);
}
//窗口看门狗中断服务程序
void WWDG_NVIC_Init()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占 2 子优先级 3 组 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //抢占 2,子优先级 3,组 2
NVIC_Init(&NVIC_InitStructure);//NVIC 初始化
}
void WWDG_IRQHandler(void)
{
// Update WWDG counter
WWDG_SetCounter(0x7F); //当禁掉此句后,窗口看门狗将产生复位
// Clear EWI flag */
WWDG_ClearFlag(); //清除提前唤醒中断标志位
// Toggle GPIO_Led pin 7 */
LED1=!LED1;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值