stm32之中断系统

发布者:HarmoniousPeace最新更新时间:2019-01-15 来源: eefocus关键字:stm32  中断系统 手机看文章 扫描二维码
随时随地手机看文章

前言:这一节以及后面的定时器部分都是学习所有的单片机时的最重要的部分,我也花了很多时间去理解手册和程序,我争取尽量全面并且细致的记录我的体会。


一、中断的概念

这里就省略了,相信你学过单片机就会懂。


二、stm32里面的NVIC是什么

NVIC的中文意思是嵌套向量中断控制器,控制着中断的相关功能(其中包括中断源、抢占优先级、响应优先级、中断的使能与失能),具体的配置方法后面会提到。


三、stm32里面的优先级

在stm32中,一个中断的优先级由两部分决定,一个是抢占式优先级,还有一个是响应优先级。两个优先级组成了一个4位的控制字。 


如图: 


这里写图片描述


那么我们就会问,这有四位,那两个优先级各占多少位。就像图中所展示的,抢占式优先级(黄色)可以沾满四位,也可以一位都不占,如果占满四位,则抢占式优先级共有0-15这些等级,占满2位,就有0-3这些等级。同理响应优先级也是这样。分配他们各占多少位的函数为:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);后面这个数字代表的是抢占式优先级的位数


抢占式优先级和响应优先级分析


这两个优先级中,抢占式优先级占主导地位,抢占式优先级高的中断会优先打断主程序或者另外一个中断程序。 


1.如果两个中断的抢占式优先级一样高,当两个中断同时发生时,响应优先级高的先发生,完了再发生另一个。但是要注意,响应优先级高的中断不会打断低的中断,也就是当一个高响应优先级的中断来时,如果正在执行一个低的中断,他不会打断他,而是等待低的执行完在执行。也就是说只有高抢占式优先级可以阻断。


四,中断运用过程


1.中断的相关配置(其中包括很多很多步骤)


2.设置优先级分组,也就是前面提到的两个优先级的位数


3.书写中断服务函数


注意:第一个步骤对应一个总的函数my_exti_init();第二步骤单独写在主函数中,第三个步骤的中断服务函数直接写在头文件中不写在第一个函数中,不用写在主函数中。总的来说这三个步骤是指主函数中的步骤。 

这三个步骤都在后面详细分析


五、配置过程详细分析


首先需要知道,stm32f4中有23个外部中断,也就是有23个外部中断线路,但是只有0-15线是用来连到io口的(平时没有连上,需要用库函数来连上) 


这里写图片描述


到这里你一定会发现,0-15这有16条线,而stm32刚好每个端口有16个针脚,于是你自然也会想到阵脚的编号肯定是与中断线路编号刚好对应上的,事实上你很聪明,就是这样。至于是哪一个端口的针脚,就需要库函数配置。


配置步骤一:因为用到io口,所以首先要配置io口,就是打开时钟,设为输入模式等操作,至于为上啦还是下拉就看外设了,因为这里外设为按键,就好判断。


配置步骤二:像前面说的,要将中断线路和io口连接起来,用到的函数是:


SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);//这里就是将A端口的0管脚接在0线路上,用到几个线路就写多少个这个函数

1

但是SYSCFG是接在APB2总线上的,所以在SYSCFG_EXTILineConfig之前需要用RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);使能SYSCFG。


配置步骤三:配置NVIC(用到多少中断就写多少组)


NVIC_InitTypeDef NVIC_InitStructure;//声明一个结构体


NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;//中断通道,根据线路修改数字

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

NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;//设置响应优先级

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//通道使能

NVIC_Init(&NVIC_InitStructure);//最后在申明下


配置步骤四:初始化外部中断EXTI(用到多少中断就写多少组)


EXTI_InitTypeDef EXTI_InitStructure;//声明结构体


EXTI_InitStructure.EXTI_Line=EXTI_Line0;//选择线路

EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//选模式,这里为中断模式

EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿触发,下降沿为Falling

EXTI_InitStructure.EXTI_LineCmd=ENABLE;//使能

EXTI_Init(&EXTI_InitStructure);


配置步骤五:编写中断服务函数(写在头文件中) 

格式:


void EXTI0_IRQHandler(void)

{

        if(EXTI_GetITStatus(EXTI_Line0)==1)//看是否确实触发了中断,值为1就为触发了

        {

                delay_ms(10);//消抖   

                if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)//再一次确定,只不过这一次是确定按钮是否按下

                {

                        while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0));

                        GPIO_ResetBits(GPIOF,GPIO_Pin_10);//open the led

                }

        }

        EXTI_ClearITPendingBit(EXTI_Line0);//注意,这一步非常重要,经常容易忘记,写在中断服务函数的最后。用于清空中断的状态,以便于下次再次使用


注意:中断函数名不是自己取得,是有规定的


 这里写图片描述 


线路一用第一个,线路二用第二个,但是线路5到9用的是一样的倒数第二个,线路10-15用的最后一个。


完整程序: 

exti.c


#include "exti.h"



void my_exti_init()

{

        NVIC_InitTypeDef NVIC_InitStructure;

        EXTI_InitTypeDef EXTI_InitStructure;


        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);


        SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);//ÖжÏÏß·µÄÓ³É䣬¾ÍÊÇ°ÑÄĸö¶Ë¿Ú¿´×öÖжÏÊäÈë

        SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);//ÖжÏÏß·µÄÓ³É䣬¾ÍÊÇ°ÑÄĸö¶Ë¿Ú¿´×öÖжÏÊäÈë

      SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);//ÖжÏÏß·µÄÓ³É䣬¾ÍÊÇ°ÑÄĸö¶Ë¿Ú¿´×öÖжÏÊäÈë

      SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);//ÖжÏÏß·µÄÓ³É䣬¾ÍÊÇ°ÑÄĸö¶Ë¿Ú¿´×öÖжÏÊäÈë



        NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;

        NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;

        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

        NVIC_Init(&NVIC_InitStructure);



      NVIC_InitStructure.NVIC_IRQChannel=EXTI2_IRQn;

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;

        NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;

        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

        NVIC_Init(&NVIC_InitStructure);



        NVIC_InitStructure.NVIC_IRQChannel=EXTI3_IRQn;

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;

        NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;

        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

        NVIC_Init(&NVIC_InitStructure);



        NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn;

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;

        NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

        NVIC_Init(&NVIC_InitStructure);


      //Line0


      EXTI_InitStructure.EXTI_Line=EXTI_Line0;

        EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//ģʽÅäÖÃΪÖжÏģʽ

        EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;

      EXTI_InitStructure.EXTI_LineCmd=ENABLE;

        EXTI_Init(&EXTI_InitStructure);


        //Line2

        EXTI_InitStructure.EXTI_Line=EXTI_Line2;

        EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//ģʽÅäÖÃΪÖжÏģʽ

        EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;

      EXTI_InitStructure.EXTI_LineCmd=ENABLE;

        EXTI_Init(&EXTI_InitStructure);


        //Line3

        EXTI_InitStructure.EXTI_Line=EXTI_Line3;

        EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//ģʽÅäÖÃΪÖжÏģʽ

        EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;

      EXTI_InitStructure.EXTI_LineCmd=ENABLE;

        EXTI_Init(&EXTI_InitStructure);



        //Line4

        EXTI_InitStructure.EXTI_Line=EXTI_Line4;

        EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//ģʽÅäÖÃΪÖжÏģʽ

        EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;

      EXTI_InitStructure.EXTI_LineCmd=ENABLE;

        EXTI_Init(&EXTI_InitStructure);

}


void EXTI0_IRQHandler(void)//ÖжÏÏß·0

{

        if(EXTI_GetITStatus(EXTI_Line0)==1)//¿´ÊÇ·ñȷʵ´¥·¢ÁËÖжϣ¬¼´¿´°´Å¥ÊÇ·ñÕæµÄ°´Ï£¬µ«×¢ÒâÕâÀïµÄ1²»ÊÇÖ¸°´Å¥µÄ״̬£¬ÊÇÖ¸ÖжϵÄ״̬

        {

                delay_ms(10);   

                if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)

                {

                        while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0));

                        GPIO_ResetBits(GPIOF,GPIO_Pin_10);//open the led

                }

        }

        EXTI_ClearITPendingBit(EXTI_Line0);

}




void EXTI2_IRQHandler(void)//ÖжÏÏß·¶þ

{

        if(EXTI_GetITStatus(EXTI_Line2)==1)//¿´ÊÇ·ñȷʵ´¥·¢ÁËÖжϣ¬¼´¿´°´Å¥ÊÇ·ñÕæµÄ°´Ï£¬µ«×¢ÒâÕâÀïµÄ1²»ÊÇÖ¸°´Å¥µÄ״̬£¬ÊÇÖ¸ÖжϵÄ״̬

        {

                delay_ms(10);   

                if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)==0)

                {

                        while(!(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)));

                        GPIO_SetBits(GPIOF,GPIO_Pin_8);

                }

        }

        EXTI_ClearITPendingBit(EXTI_Line2);

}


void EXTI3_IRQHandler(void)//ÖжÏÏß·Èý

{

        if(EXTI_GetITStatus(EXTI_Line3)==1)//¿´ÊÇ·ñȷʵ´¥·¢ÁËÖжϣ¬¼´¿´°´Å¥ÊÇ·ñÕæµÄ°´Ï£¬µ«×¢ÒâÕâÀïµÄ1²»ÊÇÖ¸°´Å¥µÄ״̬£¬ÊÇÖ¸ÖжϵÄ״̬

        {

                delay_ms(10);   

                if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==0)

                {

                        while(!(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)));

                        GPIO_SetBits(GPIOF,GPIO_Pin_10);//turn off the led

                }

        }

        EXTI_ClearITPendingBit(EXTI_Line3);

}



void EXTI4_IRQHandler(void)//ÖжÏÏß·ËÄ

{

        if(EXTI_GetITStatus(EXTI_Line4)==1)//¿´ÊÇ·ñȷʵ´¥·¢ÁËÖжϣ¬¼´¿´°´Å¥ÊÇ·ñÕæµÄ°´Ï£¬µ«×¢ÒâÕâÀïµÄ1²»ÊÇÖ¸°´Å¥µÄ״̬£¬ÊÇÖ¸ÖжϵÄ״̬

        {

                delay_ms(10);   

                if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0)

                {

                        while(!(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)));

                        GPIO_ResetBits(GPIOF,GPIO_Pin_8);

                }

        }

        EXTI_ClearITPendingBit(EXTI_Line4);

}


main.c


int main()

{

    RCC_HSE_Config(8,336,2,7);

    Beep_Init();

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    SysTick_Init(168);

    key_init();

    LED_Init();

    my_exti_init();

    while(1)

    {


    }


}


说明:去前面一节的按钮实验现象虽然相同,但是原理不同,前面的按钮实验是通过不断检测按钮的状态,而这里是用的中断,满足触发条件自动执行。


关键字:stm32  中断系统 引用地址:stm32之中断系统

上一篇:STM32F0xx_EXTI中断配置详细过程-按键检测
下一篇:STM32的EXTI小实验

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

STM32----LTDC与DMA2D
一、硬件环境 第一代野火F29开发板,MCU为stm32f429IGT6。板载IS42S16400J SDRAM,16bit位宽 8M容量。 TFT为RG888接口,分辨率为800*480。 二、LTCD初始化 (1)初始化GPIO与SDRAM (2)初始化相关时钟 //2、LTDC相关时钟初始化 /* 配置 PLLSAI 分频器,它的输出作为像素同步时钟CLK*/ /* PLLSAI_VCO 输入时钟 = HSE_VALUE/PLL_M = 1 Mhz */ /* PLLSAI_VCO 输出时钟 = PLLSAI_VCO输入 * PLLSAI_N = 420 Mhz */ /* P
[单片机]
STM32----LTDC与DMA2D
STM32:stm32f10x_gpio.c中GPIO_Init的分析说明
1 /** 2 *函数功能:初始化引脚模式 3 *参数说明:GPIOx,该参数为GPIO_TypeDef 类型的指针,指向GPIO 端口的地址 4 * GPIO_InitTypeDef:GPIO_InitTypeDef 结构体指针,指向初始化变量 5 */ 6 void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) 7 { 8 uint32_t currentmode =0x00,currentpin = 0x00,pinpos = 0x00,pos = 0x00; 9 uint32_t tmpreg = 0x00, pinmas
[单片机]
Python 和OpenMV如何玩转 STM32 MCU
如今网络边缘侧的机器学习现状如何?哪些工具可以帮助工程师收集数据并执行推断运算?在哪里可以找到ST MEMS,它们对现实生活中的产品有哪些影响?本文是我们即将举行的STM32全国研讨会系列的第二篇专题文章。在第14届STM32全国研讨会上,我们将通过应用演示、产品展示以及工程师与观众互动回答问题的方式,来与蝶粉社区近距离交流。在STM32全国研讨会专题系列报道第一部分我们着重介绍了云连接方面的用例,如一款新的智能门铃功能演示,还介绍了工业和数据安全相关应用。 今天,我们将重点探讨人工智能、计算以及感知技术。 人工智能与计算 Qeexo 和STM32Cube.AI 当今边缘机器学习解决方案的种类越来越多,本届STM32全国
[嵌入式]
STM32学习—systick系统定时器
SysTick定时器配置步骤 SysTick定时器的操作可以分为 4 步: (1)设置SysTick定时器的时钟源。 (2)设置SysTick定时器的重装初始值(如果要使用中断的话,就将中 断使能打开)。 (3)清零SysTick定时器当前计数器的值。 (4)打开SysTick定时器。 SysTick_Init()函数: void SysTick_Init(u8 SYSCLK) //SYSCLK默认系统时钟是72M { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //对系统是进行8分频 fac_us=SYSCLK/8; //1 us所需要的次数 fac
[单片机]
意法推出配备1MB闪存的STM32微控制器
    意法半导体扩大STM32 微控制器产品阵容,增加更多特性和最高1MB的片上闪存。新增闪存容量让STM32开发人员可用存储容量增加一倍以上,可支持未来的产品升级,可提高系统性能,并提供先进的应用特性,如消费电子和工业产品的下一代图形用户界面。     随着STM32 XL高密度产品的发布,意法半导体现有STM32微控制器达99款 ,是业内产品型号最多的ARM Cortex-M3 32位微控制器,提供各种存储密度和操作速度,并集成多种功能特性,以满足各种的应用需求。。所有的STM32产品的引脚和软件都相互兼容,共用同一个外设资源库。这种平台共用性让开发人员只需少量的设计即可升级产品,将相同的知识产权、工具和硬件用于多
[单片机]
STM32移植LWIP官方demo
本文使用的IDE是IAR7.2,考虑到很多很使用Keil,本文也有keil版本的说明 1、硬件说明 主控:STM32F207VCT6,100管脚的封装 网络PHY芯片:RTL8201EL,48管脚封装,34和35管脚下拉,也就是芯片地址:0 使用的网络接口:MII接口 2、移植步骤 2.1、修改IAR配置文件 修改芯片设置(其实不用修改) 硬件使用的是SWD模式 2.2、修改网络PHY地址 在stm32f2x7_eth_bsp.h文件中 2.3、修改硬件IO 在stm32f2x7_eth_bsp.c中 2.4、屏蔽无用的东西和修改IP 在main.h中 修改IP地址(以读者本机I
[单片机]
<font color='red'>STM32</font>移植LWIP官方demo
STM32开发笔记69: 外设启动的先后次序
单片机型号:STM32F070F6P6 今天,在程序框架中增加了Timer16定时器驱动,但程序不能正常运行,本篇日志记录其原因。 驱动程序框架,定义了回调函数Timer16_InterruptFunction,写在main.cpp中用于逻辑层设计。Timer16_InterruptFunction调用的间隔为1ms,具体程序如下: void Timer16_InterruptFunction(void) { Target.HAL.L2.Turn(); } 此程序完成以1ms为间隔L2闪烁的程序,但是将此程序烧写到目标板后,程序不能正常运行。经过调试,最后将问题锁定在启动顺序上,看一下程序外设的启动顺序,具体程序
[单片机]
STM32 系统架构
简介:这里所讲的 STM32 系统架构主要针对的 STM32F103 这些非互联型芯片。STM32 主系统主要由四个驱动单元和四个被动单元构成。 四个驱动单元是: 内核DCode总线;系统总线;通用DMA1;通用DMA2; 四被动单元是: AHB到APB的桥:连接所有的APB设备;内部FlASH闪存;内部SRAM;FSMC; 下面我们具体看一下图中几个总线的知识: ①ICode总线:该总线将M3内核指令总线和闪存指令接口相连,指令的预取在该总线上面完成。 ②DCode总线:该总线将M3内核的DCode总线与闪存存储器的数据接口相连接,常量加载和调试访问在该总线上面完成。 ③系统总线:该总线连
[单片机]
<font color='red'>STM32</font> 系统架构
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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