EXTI—外部中断/事件控制器
EXTI 简介
EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了控制器的 20 个中断/事件线。
每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。
EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。
EXTI 功能框图

EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件。
红色虚线指示的电路流程。它是一个产生中断的线路,最终信号流入到 NVIC 控制器内。
编号 1 是输入线, EXTI 控制器有 19 个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个 GPIO,也可以是一些外设的事件,输入线一般是存在电平变化的信号。
编号 2 是一个边沿检测电路,它会根据上升沿触发选择寄存器 (EXTI_RTSR) 和下降沿触发选择寄存器 (EXTI_FTSR) 对应位的设置来控制信号触发。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号 1 给编号 3 电路,否则输出无效信号 0。EXTI_RTSR 和EXTI_FTSR 两个寄存器可以控制器需要检测哪些类型的电平跳变过程,可以是只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发。
编号 3 电路实际就是一个或门电路,它一个输入来自编号 2 电路,另外一个输入来自软件中断事件寄存器 (EXTI_SWIER)。EXTI_SWIER 允许我们通过程序控制就可以启动中断/事件线。
编号 4 电路是一个与门电路,它一个输入是编号 3 电路,另外一个输入来自中断屏蔽寄存器(EXTI_IMR)。
编号 5 是将 EXTI_PR 寄存器内容输出到 NVIC 内,从而实现系统中断事件控制。
绿色虚线指示的电路流程。它是一个产生事件的线路,最终输出一个脉冲信号。
编号 6 电路是一个与门,它一个输入来自编号 3 电路,另外一个输入来自事件屏蔽寄存器 (EXTI_EMR)。
编号 7 是一个脉冲发生器电路,当它的输入端,即编号 6 电路的输出端,是一个有效信号 1 时就会产生一个脉冲;如果输入端是无效信号就不会输出脉冲。
编号 8 是一个脉冲信号,就是产生事件的线路最终的产物,这个脉冲信号可以给其他外设电路使用,比如定时器 TIM、模拟数字转换器 ADC 等等,这样的脉冲信号一般用来触发 TIM 或者 ADC开始转换。
产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
EXTI 是在 APB2 总线上的。
中断/事件线
EXTI 有 20 个中断/事件线,每个 GPIO 都可以被设置为输入线,占用 EXTI0 至 EXTI15,还有另外七根用于特定的外设事件。

EXTI0 至 EXTI15 用于 GPIO,通过编程控制可以实现任意一个 GPIO 作为 EXTI 的输入源。
EXTI0 可以通过 AFIO 的外部中断配置寄存器 1(AFIO_EXTICR1) 的EXTI0[3:0] 位选择配置为 PA0、 PB0、 PC0、 PD0、 PE0、 PF0、 PG0、 PH0 或者 PI0。

EXTI 初始化结构体详解

1) EXTI_Line: EXTI 中断/事件线选择,可选 EXTI0 至 EXTI19,可参考表 EXTI 中断 _ 事件线选择。
2) EXTI_Mode: EXTI 模式选择,可选为产生中断 (EXTI_Mode_Interrupt) 或者产生事件(EXTI_Mode_Event)。
3) EXTI_Trigger: EXTI 边沿触发事件,可选上升沿触发 (EXTI_Trigger_Rising)、下降沿触发 (EXTI_Trigger_Falling) 或者上升沿和下降沿都触发 ( EXTI_Trigger_Rising_Falling)。
4) EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线 (ENABLE) 或禁用 (DISABLE)。
外部中断控制实验
1) 初始化用来产生中断的 GPIO;
2) 初始化 EXTI;
3) 配置 NVIC;
4) 编写中断服务函数;
EXTI代码
exti.h
#ifndef _EXTI_H
#define _EXTI_H
#include "stm32f10x.h"
#define EXTI_KEY_RCC RCC_APB2Periph_AFIO
#define EXTI_KEY_1_Line EXTI_Line0
#define EXTI_KEY_2_Line EXTI_Line13
#define EXTI_KEY_1_PortSource GPIO_PortSourceGPIOA
#define EXTI_KEY_2_PortSource GPIO_PortSourceGPIOC
#define EXTI_KEY_1_PinSource GPIO_PinSource0
#define EXTI_KEY_2_PinSource GPIO_PinSource13
#define EXTI_KEY_1_IRQn EXTI0_IRQn
#define EXTI_KEY_2_IRQn EXTI15_10_IRQn
#define EXTI_KEY_1_IRQHandler EXTI0_IRQHandler
#define EXTI_KEY_2_IRQHandler EXTI15_10_IRQHandler
void EXTI_Config(void);
#endif
exti.c
#include "exti.h"
#include "key.h"
static void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
//配置中断优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//NVIC中断控制器结构体配置
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
//配置按键1中断控制器通道和初始化按键1中断控制器
NVIC_InitStruct.NVIC_IRQChannel = EXTI_KEY_1_IRQn;
NVIC_Init(&NVIC_InitStruct);
//配置按键2中断控制器通道和初始化按键2中断控制器
NVIC_InitStruct.NVIC_IRQChannel = EXTI_KEY_2_IRQn;
NVIC_Init(&NVIC_InitStruct);
}
void EXTI_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
//使能KEY1和KEY2以及EXTI中断时钟
RCC_APB2PeriphClockCmd(KEY_1_RCC | KEY_2_RCC | EXTI_KEY_RCC,ENABLE);
//KEY1和KEY2的GPIO结构体配置
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = KEY_1_PIN | KEY_2_PIN;
GPIO_Init(KEY_1_PORT,&GPIO_InitStruct);
GPIO_Init(KEY_2_PORT,&GPIO_InitStruct);
//EXTI结构体配置
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
//KEY1的EXTI结构体配置
GPIO_EXTILineConfig(EXTI_KEY_1_PortSource,EXTI_KEY_1_PinSource);
EXTI_InitStruct.EXTI_Line = EXTI_KEY_1_Line;
EXTI_Init(&EXTI_InitStruct);
//KEY2的EXTI结构体配置
GPIO_EXTILineConfig(EXTI_KEY_2_PortSource,EXTI_KEY_2_PinSource);
EXTI_InitStruct.EXTI_Line = EXTI_KEY_2_Line;
EXTI_Init(&EXTI_InitStruct);
//开启中断服务
NVIC_Config();
}
按键代码
key.h
#ifndef _KEY_H
#define _KEY_H
#include "stm32f10x.h"
#define KEY_1_RCC RCC_APB2Periph_GPIOA
#define KEY_1_PIN GPIO_Pin_0
#define KEY_1_PORT GPIOA
#define KEY_2_RCC RCC_APB2Periph_GPIOC
#define KEY_2_PIN GPIO_Pin_13
#define KEY_2_PORT GPIOC
#define PRESS 1
#define RELEASE 0
enum
{
KEY_1,
KEY_2
};
void KEY_Init(void);
uint8_t KEY_Scan(unsigned char key);
#endif
key.c
#include "key.h"
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(KEY_1_RCC | KEY_2_RCC,ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = KEY_1_PIN | KEY_2_PIN;
GPIO_Init(KEY_1_PORT,&GPIO_InitStruct);
GPIO_Init(KEY_2_PORT,&GPIO_InitStruct);
}
uint8_t KEY_Scan(unsigned char key)
{
uint8_t key_state;
switch (key)
{
case KEY_1:
if(GPIO_ReadInputDataBit(KEY_1_PORT,KEY_1_PIN) == PRESS)
{
while(GPIO_ReadInputDataBit(KEY_1_PORT,KEY_1_PIN) == PRESS);
key_state = PRESS;
}
else
key_state = RELEASE;
break;
case KEY_2:
if(GPIO_ReadInputDataBit(KEY_2_PORT,KEY_2_PIN) == PRESS)
{
while(GPIO_ReadInputDataBit(KEY_2_PORT,KEY_2_PIN) == PRESS);
key_state = PRESS;
}
else
key_state = RELEASE;
break;
}
return key_state;
}
LED灯代码
led.h
#ifndef _LED_H
#define _LED_H
#include "stm32f10x.h"
#define LED_G_RCC RCC_APB2Periph_GPIOB
#define LED_G_PIN GPIO_Pin_0
#define LED_G_PORT GPIOB
#define LED_R_RCC RCC_APB2Periph_GPIOB
#define LED_R_PIN GPIO_Pin_5
#define LED_R_PORT GPIOB
#define LED_B_RCC RCC_APB2Periph_GPIOB
#define LED_B_PIN GPIO_Pin_1
#define LED_B_PORT GPIOB
#define ON 1
#define OFF 0
enum
{
LED_G, /* LED_G*/
LED_R, /* LED_R*/
LED_B /* LED_B*/
};
void LED_Init(void);
void LED_Config(unsigned char led,unsigned char state);
void LED_Toggle(unsigned char led);
#endif
led.c
#include "led.h"
/*
led初始化
*/
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(LED_G_RCC | LED_R_RCC | LED_B_RCC,ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = LED_G_PIN | LED_R_PIN | LED_B_PIN;
GPIO_Init(LED_G_PORT,&GPIO_InitStruct);
GPIO_Init(LED_R_PORT,&GPIO_InitStruct);
GPIO_Init(LED_B_PORT,&GPIO_InitStruct);
//默认关闭LED
GPIO_SetBits(LED_G_PORT,LED_G_PIN);
GPIO_SetBits(LED_R_PORT,LED_R_PIN);
GPIO_SetBits(LED_B_PORT,LED_B_PIN);
}
/*
Fun:led设置(配置)
Para1:led 选择(LED_G/LED_R/LED_B)
Para2:led 状态(ON/OFF)
*/
void LED_Config(unsigned char led,unsigned char state)
{
switch(led)
{
case LED_G:
if(state == ON)
GPIO_ResetBits(LED_G_PORT,LED_G_PIN);
else
GPIO_SetBits(LED_G_PORT,LED_G_PIN);
break;
case LED_R:
if(state == ON)
GPIO_ResetBits(LED_R_PORT,LED_R_PIN);
else
GPIO_SetBits(LED_R_PORT,LED_R_PIN);
break;
case LED_B:
if(state == ON)
GPIO_ResetBits(LED_B_PORT,LED_B_PIN);
else
GPIO_SetBits(LED_B_PORT,LED_B_PIN);
break;
}
}
/*
Fun:led反转
Para:led 选择(LED_G/LED_R/LED_B)
*/
void LED_Toggle(unsigned char led)
{
switch (led)
{
case LED_G:
LED_G_PORT->ODR ^= LED_G_PIN;
break;
case LED_R:
LED_R_PORT->ODR ^= LED_R_PIN;
break;
case LED_B:
LED_B_PORT->ODR ^= LED_B_PIN;
break;
}
}
中断服务函数代码
void EXTI_KEY_1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_KEY_1_Line) == SET)
{
LED_Toggle(LED_G);
EXTI_ClearITPendingBit(EXTI_KEY_1_Line);
}
}
void EXTI_KEY_2_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_KEY_2_Line) == SET)
{
LED_Toggle(LED_G);
EXTI_ClearITPendingBit(EXTI_KEY_2_Line);
}
}
EXTI是STM32中的外部中断/事件控制器,管理20个中断线,支持GPIO和特定外设事件。每个中断线可配置为中断或事件,检测上升沿和下降沿。中断线通过NVIC触发中断服务函数,事件则产生脉冲信号供硬件级使用。初始化涉及GPIO、EXTI和NVIC配置。
1万+

被折叠的 条评论
为什么被折叠?



