当前位置: 首页 > news >正文

掌握外部中断基于GD32F407VE的天空星的配置

掌握外部中断基于GD32F407VE的天空星的配置

一、中断概述

什么是中断?

在这里插入图片描述

想象这样一个场景:
⏰ 闹钟中断
场景:清晨深度睡眠中
正常执行:睡眠状态
中断发生:闹钟响起
中断处理:醒来关闹钟,起床洗漱
返回继续:不返回睡眠,开始新任务
特点:任务切换型中断

在计算机系统中,中断正是这样一种机制:

  • 中断概念:计算机响应外部或内部事件的机制,使单片机暂时中断正在执行的程序,转去执行中断处理函数,处理完毕后再返回原程序继续执行
  • 中断意义:提高了计算机的实时性和可靠性,使其能够及时响应各种事件

中断分类与触发条件

中断类型描述实例
外部设备请求外部设备请求主机处理事件键盘按键、鼠标点击触发中断
时钟中断系统计时器周期性触发中断操作系统定时任务切换
硬件故障硬件错误触发中断保护系统内存错误触发中断
软件中断软件通过指令请求系统功能应用程序调用系统服务
异常执行过程发生异常触发中断除零错误触发异常中断

中断向量表

在这里插入图片描述

中断向量表是一块固定的内存区域(4字节对齐),存放各个中断服务函数的首地址。当发生中断时,CPU会自动执行对应的中断服务函数。
中断向量对应函数
在这里插入图片描述

二、外部中断EXTI

2.1 外部中断概念

外部中断(EXTI,External Interrupt)是芯片引脚电平变化触发的中断。

触发机制

  • 硬件触发:引脚电平变化触发

    • 上升沿触发
    • 下降沿触发
    • 任意沿触发
      在这里插入图片描述
  • 软件触发:手动触发中断事件

重要特性

  • 总共16个外部中断线(0-15)
  • 同一PIN编号的引脚(如PA0和PB0)不能同时触发中断

在这里插入图片描述

2.2 硬件外部中断实现

基本配置步骤
#define EXTI2_RCU           RCU_GPIOC
#define EXTI2_PORT          GPIOC
#define EXTI2_PUPD			GPIO_PUPD_PULLUP
#define EXTI2_SOURCE_PORT   EXTI_SOURCE_GPIOC
#define EXTI2_TRIG_TYPE     EXTI_TRIG_BOTH 
#define	EXTI2_PRIORITY		2, 2void EXTI2_config() {	// ================== EXTI2 配置// 时钟使能  syscfgrcu_periph_clock_enable(RCU_SYSCFG);// 中断线连接 syscfgsyscfg_exti_line_config(EXTI2_SOURCE_PORT, EXTI_SOURCE_PIN2);// exti 初始化//        中断线      模式:中断     触发类型(条件): 上升或下降沿exti_init(EXTI_2, EXTI_INTERRUPT, EXTI2_TRIG_TYPE);// 使能外部中断exti_interrupt_enable(EXTI_2);// 中断优先级,使能中断请求  nvic_irq_enable在misc.h中// 参数1: 中断类型枚举常量, 在 gd32f4xx.h第128行// 参数2: 抢占优先级// 参数3: 响应优先级nvic_irq_enable(EXTI2_IRQn, EXTI2_PRIORITY);
}
实际应用示例

示例1:PA0按键中断

#include "gd32f4xx.h"
#include "systick.h"
#include "USART0.h"// 收到串口0数据,回调函数
void USART0_on_recv(uint8_t* data, uint32_t len) {printf("recv[%d] = %s\n", len, data);
}#define EXTI0_RCU           RCU_GPIOA
#define EXTI0_PORT          GPIOA
#define EXTI0_PUPD			GPIO_PUPD_NONE
#define EXTI0_SOURCE_PORT   EXTI_SOURCE_GPIOA
#define EXTI0_TRIG_TYPE     EXTI_TRIG_BOTH
#define	EXTI0_PRIORITY		2, 2void EXTI0_config() {// ==================  PA0 初始化  浮空输入GPIO_input(EXTI0_RCU, EXTI0_PORT, GPIO_PIN_0, EXTI0_PUPD);// ================== EXTI0 配置// 时钟使能  syscfgrcu_periph_clock_enable(RCU_SYSCFG);// 中断线连接 syscfgsyscfg_exti_line_config(EXTI0_SOURCE_PORT, EXTI_SOURCE_PIN0);// exti 初始化//        中断线      模式:中断     触发类型(条件): 上升或下降沿exti_init(EXTI_0, EXTI_INTERRUPT, EXTI0_TRIG_TYPE);// 使能外部中断exti_interrupt_enable(EXTI_0);// 中断优先级,使能中断请求  nvic_irq_enable在misc.h中// 参数1: 中断类型枚举常量, 在 gd32f4xx.h第128行// 参数2: 抢占优先级// 参数3: 响应优先级nvic_irq_enable(EXTI0_IRQn, EXTI0_PRIORITY);
}#define  KEY	GPIOA, GPIO_PIN_0
#define  DOWN	SET
#define	 UP		RESETvolatile static uint64_t start_tick = 0;// 外部中断0处理函数    启动汇编文件的第93行拷贝名字
void EXTI0_IRQHandler() {if (SET == exti_interrupt_flag_get(EXTI_0)) {exti_interrupt_flag_clear(EXTI_0); // 软件清零FlagStatus state = gpio_input_bit_get(KEY);if (DOWN == state) {// 获取起点时间start_tick = get_tick_us();//			printf("按下\n");} else {
//			printf("抬起\n");// 获取终点时间uint64_t duration = get_tick_us() - start_tick; // us为单位duration = duration / 1000; // 转换为msprintf("duration = %llu ms\n", duration);if (duration <= 50) { // < 50 ms, 不处理,忽略} else if (duration <= 500) {printf("short press\n");} else if (duration <= 2000) {printf("long press\n");}}}
}
int main(void) {// 系统滴答定时器初始化systick_config();USART0_init(); // 串口初始化调用EXTI0_config(); // 外部中断配置while(1) {
//		printf("========while(1)========\n");delay_1ms(1000);}	
}

示例2:PC0按键中断

#include "gd32f4xx.h"
#include "systick.h"
#include "USART0.h"
// 收到串口0数据,回调函数
void USART0_on_recv(uint8_t* data, uint32_t len) {printf("recv[%d] = %s\n", len, data);
}
#define EXTI0_RCU           RCU_GPIOC
#define EXTI0_PORT          GPIOC
#define EXTI0_PUPD			GPIO_PUPD_PULLUP
#define EXTI0_SOURCE_PORT   EXTI_SOURCE_GPIOC
#define EXTI0_TRIG_TYPE     EXTI_TRIG_BOTH
#define	EXTI0_PRIORITY		2, 2
void EXTI0_config() {// ==================  PA0 初始化  浮空输入GPIO_input(EXTI0_RCU, EXTI0_PORT, GPIO_PIN_0, EXTI0_PUPD);// ================== EXTI0 配置// 时钟使能  syscfgrcu_periph_clock_enable(RCU_SYSCFG);// 中断线连接 syscfgsyscfg_exti_line_config(EXTI0_SOURCE_PORT, EXTI_SOURCE_PIN0);// exti 初始化//        中断线      模式:中断     触发类型(条件): 上升或下降沿exti_init(EXTI_0, EXTI_INTERRUPT, EXTI0_TRIG_TYPE);// 使能外部中断exti_interrupt_enable(EXTI_0);// 中断优先级,使能中断请求  nvic_irq_enable在misc.h中// 参数1: 中断类型枚举常量, 在 gd32f4xx.h第128行// 参数2: 抢占优先级// 参数3: 响应优先级nvic_irq_enable(EXTI0_IRQn, EXTI0_PRIORITY);
}#define  KEY	GPIOC, GPIO_PIN_0
#define  DOWN	RESET
#define	 UP		SETvolatile static uint64_t start_tick = 0;
volatile static uint64_t last_tick = 0;  // 上一次的时间// 外部中断0处理函数    启动汇编文件的第93行拷贝名字
void EXTI0_IRQHandler() {if (SET == exti_interrupt_flag_get(EXTI_0)) {exti_interrupt_flag_clear(EXTI_0); // 软件清零// 获取当前的时间uint64_t cur_tick = get_tick_us();uint64_t shake_dura = (cur_tick - last_tick) / 1000; // 转为mslast_tick = cur_tick; // 保存上一次的状态if (shake_dura < 20) return;  // 少于30ms,不能往下执行,去抖动FlagStatus state = gpio_input_bit_get(KEY);if (DOWN == state) {// 获取起点时间start_tick = get_tick_us();//			printf("按下\n");} else {
//			printf("抬起\n");// 获取终点时间uint64_t duration = get_tick_us() - start_tick; // us为单位duration = duration / 1000; // 转换为ms
//			printf("duration = %llu ms\n", duration);if (duration <= 30) { // < 30 ms, 不处理,忽略} else if (duration <= 500) {printf("short press\n");} else if (duration <= 2000) {printf("long press\n");}}}
}int main(void) {// 系统滴答定时器初始化systick_config();USART0_init(); // 串口初始化调用EXTI0_config(); // 外部中断配置while(1) {
//		printf("========while(1)========\n");delay_1ms(1000);}	
}
中断消抖处理

Winvalid-source-encoding警告消除

 -Wno-invalid-source-encoding

在这里插入图片描述

滴答定时器中断消抖处理思路

  • SysTick 定时器,是硬件级别的计时器
    在这里插入图片描述

systick.c 文件中添加一个函数

#include "gd32f4xx.h"
#include "systick.h"volatile static uint32_t delay;
//按键按下的时间获取
volatile static uint64_t tick_us = 0;/*!\brief    configure systick\param[in]  none\param[out] none\retval     none
*/
void systick_config(void)
{/* setup systick timer for 1000000Hz interrupts */if(SysTick_Config(SystemCoreClock / 1000000U)) {/* capture error */while(1) {}}/* configure the systick handler priority */NVIC_SetPriority(SysTick_IRQn, 0x00U);
}/*!\brief    delay a time in milliseconds\param[in]  count: count in milliseconds\param[out] none\retval     none
*/
void delay_1ms(uint32_t count)
{delay = count * 1000;while(0U != delay) {}
}void delay_1us(uint32_t count)
{delay = count;while(0U != delay) {}
}
/*!\brief    delay decrement\param[in]  none\param[out] none\retval     none
*/
void delay_decrement(void)
{//累加时间tick_us ++;if(0U != delay) {delay--;}
}
//获取按键按下的时间
uint64_t get_tick_us() {return tick_us;
}

systick.h 文件中添加一个函数

#ifndef SYS_TICK_H
#define SYS_TICK_H#include <stdint.h>/* configure systick */
void systick_config(void);
/* delay a time in milliseconds */
void delay_1ms(uint32_t count);
/* delay a time in microseconds */
void delay_1us(uint32_t count);
/* delay decrement */
void delay_decrement(void);uint64_t get_tick_us();#endif /* SYS_TICK_H */

机械按键存在抖动问题,消抖处理,用按下的时间判断:

volatile static uint64_t last_tick = 0;  // 上一次的时间
// 外部中断0处理函数    启动汇编文件的第93行拷贝名字
void EXTI0_IRQHandler() {if (SET == exti_interrupt_flag_get(EXTI_0)) {exti_interrupt_flag_clear(EXTI_0); // 软件清零// 获取当前的时间uint64_t cur_tick = get_tick_us();uint64_t shake_dura = (cur_tick - last_tick) / 1000; // 转为mslast_tick = cur_tick; // 保存上一次的状态if (shake_dura < 20) return;  // 少于30ms,不能往下执行,去抖动FlagStatus state = gpio_input_bit_get(KEY);if (DOWN == state) {// 获取起点时间start_tick = get_tick_us();
//			printf("按下\n");} else {
//			printf("抬起\n");// 获取终点时间uint64_t duration = get_tick_us() - start_tick; // us为单位duration = duration / 1000; // 转换为ms
//			printf("duration = %llu ms\n", duration);if (duration <= 30) { // < 30 ms, 不处理,忽略} else if (duration <= 500) {printf("short press\n");} else if (duration <= 2000) {printf("long press\n");}}}
}

2.3 软件外部中断

软件中断无需硬件引脚变化,通过代码手动触发:

#include "gd32f4xx.h"
#include "systick.h"
#include "USART0.h"
#include "EXTI.h"// 收到串口0数据,回调函数
void USART0_on_recv(uint8_t* data, uint32_t len) {printf("recv[%d] = %#x\n", len, data[0]);switch(data[0]){case 0x0: exti_software_interrupt_enable(EXTI_0); break; case 0x1: exti_software_interrupt_enable(EXTI_1); break; case 0x2: exti_software_interrupt_enable(EXTI_2); break; case 0x3: exti_software_interrupt_enable(EXTI_3); break; case 0x4: exti_software_interrupt_enable(EXTI_4); break; case 0x5: exti_software_interrupt_enable(EXTI_5); break; case 0x6: exti_software_interrupt_enable(EXTI_6); break; case 0x7: exti_software_interrupt_enable(EXTI_7); break; case 0x8: exti_software_interrupt_enable(EXTI_8); break; case 0x9: exti_software_interrupt_enable(EXTI_9); break; case 0xA: exti_software_interrupt_enable(EXTI_10); break; case 0xB: exti_software_interrupt_enable(EXTI_11); break; case 0xC: exti_software_interrupt_enable(EXTI_12); break; case 0xD: exti_software_interrupt_enable(EXTI_13); break; case 0xE: exti_software_interrupt_enable(EXTI_14); break; case 0xF: exti_software_interrupt_enable(EXTI_15); break; default:  break; }
}void EXTI0_on_trig() {printf("===============EXTI0_on_trig================\n");
}void EXTI1_on_trig() {printf("===============EXTI1_on_trig================\n");
}void EXTI2_on_trig() {printf("===============EXTI2_on_trig================\n");
}void EXTI3_on_trig() {printf("===============EXTI3_on_trig================\n");
}void EXTI4_on_trig() {printf("===============EXTI4_on_trig================\n");
}void EXTI5_on_trig() {printf("===============EXTI5_on_trig================\n");
}void EXTI6_on_trig() {printf("===============EXTI6_on_trig================\n");
}void EXTI7_on_trig() {printf("===============EXTI7_on_trig================\n");
}void EXTI8_on_trig() {printf("===============EXTI8_on_trig================\n");
}void EXTI9_on_trig() {printf("===============EXTI9_on_trig================\n");
}void EXTI10_on_trig() {printf("===============EXTI10_on_trig================\n");
}void EXTI11_on_trig() {printf("===============EXTI11_on_trig================\n");
}void EXTI12_on_trig() {printf("===============EXTI12_on_trig================\n");
}void EXTI13_on_trig() {printf("===============EXTI13_on_trig================\n");
}void EXTI14_on_trig() {printf("===============EXTI14_on_trig================\n");
}void EXTI15_on_trig() {printf("===============EXTI15_on_trig================\n");
}int main(void) {//            抢占  [0, 3]    响应  [0, 3]nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组// 系统滴答定时器初始化systick_config();USART0_init(); // 串口初始化调用EXTI_init();   // 外部中断初始化, 包含所有,有宏定义开关while(1) {
//		printf("========while(1)========\n");delay_1ms(1000);}	
}

三、中断优先级

3.1 优先级理论

NVIC(嵌套向量中断控制器)管理中断优先级:

  • 抢占优先级:高优先级可打断低优先级任务(大老板)
  • 响应优先级:同抢占级时决定执行顺序(正式工)
  • 自然优先级:中断向量表序号,序号越小优先级越高(临时工)

优先级分组

nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);  // 4位抢占,0位响应
nvic_priority_group_set(NVIC_PRIGROUP_PRE3_SUB1);  // 3位抢占,1位响应  
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 2位抢占,2位响应
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);  // 1位抢占,3位响应
nvic_priority_group_set(NVIC_PRIGROUP_PRE0_SUB4);  // 0位抢占,4位响应

3.2 优先级规则

  1. 抢占不同,响应相同:高抢占级可打断低抢占级任务
  2. 抢占相同,响应不同:高响应级排前面,不打断只重排序
  3. 抢占相同,响应相同:比较自然优先级,不打断只重排序

注意:串口中断优先级应设置较高,否则可能无法正常触发接收中断。

四、Library封装

4.1 统一配置接口

EXTI.h

#ifndef __EXTI_H__
#define __EXTI_H__#include "gd32f4xx.h"#include "EXTI_config.h"void EXTI_init();// 非函数指针的回调函数
void EXTI0_on_trig();
void EXTI1_on_trig();
void EXTI2_on_trig();
void EXTI3_on_trig();
void EXTI4_on_trig();
void EXTI5_on_trig();
void EXTI6_on_trig();
void EXTI7_on_trig();
void EXTI8_on_trig();
void EXTI9_on_trig();
void EXTI10_on_trig();
void EXTI11_on_trig();
void EXTI12_on_trig();
void EXTI13_on_trig();
void EXTI14_on_trig();
void EXTI15_on_trig();#endif

EXTI.c

#include "EXTI.h"
#include "gpio_cfg.h"
#include <stdio.h>/*********************************************************** @brief    配置外部中断引脚* @param    rcu                    外设时钟控制器,指定要启用的外设时钟* @param    port                   GPIO端口,指定要配置的GPIO端口* @param    pin                    GPIO引脚,指定要配置的GPIO引脚* @param    pull_up_down           上拉/下拉配置,指定GPIO引脚的上拉或下拉电阻配置* @param    exti_port              EXTI端口,指定要配置的外部中断端口* @param    exti_pin               EXTI引脚,指定要配置的外部中断引脚* @param    linex                  EXTI线,指定要配置的外部中断线* @param    trig_type              触发类型,指定中断触发的类型(上升沿、下降沿、双边沿)* @param    nvic_irq               NVIC中断,指定要启用的NVIC中断* @param    nvic_irq_pre_priority  NVIC抢占优先级,指定NVIC中断的抢占优先级* @param    nvic_irq_sub_priority  NVIC子优先级,指定NVIC中断的子优先级* @return   无**********************************************************/
static void EXTI_config(rcu_periph_enum rcu, uint32_t port, uint32_t pin, uint32_t pull_up_down, uint8_t exti_port, uint8_t exti_pin, exti_line_enum linex, exti_trig_type_enum trig_type,uint8_t nvic_irq, uint8_t nvic_irq_pre_priority, uint8_t nvic_irq_sub_priority) {// ==================  引脚初始化  浮空输入GPIO_input(rcu, port, pin, pull_up_down);// ================== EXTI 配置// 时钟使能  syscfgrcu_periph_clock_enable(RCU_SYSCFG);// 中断线连接 syscfgsyscfg_exti_line_config(exti_port, exti_pin);// exti 初始化//        中断线      模式:中断     触发类型(条件)exti_init(linex, EXTI_INTERRUPT, trig_type);// 使能外部中断exti_interrupt_enable(linex);// 中断优先级,使能中断请求  nvic_irq_enable在misc.h中// 参数1: 中断类型枚举常量, 在 gd32f4xx.h 拷贝// 参数2: 抢占优先级// 参数3: 响应优先级nvic_irq_enable(nvic_irq, nvic_irq_pre_priority, nvic_irq_sub_priority);}void EXTI_init(void) {
#if USE_EXTI_0EXTI_config(EXTI0_RCU, EXTI0_PORT, GPIO_PIN_0, EXTI0_PUPD,EXTI0_SOURCE_PORT, EXTI_SOURCE_PIN0, EXTI_0, EXTI0_TRIG_TYPE,EXTI0_IRQn, EXTI0_PRIORITY);
#endif#if USE_EXTI_1EXTI_config(EXTI1_RCU, EXTI1_PORT, GPIO_PIN_1, EXTI1_PUPD,EXTI1_SOURCE_PORT, EXTI_SOURCE_PIN1, EXTI_1, EXTI1_TRIG_TYPE,EXTI1_IRQn, EXTI1_PRIORITY);
#endif#if USE_EXTI_2EXTI_config(EXTI2_RCU, EXTI2_PORT, GPIO_PIN_2, EXTI2_PUPD,EXTI2_SOURCE_PORT, EXTI_SOURCE_PIN2, EXTI_2, EXTI2_TRIG_TYPE,EXTI2_IRQn, EXTI2_PRIORITY);
#endif#if USE_EXTI_3EXTI_config(EXTI3_RCU, EXTI3_PORT, GPIO_PIN_3, EXTI3_PUPD,EXTI3_SOURCE_PORT, EXTI_SOURCE_PIN3, EXTI_3, EXTI3_TRIG_TYPE,EXTI3_IRQn, EXTI3_PRIORITY);
#endif#if USE_EXTI_4EXTI_config(EXTI4_RCU, EXTI4_PORT, GPIO_PIN_4, EXTI4_PUPD,EXTI4_SOURCE_PORT, EXTI_SOURCE_PIN4, EXTI_4, EXTI4_TRIG_TYPE,EXTI4_IRQn, EXTI4_PRIORITY);
#endif#if USE_EXTI_5EXTI_config(EXTI5_RCU, EXTI5_PORT, GPIO_PIN_5, EXTI5_PUPD,EXTI5_SOURCE_PORT, EXTI_SOURCE_PIN5, EXTI_5, EXTI5_TRIG_TYPE,EXTI5_9_IRQn, EXTI5_PRIORITY);
#endif#if USE_EXTI_6EXTI_config(EXTI6_RCU, EXTI6_PORT, GPIO_PIN_6, EXTI6_PUPD,EXTI6_SOURCE_PORT, EXTI_SOURCE_PIN6, EXTI_6, EXTI6_TRIG_TYPE,EXTI5_9_IRQn, EXTI6_PRIORITY);
#endif#if USE_EXTI_7EXTI_config(EXTI7_RCU, EXTI7_PORT, GPIO_PIN_7, EXTI7_PUPD,EXTI7_SOURCE_PORT, EXTI_SOURCE_PIN7, EXTI_7, EXTI7_TRIG_TYPE,EXTI5_9_IRQn, EXTI7_PRIORITY);
#endif#if USE_EXTI_8EXTI_config(EXTI8_RCU, EXTI8_PORT, GPIO_PIN_8, EXTI8_PUPD,EXTI8_SOURCE_PORT, EXTI_SOURCE_PIN8, EXTI_8, EXTI8_TRIG_TYPE,EXTI5_9_IRQn, EXTI8_PRIORITY);
#endif#if USE_EXTI_9EXTI_config(EXTI9_RCU, EXTI9_PORT, GPIO_PIN_9, EXTI9_PUPD,EXTI9_SOURCE_PORT, EXTI_SOURCE_PIN9, EXTI_9, EXTI9_TRIG_TYPE,EXTI5_9_IRQn, EXTI9_PRIORITY);
#endif#if USE_EXTI_10EXTI_config(EXTI10_RCU, EXTI10_PORT, GPIO_PIN_10, EXTI10_PUPD,EXTI10_SOURCE_PORT, EXTI_SOURCE_PIN10, EXTI_10, EXTI10_TRIG_TYPE,EXTI10_15_IRQn, EXTI10_PRIORITY);
#endif#if USE_EXTI_11EXTI_config(EXTI11_RCU, EXTI11_PORT, GPIO_PIN_11, EXTI11_PUPD,EXTI11_SOURCE_PORT, EXTI_SOURCE_PIN11, EXTI_11, EXTI11_TRIG_TYPE,EXTI10_15_IRQn, EXTI11_PRIORITY);
#endif#if USE_EXTI_12EXTI_config(EXTI12_RCU, EXTI12_PORT, GPIO_PIN_12, EXTI12_PUPD,EXTI12_SOURCE_PORT, EXTI_SOURCE_PIN12, EXTI_12, EXTI12_TRIG_TYPE,EXTI10_15_IRQn, EXTI12_PRIORITY);
#endif#if USE_EXTI_13EXTI_config(EXTI13_RCU, EXTI13_PORT, GPIO_PIN_13, EXTI13_PUPD,EXTI13_SOURCE_PORT, EXTI_SOURCE_PIN13, EXTI_13, EXTI13_TRIG_TYPE,EXTI10_15_IRQn, EXTI13_PRIORITY);
#endif#if USE_EXTI_14EXTI_config(EXTI14_RCU, EXTI14_PORT, GPIO_PIN_14, EXTI14_PUPD,EXTI14_SOURCE_PORT, EXTI_SOURCE_PIN14, EXTI_14, EXTI14_TRIG_TYPE,EXTI10_15_IRQn, EXTI14_PRIORITY);
#endif#if USE_EXTI_15EXTI_config(EXTI15_RCU, EXTI15_PORT, GPIO_PIN_15, EXTI15_PUPD,EXTI15_SOURCE_PORT, EXTI_SOURCE_PIN15, EXTI_15, EXTI15_TRIG_TYPE,EXTI10_15_IRQn, EXTI15_PRIORITY);
#endif
}#if USE_EXTI_0
// 外部中断0处理函数    启动汇编文件的第93行拷贝名字
void EXTI0_IRQHandler() {if (SET == exti_interrupt_flag_get(EXTI_0)) {exti_interrupt_flag_clear(EXTI_0); // 软件清零EXTI0_on_trig();}
}
#endif#if USE_EXTI_1
// 外部中断1处理函数    
void EXTI1_IRQHandler() {if (SET == exti_interrupt_flag_get(EXTI_1)) {exti_interrupt_flag_clear(EXTI_1); // 软件清零EXTI1_on_trig();}
}
#endif#if USE_EXTI_2
// 外部中断2处理函数    
void EXTI2_IRQHandler() {if (SET == exti_interrupt_flag_get(EXTI_2)) {exti_interrupt_flag_clear(EXTI_2); // 软件清零EXTI2_on_trig();}
}
#endif#if USE_EXTI_3
// 外部中断3处理函数    
void EXTI3_IRQHandler() {if (SET == exti_interrupt_flag_get(EXTI_3)) {exti_interrupt_flag_clear(EXTI_3); // 软件清零EXTI3_on_trig();}
}
#endif#if USE_EXTI_4
// 外部中断4处理函数    
void EXTI4_IRQHandler() {if (SET == exti_interrupt_flag_get(EXTI_4)) {exti_interrupt_flag_clear(EXTI_4); // 软件清零EXTI4_on_trig();}
}
#endif#if USE_EXTI_5 || USE_EXTI_6 || USE_EXTI_7 || USE_EXTI_8 || USE_EXTI_9
// 外部中断5~9处理函数    
void EXTI5_9_IRQHandler() {#if USE_EXTI_5if (SET == exti_interrupt_flag_get(EXTI_5)) {exti_interrupt_flag_clear(EXTI_5); // 软件清零EXTI5_on_trig();}#endif#if USE_EXTI_6if (SET == exti_interrupt_flag_get(EXTI_6)) {exti_interrupt_flag_clear(EXTI_6); // 软件清零EXTI6_on_trig();}#endif#if USE_EXTI_7if (SET == exti_interrupt_flag_get(EXTI_7)) {exti_interrupt_flag_clear(EXTI_7); // 软件清零EXTI7_on_trig();}#endif#if USE_EXTI_8if (SET == exti_interrupt_flag_get(EXTI_8)) {exti_interrupt_flag_clear(EXTI_8); // 软件清零EXTI8_on_trig();}#endif#if USE_EXTI_9if (SET == exti_interrupt_flag_get(EXTI_9)) {exti_interrupt_flag_clear(EXTI_9); // 软件清零EXTI9_on_trig();}#endif
}
#endif#if USE_EXTI_10 || USE_EXTI_11 || USE_EXTI_12 || USE_EXTI_13 || USE_EXTI_14 || USE_EXTI_15
// 外部中断10~15处理函数    
void EXTI10_15_IRQHandler() {#if USE_EXTI_10if (SET == exti_interrupt_flag_get(EXTI_10)) {exti_interrupt_flag_clear(EXTI_10); // 软件清零EXTI10_on_trig();}#endif#if USE_EXTI_11if (SET == exti_interrupt_flag_get(EXTI_11)) {exti_interrupt_flag_clear(EXTI_11); // 软件清零EXTI11_on_trig();}#endif#if USE_EXTI_12if (SET == exti_interrupt_flag_get(EXTI_12)) {exti_interrupt_flag_clear(EXTI_12); // 软件清零EXTI12_on_trig();}#endif#if USE_EXTI_13if (SET == exti_interrupt_flag_get(EXTI_13)) {exti_interrupt_flag_clear(EXTI_13); // 软件清零EXTI13_on_trig();}#endif#if USE_EXTI_14if (SET == exti_interrupt_flag_get(EXTI_14)) {exti_interrupt_flag_clear(EXTI_14); // 软件清零EXTI14_on_trig();}#endif#if USE_EXTI_15if (SET == exti_interrupt_flag_get(EXTI_15)) {exti_interrupt_flag_clear(EXTI_15); // 软件清零EXTI15_on_trig();}#endif
}
#endif

4.2 配置信息提取

通过配置文件管理所有外部中断参数:

#ifndef __EXTI_CONFIG_H__
#define __EXTI_CONFIG_H__#include "gd32f4xx.h"
//中断的开关1是开,0是关
#define USE_EXTI_0     1
#define USE_EXTI_1     0
#define USE_EXTI_2     0
#define USE_EXTI_3     1
#define USE_EXTI_4     0
#define USE_EXTI_5     0
#define USE_EXTI_6     0
#define USE_EXTI_7     0
#define USE_EXTI_8     0
#define USE_EXTI_9     0
#define USE_EXTI_10    0
#define USE_EXTI_11    0
#define USE_EXTI_12    0
#define USE_EXTI_13    0
#define USE_EXTI_14    0
#define USE_EXTI_15    0#if USE_EXTI_0#define EXTI0_RCU           RCU_GPIOA#define EXTI0_PORT          GPIOA#define EXTI0_PUPD			GPIO_PUPD_NONE#define EXTI0_SOURCE_PORT   EXTI_SOURCE_GPIOA#define EXTI0_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI0_PRIORITY		2, 2
#endif#if USE_EXTI_1#define EXTI1_RCU           RCU_GPIOC#define EXTI1_PORT          GPIOC  #define EXTI1_PUPD          GPIO_PUPD_PULLUP#define EXTI1_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI1_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI1_PRIORITY		2, 2
#endif#if USE_EXTI_2#define EXTI2_RCU           RCU_GPIOC#define EXTI2_PORT          GPIOC#define EXTI2_PUPD			GPIO_PUPD_PULLUP#define EXTI2_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI2_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI2_PRIORITY	2, 2
#endif#if USE_EXTI_3#define EXTI3_RCU           RCU_GPIOC#define EXTI3_PORT          GPIOC#define EXTI3_PUPD          GPIO_PUPD_PULLUP#define EXTI3_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI3_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI3_PRIORITY      2, 2
#endif#if USE_EXTI_4#define EXTI4_RCU           RCU_GPIOC#define EXTI4_PORT          GPIOC#define EXTI4_PUPD          GPIO_PUPD_PULLUP#define EXTI4_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI4_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI4_PRIORITY      2, 2
#endif#if USE_EXTI_5#define EXTI5_RCU           RCU_GPIOC#define EXTI5_PORT          GPIOC#define EXTI5_PUPD          GPIO_PUPD_PULLUP#define EXTI5_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI5_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI5_PRIORITY      2, 2
#endif#if USE_EXTI_6#define EXTI6_RCU           RCU_GPIOC#define EXTI6_PORT          GPIOC#define EXTI6_PUPD          GPIO_PUPD_PULLUP#define EXTI6_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI6_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI6_PRIORITY      2, 2
#endif#if USE_EXTI_7#define EXTI7_RCU           RCU_GPIOC#define EXTI7_PORT          GPIOC#define EXTI7_PUPD          GPIO_PUPD_PULLUP#define EXTI7_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI7_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI7_PRIORITY      2, 2
#endif#if USE_EXTI_8#define EXTI8_RCU           RCU_GPIOC#define EXTI8_PORT          GPIOC#define EXTI8_PUPD          GPIO_PUPD_PULLUP#define EXTI8_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI8_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI8_PRIORITY      2, 2
#endif#if USE_EXTI_9#define EXTI9_RCU           RCU_GPIOC#define EXTI9_PORT          GPIOC#define EXTI9_PUPD          GPIO_PUPD_PULLUP#define EXTI9_SOURCE_PORT   EXTI_SOURCE_GPIOC#define EXTI9_TRIG_TYPE     EXTI_TRIG_BOTH#define EXTI9_PRIORITY      2, 2
#endif#if USE_EXTI_10#define EXTI10_RCU          RCU_GPIOC#define EXTI10_PORT         GPIOC#define EXTI10_PUPD         GPIO_PUPD_PULLUP#define EXTI10_SOURCE_PORT  EXTI_SOURCE_GPIOC#define EXTI10_TRIG_TYPE    EXTI_TRIG_BOTH#define EXTI10_PRIORITY     2, 2
#endif#if USE_EXTI_11#define EXTI11_RCU          RCU_GPIOC#define EXTI11_PORT         GPIOC#define EXTI11_PUPD         GPIO_PUPD_PULLUP#define EXTI11_SOURCE_PORT  EXTI_SOURCE_GPIOC#define EXTI11_TRIG_TYPE    EXTI_TRIG_BOTH#define EXTI11_PRIORITY     2, 2
#endif#if USE_EXTI_12#define EXTI12_RCU          RCU_GPIOC#define EXTI12_PORT         GPIOC#define EXTI12_PUPD         GPIO_PUPD_PULLUP#define EXTI12_SOURCE_PORT  EXTI_SOURCE_GPIOC#define EXTI12_TRIG_TYPE    EXTI_TRIG_BOTH#define EXTI12_PRIORITY     2, 2
#endif#if USE_EXTI_13#define EXTI13_RCU          RCU_GPIOC#define EXTI13_PORT         GPIOC#define EXTI13_PUPD         GPIO_PUPD_PULLUP#define EXTI13_SOURCE_PORT  EXTI_SOURCE_GPIOC#define EXTI13_TRIG_TYPE    EXTI_TRIG_BOTH#define EXTI13_PRIORITY     2, 2
#endif#if USE_EXTI_14#define EXTI14_RCU          RCU_GPIOC#define EXTI14_PORT         GPIOC#define EXTI14_PUPD         GPIO_PUPD_PULLUP#define EXTI14_SOURCE_PORT  EXTI_SOURCE_GPIOC#define EXTI14_TRIG_TYPE    EXTI_TRIG_BOTH#define EXTI14_PRIORITY     2, 2
#endif#if USE_EXTI_15#define EXTI15_RCU          RCU_GPIOC#define EXTI15_PORT         GPIOC#define EXTI15_PUPD         GPIO_PUPD_PULLUP#define EXTI15_SOURCE_PORT  EXTI_SOURCE_GPIOC#define EXTI15_TRIG_TYPE    EXTI_TRIG_BOTH#define EXTI15_PRIORITY     2, 2
#endif
#endif

函数解读

/* 将EXTI恢复为默认状态(复位) */
void exti_deinit(void);
/* 初始化EXTI线x */
void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type);
/* 使能EXTI线x的中断 */
void exti_interrupt_enable(exti_line_enum linex);
/* 禁用EXTI线x的中断 */
void exti_interrupt_disable(exti_line_enum linex);
/* 使能EXTI线x的事件 */
void exti_event_enable(exti_line_enum linex);
/* 禁用EXTI线x的事件 */
void exti_event_disable(exti_line_enum linex);
/* 使能EXTI线x的软件中断事件 */
void exti_software_interrupt_enable(exti_line_enum linex);
/* 禁用EXTI线x的软件中断事件 */
void exti_software_interrupt_disable(exti_line_enum linex);/* 中断与标志函数 */
/* 获取EXTI线x的中断挂起标志 */
FlagStatus exti_flag_get(exti_line_enum linex);
/* 清除EXTI线x的中断挂起标志 */
void exti_flag_clear(exti_line_enum linex);
/* 获取EXTI线x的中断挂起标志 */
FlagStatus exti_interrupt_flag_get(exti_line_enum linex);
/* 清除EXTI线x的中断挂起标志 */
void exti_interrupt_flag_clear(exti_line_enum linex);

函数作用详解

EXTI(External Interrupt/Event Controller,外部中断/事件控制器)是MCU用于处理外部引脚触发信号的核心外设,可实现“外部信号→中断/事件”的转换。以下是各函数的具体作用:

一、初始化与复位函数(基础配置)
  1. exti_deinit

    • 作用:将EXTI控制器的所有配置恢复为复位默认状态(清除所有中断线的模式、触发方式等配置)。
    • 用途:初始化EXTI前的“清零操作”,确保配置从默认状态开始,避免残留配置影响新功能。
  2. exti_init

    • 作用:配置指定EXTI线(linex)的工作模式和触发类型,是EXTI功能的核心配置函数。
    • 参数说明:
      • linex:指定要配置的中断线(如EXTI_Line0对应GPIO引脚的第0号线,需与GPIO复用映射配合);
      • mode:工作模式(EXTI_MODE_INTERRUPT中断模式/EXTI_MODE_EVENT事件模式);
      • trig_type:触发类型(EXTI_TRIG_RISING上升沿/EXTI_TRIG_FALLING下降沿/EXTI_TRIG_BOTH双边沿)。
    • 示例:配置EXTI线0为“上升沿触发的中断模式”,用于检测按键按下(按键按下时引脚电平从低到高跳变)。
二、中断与事件控制函数(功能开关)

EXTI的“中断”和“事件”是两个核心概念:

  • 中断:触发后会向CPU发送中断请求,CPU会暂停当前任务转而执行中断服务函数(需配置NVIC);
  • 事件:触发后仅会产生一个内部脉冲信号,可用于触发其他外设(如DMA、定时器),不会打断CPU运行。
  1. exti_interrupt_enable / disable

    • 作用:单独使能/禁用指定EXTI线的“中断功能”(即使exti_init配置了中断模式,也需调用此函数使能才会生效)。
  2. exti_event_enable / disable

    • 作用:单独使能/禁用指定EXTI线的“事件功能”(与中断功能独立,可同时开启或仅开启其一)。
    • 应用场景:如通过EXTI事件触发ADC采样(无需CPU干预,提高效率)。
三、软件中断控制函数(软件触发)

除了外部引脚信号,EXTI还支持通过软件主动触发中断/事件,用于模拟外部信号或软件控制流程。

  1. exti_software_interrupt_enable / disable
    • 作用:通过软件主动触发/取消触发指定EXTI线的中断/事件(无论外部引脚是否有信号)。
    • 用途:调试时模拟外部触发信号,或在特定软件逻辑中主动触发中断(如定时检查外部设备状态)。
四、标志与中断函数(状态查询与清除)

EXTI触发后会设置对应的“挂起标志位”,需通过函数查询状态或清除标志,避免重复触发。

  1. exti_flag_get

    • 作用:获取指定EXTI线的“事件标志位”状态(SET表示已触发事件,RESET表示未触发)。
    • 用途:查询方式判断事件是否发生(适用于事件模式)。
  2. exti_flag_clear

    • 作用:清除指定EXTI线的“事件标志位”(事件触发后标志位会保持SET,需手动清除才能检测下一次触发)。
  3. exti_interrupt_flag_get

    • 作用:获取指定EXTI线的“中断标志位”状态(SET表示已触发中断,RESET表示未触发)。
    • 用途:在中断服务函数中判断是否是当前EXTI线触发的中断(避免误处理)。
  4. exti_interrupt_flag_clear

    • 作用:清除指定EXTI线的“中断标志位”(中断触发后标志位会保持SET,若不清除,会重复进入中断服务函数)。
    • 注意:必须在中断服务函数中调用,否则中断会无限触发。

总结

EXTI函数的核心逻辑是“配置→使能→触发→查询/清除标志”,关键是区分“中断”和“事件”的不同用途:

  • 需CPU处理的场景(如按键响应、异常处理)用中断模式,配合exti_interrupt_enable和中断标志函数;
  • 无需CPU干预的外设联动(如信号触发采样)用事件模式,配合exti_event_enable和事件标志函数;
  • 软件模拟外部信号用软件中断函数,灵活控制触发时机。

掌握这些函数可实现对外部信号的高效响应,是嵌入式开发中处理按键、传感器等外设的基础。

http://www.dtcms.com/a/461297.html

相关文章:

  • 销售部网站建设费crm客户管理系统模块
  • PyTorch深度学习(入门笔记)
  • SikuliX实战指南:可视化自动化与测试的核心!
  • 【ShiMetaPi M4-R1】OpenHarmony应用开发01:RArkUI 框架
  • 10.8考研笔记
  • auracast音箱-新标准新体验
  • 网站建设素材网页常州市钟楼区建设局网站
  • 网站付费怎么做海南学校网站建设
  • 前端学习 JavaScript(2)
  • Zookeeper删除提供者服务中的指定IP节点
  • 浦东建设网站制作来宾网站建设
  • 网站模板用什么打开wordpress移动广告不显示不出来
  • ArrayList和LinkedList的区别是什么?
  • 有没有做底单的网站做网站优化选阿里巴巴还是百度
  • 读写分离中间件简介
  • MR(混合现实)与AI(人工智能)结合的自主飞行技术
  • 鸿蒙:WaterFlow瀑布流组件的使用
  • Git高级操作:提升开发效率的实用别名设置
  • C++分布式语音识别服务实践——架构设计与关键技术
  • Hadoop YARN 与 MapReduce 基础关系及 YARN 核心架构细化解析
  • 网站续费模版秦皇岛网站建设价格
  • 16.链路聚合手动配置(2025年10月9日)
  • 做网站的技术门槛高吗做营销型网站费用
  • 做网站的网页图片素材怎么找海南省人才在线
  • opencv中旋转角度使用atan函数或atan2函数计算角度
  • 做详情页到那个网站找模特素材《高性能网站建设指南
  • 【蓝牙协议栈】蓝牙核心规范6.0新特性学习
  • vue中的 watchEffect、watchAsyncEffect、watchPostEffect的区别
  • Python从入门到实战:全面学习指南2
  • 今天我们开始学习python3编程之python基础