stm32之外部中断该如何使用

发布者:科技徜徉最新更新时间:2021-06-21 来源: eefocus关键字:STM32  外部中断 手机看文章 扫描二维码
随时随地手机看文章

  中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在C51单片机时代,一共只有5个中断,其中2个外部中断,2个定时/计数器中断和一个串口中断,但是在STM32中,中断数量大大增加,而且中断的设置也更加复杂。今天就将来探讨一下关于STM32中的中断系统


  1 基本概念


  ARM Coetex-M3内核共支持256个中断,其中16个内部中断,240个外部中断和可编程的256级中断优先级的设置。STM32目前支持的中断共84个(16个内部+68个外部),还有16级可编程的中断优先级的设置,仅使用中断优先级设置8bit中的高4位。


  STM32可支持68个中断通道,已经固定分配给相应的外部设备,每个中断通道都具备自己的中断优先级控制字节PRI_n(8位,但是STM32中只使用4位,高4位有效),每4个通道的8位中断优先级控制字构成一个32位的优先级寄存器。68个通道的优先级控制字至少构成17个32位的优先级寄存器。


  4bit的中断优先级可以分成2组,从高位看,前面定义的是抢占式优先级,后面是响应优先级。按照这种分组,4bit一共可以分成5组


  第0组:所有4bit用于指定响应优先级;


  第1组:最高1位用于指定抢占式优先级,后面3位用于指定响应优先级;


  第2组:最高2位用于指定抢占式优先级,后面2位用于指定响应优先级;


  第3组:最高3位用于指定抢占式优先级,后面1位用于指定响应优先级;


  第4组:所有4位用于指定抢占式优先级。


  所谓抢占式优先级和响应优先级,他们之间的关系是:具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套。


  当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。每一个中断源都必须定义2个优先级。


  有几点需要注意的是:


  1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;


  2)抢占式优先级别相同的中断源之间没有嵌套关系;


  3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。


  2 GPIO外部中断


  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重点在于如何开发程序,所以内部的一些东西,在此我就不详细说明了,有感兴趣的可以参看上面提到的那本数。


  3 程序开发


  其实上面那些基本概念和知识只是对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的学习笔记中有了详细了解释。详细代码如下:



 void RCC_cfg()


  {


  //打开PE PD PC PB端口时钟,并且打开复用时钟


  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE| RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO, ENABLE);


  }



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


  2. 设置好相应的中断


  设置相应的中断实际上就是设置NVIC,在STM32的固件库中有一个结构体NVIC_InitTypeDef,里面有相应的标志位设置,然后再用NVIC_Init()函数进行初始化。详细代码如下:



 void NVIC_cfg()


  {


  NVIC_InitTypeDefNVIC_InitStructure;


  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择中断分组2


  NVIC_InitStructure.NVIC_IRQChannel= EXTI2_IRQChannel; //选择中断通道2


  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0; //抢占式中断优先级设置为0


  NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0; //响应式中断优先级设置为0


  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断


  NVIC_Init(&NVIC_InitStructure);


  NVIC_InitStructure.NVIC_IRQChannel=EXTI3_IRQChannel; //选择中断通道3


  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 1; //抢占式中断优先级设置为1


  NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1; //响应式中断优先级设置为1


  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断


  NVIC_Init(&NVIC_InitStructure);


  NVIC_InitStructure.NVIC_IRQChannel= EXTI9_5_IRQChannel; //选择中断通道5


  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2; //抢占式中断优先级设置为2


  NVIC_InitStructure.NVIC_IRQChannelSubPriority= 2; //响应式中断优先级设置为2


  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断


  NVIC_Init(&NVIC_InitStructure);


  }



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


  3. IO口初始化



void IO_cfg()


  {


  GPIO_InitTypeDefGPIO_InitStructure;


  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; //选择引脚2


  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //输出频率最大50MHz


  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //带上拉电阻输出


  GPIO_Init(GPIOE,&GPIO_InitStructure);


  GPIO_ResetBits(GPIOE,GPIO_Pin_2); //将PE.2引脚设置为低电平输出


  GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5; //选择引脚2 3 5


  GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING; //选择输入模式为浮空输入


  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //输出频率最大50MHz


  GPIO_Init(GPIOC,&GPIO_InitStructure); //设置PC.2/PC.3/PC.5


  GPIO_InitStructure.GPIO_Pin= GPIO_Pin_3 |GPIO_Pin_6; //选择引脚3 6


  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //输出频率最大50MHz


  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //带上拉电阻输出


  GPIO_Init(GPIOD,&GPIO_InitStructure);


  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; //选择引脚5


  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //输出频率最大50MHz


  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //带上拉电阻输出


  GPIO_Init(GPIOB,&GPIO_InitStructure);


  }


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


  4. 把相应的IO口设置为中断线路


  由于GPIO并不是专用的中断引脚,因此在用GPIO来触发外部中断的时候需要设置将GPIO相应的引脚和中断线连接起来,具体代码如下:



 void EXTI_cfg()


  {


  EXTI_InitTypeDefEXTI_InitStructure;


  //清空中断标志


  EXTI_ClearITPendingBit(EXTI_Line2);


  EXTI_ClearITPendingBit(EXTI_Line3);


  EXTI_ClearITPendingBit(EXTI_Line5);


  //选择中断管脚PC.2 PC.3 PC.5


  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource2);


  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource3);


  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);


  EXTI_InitStructure.EXTI_Line= EXTI_Line2 | EXTI_Line3 | EXTI_Line5; //选择中断线路2 3 5


  EXTI_InitStructure.EXTI_Mode= EXTI_Mode_Interrupt; //设置为中断请求,非事件请求


  EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Rising_Falling; //设置中断触发方式为上下降沿触发


  EXTI_InitStructure.EXTI_LineCmd=ENABLE; //外部中断使能


  EXTI_Init(&EXTI_InitStructure);


  }


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


  5. 写中断响应函数


  STM32不像C51单片机那样,可以用过interrupt关键字来定义中断响应函数,STM32的中断响应函数接口存在中断向量表中,是由启动代码给出的。默认的中断响应函数在stm32f10x_it.c中。因此我们需要把这个文件加入到工程中来。


  在这个文件中,我们发现,很多函数都是只有一个函数名,并没有函数体。我们找到EXTI2_IRQHandler()这个函数,这就是EXTI2中断响应的函数。我的目标是将LED灯点亮,所以函数体其实很简单:



 voidEXTI2_IRQHandler(void)


  {


  //点亮LED灯


  GPIO_SetBits(GPIOD,GPIO_Pin_6);


  //清空中断标志位,防止持续进入中断


  EXTI_ClearITPendingBit(EXTI_Line2);


  }


  voidEXTI3_IRQHandler(void)


  {


  GPIO_SetBits(GPIOD,GPIO_Pin_3);


  EXTI_ClearITPendingBit(EXTI_Line3);


  }


  voidEXTI9_5_IRQHandler(void)


  {


  GPIO_SetBits(GPIOB,GPIO_Pin_5);


  EXTI_ClearITPendingBit(EXTI_Line5);


  }



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


  6. 写主函数



 #include"stm32f10x_lib.h"


  void RCC_cfg();


  void IO_cfg();


  void EXTI_cfg();


  void NVIC_cfg();


  int main()


  {


  RCC_cfg();


  IO_cfg();


  NVIC_cfg();


  EXTI_cfg();


  while(1);


  }



  main函数前是函数声明,main函数函数体中都是调用初始化配置函数,然后进入死循环,等待中断响应。


  由于文中牵涉到很多库函数,我们可以通过查找库函数说明文档来了解相应的函数有些什么作用,在《ARM®-based32-bit MCU STM32F101xx and STM32F103xx firmware library》中。网上也有中文版的说明文档可供参考。


关键字:STM32  外部中断 引用地址:stm32之外部中断该如何使用

上一篇:关于STM32F中按键中断分析
下一篇:单片机学习笔记之--SPI通信基础

推荐阅读最新更新时间:2024-11-19 16:30

嵌入式系统学习——STM32之GPIO
----第一篇:GPIO库 文档说明和约定: 该文档主要是对STM32F4各个模块的库进行翻译和说明。文档中加入了作者的一些理解,建议和小贴士。并且在文档最后,加入了一些使用该库模块的案例。希望大家通过对该文档的阅读,可以更好的使用STM32的库函数进行学习和项目开发。之所以选用1.4.0版本进行翻译和说明,因为该版本群众基础较好,有大量的使用者和相关资料。后续也会推出新版本库和CubeMX库的翻译和说明,希望大家喜欢和支持。如果大家觉得文档有什么问题,麻烦请提出,如果确认问题存在,作者会及时修改。 相关术语说明: gpio:通用输入输出接口 gpio管脚:一个io管脚,这个管脚可以有多个配置。在库函数中用GPIO_Pin_1
[单片机]
STM32中的独立看门狗和窗口看门狗是什么
一、前言 在早期的MCU中是没有看门狗这种东西的,所以产品就很容易出现死机,跑飞的情况。为了避免这种情况的出现,后期的MCU都集成了看门狗的功能。但是目前看门狗发展到今天基本上分为两大类:独立看门狗和窗口看门狗。 独立看门狗 :使用的是外部时钟,即使主频不工作了,看门狗也能正常工作。只要在到达喂狗时间的上限前喂狗即表示程序是正常的,这点和窗口看门狗是有区别的。另外独立看门狗是独立于整个系统之外的,这也是独立看门狗名字的由来,他有自己独立的时钟,不受整个系统的影响,所以独立看门狗主要用来监控硬件上的错误。 窗口看门狗 :使用芯片内部时钟。喂狗的时间既有上限又有下限,即喂狗太早或者太晚都不行,比如我要求你在0.8s到0.9s内
[单片机]
<font color='red'>STM32</font>中的独立看门狗和窗口看门狗是什么
不一样的STM32“脱机”烧录器
用SBC给STM32F746Discovery烧写程序。SBC就是单板电脑的意思,也可以叫卡片电脑(神奇的ARM小电脑),他是一个统称;常见的SBC有树莓派、Friendly ARM、香橙派、栗子派、Firefly等。 硬件的接法很简单,就像上面那样,把STM32Discovery的板载ST-Link V2的USB接口接到SBC的USB接口上就好了。 过去,我们如果要给STM32单片机烧写程序,需要用到桌面电脑,或者笔记本电脑。这些都是X86平台的,非常不方便。所以,我们今天要来个骚操作,DIY一个小作品,用栗子派代替传统的X86电脑,把它做成一台小型的STM32烧录器。借助Linux系统的SSH服务,间接地也实现了远程烧
[单片机]
不一样的<font color='red'>STM32</font>“脱机”烧录器
STM32开发 -- Systick定时器
一、Systick定时器介绍 参看:STM32菜鸟成长记录—系统滴答定时器(systick)应用 参看:SysTick定时器和delay延迟函数 SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 **优点: **节省
[单片机]
<font color='red'>STM32</font>开发 -- Systick定时器
stm32 DMA的Stream和Channel的映射关系
DMA框图 DMA1中总共有8个stream,而每个stream可以配置成不同的传输源和目的地址,这就是channel。1个不同的源和目的就叫1个channel。
[单片机]
<font color='red'>stm32</font> DMA的Stream和Channel的映射关系
STM32使用问题总结
1.串口发送第一个字节丢失 问题代码 void USART1_SendBuf(uint8_t *pbuf , uint8_t len) { for( uint8_t i = 0 ; i len ; i++ ) { /* 写一个字节到USART1 */ USART_SendData(USART1, *pbuf++); /* 等待发送结束 */ while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {} } } 修正代码 void USART1_SendBuf(uint8_t *
[单片机]
stm32 数据类型的定义
在Keil MDK 开发环境里,比如一个 无符号32位整形数据会有很多种表示方法:1,unsigned int 32 (C语言标准表达方法) 2,uint32_t ; 3 ,u32; 这三种方式都是在表达同一个意思,可为什么ST的开发人员要搞的这么乱呢? 还有其他好多你可能看起来很陌生 ,很不好理解的表达方式,如:_IO int32_t 他等同于vs32(这个你同样很陌生),不过他还等同于 volatile int32_t, 还等同于 volatile signed int 32;最后这种表达方式才是C语言的标准表达方式,够乱吧,能把初学者弄的晕头转向。 其实ST 搞这么多花样,无非是想开发人员在写代码时定义数据类型能少写几个符
[单片机]
关于单片机外部中断的扩展
单片机外部中断有限,仅有两个,在某些系统设计中可能会不够用。这里给大家推荐一个比较简单的扩展外部中断的方法。灵感来至于单片机键盘设计! 在有些键盘设计中,如果在程序中采用轮询的方法在检测按键,会花费大量的cpu资源,特别是还要进行大量的数据处理的情况下。所以很多按键设计都加入了中断,上一篇博文里的按键设计其实都可以加入中断,这样可以更好的利用cpu资源。 一般在按键设计中只会用一个中断,但是却可以控制n多的按键。每一个按键的按下都相当于产生了一个中断,所以利用这个原理,我们也可以 无限 的扩展外部中断。一个简单的电路图如下: 这样当外部送来一个低电平的信号时,通过与非门后将产生一个中断信号,这个信号可以送到单片机的外部中断
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved