STM32学习笔记:外部中断的使用

STM32中,每一个GPIO都可以触发一个外部 中断 ,但是,GPIO的中断是以组位一个单位的,同组间的外部 中断 同一时间只能使用一个。比如说,PA0,PB0,PC0,PD0,PE0,PF0,PG0这些为1组,如果我们使用PA0作为外部中断源,那么别的就不能够再使用了,在此情况下,我们智能使用类似于PB1,PC2这种末端序号不同的外部中断源。每一组使用一个中断标志EXTIx。EXTI0 – EXTI4这5个外部中断有着自己的单独的中断响应函数,EXTI5-9共用一个中断响应函数,EXTI10-15共用一个中断响应函数。

对于中断的控制,STM32有一个专用的管理机构:NVIC。对于NVIC的详细解释,可以参考《ARM Cortex-M3权威指南》,Joseph Yiu著,宋岩译,北京航空航天大学出版社出版,第8章NVIC与中断控制。中断的使能,挂起,优先级,活动等等部都是NVIC在管理的。因为我学习STM32重点在于如何开发程序,所以内部的一些东西,在此我就不详细说明了,有感兴趣的可以参看上面提到的那本数。

程序开发
其实上面那些基本概念和知识只是对STM32的中断系统有一个大概的认识,用程序说话将会更能够加深如何使用中断。使用 外部中断 的基本步骤如下:
1.设置好相应的时钟;
2.设置相应的中断;
3.IO口初始化;
4.把相应的IO口设置为中断线路(要在设置外部中断之前)并初始化;
5.在选择的中断通道的响应函数中中断函数。

由于我用的奋斗开发板没有引出相应的芯片引脚,所以只能用按键来触发相应的中断。根据原理图,K1/K2/K3连接的是PC5/PC2/PC3,因此我将用EXTI5/EXTI2/EXTI3三个外部中断。PB5/PD6/PD3分别连接了三个LED灯。中断的效果是按下按键,相应的LED灯将会被点亮。
1.设置相应的时钟
首先需要打开GPIOB、GPIOC和GPIOE(因为按键另外一端连接的是PE口)。然后由于是要用于触发中断,所以还需要打开GPIO复用的时钟。相应的函数在GPIO的学习笔记中有了详细了解释。详细代码如下:

  1. void RCC_cfg()
  2. {
  3.        //打开PE PD PC PB端口时钟,并且打开复用时钟
  4.        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
  5. }
复制代码

    设置相应的时钟所需要的RCC函数在stm32f10x_rcc.c中,所以要在工程中添加此文件。

2.设置好相应的中断
设置相应的中断实际上就是设置NVIC,在STM32的固件库中有一个结构体NVIC_InitTypeDef,里面有相应的标志位设置,然后再用NVIC_Init()函数进行初始化。详细代码如下:
  1. void NVIC_cfg()
  2. {
  3.         NVIC_InitTypeDef NVIC_InitStructure;
  4.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                          //选择中断分组2
  5.         
  6.         
  7. NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel;     //选择中断通道2
  8. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置为0
  9.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //响应式中断优先级设置为0
  10.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                   //使能中断
  11.         NVIC_Init(&NVIC_InitStructure);
  12.         
  13.         NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQChannel;            //选择中断通道3
  14.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占式中断优先级设置为1
  15.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  //响应式中断优先级设置为1
  16.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                   //使能中断
  17.         NVIC_Init(&NVIC_InitStructure);
  18.         
  19.         NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;  //选择中断通道5
  20.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占式中断优先级设置为2
  21.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //响应式中断优先级设置为2
  22.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                   //使能中断
  23.         NVIC_Init(&NVIC_InitStructure);
  24. }
复制代码

由于有3个中断,因此根据前文所述,需要有3个bit来指定抢占优先级,所以选择第2组。又由于EXTI5-9共用一个中断响应函数,所以EXTI5选择的中断通道是EXTI9_5_IRQChannel,详细信息可以在头文件中查询得到。用到的NVIC相关的库函数在stm32f10x_nivc.c中,需要将此文件复制并添加到工程中。具体位置可以查看关于GPIO的笔记。这段代码编译起来没有任何问题,但是在链接的时候就会报错,需要把STM32F10xR.LIB加入工程中,具体位置在…KeilARMRV31LIBSTSTM32F10xR.LIB。

3.IO口初始化
  1. void IO_cfg()
  2. {
  3.        GPIO_InitTypeDef GPIO_InitStructure;
  4.       
  5.        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;                                             //选择引脚2
  6.        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;           //输出频率最大50MHz
  7.       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //带上拉电阻输出
  8.        GPIO_Init(GPIOE,&GPIO_InitStructure);
  9.        GPIO_ResetBits(GPIOE,GPIO_Pin_2);                              //将PE.2引脚设置为低电平输出
  10.       
  11.        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5; //选择引脚2 3 5
  12.        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //选择输入模式为浮空输入
  13.        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;          //输出频率最大50MHz
  14.        GPIO_Init(GPIOC,&GPIO_InitStructure);                                 //设置PC.2/PC.3/PC.5
  15.       
  16.       
  17.        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6;                  //选择引脚3 6
  18.        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;           //输出频率最大50MHz
  19.       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //带上拉电阻输出
  20.        GPIO_Init(GPIOD,&GPIO_InitStructure);
  21.       
  22.       
  23.        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                                         //选择引脚5
  24.        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;          //输出频率最大50MHz
  25.       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //带上拉电阻输出
  26.        GPIO_Init(GPIOB,&GPIO_InitStructure);        
  27. }
复制代码

其中连接外部中断的引脚需要设置为输入状态,而连接LED的引脚需要设置为输出状态,初始化PE.2是为了使得按键的另外一端输出低电平。GPIO中的函数在stm32f10x_gpio.c中。

4.把相应的IO口设置为中断线路
由于GPIO并不是专用的中断引脚,因此在用GPIO来触发外部中断的时候需要设置将GPIO相应的引脚和中断线连接起来,具体代码如下:
  1. void EXTI_cfg()
  2. {
  3.        EXTI_InitTypeDef EXTI_InitStructure;
  4.        //清空中断标志
  5.        EXTI_ClearITPendingBit(EXTI_Line2);
  6.        EXTI_ClearITPendingBit(EXTI_Line3);
  7.        EXTI_ClearITPendingBit(EXTI_Line5);
  8.        //选择中断管脚PC.2 PC.3 PC.5
  9.        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2);
  10.        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource3);
  11.        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5);
  12.        EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line5; //选择中断线路2 3 5
  13.        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置为中断请求,非事件请求
  14.        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //设置中断触发方式为上下降沿触发
  15.        EXTI_InitStructure.EXTI_LineCmd = ENABLE;                           //外部中断使能
  16.       EXTI_Init(&EXTI_InitStructure);
  17. }
复制代码


EXTI_cfg中需要调用到的函数都在stm32f10x_exti.c。

5.写中断响应函数
STM32不像C51单片机那样,可以用过interrupt关键字来定义中断响应函数,STM32的中断响应函数接口存在中断向量表中,是由启动代码给出的。默认的中断响应函数在stm32f10x_it.c中。因此我们需要把这个文件加入到工程中来。
在这个文件中,我们发现,很多函数都是只有一个函数名,并没有函数体。我们找到EXTI2_IRQHandler()这个函数,这就是EXTI2中断响应的函数。我的目标是将LED灯点亮,所以函数体其实很简单:
  1. void EXTI2_IRQHandler(void)
  2. {
  3.        //点亮LED灯
  4.        GPIO_SetBits(GPIOD,GPIO_Pin_6);
  5.        //清空中断标志位,防止持续进入中断
  6.        EXTI_ClearITPendingBit(EXTI_Line2);
  7. }
  8. void EXTI3_IRQHandler(void)
  9. {
  10.        GPIO_SetBits(GPIOD,GPIO_Pin_3);
  11.        EXTI_ClearITPendingBit(EXTI_Line3);
  12. }
  13. void EXTI9_5_IRQHandler(void)
  14. {
  15.        GPIO_SetBits(GPIOB,GPIO_Pin_5);
  16.        EXTI_ClearITPendingBit(EXTI_Line5);
  17. }
复制代码

由于EXTI5-9是共用一个中断响应函数,因此所有的EXTI5 – EXTI9的响应函数都写在这个里面。

6.写主函数
  1. #include "stm32f10x_lib.h"
  2. void RCC_cfg();
  3. void IO_cfg();
  4. void EXTI_cfg();
  5. void NVIC_cfg();
  6. int main()
  7. {
  8.           RCC_cfg();
  9.           IO_cfg();
  10.           NVIC_cfg();
  11.           EXTI_cfg();
  12.           while(1);            
  13. }
复制代码

main函数前是函数声明,main函数函数体中都是调用初始化配置函数,然后进入死循环,等待中断响应。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值