EXTI外部中断和看门狗实验 IO口外部中断:
①STM32的每个IO都可以作为外部中断输入。
②每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位。
GPIO和中断线映射关系:
外部中断线59分配一个中断向量,共用一个服务函数外部中断线1015分配一个中断向量,共用一个中断服务函数。
13
可设置
EXTI0
EXTI线0中断
14
可设置
EXTI1
EXTI线1中断
14
可设置
EXTI2
EXTI线2中断
16
可设置
EXTI3
EXTI线3中断
17
可设置
EXTI4
EXTI线4中断
30
可设置
EXTI9_5
EXTI线[9:5]中断
47
可设置
EXTI15_10
EXTI线[15:10]中断
外部中断配置 :
外部中断的中断线映射配置和触发方式都是在GPIO初始化函数中完成:
1 2 3 4 5 GPIO_InitTypeDef GPIO_Initure; GPIO_Initure.Pin=GPIO_PIN_0; GPIO_Initure.Mode=GPIO_MODE_IT_RISING; GPIO_Initure.Pull=GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA,&GPIO_Initure);
和串口中断一样,HAL库同样提供了外部中断通用处理函数HAL_GPIO_EXTI_IRQHandler,我们在外部中断服务函数中会调用该函数处理中断。
1 2 3 4 5 6 7 8 9 10 void EXTI0_IRQHandler (void ) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); } void EXTI2_IRQHandler (void ) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); }
外部中断的一般配置步骤 :
① 使能IO口时钟。
② 初始化IO口,设置触发方式:HAL_GPIO_Init();
③ 设置中断优先级,并使能中断通道。
④ 编写中断服务函数:
函数中调用外部中断通用处理函数HAL_GPIO_EXTI_IRQHandler。
⑥ 编写外部中断回调函数:HAL_GPIO_EXTI_Callback;
外部中断实验exti.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 #include "exti.h" #include "led.h" #include "delay.h" #include "key.h" void EXTI_Init (void ) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); GPIO_Initure.Pin=GPIO_PIN_0; GPIO_Initure.Mode=GPIO_MODE_IT_RISING; GPIO_Initure.Pull=GPIO_PULLDOWN; GPIO_Initure.Speed=GPIO_SPEED_HIGH; HAL_GPIO_Init(GPIOA,&GPIO_Initure); GPIO_Initure.Pin=GPIO_PIN_13; GPIO_Initure.Mode=GPIO_MODE_IT_FALLING; GPIO_Initure.Pull=GPIO_PULLUP; GPIO_Initure.Speed=GPIO_SPEED_HIGH; HAL_GPIO_Init(GPIOC,&GPIO_Initure); GPIO_Initure.Pin=GPIO_PIN_2|GPIO_PIN_3; HAL_GPIO_Init(GPIOH,&GPIO_Initure); HAL_NVIC_EnableIRQ(EXTI0_IRQn); HAL_NVIC_SetPriority(EXTI0_IRQn,2 ,0 ); HAL_NVIC_EnableIRQ(EXTI2_IRQn); HAL_NVIC_SetPriority(EXTI2_IRQn,2 ,1 ); HAL_NVIC_EnableIRQ(EXTI3_IRQn); HAL_NVIC_SetPriority(EXTI3_IRQn,2 ,2 ); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); HAL_NVIC_SetPriority(EXTI15_10_IRQn,2 ,3 ); } void EXTI0_IRQHandler (void ) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); } void EXTI2_IRQHandler (void ) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); } void EXTI3_IRQHandler (void ) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); } void EXTI15_10_IRQHandler (void ) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); } void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) { delay_ms(100 ); switch (GPIO_Pin) { case GPIO_PIN_0: if (WK_UP==0 ) { LED1=!LED1; LED0=!LED1; break ; } case GPIO_PIN_2: if (KEY1==0 ) { LED1=!LED1; break ; } case GPIO_PIN_3: if (KEY0==0 ) { LED0=!LED0; LED1=!LED1; break ; } case GPIO_PIN_13: if (KEY2==0 ) { LED0=!LED0; break ; } } }
独立看门狗 在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) 。 在系统跑飞(程序异常执行)的情况,使系统复位,程序重新执行。
独立看门狗工作原理 在键值寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗。此时计数器开始从其复位值0xFFF递减,当计数器值计数到尾值0x000时会产生一个复位信号(IWDG_RESET)。
无论何时,只要在键值寄存器IWDG_KR中写入0xAAAA(通常说的喂狗), 自动重装载寄存器IWDG_RLR的值就会重新加载到计数器,从而避免看门狗复位。
如果程序异常,就无法正常喂狗,从而系统复位。
独立看门狗超时时间 溢出时间计算:
Tout=((4×2^prer) ×rlr) /32 (M4) prer 预分频系数 rlr 重装载值
独立看门狗寄存器 ① IWDG_KR:键值寄存器,0~15位有效
② IWDG_PR:预分频寄存器,0~2位有效。
具有写保护功能,要操作先取消写保护
③ IWDG_RLR:重装载寄存器,0~11位有效。
具有写保护功能,要操作先取消写保护。
④ IWDG_SR:状态寄存器,0~1位有效
独立看门狗操作步骤 ①初始化看门狗:预分频系数,重装载值。
1 HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 typedef struct { IWDG_TypeDef *Instance; IWDG_InitTypeDef Init; HAL_LockTypeDef Lock; __IO HAL_IWDG_StateTypeDef State; }IWDG_HandleTypeDef; typedef struct { uint32_t Prescaler; uint32_t Reload; }IWDG_InitTypeDef;
该函数在操作PR和RLR寄存器之前会取消
写保护。
②独立看门狗初始化回调函数
1 void HAL_IWDG_MspInit (IWDG_HandleTypeDef *hiwdg) ;
③启动看门狗
1 HAL_IWDG_Start(IWDG_HandleTypeDef *hiwdg);
④喂狗:
1 HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);
(获取状态)
1 2 3 4 5 6 7 8 9 10 HAL_IWDG_StateTypeDef HAL_IWDG_GetState (IWDG_HandleTypeDef *hiwdg) ;typedef enum { HAL_IWDG_STATE_RESET = 0x00 , HAL_IWDG_STATE_READY = 0x01 , HAL_IWDG_STATE_BUSY = 0x02 , HAL_IWDG_STATE_TIMEOUT = 0x03 , HAL_IWDG_STATE_ERROR = 0x04 }HAL_IWDG_StateTypeDef;
独立看门狗实验程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "key.h" IWDG_HandleTypeDef iwdg_handler; int main (void ) { HAL_Init(); Stm32_Clock_Init(360 ,25 ,2 ,8 ); delay_init(180 ); uart_init(115200 ); LED_Init(); KEY_Init(); delay_ms(100 ); iwdg_handler.Instance=IWDG; iwdg_handler.Init.Prescaler=IWDG_PRESCALER_64; iwdg_handler.Init.Reload=500 ; HAL_IWDG_Init(&iwdg_handler); HAL_IWDG_Start(&iwdg_handler); LED0=0 ; while (1 ) { if (KEY_Scan(0 )==WKUP_PRES) { HAL_IWDG_Refresh(&iwdg_handler); } delay_ms(10 ); } }
窗口看门狗 之所以称为窗口就是因为其喂狗时间是一个有上下限的范围内(窗口),你可以通过设定相关寄存器,设定其上限时间(下限固定)。喂狗的时间不能过早也不能过晚。
而独立看门狗限制喂狗时间在0-x内,x由相关寄存器决定。喂狗的时间不能过晚。
窗口看门狗工作过程 STM32F的窗口看门狗中有一个7位的递减计数器T[6:0],它会在出现下述2种情况之一时产生看门狗复位:
①当喂狗的时候如果计数器的值大于某一设定数值W[6:0]时,此设定数值在WWDG_CFR寄存器定义。
② 当计数器的数值从0x40减到0x3F时【T6位跳变到0】。
如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于喂狗以避免WWDG复位。
窗口看门狗超时时间 窗口看门狗的超时公式如下
Twwdg=(4096✖2^WDGTB✖(T[5:0]+1))/Fpclk1
Twwdg: WWDG超时时间单位为ms
Fpclk1: APB1的时钟频率单位为Khz
WDGTB:WWDG的预分频系数
T[5:0]: 窗口看门狗的计数器低6位
窗口看门狗配置过程 ①使能窗口看门狗时钟:
HAL_WWDG_MspInit;
② 初始化窗口看门狗:设置分频系数,窗口值,计数值等。
HAL_WWDG_Init();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 typedef struct { WWDG_TypeDef *Instance; WWDG_InitTypeDef Init; HAL_LockTypeDef Lock; __IO HAL_WWDG_StateTypeDef State; }WWDG_HandleTypeDef; typedef struct { uint32_t Prescaler; uint32_t Window; uint32_t Counter; }WWDG_InitTypeDef;
该函数还可以使能窗口看门狗提前唤醒中断 。
③ 设置提前唤醒中断优先级:
HAL_WWDG_MspInit
④ 启动看门狗
HAL_WWDG_Start()
HAL_WWDG_Start_IT() 还开启了提前唤醒中断
⑤ 喂狗:
HAL_WWDG_Refresh();
⑥ 编写提前唤醒中断处理函数
中断处理函数
HAL_WWDG_IRQHandler()
提前唤醒回调函数
HAL_WWDG_EarlyWakeupCallback()
窗口看门狗源程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "key.h" WWDG_HandleTypeDef wwdg_handler; void HAL_WWDG_MspInit (WWDG_HandleTypeDef *hwwdg) { __HAL_RCC_WWDG_CLK_ENABLE(); HAL_NVIC_EnableIRQ(WWDG_IRQn); HAL_NVIC_SetPriority(WWDG_IRQn,2 ,3 ); } void WWDG_IRQHandler (void ) { HAL_WWDG_IRQHandler(&wwdg_handler); } void HAL_WWDG_WakeupCallback (WWDG_HandleTypeDef *hwwdg) { HAL_WWDG_Refresh(&wwdg_handler,0x7f ); LED1=!LED1; } int main (void ) { HAL_Init(); Stm32_Clock_Init(360 ,25 ,2 ,8 ); delay_init(180 ); uart_init(115200 ); LED_Init(); KEY_Init(); LED0=0 ; delay_ms(300 ); wwdg_handler.Instance=WWDG; wwdg_handler.Init.Prescaler=WWDG_PRESCALER_8; wwdg_handler.Init.Window=0x5f ; wwdg_handler.Init.Counter=0x7f ; HAL_WWDG_Init(&wwdg_handler); HAL_WWDG_Start_IT(&wwdg_handler); while (1 ) { LED0=1 ; } }