這一節(jié),我們將向大家介紹如何使用STM32的外部輸入中斷。通過第1、2節(jié)的學習,我們掌握了STM32的IO口最基本的操作。這節(jié)我們將介紹作為外部中斷輸入口,STM32的需要做哪些設(shè)置。本節(jié)分為如下幾個部分:
3.4.1 STM32外部中斷簡介
3.4.2 硬件設(shè)計
3.4.3 軟件設(shè)計
3.4.4 下載與測試
3.4.1 STM32外部中斷簡介
STM32的IO口在本章第一節(jié)有詳細介紹,而外部中斷在第二章也有詳細的闡述。這里我們將介紹如何將這兩者結(jié)合起來,實現(xiàn)外部中斷輸入。
STM32的每個IO口都可以作為中斷輸入,這點很好用。要把IO口作為外部中斷輸入,有以下幾個步驟:
1)初始化IO口為輸入。
這一步設(shè)置你要作為外部中斷輸入的IO口的狀態(tài),可以設(shè)置為上拉/下拉輸入,也可以設(shè)置為浮空輸入,但浮空的時候外部一定要帶上拉,或者下拉電阻。否則可能導(dǎo)致中斷不停的觸發(fā)。在干擾較大的地方,就算使用了上拉/下拉,也建議使用外部上拉/下拉電阻,這樣可以一定程度防止外部干擾帶來的影響。
2)開啟IO口復(fù)用時鐘,設(shè)置IO口與中斷線的映射關(guān)系。
STM32的IO口與中斷線的對應(yīng)關(guān)系需要配置外部中斷配置寄存器EXTICR,這樣我們要先開啟復(fù)用時鐘,然后配置IO口與中斷線的對應(yīng)關(guān)系。才能把外部中斷與中斷線連接起來。
3)開啟與該IO口相對的線上中斷/事件,設(shè)置觸發(fā)條件。
這一步,我們要配置中斷產(chǎn)生的條件,STM32可以配置成上升沿觸發(fā),下降沿觸發(fā),或者任意電平變化觸發(fā),但是不能配置成高電平觸發(fā)和低電平觸發(fā)。這里根據(jù)自己的實際情況來配置。同時要開啟中斷線上的中斷,這里需要注意的是:如果使用外部中斷,并設(shè)置該中斷的EMR位的話,會引起軟件仿真不能跳到中斷,而硬件上是可以的。而不設(shè)置EMR,軟件仿真就可以進入中斷服務(wù)函數(shù),并且硬件上也是可以的。建議不要配置EMR位。
4)配置中斷分組(NVIC),并使能中斷。
這一步,我們就是配置中斷的分組,以及使能,對STM32的中斷來說,只有配置了NVIC的設(shè)置,并開啟才能被執(zhí)行,否則是不會執(zhí)行到中斷服務(wù)函數(shù)里面去的。關(guān)于NVIC的詳細介紹,請參考前面章節(jié)。
5)編寫中斷服務(wù)函數(shù)。
這是中斷設(shè)置的最后一步,中斷服務(wù)函數(shù),是必不可少的,如果在代碼里面開啟了中斷,但是沒編寫中斷服務(wù)函數(shù),就可能引起硬件錯誤,從而導(dǎo)致程序崩潰!所以在開啟了某個中斷后,一定要記得為該中斷編寫服務(wù)函數(shù)。在中斷服務(wù)函數(shù)里面編寫你要執(zhí)行的中斷后的操作。
通過以上幾個步驟的設(shè)置,我們就可以正常使用外部中斷了。
這一節(jié),我們將實現(xiàn)同第二節(jié)差不多的功能,但是這里我們使用的是中斷來檢測按鍵,還是通過WK_UP按鍵實現(xiàn)按一次DS0和DS1同時翻轉(zhuǎn),按KEY0翻轉(zhuǎn)DS0,按KEY1翻轉(zhuǎn)DS1。
3.4.2 硬件設(shè)計
這里的硬件電路和第二節(jié)一模一樣,不再多做介紹了。
3.4.3 軟件設(shè)計
軟件設(shè)計我們還是在之前的工程上面增加,首先在HARDWARE文件夾下新建EXTI的文件夾。然后打開USER文件夾下的工程,新建一個exti.c的文件和exti.h的頭文件,保存在EXTI文件夾下,并將EXTI文件夾加入頭文件包含路徑(即設(shè)定編譯器包含路徑,第二章已有介紹。以下類似)。
我們在exit.c里輸入如下代碼:
#include "exti.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
//Mini STM32開發(fā)板
//外部中斷 驅(qū)動代碼
//正點原子@ALIENTEK
//2010/5/30
//外部中斷0服務(wù)程序
void EXTI0_IRQHandler(void)
{
delay_ms(10);//消抖
if(KEY2==1) //按鍵2
{
LED0=!LED0;
LED1=!LED1;
}
EXTI->PR=1<<0; //清除LINE0上的中斷標志位
}
//外部中斷15~10服務(wù)程序
void EXTI15_10_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY0==0) //按鍵0
{
LED0=!LED0;
}else if(KEY1==0)//按鍵1
{
LED1=!LED1;
}
EXTI->PR=1<<13; //清除LINE13上的中斷標志位
EXTI->PR=1<<15; //清除LINE15上的中斷標志位
}
//外部中斷初始化程序
//初始化PA0,PA13,PA15為中斷輸入.
void EXTIX_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA時鐘
RCC->APB2ENR|=1<<0; //開啟輔助時鐘
AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
AFIO->MAPR|=0X04000000; //關(guān)閉JTAG
GPIOA->CRL&=0XFFFFFFF0;//PA0設(shè)置成輸入
GPIOA->CRL|=0X00000008;
GPIOA->CRH&=0X0F0FFFFF;//PA13,15設(shè)置成輸入
GPIOA->CRH|=0X80800000;
GPIOA->ODR|=1<<13; //PA13上拉,PA0默認下拉
GPIOA->ODR|=1<<15; //PA15上拉
Ex_NVIC_Config(GPIO_A,0,RTIR); //上升沿觸發(fā)
Ex_NVIC_Config(GPIO_A,13,F(xiàn)TIR);//下降沿觸發(fā)
Ex_NVIC_Config(GPIO_A,15,F(xiàn)TIR);//下降沿觸發(fā)
MY_NVIC_Init(2,2,EXTI0_IRQChannel,2); //搶占2,子優(yōu)先級2,組2
MY_NVIC_Init(2,2,EXTI15_10_IRQChannel,2);//搶占2,子優(yōu)先級1,組2
}
exit.c文件總共包含3個函數(shù)。一個是外部中斷初始化函數(shù)void EXTIX_Init(void),另外兩個都是中斷服務(wù)函數(shù)。void EXTI0_IRQHandler(void)是外部中斷0的服務(wù)函數(shù),負責WK_UP按鍵的中斷檢測。void EXTI15_10_IRQHandler(void)是外部中斷10~15的中斷服務(wù)函數(shù),這里我們是用了中斷13和15,這兩個中斷共用一個中斷服務(wù)函數(shù)。下面我們分別介紹這幾個函數(shù)。
首先是外部中斷初始化函數(shù)void EXTIX_Init(void),該函數(shù)嚴格按照我們之前的步驟來初始化外部中斷,這里有個關(guān)閉JTAG的操作,和第二節(jié)的功能是一樣的。這里面調(diào)用了兩個函數(shù)Ex_NVIC_Config和MY_NVIC_Init,其作用在第二章已經(jīng)介紹了,有不明白的可以翻到前面看看,這里不再多說。需要說明的是因為我們的WK_UP按鍵是高電平有效的,KEY0和KEY1是低電平有效的,所以我們設(shè)置WK_UP按鍵下拉輸入,而KEY0和KEY1設(shè)置成上拉輸入。當中斷觸發(fā)的時候,在WK_UP上會檢測到上升沿,而KEY0和KEY1會產(chǎn)生下降沿。這里我們把所有中斷都分配到第二組,把按鍵的搶占優(yōu)先級設(shè)置成一樣,而子優(yōu)先級不同,KEY0和KEY1的子優(yōu)先級大于WK_UP。
接下來我們介紹兩個中斷服務(wù)函數(shù)。先看WK_UP的中斷服務(wù)函數(shù)void EXTI0_IRQHandler(void),該函數(shù)代碼比較簡單,先延時10ms以消抖,再檢測KEY2(WK_UP)是否還是為高電平,如果是,則執(zhí)行此次操作(翻轉(zhuǎn)DS0和DS1),如果不是,則直接跳過,在最后有一句EXTI->PR=1<<0;通過該句清除已經(jīng)發(fā)生的中斷請求。再看KEY0和KEY1的中斷服務(wù)函數(shù)void EXTI15_10_IRQHandler(void),該函數(shù)和KEY2的中斷服務(wù)函數(shù)有點區(qū)別,從函數(shù)名就可以看出是給中斷線10~15服務(wù)的,也就是多個中斷線上的中斷共用一個中斷服務(wù)函數(shù)。在該函數(shù)里面我們先對進入中斷的信號進行區(qū)分(通過中斷輸入IO口上的電平判斷),再分別進行處理。最后也是通過向EXTI->PR的對應(yīng)位寫1清除中斷線上的中斷請求。
我們將exti.c文件保存,然后加入到HARDWARE組下。在exti.h文件里面,我們輸入如下代碼:
#ifndef __EXTI_H
#define __EXIT_H
void EXTIX_Init(void);//IO初始化
#endif
這部分代碼就很簡單了,我們這里不多廢話,保存就可以了。接著我們在test.c里面寫入如下內(nèi)容:
#include
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
//Mini STM32開發(fā)板范例代碼4
//外部中斷實驗
//正點原子@ALIENTEK
//2010.5.27
int main(void)
{
Stm32_Clock_Init(9); //系統(tǒng)時鐘設(shè)置
delay_init(72); //延時初始化
uart_init(72,9600); //串口初始化
LED_Init(); //初始化與LED連接的硬件接口
EXTIX_Init(); //外部中斷初始化
while(1)
{
printf("OKn");
delay_ms(1000);
}
}
該部分代碼很簡單,在初始化完中斷后,就進入死循環(huán)等待了,這里死循環(huán)里面通過一個printf函數(shù)來告訴我們系統(tǒng)正在運行。其他在在這里不再多說。
3.4.4 下載與測試
在編譯成功之后,我們就可以下載代碼到MiniSTM32開發(fā)板上,實際驗證一下,我們的程序是否正確。下載代碼后,可以通過按下KEY0、KEY1、KEY2來觀看DS0、DS1是否跟著按鍵的變化而變化。