STM32学习笔记(九) 外部中断,待机模式和事件唤醒

 学会知识只需要不段的积累和提高,但是如何将知识系统的讲解出来就需要深入的认知和系统的了解。外部中断和事件学习难度并不高,不过涉及到STM32的电源控制部分,还是值得认真了解的,在本文中我将以实际代码为例详细讲解这些内容,希望对每一个阅读者有帮助。

  1.外部中断

如果已经学习了SysTick系统时钟滴答实验,掌握了Cortex-M3中断的相关知识,那么外部中断也是比较好理解的,和SysTick中断一样,外部中断也是当有信号触发时,如果中断屏蔽寄存器允许触发,就会产生中断,这时CPU查找中断向量表,找到入口函数,就会正确的执行相关代码,因为外部中断本身就是依托于普通GPIO口的上升沿或者下降沿信号的,所以本例中以按键作为测试外部中断的硬件电路。

  根据工作原理图:KEY1 ~ PC4;  KEY2 ~ PB10;

          KEY3 ~ PC13;  KEY4 ~ PA0;

       其中KEY1,2,3作为外部中断引脚,KEY4作为唤醒引脚,后续会讲解。

知晓了工作原理图,下面就要确定其对应的中断线号了,这个在参考手册外部中断/事件线路映像章节中有详细的说明,这里截图部分:

   

  从上面可以看出,不同区域的相同位置的管脚共用同一个中断线号,依次类推,上面的四个管脚分别对应的中断线号为EXIT4, EXIT10, EXIT13,EXIT0,在这里还有个注意点:那就是一个中断线号只能反过来对应一个管脚,这就需要设计外部中断硬件电路时不要重复,如PA0和PB0不能同时设计为外部中断。

  了解了这些之后,如果熟悉STM32设计流程的话,那么就知道顺序是:

1.外部中断管脚GPIO初始化,代码如下:

/****************************************************************
* function    : EXTI_GPIO_Config

* Description : 外部中断触发对应GPIO口配置
                KEY1 PC4  外部中断4
                KEY2 PB10 外部中断10
                KEY3 PC13 外部中断13
                KEY4 PA0  WAKEUP唤醒事件

* input       : 无

* output      : 无
*****************************************************************/
void EXTI_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB
                           | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Pin = EXTI_KEY1_Pin;
    GPIO_Init(EXTI_KEY1_Port, &GPIO_InitStructure);
   GPIO_EXTILineConfig(EXTI_KEY1_PortSource, EXTI_KEY1_PinSource);        //将GPIO复用为外部中洞触发端口

    GPIO_InitStructure.GPIO_Pin = EXTI_KEY1_Pin;
    GPIO_Init(EXTI_KEY2_Port, &GPIO_InitStructure);
    GPIO_EXTILineConfig(EXTI_KEY2_PortSource, EXTI_KEY2_PinSource);

    GPIO_InitStructure.GPIO_Pin = EXTI_KEY3_Pin;
    GPIO_Init(EXTI_KEY3_Port, &GPIO_InitStructure);
   GPIO_EXTILineConfig(EXTI_KEY3_PortSource, EXTI_KEY3_PinSource);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_InitStructure.GPIO_Pin = EXTI_KEY4_Pin;
    GPIO_Init(EXTI_KEY4_Port, &GPIO_InitStructure);
   GPIO_EXTILineConfig(EXTI_KEY4_PortSource, EXTI_KEY4_PinSource);
}

2.外设EXTI初始化

3.在中断屏蔽寄存器中允许对应中断触发

/****************************************************************
* function    : EXTI_MODE_Config

* Description : 外部中断触发配置及向量表开启对应中断
                其中KEY1作为中断进入_WFE模式
                KEY2和KEY3作为普通中断点亮对应LED灯
                KEY4作为事件用来唤醒CPU

* input       : 无

* output      : 无
*****************************************************************/
void EXTI_MODE_Config(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    EXTI_DeInit();

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;        //外部按键触发中断
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;    //下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;                  //外部中断使能
    EXTI_InitStructure.EXTI_Line = EXTI_KEY1_Line;             //外部中断线号4
    EXTI_Init(&EXTI_InitStructure);

    EXTI_InitStructure.EXTI_Line = EXTI_KEY2_Line;             //外部中断线号10
    EXTI_Init(&EXTI_InitStructure);

    EXTI_InitStructure.EXTI_Line = EXTI_KEY3_Line;             //外部中断线号13
    EXTI_Init(&EXTI_InitStructure);

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;            //外部按键触发事件
    EXTI_InitStructure.EXTI_Line = EXTI_KEY4_Line;             //外部中断线号0
    EXTI_Init(&EXTI_InitStructure);
    //PWR_WakeUpPinCmd(ENABLE);                                //PA0作为唤醒引脚使能

    NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);               //向量表位于FLASH中,偏移0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    /*在向量表中激活对应的中断线号*/
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI_KEY1_IRQn;
    NVIC_Init(&NVIC_InitStructure);

//    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
//    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
//    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
//    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI_KEY2_3_IRQn;
    NVIC_Init(&NVIC_InitStructure);
}

4.中断函数处理

按键PC4对应外部中断入口,因为按键默认高电平,当有按键按下时,就会产生下降沿信号,触发中断,此时CPU就在中断向量表里查询外部中断的入口地址,如PC4对应的入口地址就是void EXTI4_IRQHandler(void) ,开始执行中断中内容,具体实现流程可参考SysTick章节。

/****************************************************************
* function       : EXTI4_IRQHandler

* Description    : 外部中断4入口函数,实现LED点亮以及系统进入_WFE模式

* input          : 无

* output         : 无
*****************************************************************/
void EXTI4_IRQHandler(void)
{
    led_light_up(0);
    EXTI_ClearFlag(EXTI_Line4);                                      //清除中断线号4
    PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE);    //进入WFE停止低功耗模式 仅事件能唤醒
    SystemInit();                                                    //退出STOP模式要初始化时钟,因为睡眠时切换到内部时钟
    LED1_OFF();
}

在stm32的头文件和启动文件设计中,中断线号10~15共用相同的入口函数,因此需要在中断中进行判断,来确定是那个信号触发了中断。

/****************************************************************
* function       : EXTI15_10_IRQHandler

* Description    : 外部中断10和13共用中断入口,通过触发后状态检查确定
                   触发中断的管脚并执行相应代码。

* input          : 无

* output         : 无
*****************************************************************/
void EXTI15_10_IRQHandler(void)
{
    ITStatus EXTI10_Status;
    ITStatus EXTI13_Status;
    EXTI10_Status = EXTI_GetITStatus(EXTI_Line10);    //获得外部中断10的状态
    EXTI13_Status = EXTI_GetITStatus(EXTI_Line13);     //获得外部中断13的状态
  if(EXTI10_Status == SET)   {     led_light_up(1);   }   if(EXTI13_Status == SET)   {     led_light_up(2);   }  EXTI_ClearFlag(EXTI_Line10 | EXTI_Line13); /*清除外部中断10或者13的挂起位 */ }

外部中断涉及到的知识并并不多,不过仔细观察上面的代码,就会发现KEY4(PA0)并没有配置为中断,而配置为了事件,且被设置为唤醒引脚,KEY1(PC4)在中断里不只点亮了LED,还调用了PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE); 这种功能其实很有用,涉及到低功耗和外部事件唤醒,下面我来详细说明。

    2.外部事件和中断的区别和联系

     外部事件和中断都是由管脚信号触发的,参考下图:

     

  这张图可以很直观的看出中断和事件的区别,当外部有信号输入时,如果通过了了事件屏蔽寄存器,那么事件信号就进入脉冲触发器,引发一个脉冲信号,直接传递给相应的外设,用于触发,这就是一个纯硬件的过程,理解DMA的应该知道,这个方式不需要CPU参与,但是这也有它的缺点,如功能比较单一,仅能提供信号,不能提供信息,也就是只能产生指定功能的事件。如果通过中断屏蔽寄存器,就被直接送到CPU中,产生中断,如进入上面的入口函数开始处理。从这就可看出,事件是单纯硬件触发执行的过程,与CPU本身设计支持有关,而中断中则可以软件实现各种功能,而低功耗模式和事件唤醒就是stm32支持的事件之一。

   3.低功耗模式和事件唤醒

低功耗模式是嵌入式设计用于可移动设备的重要功能,在这种状态下,CPU会关闭时钟,从而降低耗电,延长单次使用时间。

上面进入的就是停机-低功耗-WFE模式,因此只能由按键4事件唤醒。其实低功耗模式还有待机模式以及睡眠模式,这里并没有使用到,以后如果用到会穿插讲解。中断无法唤醒,另外,当CPU退出停止模式时,会强制切换到内部时钟,因此在进入停止模式后一句要加上SystemInit()重新配置系统时钟,避免时钟改变。具体代码参考:http://files.cnblogs.com/files/zc110747/7.EXTI_LED.7z

时间: 2024-10-29 10:45:35

STM32学习笔记(九) 外部中断,待机模式和事件唤醒的相关文章

STM32学习之路-外部中断(2)

OK,继续上篇的内容. 配置好外部中断源以后, 就得使能外部中断线了. 为了方便看再借下这个图: 对外部中断的使能其实就是配置上面这些寄存器.即使能哪EXIT线,选择上面模式,是中断还是事件,选择下降沿还是上升沿. 具体怎么写寄存器这就不研究了, = = 太麻烦了.. 直接用STM32的库就行了,来看看它的代码吧 这是EXTI结构体的初始化函数, void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct) { EXTI_InitStruct->

STM32学习之路-外部中断(1)

今天起得比较晚,又浪费了点时间,真可耻.. 下午又为校赛出了俩题,至此,校赛的四道题目已经完毕.又检查了一番,没有错误,就等待着明天的汇总了~. AC自动机的题目今天就刷了三道,还是没有完成之前的目标.现在vj也进不去了,想通宵,都不给机会~~ 只能等明天再刷完了,拖延不是一个好习惯. ----------------------------------------------------------------------------------------------------------

STM32学习笔记(四)——串口控制LED(中断方式)

目录: 一.时钟使能,包括GPIO的时钟和串口的时钟使能 二.设置引脚复用映射 三.GPIO的初始化配置,注意要设置为复用模式 四.串口参数初始化配置 五.中断分组和中断优先级配置 六.设置串口中断类型并使能串口中断 七.编写中断服务函数函数名格式为函数名格式为 USARTxIRQHandler(x 对应串口号). 八.主函数的实现. 一.时钟使能,包括GPIO的时钟和串口的时钟使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //

STM32学习之路-按键中断测试(外部中断)

终于有时间再来学习STM32了~ 这几天都在忙着该死的考试.直接进入正题 开发板:奋斗V5 这个按键中断测试的要求是:按键2(K2)按下,LED2(V7)亮, 再一次按下就灭,循环.. 好,先看看按键和LED的原理图 好吧~ 虽然图截得不是很好看,但是能看到K2接的是PC2, LED2接的是PD6 ok,剩下的就是配置工作了.. 先来理一理思路: (1)初始化系统时钟 (2)初始化外部时钟(你所用到的东西) (3)配置LED (4)配置中断优先级 (5)配置外部中断线 (6)中断处理函数 恩,差

STM32学习笔记——USART串口(向原子哥和火哥学习)

一.USART简介 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换.USART利用分数波特率发生器提供宽范围的波特率选择. STM32 的串口资源相当丰富的,功能也相当强劲.STM32F103ZET6 最多可提供 5 路串口,有分数波特率发生器,支持同步单向通信和半双工单线通信,支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作.它还允许多处理器通信.

STM32学习笔记6(TIM通用模块生成PWM)

1.     TIMER输出PWM基本概念   脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术.简单一点,就是对脉冲宽度的控制.一般用来控制步进电机的速度等等. STM32的定时器除了TIM6和TIM7之外,其他的定时器都可以用来产生PWM输出,其中高级定时器TIM1和TIM8可以同时产生7路的PWM输出,而通用定时器也能同时产生4路的PWM输出. 1.1   PWM输出模式 S

STM32学习笔记4(TIM32位定时器的实现)

关于STM32的CPU为32位,定时器却为16位的探讨 STM32的通用定时器可以实现很多功能,例如:定时计数.测量外部信号脉冲宽度.产生PWM波形.测量输入的PWM波形等.在所有这些操作中,定时器的位数主要影响两个参数,一个是定时或测量的精度,另一个是定时的时间长度.下面我们以一个列表看一下定时的精度和定时的长度有多少: 关于各个预分频器的作用请参考下图的右半部分: 从表中可以看出,在最高精度下(14ns)定时长度只有0.91ms,在精度为250ns(即4MHz)时定时长度可达16.38ms.

STM32学习笔记1(ADC多通道采样)

STM32 ADC多通道转换描述:用ADC连续采集11路模拟信号,并由DMA传输到内存.ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ.在每次转换结束后,由DMA循环将转换的数据传输到内存中.ADC可以连续采集N次求平均值.最后通过串口传输出最后转换的结果.程序如下:#i nclude "stm32f10x.h" //这个头文件包括STM32F10x所有外围寄存器.位.内存映射的定义#i nclude "eval.h" //头文件(包括串口.按键.L

STM32学习笔记2(TIM模块定时器)

TIM模块定时器向上溢出 & 输出比较 首先我们必须肯定ST公司的实力,也承认STM32的确是一款非常不错的Cortex-M3核单片机,但是,他的手册实在是让人觉得无法理解,尤其是其中的TIM模块,没有条理可言,看了两天几乎还是不知所云,让人很是郁闷.同时配套的固件库的说明也很难和手册上的寄存器对应起来,研究起来非常费劲!功能强大倒是真的,但至少也应该配套一个让人看的明白的说明吧~~两天时间研究了STM32定时器的最最基础的部分,把定时器最基础的两个功能实现了,余下的功能有待继续学习.首先有一点