你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

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

[复制链接]
pwdzsj 发布时间:2015-10-18 17:08



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函数函数体中都是调用初始化配置函数,然后进入死循环,等待中断响应。

2 收藏 10 评论12 发布时间:2015-10-18 17:08

举报

12个回答
与非社区小虫 回答时间:2015-10-18 17:18:01
支持一个,学习 blank0.png
netlhx 回答时间:2015-10-18 17:58:56
赞,思路很清晰。

另贴代码的时候用专用的代码格式可能看起来更好!
你好我好大家好! 回答时间:2015-10-18 18:18:47
学校学校
lkl0305 回答时间:2015-10-18 20:52:49
学习了
disheng4688 回答时间:2015-10-19 08:28:19
学习                                 
peter001 回答时间:2015-10-19 09:22:42
学习学习
黑驴蹄子 回答时间:2015-10-19 14:48:13
好帖
ruilimeng 回答时间:2015-10-20 23:48:05
谢谢分享!

futu.png
钊钊 回答时间:2015-10-21 00:18:16
先顶再看,
12下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版