5.7 EXTI 使用说明
本章说明 N32G41x 标准外设库中 EXTI 驱动的文件组成与 9 个公开函数,内容包括中断线的复位与初始化、中断与事件标志及中断状态的查询与清除、软件中断触发,以及 RTC 时间戳触发源选择;示例部分说明 KeyInterrupt 按键中断。EXTI 的 26 条中断线与 GPIO 引脚的映射及边沿触发、屏蔽配置请配合用户手册的“中断和事件”章节阅读,EXTI 线到引脚的映射还需参考“GPIO和AFIO”章节,芯片已知问题以勘误手册为准。
5.7.1 相关文件
| 相对路径 | 作用 |
|---|---|
firmware/n32g41x_std_periph_driver/inc/n32g41x_exti.h |
定义 EXTI_InitType 结构体、模式与触发沿枚举及中断线宏,并按复位与初始化、中断与标志管理、配置三个区段声明 9 个公开函数 |
firmware/n32g41x_std_periph_driver/src/n32g41x_exti.c |
实现上述 9 个函数:中断线寄存器复位,模式与触发沿写入,软件中断触发,标志与中断状态的读取与清除,RTC 时间戳触发源选择 |
projects/n32g41x_EVAL/examples/EXTI/ |
EXTI 示例根目录,含 KeyInterrupt 1 个示例 |
projects/n32g41x_EVAL/examples/EXTI/KeyInterrupt/ |
该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt |
projects/n32g41x_EVAL/bsp/ |
该示例引用的板级支持文件:评估板 LED 与按键定义、毫秒延时函数 |
5.7.2 API 参考
以下 9 个公开函数按 n32g41x_exti.h 的声明顺序分为 3 组;每个条目给出功能摘要与 n32g41x_exti.c 中该函数正上方的注释原文。
复位与初始化
EXTI_DeInit、EXTI_InitPeripheral、EXTI_InitStruct
中断与标志管理
EXTI_TriggerSWInt、EXTI_GetStatusFlag、EXTI_ClrStatusFlag、EXTI_GetITStatus、EXTI_ClrITPendBit
配置RTC时间戳
EXTI_RTCTimeStampSel
void EXTI_DeInit(void)复位 EXTI 寄存器。
name EXTI_DeInit.
fun Reset the EXTI registers.
return none
使用提示: 实现依次清空 EXTI->IMASK、EXTI->EMASK、EXTI->RT_CFG、EXTI->FT_CFG,并对 EXTI->PEND 写入 EXTI_LINEALL(0x03FFFFFF)清除全部挂起位。
void EXTI_InitPeripheral(const EXTI_InitType *EXTI_InitParam)按 EXTI_InitType 初始化 EXTI。
name EXTI_InitPeripheral.
fun Initializes the EXTI according to EXTI_InitType.
param EXTI_InitParam(The input parameters must be the following values) :
- EXTI_Line
- EXTI_LINE0
- EXTI_LINE1
- EXTI_LINE2
- EXTI_LINE3
- EXTI_LINE4
- EXTI_LINE5
- EXTI_LINE6
- EXTI_LINE7
- EXTI_LINE8
- EXTI_LINE9
- EXTI_LINE10
- EXTI_LINE11
- EXTI_LINE12
- EXTI_LINE13
- EXTI_LINE14
- EXTI_LINE15
- EXTI_LINE16
- EXTI_LINE17
- EXTI_LINE18
- EXTI_LINE19
- EXTI_LINE20
- EXTI_LINE21
- EXTI_LINE22
- EXTI_LINE23
- EXTI_LINE24
- EXTI_LINE25
- EXTI_Mode
- EXTI_Mode_Interrupt
- EXTI_Mode_Event
- EXTI_Trigger
- EXTI_Trigger_Rising
- EXTI_Trigger_Falling
- EXTI_Trigger_Rising_Falling
- EXTI_LineCmd:
- ENABLE
- DISABLE
return none
使用提示:EXTI_LineCmd 不等于 DISABLE 时,实现先清除该线的使能与边沿配置位,再按 EXTI_Mode、EXTI_Trigger 置位;EXTI_Mode 或 EXTI_Trigger 传入枚举之外的值时不改动对应的使能或边沿寄存器。
void EXTI_InitStruct(EXTI_InitType *EXTI_StructInit)为 EXTI_InitType 的每个成员填充默认值。
name EXTI_InitStruct.
fun Fills each EXTI_InitType member with its default value.
param EXTI_StructInit : Pointer to the EXTI_InitType structure to be initialized.
return none
void EXTI_TriggerSWInt(uint32_t EXTI_Line)产生一次软件中断。
name EXTI_TriggerSWInt.
fun Generates a Software interrupt.
param EXTI_Line(The input parameters must be the following values) :
- EXTI_LINE0
- EXTI_LINE1
- EXTI_LINE2
- EXTI_LINE3
- EXTI_LINE4
- EXTI_LINE5
- EXTI_LINE6
- EXTI_LINE7
- EXTI_LINE8
- EXTI_LINE9
- EXTI_LINE10
- EXTI_LINE11
- EXTI_LINE12
- EXTI_LINE13
- EXTI_LINE14
- EXTI_LINE15
- EXTI_LINE16
- EXTI_LINE17
- EXTI_LINE18
- EXTI_LINE19
- EXTI_LINE20
- EXTI_LINE21
- EXTI_LINE22
- EXTI_LINE23
- EXTI_LINE24
- EXTI_LINE25
return none
FlagStatus EXTI_GetStatusFlag(uint32_t EXTI_Line)获取 EXTI 线标志状态。
name EXTI_GetStatusFlag.
fun Get EXTI line flag status.
param EXTI_Line(The input parameters must be the following values) :
- EXTI_LINE0
- EXTI_LINE1
- EXTI_LINE2
- EXTI_LINE3
- EXTI_LINE4
- EXTI_LINE5
- EXTI_LINE6
- EXTI_LINE7
- EXTI_LINE8
- EXTI_LINE9
- EXTI_LINE10
- EXTI_LINE11
- EXTI_LINE12
- EXTI_LINE13
- EXTI_LINE14
- EXTI_LINE15
- EXTI_LINE16
- EXTI_LINE17
- EXTI_LINE18
- EXTI_LINE19
- EXTI_LINE20
- EXTI_LINE21
- EXTI_LINE22
- EXTI_LINE23
- EXTI_LINE24
- EXTI_LINE25
return SET or RESET
void EXTI_ClrStatusFlag(uint32_t EXTI_Line)清除 EXTI 线标志状态。
name EXTI_ClrStatusFlag.
fun Clear EXTI line flag status.
param EXTI_Line :
- EXTI_LINE0
- EXTI_LINE1
- EXTI_LINE2
- EXTI_LINE3
- EXTI_LINE4
- EXTI_LINE5
- EXTI_LINE6
- EXTI_LINE7
- EXTI_LINE8
- EXTI_LINE9
- EXTI_LINE10
- EXTI_LINE11
- EXTI_LINE12
- EXTI_LINE13
- EXTI_LINE14
- EXTI_LINE15
- EXTI_LINE16
- EXTI_LINE17
- EXTI_LINE18
- EXTI_LINE19
- EXTI_LINE20
- EXTI_LINE21
- EXTI_LINE22
- EXTI_LINE23
- EXTI_LINE24
- EXTI_LINE25
return none
INTStatus EXTI_GetITStatus(uint32_t EXTI_Line)获取 EXTI 线中断状态。
name EXTI_GetITStatus.
fun GET EXTI line interrupt status.
param EXTI_Line :
- EXTI_LINE0
- EXTI_LINE1
- EXTI_LINE2
- EXTI_LINE3
- EXTI_LINE4
- EXTI_LINE5
- EXTI_LINE6
- EXTI_LINE7
- EXTI_LINE8
- EXTI_LINE9
- EXTI_LINE10
- EXTI_LINE11
- EXTI_LINE12
- EXTI_LINE13
- EXTI_LINE14
- EXTI_LINE15
- EXTI_LINE16
- EXTI_LINE17
- EXTI_LINE18
- EXTI_LINE19
- EXTI_LINE20
- EXTI_LINE21
- EXTI_LINE22
- EXTI_LINE23
- EXTI_LINE24
- EXTI_LINE25
return SET or RESET
使用提示: 实现只在 EXTI->PEND 对应位置位且 EXTI->IMASK 对应位使能时返回 SET,与只查 EXTI->PEND 的 EXTI_GetStatusFlag 不同。
void EXTI_ClrITPendBit(uint32_t EXTI_Line)清除 EXTI 线中断挂起位。
name EXTI_ClrITPendBit.
fun Clear EXTI line interrupt pend bit.
param EXTI_Line :
- EXTI_LINE0
- EXTI_LINE1
- EXTI_LINE2
- EXTI_LINE3
- EXTI_LINE4
- EXTI_LINE5
- EXTI_LINE6
- EXTI_LINE7
- EXTI_LINE8
- EXTI_LINE9
- EXTI_LINE10
- EXTI_LINE11
- EXTI_LINE12
- EXTI_LINE13
- EXTI_LINE14
- EXTI_LINE15
- EXTI_LINE16
- EXTI_LINE17
- EXTI_LINE18
- EXTI_LINE19
- EXTI_LINE20
- EXTI_LINE21
- EXTI_LINE22
- EXTI_LINE23
- EXTI_LINE24
- EXTI_LINE25
return none
使用提示: 实现与 EXTI_ClrStatusFlag 相同,均对 EXTI->PEND 写入 EXTI_Line。
void EXTI_RTCTimeStampSel(uint32_t EXTI_TSSEL_Line)选择一路 EXTI 输入作为 RTC 时间戳事件的触发源。
name EXTI_RTCTimeStampSel.
fun Select one of EXTI inputs to the RTC TimeStamp event.
param EXTI_TSSEL_Line(The input parameters must be the following values) :
- EXTI_TSSEL_LINE0
- EXTI_TSSEL_LINE1
- EXTI_TSSEL_LINE2
- EXTI_TSSEL_LINE3
- EXTI_TSSEL_LINE4
- EXTI_TSSEL_LINE5
- EXTI_TSSEL_LINE6
- EXTI_TSSEL_LINE7
- EXTI_TSSEL_LINE8
- EXTI_TSSEL_LINE9
- EXTI_TSSEL_LINE10
- EXTI_TSSEL_LINE11
- EXTI_TSSEL_LINE12
- EXTI_TSSEL_LINE13
- EXTI_TSSEL_LINE14
- EXTI_TSSEL_LINE15
return none
使用提示: 实现读改写 EXTI->TS_SEL,先清掉 EXTI_TSSEL_LINE_MASK(低 4 位)再写入 EXTI_TSSEL_Line,只能选择 EXTI0~EXTI15 中的一路。
5.7.3 Demo 示例说明
本节说明 EXTI 的 1 个示例:KeyInterrupt 用两个按键的下降沿分别触发 EXTI4 与 EXTI5 中断,中断服务函数切换当前 LED,主循环闪烁该 LED 并打印当前按键。
5.7.3.1 KeyInterrupt 按键中断
工程目录: projects/n32g41x_EVAL/examples/EXTI/KeyInterrupt/
初始化打印串口→配置 LED1、LED2 为推挽输出、KEY1 与 KEY2 为上拉输入→把 KEY1、KEY2 引脚映射到 EXTI 线并配为下降沿中断→使能 EXTI4、EXTI5_9 两条中断通道→主循环按当前按键闪烁 LED 并打印按键信息
| 项目 | 源码解读 |
|---|---|
| 功能 | 按下 KEY1(PA4)触发 EXTI4 中断,按下 KEY2(PA5)触发 EXTI5 中断; 中断服务函数切换当前 LED,主循环闪烁该 LED 并在串口打印当前按键。 |
| 源码组成 | src/main.c:main、EXTI_KEY_Configuration 与 LED、KEY 辅助函数;src/n32g41x_it.c:EXTI4 与 EXTI5_9 中断服务函数及其它向量;inc/main.h:MAX_LED_KEY_CNT 与 LED、KEY 函数声明;inc/n32g41x_it.h:中断函数声明;readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | LED1 为 PA1、LED2 为 PA7,均配为 GPIO_MODE_OUTPUT_PP、GPIO_NO_PULL、GPIO_DS_HIGH、GPIO_SLEW_RATE_FAST;KEY1 为 PA4、KEY2 为 PA5,配为 GPIO_MODE_INPUT、GPIO_PULL_UP,按下电平为 Bit_RESET。KEY1 用 EXTI_LINE4、EXTI_Mode_Interrupt、EXTI_Trigger_Falling,对应通道 EXTI4_IRQn;KEY2 用 EXTI_LINE5,对应通道 EXTI5_9_IRQn,两条通道的抢占优先级与子优先级均为 0。系统时钟为 HSI+PLL,N32G412 为 80 MHz,N32G415 为 96 MHz; 打印串口为 PA9、波特率 115200。 |
| 程序与数据路径 | main 调用 log_init 并打印 EXTI key interrupt demo!,用 LED_Init、KEY_Init 初始化外设后调用 EXTI_KEY_Configuration;按键触发后 EXTI4_IRQHandler 把 key_cnt 置 0、EXTI5_9_IRQHandler 置 1 并置 exti_int 为 1;主循环在 exti_int 非 0 时打印 str[key_cnt] 与 LED 编号,再用 LED_Blink 翻转 LedPort[key_cnt]。 |
| 主要 API | EXTI_InitStruct、EXTI_InitPeripheral、EXTI_GetStatusFlag、EXTI_ClrITPendBit、GPIO_ConfigEXTILine、NVIC_Init |
| 验证方法 | 复位运行后串口打印 EXTI key interrupt demo!,LED1 闪烁;按下 KEY1 后 LED1 闪烁并打印 KEY1(PA4),按下 KEY2 后 LED2 闪烁并打印 KEY2(PA5)。 |
| 使用提示 | KEY1(PA4)经 EXTI_LINE4 接到 EXTI4_IRQn,KEY2(PA5)经 EXTI_LINE5 接到 EXTI5_9_IRQn;按键为上拉输入、按下为低电平,故配置为下降沿触发。 支持 N32G412x8L7、N32G412xBL7、N32G415x8L7、N32G415xBL7; 开发环境为 KEIL MDK-ARM 5.34 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
示例先用板级宏取到 LED 引脚,再把 GPIO 引脚逐级接到 EXTI 线、使能中断通道,最后在中断与主循环中切换 LED 并打印。
数据路径: EXTI_KEY_Configuration → GPIO_ConfigEXTILine 映射 PA4、PA5 → EXTI_InitStruct 取默认值 → EXTI_InitPeripheral 写入 EXTI_LINE4、EXTI_LINE5 的模式与触发沿 → NVIC_Init 使能中断通道 → 按键下降沿 → EXTI4_IRQHandler、EXTI5_9_IRQHandler 更新 key_cnt、exti_int → 主循环 LED_Blink 与打印
1. 板级宏给出 LED 引脚。 评估板的 LED 端口、引脚与时钟集中定义在 BSP 头文件中,示例通过 LED1_PORT、LED1_PIN 等宏引用,中断与主循环都用这组宏定位 LED。
/* LED defines ------------------------------------------------------------------*/
#define LED1_STB
#define LED1_PORT GPIOA
#define LED1_PIN GPIO_PIN_1
#define LED1_CLOCK RCC_AHB_PERIPH_GPIO
#define LED1_CLOCK_ENABLE RCC_EnableAHBPeriphClk(LED1_CLOCK, ENABLE)
#define LED1_ON_STATE Bit_SET
#define LED2_STB
#define LED2_PORT GPIOA
#define LED2_PIN GPIO_PIN_7
#define LED2_CLOCK RCC_AHB_PERIPH_GPIO
#define LED2_CLOCK_ENABLE RCC_EnableAHBPeriphClk(LED2_CLOCK, ENABLE)
#define LED2_ON_STATE Bit_SET
更换板卡或 LED 引脚时只需修改这组宏,示例代码不用改动。
2. 把 GPIO 引脚映射到 EXTI 线并初始化。 EXTI_KEY_Configuration 先用 EXTI_InitStruct 取默认值,把 PA4 映射到 EXTI4 并按下降沿、中断模式使能;KEY2 复用同一结构体,只改线号再次调用。
EXTI_InitType EXTI_InitStructure;
NVIC_InitType NVIC_InitStructure;
EXTI_InitStruct(&EXTI_InitStructure);
/* Configure KEY1 PA4 -> EXTI_LINE4 */
GPIO_ConfigEXTILine(GPIOA_PORT_SOURCE, GPIO_PIN_SOURCE4);
EXTI_InitStructure.EXTI_Line = EXTI_LINE4;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitPeripheral(&EXTI_InitStructure);
/* Configure KEY2 PA5 -> EXTI_LINE5 */
GPIO_ConfigEXTILine(GPIOA_PORT_SOURCE, GPIO_PIN_SOURCE5);
EXTI_InitStructure.EXTI_Line = EXTI_LINE5;
EXTI_InitPeripheral(&EXTI_InitStructure);
映射用的 GPIO_ConfigEXTILine 属于 GPIO 驱动,移植到其它引脚时要同步改引脚源与 EXTI_Line。
3. 使能两条 EXTI 中断通道。 中断线使能后还须在 NVIC 中打开对应通道;PA4 与 PA5 分别落在独立通道 EXTI4_IRQn 与共用通道 EXTI5_9_IRQn。
/* Enable EXTI4 interrupt */
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRE_PRIORITY_0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SUB_PRIORITY_0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable EXTI5_9 interrupt */
NVIC_InitStructure.NVIC_IRQChannel = EXTI5_9_IRQn;
NVIC_Init(&NVIC_InitStructure);
移植到其它中断线时,要按用户手册的向量表改 NVIC_IRQChannel,例如 EXTI10~EXTI15 共用 EXTI15_10_IRQn。
4. 中断服务函数切换按键并清挂起位。 两个处理函数都先查标志、再改当前按键序号,最后对 EXTI_PEND 写入本线编号清除挂起位。
void EXTI4_IRQHandler(void)
{
if (EXTI_GetStatusFlag(EXTI_LINE4) != RESET)
{
LED_Off(LedPort[key_cnt], LedPin[key_cnt]);
key_cnt = 0;
exti_int = 1;
EXTI_ClrITPendBit(EXTI_LINE4);
}
}
void EXTI5_9_IRQHandler(void)
{
if (EXTI_GetStatusFlag(EXTI_LINE5) != RESET)
{
LED_Off(LedPort[key_cnt], LedPin[key_cnt]);
key_cnt = 1;
exti_int = 1;
EXTI_ClrITPendBit(EXTI_LINE5);
}
}
两个处理函数各自只清本线的挂起位;若同时使能多条线,须逐条判断并清除。
5. 主循环按当前按键闪烁并打印。 主循环只检查 exti_int 标志,非 0 时打印当前按键并清零标志,然后持续翻转 LedPort[key_cnt]。
while (1)
{
if(exti_int != 0)
{
printf("Current key: %s, LED%lu blinking\r\n", str[key_cnt], (unsigned long)(key_cnt + 1));
exti_int = 0;
}
LED_Blink(LedPort[key_cnt], LedPin[key_cnt]);
SysTick_Delay_Ms(500);
}
修改闪烁节拍改 SysTick_Delay_Ms 的参数;切换 LED 与按键的对应关系改中断里 key_cnt 的赋值。
对应源码: src/main.c、src/n32g41x_it.c、projects/n32g41x_EVAL/bsp/inc/n32g41x_stb.h
5.7.4 注意与排障
| 场景 | 检查与建议 | 来源 |
|---|---|---|
| 通过 GPIO 引脚产生外部中断 | 用户手册的“中断和事件”章节写明,用 AFIO 的 EXTI 配置寄存器把 GPIO 线映射到中断前必须先使能 AFIO 时钟; “GPIO和AFIO”章节同时要求该端口配置为输入模式。 |
用户手册 |
| 配置了 EXTI 线仍不产生中断 | 中断除在 EXTI_IMASK 使能对应线外,还须使能该线的 NVIC 中断通道;EXTI0~EXTI4 各有独立通道,EXTI5~EXTI9 共用 EXTI5_9 通道,EXTI10~EXTI15 共用 EXTI15_10 通道。 |
用户手册 |
| 内部模块触发的 EXTI 线 | EXTI16~EXTI19 接 PVD 与 RTC 闹钟、时间戳、唤醒事件,EXTI20~EXTI25 接 BTIM1、COMP1~COMP3 与 USART1、USART4; 手册“注意”注明 EXTI20~EXTI25 仅支持上升沿触发。 |
用户手册 |
| 清除中断请求 | 在 EXTI_PEND 的对应位写 1 清除挂起请求,改变边沿检测极性也会清除该位。 |
用户手册 |
| 保留位 | EXTI_EMASK、EXTI_IMASK、EXTI_RT_CFG、EXTI_FT_CFG、EXTI_PEND、EXTI_SWIE 的位 31:26 与 EXTI_TS_SEL 的位 31:4 为保留位,必须保持复位值。 |
用户手册 |
N32G412、N32G415 系列勘误手册 V1.0.0(2026.6.30)的勘误列表只列出一行 A 版芯片条目,勘误链接列为空,未列出具体条目。