cortex_m3_stm32嵌入式學習筆記(四):外部中斷實驗
本章學習將STM32的IO口作為外部中斷輸入(實現和按鍵掃描一樣的功能)
STM32 的每個 IO 都可以作為外部中斷的中斷輸入口,這點也是 STM32 的強大之處。 STM32F103 的中斷控制器支援 19
個外部中斷/事件請求。每個中斷設有狀位,每個中斷/事件都有獨立的觸發和遮蔽設定。 STM32F103 的19 個外部中斷為:
線 0~15:對應外部 IO 口的輸入中斷。(本章只學習這一種)
線 16:連線到 PVD 輸出。
線 17:連線到 RTC 鬧鐘事件。
線 18:連線到 USB 喚醒事件。
從上面可以看出, STM32 供 IO 口使用的中斷線只有 16 個,但是 STM32 的 IO 口卻遠遠不止 16 個,那麼 STM32 是怎麼把 16 箇中斷線和 IO 口一一對應起來的呢?於是 STM32 就這樣設計,
GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E, F,G)分別對應中斷線 0~15。(原文是15-0 我感覺它寫錯了QAQ)
有了對映關係 很明顯 KEY0(PC5)對應中斷線5(EXTI5)KEY1(PA15)對應中斷線15(EXTI15) WK_UP(PA0)對應中斷線0(EXTI0)
接下來就是配置中斷了,編寫exti.c 新增到工程
#include "exti.h" #include "led.h" #include "key.h" #include "delay.h" #include "usart.h" void EXTIx_Init(void) { EXTI_InitTypeDef EXTI_ist; NVIC_InitTypeDef NVIC_ist; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中斷,需要使能 AFIO 時鐘 KEY_Init(); //GPIOC.5 中斷線以及中斷初始化配置 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5); EXTI_ist.EXTI_Line=EXTI_Line5; EXTI_ist.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_ist.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿觸發 EXTI_ist.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_ist); //GPIOA.15 中斷線以及中斷初始化配置 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15); EXTI_ist.EXTI_Line=EXTI_Line15; EXTI_ist.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_ist.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿觸發(1->0) EXTI_ist.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_ist); //GPIOA.0 中斷線以及中斷初始化配置 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); EXTI_ist.EXTI_Line=EXTI_Line0; EXTI_ist.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_ist.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿觸發(0->1) EXTI_ist.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_ist); //配置NVIC NVIC_ist.NVIC_IRQChannel = EXTI0_IRQn;//使能按鍵所在的外部中斷通道 NVIC_ist.NVIC_IRQChannelPreemptionPriority = 0x02; //搶佔優先順序 2 NVIC_ist.NVIC_IRQChannelSubPriority = 0x01; //子優先順序 1 NVIC_ist.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道 NVIC_Init(&NVIC_ist); NVIC_ist.NVIC_IRQChannel = EXTI9_5_IRQn;//使能按鍵所在的外部中斷通道 //NVIC_ist.NVIC_IRQChannelPreemptionPriority = 0x02; //搶佔優先順序 2 //NVIC_ist.NVIC_IRQChannelSubPriority = 0x01; //子優先順序 1 //NVIC_ist.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道 NVIC_Init(&NVIC_ist); NVIC_ist.NVIC_IRQChannel = EXTI15_10_IRQn;//使能按鍵所在的外部中斷通道 //NVIC_ist.NVIC_IRQChannelPreemptionPriority = 0x02; //搶佔優先順序 2 //NVIC_ist.NVIC_IRQChannelSubPriority = 0x01; //子優先順序 1 //NVIC_ist.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道 NVIC_Init(&NVIC_ist); } void EXTI0_IRQHandler(void)//中斷服務函式 { delay_ms(10); //消抖 if(WK_UP==1) { LED0=!LED0; LED1=!LED1; } EXTI_ClearITPendingBit(EXTI_Line0); //清除 EXTI0 線路掛起位 } void EXTI9_5_IRQHandler(void) { delay_ms(10); //消抖 if(KEY0==0) { LED0=!LED0; } EXTI_ClearITPendingBit(EXTI_Line5); //清除 LINE5 上的中斷標誌位 } void EXTI15_10_IRQHandler(void) { delay_ms(10); //消抖 if(KEY1==0) { LED1=!LED1; } EXTI_ClearITPendingBit(EXTI_Line15); //清除 LINE15 上的中斷標誌位 }
這裡面有4個函式,一個初始化中斷的函式,3箇中斷服務函式(就是中斷了之後你讓他去幹什麼)
初始化中比較麻煩
因為3個按鍵用到了3條中斷線,所以3條中斷線都要初始化,但3條線的初始化很相似,我們就以 EXTI0 為例吧 將程式碼摳出來
第一句是將 GPIO 埠與中斷線對映起來,然後選中斷線,選擇中斷模式(還有一種模式為事件模式,去論壇搜了一下沒太明白。。算了學到再說吧)GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); EXTI_ist.EXTI_Line=EXTI_Line0; EXTI_ist.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_ist.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿觸發(0->1) EXTI_ist.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_ist);
接下來選擇觸發模式,一般有上升沿觸發(電平從0->1),下降沿觸發(電平從1->0),和任意觸發模式。根據按鍵的有效性(因為WK_UP是高電平有效,所以選擇上升沿觸發,而另外兩個按鍵選擇下降沿觸發模式),最後使能外部中斷通道(不太懂。。強記吧先)
在接下來就要配置NVIC中斷優先順序,NVIC又是一個陌生詞,度娘了一下:提供中斷控制器,用於總體管理異常,稱之為“巢狀向量中斷控制器:Nested Vectored Interrupt Controller (NVIC)”。
就是用來管理中斷優先順序的
中斷優先順序有兩項:搶佔優先順序和響應優先順序,手冊上原話:
第一,如果兩個中斷的搶佔優先順序和響應優先順序都是一樣的話,則看哪個中斷先發生就先執行;第二,高優先順序的搶佔優先順序是可以打斷正在進行的低搶佔優先順序
中斷的。而搶佔優先順序相同的中斷,高優先順序的響應優先順序不可以打斷低響應優先順序的中斷。
意思是好像搶佔優先順序的地位比響應優先順序的地位高?
但我沒實現優先順序的實驗,因為好像是隻有在中斷同時進行的時候才會用到優先順序,而次實驗中斷是靠按鍵觸發的,也就是說要兩個按鍵同時按下。。這幾乎是不可能的
中斷服務函式就相對簡單了 注意最後清除中短線上中斷標誌位那條語句,一定要寫。。沒有的後果是你按下鍵後他可能不靈敏,就是有可能需要按多次才能看到應有的效果
exti.h 基本沒東西
#ifndef _EXTI_H
#define _EXIT_H
#include "sys.h"
void EXTIx_Init(void);
#endif
主函式就是呼叫一堆初始化的函式。。
#include "led.h"
#include "key.h"
#include "sys.h"
#include "delay.h"
#include "exti.h"
#include "usart.h"
void init(void)
{
delay_init();
LED_Init();
EXTIx_Init();
NVIC_Configuration();
uart_init(9600);
}
int main(void)
{
init();
LED0=0;
while(1)
{
//檢測程式是否正常執行,沒什麼用 去掉也行
printf("OK\n");
delay_ms(100);
}
}
注意。。有一些相關的檔案沒貼。。那都是之前寫過的。。像led.c key.c 什麼的