下面的代码,是把PA0当做一个按键口,芯片内部上拉,按键闭合时,IO口被拉低,触发中断。
#include "stm32_lib/inc/stm32f0xx_rcc.h"
#include "stm32_lib/inc/stm32f0xx_exti.h"
#include "stm32_lib/inc/stm32f0xx_gpio.h"
#include "stm32_lib/inc/stm32f0xx_syscfg.h"
#include "stm32_lib/inc/stm32f0xx_misc.h"
int main(void)
{
//时钟使能
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//外部按键GPIO初始华,PA0
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//将EXTI0指向PA0
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
//EXTI0中断线配置
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
//EXTI0中断向量配置
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority=0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
while(1){
}
}
void EXTI0_1_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
//中断处理
}
//退出中断时注意清除标志位
EXTI_ClearFlag(EXTI_Line0);
}
我们可通过EXTI的头文件查看,库是怎么定义EXTI_InitTypeDef
typedef struct
{
uint32_t EXTI_Line;<span style="white-space:pre"> </span>//线
EXTIMode_TypeDef EXTI_Mode; <span style="white-space:pre"> </span>//模式
EXTITrigger_TypeDef EXTI_Trigger; <span style="white-space:pre"> </span>//触发类型
FunctionalState EXTI_LineCmd; <span style="white-space:pre"> </span>//使能
}EXTI_InitTypeDef;
关于EXTI_Line,继续看头文件
#define EXTI_Line0 ((uint32_t)0x00000001) /*!< External interrupt line 0 */
#define EXTI_Line1 ((uint32_t)0x00000002) /*!< External interrupt line 1 */
#define EXTI_Line2 ((uint32_t)0x00000004) /*!< External interrupt line 2 */
#define EXTI_Line3 ((uint32_t)0x00000008) /*!< External interrupt line 3 */
#define EXTI_Line4 ((uint32_t)0x00000010) /*!< External interrupt line 4 */
#define EXTI_Line5 ((uint32_t)0x00000020) /*!< External interrupt line 5 */
#define EXTI_Line6 ((uint32_t)0x00000040) /*!< External interrupt line 6 */
#define EXTI_Line7 ((uint32_t)0x00000080) /*!< External interrupt line 7 */
#define EXTI_Line8 ((uint32_t)0x00000100) /*!< External interrupt line 8 */
#define EXTI_Line9 ((uint32_t)0x00000200) /*!< External interrupt line 9 */
#define EXTI_Line10 ((uint32_t)0x00000400) /*!< External interrupt line 10 */
#define EXTI_Line11 ((uint32_t)0x00000800) /*!< External interrupt line 11 */
#define EXTI_Line12 ((uint32_t)0x00001000) /*!< External interrupt line 12 */
#define EXTI_Line13 ((uint32_t)0x00002000) /*!< External interrupt line 13 */
#define EXTI_Line14 ((uint32_t)0x00004000) /*!< External interrupt line 14 */
#define EXTI_Line15 ((uint32_t)0x00008000) /*!< External interrupt line 15 */
#define EXTI_Line16 ((uint32_t)0x00010000) /*!< External interrupt line 16
Connected to the PVD Output */
#define EXTI_Line17 ((uint32_t)0x00020000) /*!< Internal interrupt line 17
Connected to the RTC Alarm
event */
#define EXTI_Line19 ((uint32_t)0x00080000) /*!< Internal interrupt line 19
Connected to the RTC Tamper
and Time Stamp events */
#define EXTI_Line21 ((uint32_t)0x00200000) /*!< Internal interrupt line 21
Connected to the Comparator 1
event */
#define EXTI_Line22 ((uint32_t)0x00400000) /*!< Internal interrupt line 22
Connected to the Comparator 2
event */
#define EXTI_Line23 ((uint32_t)0x00800000) /*!< Internal interrupt line 23
Connected to the I2C1 wakeup
event */
#define EXTI_Line25 ((uint32_t)0x02000000) /*!< Internal interrupt line 25
Connected to the USART1 wakeup
event */
#define EXTI_Line27 ((uint32_t)0x08000000) /*!< Internal interrupt line 27
Connected to the CEC wakeup
event */
这里定义了N多EXTI_Line,其中Line0-Line15表示GPIOX_Pin_N的中断。如何区分GPIOX呢?这也就是概念2要补充的了。这里通过SYSCFG_EXTILineConfig函数来配置。
//将EXTI0指向PA0
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
继续看头文件,了解EXTI的MODE
typedef enum
{
EXTI_Mode_Interrupt = 0x00,
EXTI_Mode_Event = 0x04
}EXTIMode_TypeDef;
一个是Interrupt中断,一个是Event事件。
中断,系统最多只能给其配置个中断向量入口,然后执行相应的软件程序。
而事件,系统中存在硬件电路,可配置其连接至需要触发硬件电路中,如触发AD转换,或者引起DMA操作等。
关于EXTITrigger_TypeDef,经常使用示波器的朋友们想必已经很清楚了,上升沿触发、下降沿触发、上升下降兼触发。
typedef enum
{
EXTI_Trigger_Rising = 0x08,
EXTI_Trigger_Falling = 0x0C,
EXTI_Trigger_Rising_Falling = 0x10
}EXTITrigger_TypeDef;
NVIC中的IRQChannel为什么是EXTI0_1_IRQN呢?
这个可以再stm32f0xx.h头文件找到EXTI0_1_IRQn对应线0和1的中断
EXTI2_3_IRQn对应线2和3的中断
EXTI4_15_IRQn对应线4-15的中断
#if defined (STM32F0XX_MD) || defined (STM32F030X8)
/****** STM32F0XX_MD and STM32F030X8 specific Interrupt Numbers *************************************/
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
PVD_IRQn = 1, /*!< PVD through EXTI Line detect Interrupt */
RTC_IRQn = 2, /*!< RTC through EXTI Line Interrupt */
FLASH_IRQn = 3, /*!< FLASH Interrupt */
RCC_IRQn = 4, /*!< RCC Interrupt */
EXTI0_1_IRQn = 5, /*!< EXTI Line 0 and 1 Interrupts */
EXTI2_3_IRQn = 6, /*!< EXTI Line 2 and 3 Interrupts */
EXTI4_15_IRQn = 7, /*!< EXTI Line 4 to 15 Interrupts
好了,问题来了,居然EXTI0_1_IRQn包含两个中断,那怎么区分呢?
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
这下应该知道中断函数里为什么加这句的原因了吧。