1. 程式人生 > >cortex_m3_stm32嵌入式學習筆記(四):外部中斷實驗

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_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("OK\n");
		delay_ms(100);
	}
}

注意。。有一些相關的檔案沒貼。。那都是之前寫過的。。像led.c key.c 什麼的