stm32 学习笔记: 中断

发布者:upsilon30最新更新时间:2016-08-25 来源: 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_InitTypeDef NVIC_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_InitTypeDef GPIO_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_InitTypeDef EXTI_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灯点亮,所以函数体其实很简单:

void EXTI2_IRQHandler(void)

{

       //点亮LED灯

       GPIO_SetBits(GPIOD,GPIO_Pin_6);

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

       EXTI_ClearITPendingBit(EXTI_Line2);

}

 

void EXTI3_IRQHandler(void)

{

       GPIO_SetBits(GPIOD,GPIO_Pin_3);

       EXTI_ClearITPendingBit(EXTI_Line3);

}

 

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

关键字:stm32  中断 引用地址:stm32 学习笔记: 中断

上一篇:stm32学习笔记 系统时钟
下一篇:stm32 GPIO 速度 模式理解

推荐阅读最新更新时间:2024-03-16 15:06

STM32 printf函数的调用
stm32中调用 printf()函数,实质上添加对应的 int fputc(int ch, FILE *f) 函数 (如 fputc对应目标是串口则printf输在串口上,如 fputc对应目标是LCD则是输在LCD) 具体步骤如下: 1、 首先要在main文件中包含 stdio.h (标准输入输出头文件) 2、在main文件中重定义函数 //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE { int handle; }; FILE __stdou
[单片机]
stm32调试时候出现 Error: Flash Download failed - "
也就是在MDK中的Flash的编程算法没有配置或没有配置正确 添加完之后就可以了
[单片机]
<font color='red'>stm32</font>调试时候出现 Error: Flash Download failed  -  "
功能强大的时钟中断
  单片机程序设计中,设置一个好的时钟中断,将能使一个CPU发挥两个CPU的功效,大大方便和简化程序的编制,提高系统的效率与可操作性。我们可以把一些例行的及需要定时执行的程序放在时钟中断中,还可以利用时钟中断协助主程序完成定时、延时等操作。   下面以6MHz时钟的AT89C51系统为例,说明时钟中断的应用。   定时器初值与中断周期 时钟中断无需过于频繁,一般取20mS(50Hz)即可。如需要百分之一秒的时基信号,可取10mS(100Hz)。这里取20mS,用定时器T0工作于16位定时器方式(方式1)。T0的工作方式为:每过一个机器周期自动加1,当计满0FFFFh,要溢出时,便会产生中断,并由硬件设置相应的标志位供软件查询。即中
[单片机]
μC/OSII的时钟中断技术研究
1 系统中断与时钟节拍 1.1 系统中断 中断是一种硬件机制,用于通知CPU有个异步事件发生了。中断一旦被系统识别,CPU则保存部分(或全部)现场(context),即部分(或全部)寄存器的值,跳转到专门的子程序,称为中断服务子程序(ISR)。中断服务子程序做事件处理,处理完成后执行任务调度,程序回到就绪态优先级最高的任务开始运行(对于可剥夺型内核)。 中断使得CPU可以在事件发生时才予以处理,而不必让微处理器连续不断地查询(polling)是否有事件发生。通过两条特殊指令:关中断(disable interrupt)和开中断(enable interrupt)可以让微处理器不响应或响应中断。在实时环境中,关中断的时间应尽量的
[单片机]
stm32专题二十:FSMC结构体分析
FSMC结构体: 控制FSMC使用SRAM存储器时主要是配置时序寄存器以及控制寄存器,利用ST标准库的SRAM时序结构体以及初始化结构体可以很方便地写入参数。 时序结构体配置: SRAM初始化结构体配置: 硬件连接: 操作的时候,就直接进行指针操作,向相应的地址写入和读出就行了,非常简单。 sram.c #include ./sram/sram.h /** * @brief 初始化控制SRAM的IO * @param 无 * @retval 无 */ static void SRAM_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitSt
[单片机]
<font color='red'>stm32</font>专题二十:FSMC结构体分析
STM32】HAL库 STM32CubeMX教程六----定时器中断
前言: 今天我们来学习定时器,32的定时器有着非常丰富的功能, 输入捕获/输出比较,PWM,中断等等。是我们学习STM32最频繁使用到的外设之一,所以一定要掌握好,这节我们讲解定时器中断,本系列教程将对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1、芯片: STM32F407ZET6/STM32F103ZET6 2、STM32CubeMx软件 3、IDE: MDK-Keil软件 4、STM32F1xx/STM32F4xxHAL库 5 知识概括: 通过本篇博客您将学到: SMT32定时器原理 STM32CubeMX创建定时器例程 HAL库TIM定时器函数库 定时器
[单片机]
【<font color='red'>STM32</font>】HAL库 STM32CubeMX教程六----定时器<font color='red'>中断</font>
STM32-一个例子搞懂EXTI外部中断/事件系统
假设一个商业帝国集团STM32 GROUPE有三家子公司,叫EXTI安保公司、AD转换技术有限公司、INT中断快递有限公司。 EXTI安保公司有一个经理和三个员工,分别为: 经理:寄存器·李 门卫:边沿检测·王 业务员:中断业务·杨 发言人:脉冲输出·赵 下图便是EXTI安保公司,黄色方框是集团董事长,绿色方框是经理,蓝色方框1~3分别是门卫、业务员、发言人。 边沿中断事件 一天,EXTI技术有限公司经理寄存器·李得到集团董事长的指示,要抓一个叫边沿的家伙,把它交给AD转换技术有限公司处理。(外部中断触发AD转换) 经理赶紧告诉门卫边沿检测·王:“小王啊,注意点,如果遇到一个叫边沿的时候告诉我一声!
[单片机]
STM32-一个例子搞懂EXTI外部<font color='red'>中断</font>/事件系统
大神教你如何快速使用DMA处理ADC
ADC: 1.STM32内部的ADC模块有三个ADC1,ADC2,ADC3,他们彼此独立,所以可以进行同步采样。 2ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生,要在RCC_CFGR配置,再ADC自己的寄存器中在没有时钟分频的配置位。 3.ADC转换时间: STM32F103xx增强型产,时钟为56MHz时为1μ s( 时钟为72MHz为1.17 μ s) 4.ADC的转换精度默认设置为12位,输入范围:ADC输入范围:V REF-≤ VIN≤ VREF+ 5.共有18个通道,其中外部16个通道,内部两个通道,内部温度传感器连接在ADC1_IN16,内部参考电压V REFINT连接在ADC1_IN17 6
[单片机]
大神教你如何快速使用DMA处理ADC
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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