cortex_m3_stm32嵌入式學習筆記(四):外部中斷實驗

ARM 352瀏覽

本章學習將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_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);

第一句是將 GPIO 端口與中斷線映射起來,然后選中斷線,選擇中斷模式(還有一種模式為事件模式,去論壇搜了一下沒太明白。。算了學到再說吧)

接下來選擇觸發模式,一般有上升沿觸發(電平從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("OKn");
		delay_ms(100);
	}
}

注意。。有一些相關的文件沒貼。。那都是之前寫過的。。像led.c key.c 什么的?

七星彩走势图2元网官网