STM32F103外部中斷編程
中斷,顧名思義就是停下手頭的活,去干另外一件急活,干完急活然后回來繼續干手頭的活。
單片機和人一樣,有時候也有更急的程序需要執行,執行完之后再回來執行之前正在執行的程序。今天就來試試如何讓單片機中斷當前任務,執行其他任務。
先看看我的實驗板上做外部中斷要用的資源:
如上圖,板子的下面有三個獨立按鍵,右下邊有三個貼片的LED,其中這兩部分的電路圖如下圖所示:
1、獨立按鍵電路:
由上圖可知,三個獨立按鍵分別接在STM32的PB7、PB8、PB9引腳上。
2、LED電路:
由上圖可知,三個LED分別接在STM32的PC1,、PC3、PC13引腳上,
我們規划是當按下按鍵K2的時候,就讓燈D2閃爍一會兒。這時候K2就是外部中斷,當按下后,觸發中斷服務函數,燈D2閃爍的程序就是中斷服務函數。
現在打開Keil V5進行編程:
先在Manage Run-time Environment界面勾選以下選項:
勾選完成后,就開始進行編程:
1、中斷初始化函數的編寫:
void Exit_Configuration(void)
{
/*
*定義結構體
*/
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/*
*時鍾配置(要打開AFIO時鍾)
*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,ENABLE);
/*
*外部中斷使用的GPIO的配置使用PB口的9引腳
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*
*外部中斷使用的GPIO引腳也就是PB口的9引腳連接到EXTILine9
*/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9);
/*
*配置外部中斷
*/
EXTI_InitStructure.EXTI_Line =EXTI_Line9;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/*
*配置NVIC
*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
2、中斷初始化函數寫好了之后,就要編寫中斷服務函數了:
void EXTI9_5_IRQHandler(void)
{
u16 aa=10;
if(EXTI_GetITStatus(EXTI_Line9)!=RESET){
//初始化燈所在的GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//通過循環讓燈閃爍
while (aa){
GPIO_SetBits(GPIOC,GPIO_Pin_3);
delay_us(100000);
GPIO_ResetBits(GPIOC,GPIO_Pin_3);
delay_us(100000);
aa--;
}
//清除中斷標志
EXTI_ClearITPendingBit(EXTI_Line9);
//使燈的狀態為滅
GPIO_SetBits(GPIOC,GPIO_Pin_3);
}
}
3、當然延時函數的實現使用的是系統滴答定時器,函數實現如下:
/*******************************************************************************
* 函 數 名 : delay_us
* 函數功能 : 延時函數,延時us
* 輸 入 : i
* 輸 出 : 無
*******************************************************************************/
void delay_us(u32 i)
{
u32 temp;
SysTick->LOAD=9*i; //設置重裝數值, 72MHZ時
SysTick->CTRL=0X01; //使能,減到零是無動作,采用外部時鍾源
SysTick->VAL=0; //清零計數器
do
{
temp=SysTick->CTRL; //讀取當前倒計數值
}
while((temp&0x01)&&(!(temp&(1<<16)))); //等待時間到達
SysTick->CTRL=0; //關閉計數器
SysTick->VAL=0; //清空計數器
}
4、以上都完成后我們就可以編寫main函數了,main函數非常簡單,只要初始化外部中斷,然后就可以空循環等待中斷。當然在正常項目中主程序一般不會空循環。main函數如下;
int main(){
Exit_Configuration();
while(1)
{
;
}
}
當程序編寫完成之后我們下載到板子上進行試驗,按下按鍵Key2,發現燈並沒有像我們想象的那樣閃爍,為什么呢?回頭查看程序:
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;這句的意思在官方庫函數文檔中的解釋是:
也就是說可以設置中斷為上升沿中斷還是下降沿中斷還是上升沿和下降沿都產生中斷。回頭看看我們的硬件電路:
PB9通過一個按鍵接地,也就是當按鍵按下去之后,PB9的輸入電平為低電平,而原本我們程序中初始化GPIO的語句如下:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO的模式配置是浮空輸入,這時候沒有信號輸入的時候相當於是低電平,而我們再按下按鍵的時候,仍然是低電平,所以並沒有產生上升沿或者下降沿,這樣的話我們就需要對電路進行修改,怎么修改呢,在PB9上連接一個大的電阻連接到VCC,這樣當按鍵沒有按下去的時候,PB9輸入高電平,當按鍵按下去之后,PB9輸入低電平,相當於觸發了外部中斷。這個我們添加的電阻,就是上拉電阻,在我之前的電子元器件的使用之電阻的使用中有講解。
通過以上的操作就可以看到,當你按下按鍵之后,燈如你所願的閃爍起來了。這就是STM32的外部中斷使用過程。
總結:
要使用STM32的外部中斷,需要以下幾個步驟:
1、使用RCC_APB2PeriphClockCmd()函數配置時鍾
2、使用GPIO_EXTILineConfig()函數連接中斷產生的引腳
3、使用EXTI_Init( )函數配置外部中斷
4、使用NVIC_Init()配置中斷優先級等
5、編寫中斷服務函數EXTI9_5_IRQHandler()
其中大家可能會疑惑,中斷服務函數的名字中的9_5是什么意思呢?
PxN管腳共用外部中斷線EXTIN和外部中斷向量EXTIN_IRQn和中斷服務程序入口EXTIN_IRQHandler,其中[9...5]共用EXTI9_5_IRQn和EXTI9_5_IRQHandler、[15...10]共用EXTI15_10_IRQn和EXTI15_10_IRQHandler,這樣的話不管我們用PA9還是PB9,都是用EXTI9_5_IRQHandler這個函數。
從上面這張圖可以看出上面講的是什么意思了
而EXTI9_5_IRQn用在什么地方呢?大家返回去看配置NVIC的程序:
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
如果覺得有用,請關注微信公眾號: