一.STM32F429 EXTI简介
STM32F429外部中断/事件控制器 (EXTI) 管理了控制器的 23 个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。
二.中断/事件线
1.STM32F429 EXTI 有 23 个中断/事件线,每个 GPIO 都可以被设置为输入线,占用 EXTI0 至 EXTI15,还有另外七根用于特定的外设事件,见表:
2.EXTI0 至 EXTI15 用于 GPIO,通过编程控制可以实现任意一个 GPIO 作为 EXTI 的输入源。由上表可知,EXTI0 可以通过 AFIO 的外部中断配置寄存器 1(AFIO_EXTICR1) 的 EXTI0[3:0] 位选择配置为 PA0、PB0、PC0、PD0、PE0、PF0、PG0、PH0 或者 PI0,其他 EXTI 线 (EXTI中断/事件线) 使用配置都是类似的。
3.中断服务程序
每开启一个中断,就必须编写其对应的中断服务函数,否则将导致死机(CPU 将找不到中断服务函数)。中断服务函数接口厂家已经在 startup_stm32f429xx.s 中做好了。STM32F4 的IO 口外部中断函数只有 7 个,分别为:
void EXTI0_IRQHandler();
void EXTI1_IRQHandler();
void EXTI2_IRQHandler();
void EXTI3_IRQHandler();
void EXTI4_IRQHandler();
void EXTI9_5_IRQHandler();
void EXTI15_10_IRQHandler();
中断线 0-4,每个中断线对应一个中断函数,中断线 5-9 用中断函数 EXTI9_5_IRQHandler,
中断线10-15共用中断函数 EXTI15_10_IRQHandler。
三.外部中断控制示例
1.中断在嵌入式应用中占有非常重要的地位,几乎每个控制器都有中断功能。中断对保证紧急事件得到第一时间处理是非常重要的。
2.电路设计
我们设计使用外接的按键来作为触发源,使得控制器产生中断,并在中断服务函数中实现控制RGB彩灯的任务,电路:
3.软件设计
1) 初始化 RGB 彩灯的 GPIO;
2) 开启按键 GPIO 时钟和 SYSCFG 时钟;
3) 配置按键 GPIO 为输入模式;
4) 将按键 GPIO 连接到 EXTI 源输入;
5) 配置按键 EXTI 中断/事件线;
6) 编写 EXTI 中断服务函数
4.代码
(1)main.c
static void SystemClock_Config(void);
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/* 系统时钟初始化成216 MHz */
SystemClock_Config();
/* LED 端口初始化 */
LED_GPIO_Config();
/* 初始化EXTI中断,按下按键会触发中断,
* 触发中断会进入stm32f7xx_it.c文件中的函数
* KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯。
*/
EXTI_Key_Config();
/* 等待中断,由于使用中断方式,CPU不用轮询按键 */
while(1)
{
}
}
(2)exit.h
#ifndef __EXTI_H
#define __EXTI_H
#include "stm32f4xx.h"
//引脚定义
/*******************************************************/
#define KEY1_INT_GPIO_PORT GPIOA
#define KEY1_INT_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE();
#define KEY1_INT_GPIO_PIN GPIO_PIN_0
#define KEY1_INT_EXTI_IRQ EXTI0_IRQn
#define KEY1_IRQHandler EXTI0_IRQHandler
#define KEY2_INT_GPIO_PORT GPIOC
#define KEY2_INT_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE();
#define KEY2_INT_GPIO_PIN GPIO_PIN_13
#define KEY2_INT_EXTI_IRQ EXTI15_10_IRQn
#define KEY2_IRQHandler EXTI15_10_IRQHandler
/*******************************************************/
void EXTI_Key_Config(void);
#endif /* __EXTI_H */
(3)exit.c
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*开启按键GPIO口的时钟*/
KEY1_INT_GPIO_CLK_ENABLE();
KEY2_INT_GPIO_CLK_ENABLE();
/* 选择按键1的引脚 */
GPIO_InitStructure.Pin = KEY1_INT_GPIO_PIN;
/* 设置引脚为输入模式 */
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
/* 设置引脚不上拉也不下拉 */
GPIO_InitStructure.Pull = GPIO_NOPULL;
/* 使用上面的结构体初始化按键 */
HAL_GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
/* 配置 EXTI 中断源 到key1 引脚、配置中断优先级*/
HAL_NVIC_SetPriority(KEY1_INT_EXTI_IRQ, 0, 0);
/* 使能中断 */
HAL_NVIC_EnableIRQ(KEY1_INT_EXTI_IRQ);
/* 选择按键2的引脚 */
GPIO_InitStructure.Pin = KEY2_INT_GPIO_PIN;
/* 其他配置与上面相同 */
HAL_GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);
/* 配置 EXTI 中断源 到key1 引脚、配置中断优先级*/
HAL_NVIC_SetPriority(KEY2_INT_EXTI_IRQ, 0, 0);
/* 使能中断 */
HAL_NVIC_EnableIRQ(KEY2_INT_EXTI_IRQ);
}
void KEY1_IRQHandler(void)
{
//确保是否产生了EXTI Line中断
if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET)
{
// LED1 取反
LED1_TOGGLE;
//清除中断标志位
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
}
}
void KEY2_IRQHandler(void)
{
//确保是否产生了EXTI Line中断
if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET)
{
// LED2 取反
LED2_TOGGLE;
//清除中断标志位
EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
}
}