STM32中断实验了该怎么办?

如题所述

具体情况具体对待,你可以看我下面的实验对号入座来分析你的问题:

实验目的:

当按键按下时,让PF10引脚的LED灯亮,
当按键再次按下时,让PF10引脚的LED灯灭;

无论按下与否,PF9引脚的LED灯循环闪烁;

实验步骤:

实验程序:

[cpp] view plain copy

    /***********************************led.c*********************************/  

    #include "stm32f4xx.h"  //在SYSTEM目录下可以找到  

    #include "sys.h"  

    void LED_Init(void){  

    RCC->AHB1ENR = 1<<5;  //使能GPIO端口的F时钟   

    GPIO_Set(GPIOF,PIN9|PIN10,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_25M,GPIO_PUPD_PU);  

    PFout(9) = 1;  

    PFout(10) = 1;  

    }  


    [cpp] view plain copy

    /***********************************led.h*********************************/  

    #ifndef _LED_H  

    #define _LED_H  

    void LED_Init(void);  

    #endif  


    [cpp] view plain copy

    /********************************************key.c***************************************/  

    #include "sys.h"  

    void Key_Init(void){  

    RCC->AHB1ENR|=1<<4;     //使能PORTE时钟  

    //void GPIO_Set(GPIO_TypeDef* GPIOx,u32 BITx,u32 MODE,u32 OTYPE,u32 OSPEED,u32 PUPD);//GPIO设置函数   

    GPIO_Set(GPIOE,PIN3,GPIO_MODE_IN,0,0,GPIO_PUPD_PU); //PE3设置上拉输入,这样的话,  

    //当按键没有按下时,默认电平为高;  

    }  



    [cpp] view plain copy

    /********************************************key.h***************************************/  

    #ifndef _KEY_H  

    #define _KEY_H  

    void Key_Init(void);  

    #endif  



    [cpp] view plain copy

    /************************************exti.c********************************/  

    #include "sys.h"  

    #include "delay.h"  

    #include "stm32f4xx.h"  

    /* 

    本示例的作用就是, 

    当按键按下时,蜂鸣器发出声音, 

    当按键再次按下时,蜂鸣器静音; 

    */  

    /* 

    中断初始化函数: 

    主要是关于寄存器的相关配置 

    */  

    void EXTI3_Init(void){  

    //方法一:  

    RCC->APB2ENR |= 1 << 14;  //开启SYSCFG时钟  

    SYSCFG->EXTICR[0] |= 0x4 << 12;//设置IO口与中断线的映射关系;  

    EXTI->IMR |= 1 << 3;  //开启对应中断线上的中断  

    EXTI->FTSR |= 1 << 3;  //设置中断触发条件  

    //SCB和NVIC,可参考STM32F3与STM32F4系列Cortex M4内核编程手册.pdf  

    SCB->AIRCR |= 0x5 << 8; //设置分组  

    NVIC->IP[9] |= 0; //设置优先级,具体可分析MY_NVIC_Init()函数;  

    NVIC->ISER[0] |= 1 << 9;  //使能中断;  

    //方法二:  

    /************************************ 

    使用SYSTEM目录下提供的API来实现, 

    具体可参考正点原子示例 

    ************************************/  

    }  

    void EXTI3_IRQHandler(void){  

    /* 

    此按键,在按键按下时,处理不是很到位, 

    有待进一步改进,主要是在连按那一个环节。 

    */  

    delay_ms(20);  //消抖  

    if(PEin(3) == 0){  

    PFout(10) = !PFout(10);  

    }  

    /* 

    在中断里边最后记得清中断: 

    */  

    EXTI->PR |= 1 << 3;  

    }   



    [cpp] view plain copy

    /*************************************exti.h*******************************/  

    #ifndef _EXTI_H  

    #define _EXTI_H  

    void EXTI3_Init(void);  

    #endif  



    [cpp] view plain copy

    /*************************************test.c*******************************/  

    #include "sys.h"  

    #include "delay.h"  

    #include "key.h"  

    #include "beep.h"  

    #include "exti.h"  

    #include "led.h"  

    //int i = 0;  

    int main(void){  

    Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz    

    delay_init(168);        //初始化延时函数  

    Beep_Init();  

    Key_Init();  

    EXTI3_Init();  

    LED_Init();  

    while(1){  

    PFout(9) = 0;  

    delay_ms(500);  

    PFout(9) = 1;  

    delay_ms(500);  

    }  

    }  



    实验分析:

    我们主要分析一下exti.c中的寄存器设置的这几个步骤:

    1. RCC->APB2ENR |= 1 << 14;

    这一步的作用就是使能SYSCFG时钟,

    在使用外部中断的时候一定要先使能SYSCFG时钟;

    2. SYSCFG->EXTICR[0] |= 0x4 << 12;

    这一步的作用就是设置IO口与中断线的映射关系;

    那么问题来了,我如何知道的我的IO口与哪根中断线是关联起来的呢?


    而我们是通过KEY1按键,对应的IO口就是PE3,所以由上图的映射关系,我们知道,我们应该选择中断线3与之对应;

    在官方提供的头文件stm32f4xx.h中,我们可以看到:

    [cpp] view plain copy

    typedef struct  

    {  

    __IO uint32_t MEMRMP;       /*!< SYSCFG memory remap register,                      Address offset: 0x00      */  

    __IO uint32_t PMC;          /*!< SYSCFG peripheral mode configuration register,     Address offset: 0x04      */  

    __IO uint32_t EXTICR[4];    /*!< SYSCFG external interrupt configuration registers, Address offset: 0x08-0x14 */  

    uint32_t      RESERVED[2];  /*!< Reserved, 0x18-0x1C                                                          */   

    [cpp] view plain copy

    __IO uint32_t CMPCR;        /*!< SYSCFG Compensation cell control register,         Address offset: 0x20      */  

    SYSCFG_TypeDef;  




    结合上述三幅图,我们可以得知:

    由于PE3对应的中断线为EXTI3,所以,我们我们这里仅需配置EXTI3,而EXTI3是在SYSCFG_EXTICR1中的;

    所以我们仅需配置SYSCFG_EXTICR1寄存器的12位-15位为0100,而SYSCFG_EXTICR1寄存器在配置文件中,

    对应的是SYSCFG->EXTICR[0],所以我们就写成了SYSCFG->EXTICR[0] |= 0x4 << 12;

    3. EXTI->IMR |= 1 << 3;

    这条语句的作用就是:开启对应中断线上的中断

    由于我们操作的中断线是EXTI3,而IMR寄存器各位解释如下:


    所以对应的,我们操作EXTI_IMR寄存器的第3位MR3即可;

    所以这条语句就写成了:EXTI->IMR |= 1 << 3

    4. EXTI->FTSR |= 1 << 3;

    这条语句的作用就是设置中断触发条件;

    在我的开发板中,当按键按下时,其端口就会变成低电平,在没有按下时,其是为高电平的;

    因为我们key.c中,将按键的引脚设置成了上拉;所以在这里,我得将其设置成下降沿触发;

    与此同时,查看EXTI_FTSR寄存器,可以看到:


    又由于我们这条中断线是中断线3,所以这条语句就写成了:EXTI->FTSR |= 1 << 3

    5. SCB->AIRCR |= 0x5 << 8;

    这条语句的作用就是:设置分组;




    所以,在这里我们只需设置SCB的AIRCR的 bit10-8即可;查看SCB的结构体,得知:


    [cpp] view plain copy

    typedef struct  

    {  

    __I  uint32_t CPUID;                   /*!< Offset: 0x000 (R/ )  CPUID Base Register                                   */  

    __IO uint32_t ICSR;                    /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register                  */  

    __IO uint32_t VTOR;                    /*!< Offset: 0x008 (R/W)  Vector Table Offset Register                          */  

    __IO uint32_t AIRCR;                   /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register      */  

    __IO uint32_t SCR;                     /*!< Offset: 0x010 (R/W)  System Control Register                               */  

    __IO uint32_t CCR;                     /*!< Offset: 0x014 (R/W)  Configuration Control Register                        */  

    __IO uint8_t  SHP[12];                 /*!< Offset: 0x018 (R/W)  System Handlers Priority Registers (4-7, 8-11, 12-15) */  

    __IO uint32_t SHCSR;                   /*!< Offset: 0x024 (R/W)  System Handler Control and State Register             */  

    __IO uint32_t CFSR;                    /*!< Offset: 0x028 (R/W)  Configurable Fault Status Register                    */  

    __IO uint32_t HFSR;                    /*!< Offset: 0x02C (R/W)  HardFault Status Register                             */  

    __IO uint32_t DFSR;                    /*!< Offset: 0x030 (R/W)  Debug Fault Status Register                           */  

    __IO uint32_t MMFAR;                   /*!< Offset: 0x034 (R/W)  MemManage Fault Address Register                      */  

    __IO uint32_t BFAR;                    /*!< Offset: 0x038 (R/W)  BusFault Address Register                             */  

    __IO uint32_t AFSR;                    /*!< Offset: 0x03C (R/W)  Auxiliary Fault Status Register                       */  

    __I  uint32_t PFR[2];                  /*!< Offset: 0x040 (R/ )  Processor Feature Register                            */  

    __I  uint32_t DFR;                     /*!< Offset: 0x048 (R/ )  Debug Feature Register                                */  

    __I  uint32_t ADR;                     /*!< Offset: 0x04C (R/ )  Auxiliary Feature Register                            */  

    __I  uint32_t MMFR[4];                 /*!< Offset: 0x050 (R/ )  Memory Model Feature Register                         */  

    __I  uint32_t ISAR[5];                 /*!< Offset: 0x060 (R/ )  Instruction Set Attributes Register                   */  

    uint32_t RESERVED0[5];  

    __IO uint32_t CPACR;                   /*!< Offset: 0x088 (R/W)  Coprocessor Access Control Register                   */  

    } SCB_Type;  


    所以,在这里,我们把这条语句写成了SCB->AIRCR |= 0x5 << 8;

    亦即设置成了101,也就是抢占优先级占2位,响应优先级占2位;

    注:抢占优先级和响应优先级一样,其值越低则表示其优先级越高;

    上述说的子优先级也就是我们说的响应优先级;

    6. NVIC->IP[9] |= 0;

    有上条语句,我们可以得知:IP寄存器由240个8bit的寄存器组成,每个可屏蔽中断占用8bit,这样总共可以表示240个可屏蔽中断,

    而STM32F4只用到了其中的82个。IP[81]~IP[0]分别对应中断81~0.而每个可屏蔽中断占用的8bit并没有全部使用,而是只用了高4位;

    这4位,又分为抢占优先级和响应优先级;抢占优先级在前,响应优先级在后;也就是说,抢占优先级在高位,响应优先级在低位;

    而我们又知道:我们这个中断是外部中断3,所以查看中断向量表可知:





    由此可知,EXTI3在中断的位置为9,所以我们只需要设置NVIC->IP[9] 即可;

    在这里我们把NVIC->IP[9] |= 0;则表示,我们设置外部中断3的抢占优先级为0,响应优先级也为0,其各占2位;

    7. NVIC->ISER[0] |= 1 << 9;

    这一步的作用就是使能中断;

    ISER是一个中断使能寄存器组;这里用8个32位寄存器来控制,每个位控制一个中断;但是STM32F4的可屏蔽中断

    最多只有82个,所以对我们来说,有用的就是三个(ISER[0~2]),总共可以表示96个中断;而STM32F4只用了其中的

    前82个中断,ISER[0]的0bit~31分别对应中断0~31;ISER[1]的bit0~32对应中断32~63;ISER[2]的bit0~32对应中断64~81;

    在这里,我们知道:我们的EXTI3对应的中断的位置是9,所以我们只需设置ISER[0]的第9位即可;所以我们在这里就将这条

    语句写成了:NVIC->ISER[0] |= 1 << 9; 

    8.至于外部中断函数的名称如何编写,我们可以从启动文件中去找到;

    当我们设置的外部中断函数与启动文件中定义的名称一致时,

    那么当这个中断条件满足时,就会去中断函数里边执行其函数体;

    我们只需要在中断发生后,记得清中断,防止中断重复发生;

    注意事项:

    在本实验中,关于按键处理那一块,处理不是很到位,

    主要应该是处在连按这一块,暂时没去整它,待我需要时,再去整整。

    转载于 http://blog.csdn.net/u010661782/article/details/50281229,感谢原作者非常详细的指导学习。

STM32 中断初识

前段时间经常用stm32f4 discovery,但是因为对NVIC , EXTI不是很了解,所以使用的过程中一直都在避免使用中断,这两天没什么事决定来学习一下stm32 的中断,写一下自己的心得,如有谬误之处,欢迎指正。 
我把用到的几份文档寄存器的文档(RM0090)、《Cortex-M技术参考手册》、《Cortex™-M4 Devices Generic User Guide》、《ARMv7-M Architecture Reference Manual》放在百度云,需要的自取

 密码:4g91网页链接

温馨提示:答案为网友推荐,仅供参考
相似回答