4.STM32之中斷式按鍵

1.STM32中斷概述

中斷優(yōu)先級(jí)

在使用中斷式按鍵之前,我們先去了解一下STM32的中斷。
關(guān)于這方面可以參考《STM32中斷優(yōu)先級(jí)和開關(guān)總中斷》這篇文檔。

STM32外部中斷有兩個(gè)優(yōu)先級(jí),搶占式優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)(副優(yōu)先級(jí))。高搶占式優(yōu)先級(jí)的中斷可以在低搶占式優(yōu)先級(jí)中斷的處理過(guò)程中被響應(yīng),這被稱為中斷嵌套。

中斷嵌套.png

如圖所示,A中斷的搶占式優(yōu)先級(jí)更高,因此它可以嵌套在B中斷中執(zhí)行。B中斷必須等待A中斷的執(zhí)行完成才能繼續(xù)執(zhí)行。優(yōu)先級(jí)屬性編號(hào)越小表明優(yōu)先級(jí)別越高。

但是當(dāng)兩個(gè)中斷的搶占式優(yōu)先級(jí)相同時(shí),它們無(wú)法進(jìn)行中斷嵌套。后到來(lái)的中斷必須等之前的中斷結(jié)束才能被響應(yīng)。
如果兩個(gè)搶占式優(yōu)先級(jí)相同的中斷同時(shí)達(dá)到,則系統(tǒng)會(huì)根據(jù)副優(yōu)先級(jí)來(lái)決定先處理哪一個(gè)。如果副優(yōu)先級(jí)也相同,則根據(jù)中斷表中的順序決定先處理哪一個(gè)。

STM32使用的是Cortex-M3內(nèi)核,Cortex-M3中定義了8個(gè)比特位用于設(shè)置中斷源的優(yōu)先級(jí),這8個(gè)比特位可以有8種分配方式。
同時(shí)Cortex-M3允許具有較少中斷源時(shí)使用較少的寄存器位指定中斷源的優(yōu)先級(jí)。
因此STM32把指定中斷優(yōu)先級(jí)的寄存器位減少到4位,這4個(gè)寄存器位的分組方式如下:
第0組:所有4位用于指定響應(yīng)優(yōu)先級(jí)
第1組:最高1位用于指定搶占式優(yōu)先級(jí),最低3位用于指定響應(yīng)優(yōu)先級(jí)
第2組:最高2位用于指定搶占式優(yōu)先級(jí),最低2位用于指定響應(yīng)優(yōu)先級(jí)
第3組:最高3位用于指定搶占式優(yōu)先級(jí),最低1位用于指定響應(yīng)優(yōu)先級(jí)
第4組:所有4位用于指定搶占式優(yōu)先級(jí)

可以通過(guò)調(diào)用STM32的固件庫(kù)中的函數(shù) NVIC_PriorityGroupConfig( ) 選擇使用哪種優(yōu)先級(jí)分組方式,這個(gè)函數(shù)的參數(shù)有下列5種:
NVIC_PriorityGroup_0 => 選擇第0組
NVIC_PriorityGroup_1 => 選擇第1組
NVIC_PriorityGroup_2 => 選擇第2組
NVIC_PriorityGroup_3 => 選擇第3組
NVIC_PriorityGroup_4 => 選擇第4組

下面以一個(gè)簡(jiǎn)單的例子說(shuō)明如何指定中斷源的搶占式優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí):

//選擇使用優(yōu)先級(jí)分組第1組  
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 );   

//使能EXTI0中斷  
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;  
//指定搶占式優(yōu)先級(jí)別1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
//指定響應(yīng)優(yōu)先級(jí)別0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );   

//使能EXTI9_5中斷  
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
//指定搶占式優(yōu)先級(jí)別0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//指定響應(yīng)優(yōu)先級(jí)別1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
開關(guān)總中斷

在STM32/Cortex-M3中是通過(guò)改變CPU的當(dāng)前優(yōu)先級(jí)來(lái)允許或禁止中斷。
PRIMASK位:只允許NMI和hard fault異常,其他中斷/ 異常都被屏蔽(當(dāng)前CPU優(yōu)先級(jí)=0)。
FAULTMASK位:只允許NMI,其他所有中斷/異常都被屏蔽(當(dāng)前CPU優(yōu)先級(jí)=-1)。
在STM32固件庫(kù)中(stm32f10x_nvic.c和stm32f10x_nvic.h) 定義了四個(gè)函數(shù)操作PRIMASK位和FAULTMASK位,改變CPU的當(dāng)前優(yōu)先級(jí),從而達(dá)到控制所有中斷的目的。

下面兩個(gè)函數(shù)等效于關(guān)閉總中斷:

void NVIC_SETPRIMASK( void );
void NVIC_SETFAULTMASK( void );

下面兩個(gè)函數(shù)等效于開放總中斷:

void NVIC_RESETPRIMASK( void );
void NVIC_RESETFAULTMASK( void );

上面兩組函數(shù)要成對(duì)使用,不能交叉使用。

第一種方法:

NVIC_SETPRIMASK( );  //關(guān)閉總中斷
NVIC_RESETPRIMASK( );//開放總中斷   

第二種方法:

NVIC_SETFAULTMASK( );  //關(guān)閉總中斷
NVIC_RESETFAULTMASK( );//開放總中斷

通常使用

NVIC_SETPRIMASK( );  //Disable Interrupts
NVIC_RESETPRIMASK( );//Enable Interrupts

在3.0的庫(kù)中已經(jīng)沒有第一種方法

NVIC_SETPRIMASK();  //關(guān)閉總中斷
NVIC_RESETPRIMASK();//開放總中斷

第二種方法:

NVIC_SETFAULTMASK( );  //關(guān)閉總中斷
NVIC_RESETFAULTMASK( );//開放總中斷

也可以用宏定義

#define CLI( )    __set_PRIMASK( 1 )
#define SEI( )    __set_PRIMASK( 0 )

2.程序代碼

按鍵的電路在之前已經(jīng)給出,可參照上一節(jié)。

程序目的:使用中斷式按鍵控制LED燈的開關(guān)。
exti.h源代碼:
#ifndef __EXTI_H
#define __EXTI_H

#include "stm32f10x.h"

void EXTI_PE4_Init(void);

#endif

exti.c源代碼:
#include "stm32f10x.h"
#include "exti.h"

/************************************************************************
PAx ~ PGx 端口的中斷事件都連接到了EXTIx,即同一時(shí)刻EXTIx只能響應(yīng)一個(gè)端口
多個(gè) GPIO 口的時(shí)間無(wú)法同一時(shí)間響應(yīng),但是可以分時(shí)復(fù)用
EXTI最普通的應(yīng)用就是接上一個(gè)按鍵,設(shè)置為下降沿觸發(fā),用中斷來(lái)檢測(cè)按鍵
************************************************************************/
static void NVIC_Configuration( void )
{
    
    NVIC_InitTypeDef NVIC_InitStructure;
    
    //將優(yōu)先級(jí)組配置成第1組
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 );
    
    /*****************************************************************************
    NVIC_IRQChannel指需要配置的中斷向量。因使用PE4口的按鍵,所以配置在4通道
    如果使用GPIO_PIN_5~GPIO_PIN9的任意一個(gè),    則配置通道為EXTI9_5_IRQn
    如果使用GPIO_PIN_10~GPIO_PIN15的任意一個(gè),則配置通道為EXTI15_10_IRQn
    ******************************************************************************/
    NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    
    NVIC_Init( &NVIC_InitStructure );
    
}

void EXTI_PE4_Init(void)
{
    
    GPIO_InitTypeDef GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;

    //打開GPIOE時(shí)鐘和AFIO時(shí)鐘
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );
    
    NVIC_Configuration();
    
    // PE4外部中斷配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉輸入
    GPIO_Init( GPIOE, &GPIO_InitStructure );
    
    GPIO_EXTILineConfig( GPIO_PortSourceGPIOE, GPIO_PinSource4 );
    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 );
    
}
中斷服務(wù)函數(shù):
/********************************************************
中斷服務(wù)函數(shù)寫在stm32f10x_it_c中,新定義一個(gè)函數(shù)即可。
它的名字必須要與啟動(dòng)文件startup中的中斷向量表定義一致。
中斷函數(shù)入口的函數(shù)名只有下面兩種寫法:
(1)
EXTI0_IRQHandler    ;EXTI Line 0
EXTI1_IRQHandler    ;EXTI Line 1
EXTI2_IRQHandler    ;EXTI Line 2
EXTI3_IRQHandler    ;EXTI Line 3
EXTI0_IRQHandler    ;EXTI Line 4
(2)
EXTI9_5_IRQHandler    ;EXTI Line 5~9
EXTI15_10_IRQHandler    ;EXTI Line 10~15
********************************************************/
void EXTI4_IRQHandler( void )
{
    //確保產(chǎn)生了 EXTI Line 中斷
    if( EXTI_GetITStatus( EXTI_Line4 ) != RESET )
    {
        LED2_REV;
        
        //清除中斷標(biāo)志位
        EXTI_ClearITPendingBit( EXTI_Line4 );
    }
}
主函數(shù)main.c:
#include "stm32f10x.h"
#include "led.h"
#include "exti.h"

int main(void)
{
    LED_Init();
    LED2(ON);
    
    EXTI_PE4_Init();
    
    while(1)
    {
        //主函數(shù)不執(zhí)行任何動(dòng)作,只需要等待中斷
    }
    
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 異常類型 Cortex-M3內(nèi)核具有強(qiáng)大的異常響應(yīng)系統(tǒng),它把能夠打斷當(dāng)前代碼執(zhí)行流程的事件分為異常(excep...
    hackvilin閱讀 3,712評(píng)論 0 4
  • 首先讓我們來(lái)看一下關(guān)于控制定時(shí)器中斷的文件timer.c中的源碼: 前兩行是頭文件的聲明,這里我們不去理會(huì),我們今...
    Jane_123閱讀 11,569評(píng)論 0 5
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,678評(píng)論 19 139
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 12,496評(píng)論 6 13
  • 專心這個(gè)詞打出來(lái)容易,說(shuō)出來(lái)也輕松,但要做到真的很難,很難。 每當(dāng)我要是做一件事失敗下一秒鐘,我就會(huì)對(duì)自己說(shuō),這次...
    痞馬閱讀 263評(píng)論 0 1

友情鏈接更多精彩內(nèi)容