往期文章:
一、EXTI简介
外部中断/事件控制器,简称:EXTI(External interrupt/event controller)。管理了20个中断/事件线,每个中断/事件线都对应有一个边沿检测而器,可实现输入信号的上升沿和下降沿的检测。EXTI可以实现每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。
EXTI有20个中断/事件线,每个GPIO都可以被设置为输入线,占用EXTI0至EXTI15.还有另外七根用于特定的外设,如下表所示:
EXTI0至EXTI15用于GPIO,通过编程可以实现任意一个GPIO作为EXTI的输入源。EXTI0可以通过中断配置寄存器1(AFIO_EXTICR1)的EXTI0[3:0]位选择配置为PA0、PB0、PC0、PE0、PF0、PG0、PH0或者PI0,如下图所示:
二、EXTI初始化结构体详解
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.h file) */
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
} NVIC_InitTypeDef;
(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)。
三、外部中断(EXTI)编程要点及例程
(1)初始化GPIO
(2)初始化EXTI
(3)初始化NVIC
(4)编写中断服务函数
exti.h
#ifndef __EXTI_H
#define __EXTI_H
#include "stm32f10x.h"
#define KEY1_INT_GPIO_PORT GPIOA
#define KEY1_INT_GPIO_CLK (RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE GPIO_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE GPIO_PinSource0
#define KEY1_INT_EXTI_LINE EXTI_Line0
#define KEY1_INT_EXTI_IRQ EXTI0_IRQn
#define KEY1_IRQHandler EXTI0_IRQHandler
void EXTI_Key_Config(void);
#endif
exyi.c
/**
******************************************************************************
* @file gpio.c
* @author 小途
* @version V1.0
* @date 2023-7-14
* @brief I/O中断应用
******************************************************************************
* @attention
*
*
******************************************************************************
*/
#include "exti.h"
/**
* @brief 配置嵌套向量中断控制器NVIC
* @param 无
* @retval 无
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置NVIC为优先级组1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置中断源:按键1 */
NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
/* 配置抢占优先级 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 配置子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断通道 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief 配置 IO为EXTI中断口,并设置中断优先级
* @param 无
* @retval 无
*/
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/*开启按键GPIO口的时钟*/
RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);
/* 配置 NVIC 中断*/
NVIC_Configuration();
/*--------------------------KEY1配置-----------------------------*/
/* 选择按键用到的GPIO */
GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
/* 配置为浮空输入 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
/* 选择EXTI的信号源 */
GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE);
EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
/* EXTI为中断模式 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 下升沿中断 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
/* 使能中断 */
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
stm32f10x_it.h
/**
* @brief This function handles KEY1 interrupt request.
* @param None
* @retval None
*/
void KEY1_IRQHandler(void)
{
//确保是否产生了EXTI Line中断
if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)
{
// LED1 取反
LED1_TOGGLE;
//清除中断标志位
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
}
}
main.c
void RCC_Configuration(void)
{
//Install system time is 72MHZ
SystemInit();
}
int main(void)
{
RCC_Configuration();//系统时钟初始化
Delay_Timer_Init();//延时函数定时器初始化
gpio_OutputConfig(RCC_APB2Periph_GPIOB, GPIO_Pin_5, GPIOB);
EXTI_Key_Config();//设置外部中断(PB6,下降沿触发)
while(1);
}
参考文献
【1】STM32F10x-参考手册中文版
【2】STM32F101xx和STM32F103xx固件函数库
【3】stm32f103数据手册中文版
【4】Cortex-M3权威指南Cn
【5】零死角玩转STM32—F103指南者
【6】STM32库开发实战指南——基于野火霸道开发板