GD32F103RCT6/GD32F303RCT6(4)外部中断

本文详细介绍了使用兆易创新GD32MCU的EXTI中断控制器进行嵌入式开发,涵盖了中断介绍、主要特性、配置方法、中断服务函数示例以及按键LED实验,展示了如何利用EXTI进行GPIO中断处理和系统唤醒。
摘要由CSDN通过智能技术生成

  本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发

向上代码兼容GD32F450ZGT6中使用

后续项目主要在下面该专栏中发布:

https://blog.csdn.net/qq_62316532/category_12608431.html?spm=1001.2014.3001.5482

感兴趣的点个关注收藏一下吧!

电机驱动开发可以跳转:

GD32F103RCT6/GD32F303RCT6-实战项目-无刷电机驱动(1)_gd32f103rct6例程-CSDN博客

BMS电源系统开发可以跳转:

暂未放链接

DCDC-双向BUCK-BOOST实战链接:

GD32实战篇-双向数控BUCK-BOOST-BUCK降压理论基础-CSDN博客

GD32实战篇-双向数控BUCK-BOOST-BOOST升压理论基础-CSDN博客

 向上代码兼容GD32F303RCT6中使用

本项目配套开发板:

基于GD32F103RCT6国产GD32平台,以下教程编写基于该开发板

ad582f26acfc4c4986f17c202c2b4848.png

中断介绍

EXTI(中断/事件控制器)包括20个相互独立的边沿检测电路并且能够向处理器内核产生中断 请求或唤醒事件。EXTI有三种触发类型:上升沿触发、下降沿触发和任意沿触发。EXTI中的每 一个边沿检测电路都可以独立配置和屏蔽。

主要特征

Cortex-M3 系统异常;

多达 68 种可屏蔽的外设中断;

4 位中断优先级配置位——16 个中断优先等级;

高效的中断处理;

支持异常抢占和咬尾中断;

将系统从省电模式唤醒;

EXTI 中有多达 20 个相互独立的边沿检测电路;

3 种触发类型:上升沿触发,下降沿触发和任意沿触发;

软件中断或事件触发;

可配置的触发源。

外部中断及事件(EXTI) 框图

e64190d34f5e4e42ab6892da7b7a0d11.png

EXTI包含多达20个相互独立的边沿检测电路并且可以向处理器产生中断请求或事件唤醒。 EXTI提供3种触发类型:上升沿触发,下降沿触发和任意沿触发。EXTI中每个边沿检测电路都 可以分别予以配置或屏蔽。

EXTI触发源包括来自I/O管脚的16根线以及来自内部模块的4根线。(包括LVD、RTC闹钟、USB 唤醒、以太网唤醒)。通过配置GPIO模块的AFIO_EXTISSx寄存器,所有的GPIO管脚都可以被 选作EXTI的触发源,具体细节请参考GPIO和AFIO章节。

EXTI触发源

EXTI 线编号

触发源

0

PA0/PB0/PC0/PD0/PE0/PF0/PG0

1

PA1/PB1/PC1/PD1/PE1/PF1/PG1

2

PA2/PB2/PC2/PD2/PE2/PF2/PG2

3

PA3/PB3/PC3/PD3/PE3/PF3/PG3

4

PA4/PB4/PC4/PD4/PE4/PF4/PG4

5

PA5/PB5/PC5/PD5/PE5/PF5/PG5

6

PA6/PB6/PC6/PD6/PE6/PF6/PG6

7

PA7/PB7/PC7/PD7/PE7/PF7/PG7

8

PA8/PB8/PC8/PD8/PE8/PF8/PG8

9

PA9/PB9/PC9/PD9/PE9/PF9/PG9

10

PA10/PB10/PC10/PD10/PE10/PF10/PG10

11

PA11/PB11/PC11/PD11/PE11/PF11/PG11

12

PA12/PB12/PC12/PD12/PE12/PF12/PG12

13

PA13/PB13/PC13/PD13/PE13/PF13/PG13

14

PA14/PB14/PC14/PD14/PE14/PF14/PG14

15

PA15/PB15/PC15/PD15/PE15/PF15/PG15

16

LVD

17

RTC 闹钟

18

USB 唤醒

注意:EXTI线19的以太网唤醒只可用于GD32F107xx设备中,故此103设备不写本通道。

EXTI 寄存器

虽然我知道大家对应寄存器这种生涩难懂的东西不是很想接触,但是毕竟是出一个教程,加上很多时候找问题的时候我们都会返回寻找寄存器,所以我这里还是需要讲一下各个寄存器

如果对寄存器不感兴趣的同学,可以跳过本小结!

EXTI基地址:0x4001 0400

中断使能寄存器(EXTI_INTEN)

作用:使能或使能对应GPIO口的中断,可写可读

地址偏移:0x00

复位值:0x0000 0000

该寄存器只能按字(32 位)访问

d0e105aa6d22449dae99e73dfaa09567.png

3c62799bf01f4240a7ae834b7fbe7aaa.png

事件使能寄存器(EXTI_EVEN)

作用:使能或使能对应端口的事件,可写可读

地址偏移:0x04

复位值:0x0000 0000 该寄存器只能按字(32 位)访问

caa7bd3fd62542668a1c0eb29672e960.png

3339b076ac2a46c8bfd80b08bd57be0a.png

b1d542a9635844f2a01514be93324206.png

上升沿触发使能寄存器(EXTI_RTEN)

作用:使能或使能对应端口的上升沿触发选项,可写可读

地址偏移:0x08

复位值:0x0000 0000 该寄存器只能按字(32位)访问

c4946f40d58e47c498ce2ea231d584bc.png

c6ecd4395e544e14aaa7dbef25affa1c.png

下降沿触发使能寄存器(EXTI_FTEN)

作用:使能或使能对应端口的下降沿触发选项,可写可读

地址偏移:0x0C

复位值:0x0000 0000 该寄存器只能按字(32位)访问

b7013d07d3c94a8faf85ad8e5d04e03c.png

c3a9b11bb12141cf885c72c752cfc772.png

软件中断事件寄存器(EXTI_SWIEV)

作用:激活或禁用对应中断线的软件软件/事件触发选项,可写可读

地址偏移:0x10

复位值:0x0000 0000 该寄存器只能按字(32位)访问

bd8d31d105da4c9aabfb776fdbfdcdf4.png

49feae000f0743efaeaf78495e301868.png

挂起寄存器(EXTI_PD)

作用:读取对应的中断/事件线的状态,并且支持清除该位,软件可以读此位,也可以通过写’1’清除此位

762e451241d446b790f4d6f2b22f08d2.png

97036c526c9440068d52d5319ec547d6.png

EXTI库函数

官方资料:

GD32F10x_Firmware_Library_V2.2.4\Firmware\GD32F10x_standard_peripheral\Include\gd32f10x_misc.h

GD32F10x_Firmware_Library_V2.2.4\Firmware\GD32F10x_standard_peripheral\Include\gd32f10x_gpio.h

以下函数位于:

GD32F10x_Firmware_Library_V2.2.4\Firmware\GD32F10x_standard_peripheral\Include\gd32f10x_misc.h

设置优先级分组

函数声明如下:

void nvic_priority_group_set(uint32_t nvic_prigroup)

参数:

gpio_periph

参数1

GPIO端口x(x = A,B,C,D,E,F,G)

返回

参数1:

含义

NVIC_PRIGROUP_PRE0_SUB4

0位用于抢占优先级,4位用于响应优先级

NVIC_PRIGROUP_PRE1_SUB3

1位用于抢占优先级,3位用于响应优先级

NVIC_PRIGROUP_PRE2_SUB2

2位用于抢占优先级,2位用于响应优先级

NVIC_PRIGROUP_PRE3_SUB1

3位用于抢占优先级,1位用于响应优先级

NVIC_PRIGROUP_PRE4_SUB0

4位用于抢占优先级,0位用于响应优先级

使能NVIC中断

函数声明如下:

void nvic_irq_enable(uint8_t nvic_irq, uint8_t nvic_irq_pre_priority, uint8_t nvic_irq_sub_priority)

参数:

nvic_irq

参数1

NVIC中断请求,详见下文

nvic_irq_pre_priority

参数2

需要设置的抢占优先级

nvic_irq_sub_priority

参数3

需要设置的子优先级

返回

参数1:

名称

功能

EXTI0_IRQn

EXTI线0中断

EXTI1_IRQn

EXTI线1中断

EXTI2_IRQn

EXTI线2中断

EXTI3_IRQn

EXTI线3中断

EXTI4_IRQn

EXTI线4中断

EXTI5_9_IRQn

EXTI线[9:5]中断

EXTI10_15_IRQn

EXTI线[15:10]中断

参数2:

根据前面选择的优先级分组填入主优先级

参数3:

根据前面选择的优先级分组填入子优先级

选择哪个引脚作为EXTI源

函数声明如下:

void gpio_exti_source_select(uint8_t output_port, uint8_t output_pin)

参数:

output_port

参数1

EXTI源端口x(x = A,B,C,D,E,F,G)

output_pin

参数2

源端口引脚x(x=0…15)

返回

初始化EXTI线x

函数声明如下:

void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type)

参数:

linex

参数1

EXTI线x(x=0,1,2…19)

mode

参数2

EXTI模式

trig_type

参数3

触发类型

返回

参数1:

EXTI线x(x=0,1,2…19)

参数2:

名称

功能

EXTI_INTERRUPT

中断模式

EXTI_EVENT

事件模式

参数3:

名称

功能

EXTI_TRIG_RISING

上升沿触发

EXTI_TRIG_FALLING

下降沿触发

EXTI_TRIG_BOTH

上升沿和下降沿均触发

清除EXTI线x中断标志位

函数声明如下:

void exti_interrupt_flag_clear(exti_line_enum linex)

参数:

linex

参数1

EXTI线x(x=0,1,2…19)

返回

获取EXTI行x中断挂起标志

函数声明如下:

FlagStatus exti_flag_get(exti_line_enum linex)

FlagStatus exti_interrupt_flag_get(exti_line_enum linex)

参数:

linex

参数1

EXTI线x(x=0,1,2…19)

返回

retval FlagStatus:

标志的状态(RESET或SET)

清除EXTI行x中断挂起标志

函数声明如下:

void exti_flag_clear(exti_line_enum linex)

void exti_interrupt_flag_clear(exti_line_enum linex)

参数:

linex

参数1

EXTI线x(x=0,1,2…19)

返回

外部中断处理函数

一旦中断发生,其所对应的中断服务函数就会被执行,那么我们就可以在中断服务函数中现实一些控制

为确定中断是否确定发生,我们会在中断服务函数中调用中断标志位状态读取函数读取外设中断标志位并判断标志位状态。

exti_interrupt_flag_get() 函数用来获取 EXTI 的中断标志位状态,如果 EXTI 线有中断发生函数返回“SET”否则返回“RESET”。

exti_interrupt_flag_get() 函数是通过读取 EXTI_PD 寄存器值来判断 EXTI 线状态的。

void EXTI1_IRQHandler(void)

{

     //判定是否是外部中断线1

     if (RESET != exti_interrupt_flag_get(EXTI_1))

     {

     //在此加入自己的控制,一般为置标志等短暂非阻塞操作



     //清除中断标记

     exti_interrupt_flag_clear(TAMPER_KEY_EXTI_LINE);

     }

}

外部中断处理函数名称要与EXTI线相对应,不然就无法在中断发生时,进入到我们编写的处理函数中,具体的表可在 startup_gd32f10x_hd.s 启动文件中查看:

5891aa27e80541ef9b3b0288e328d0f7.png

891be66472f44b2f8acbcad7dbec17cb.png

e122470358324e5e9f3dbb34f6a10576.png

代码编写:

接下来我们开始代码部分的编写

按键输入实验

使用开发板上三个按键采用中断控制三个LED灯亮灭。

按键硬件电路如下:

cd99e0dd27ee4507b8ca5348c381e5fa.png

如果硬件上已外部上拉或下拉,则选择浮空输入模式。

如果硬件外部没有上拉,则选择内部上拉模式。

LED硬件电路如下:

//管脚复用时钟使能

rcu_periph_clock_enable(RCU_AF);

//PB4和PB3管脚默认是NJTRST,要当GPIO,需要重映射

gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE)

不要忘记重映射

需要按步骤进行以下操作:

1.使能 GPIO 端口时钟

2.初始化 EXTI

3.配置 NVIC

4.编写中断服务函数

配置 EXTI 信号源的时候需要用到 AFIO 的外部中断控制寄存器 AFIO_EXTISSx,所以用到 EXTI 必须开启 AFIO 时钟

抢占优先级,数字越小,优先级越高

若抢占优先级相同,判断子优先级,同样,数字越小,优先级越高

当中断发生时,对应的中断服务函数就会被执行,我们可以在中断服务函数实现一些控制。

一般为确保中断确实发生,我们会在中断服务函数中调用中断标志位状态读取函数读取外设中断标志位并判断标志位状态。

exti_interrupt_flag_get() 函数用来获取 EXTI 的中断标志位状态,如果 EXTI 线有中断发生函数返回“SET”否则返回“RESET”。

这里因为中断5、6、7都是属于5-9中断源中的,我们要进行区分,所以我定义了一个state_choose_flag变量去对当前中断进行区分,同时

在最后清楚这个标志位,读者可以自行去编写这部分处理代码,我的源代码会贴在例程中

按键初始化:



//GPIOB时钟使能

rcu_periph_clock_enable(RCU_GPIOB);

//PB5配置成上拉输入

gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_5);

//PB6配置成上拉输入

gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_6);

//PB7配置成上拉输入

gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_7);



中断初始化:

// AFIO时钟使能

rcu_periph_clock_enable(RCU_AF);

// 设置优先级分组

nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

// 设置优先级

nvic_irq_enable(EXTI5_9_IRQn, 2U, 2U);

// 设置EXTI触发源

gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_5);

gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_6);

gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_7);



// 下降沿中断

exti_init(EXTI_5, EXTI_INTERRUPT, EXTI_TRIG_FALLING);

exti_init(EXTI_6, EXTI_INTERRUPT, EXTI_TRIG_FALLING);

exti_init(EXTI_7, EXTI_INTERRUPT, EXTI_TRIG_FALLING);



// 清中断标志

exti_interrupt_flag_clear(EXTI_5);

exti_interrupt_flag_clear(EXTI_6);

exti_interrupt_flag_clear(EXTI_7);

编写中断服务函数:

 

//先是函数弱定义

__attribute__((weak)) void Key_GPIO_IrqCallback(void)

{



}

//定义中断线判断标志位

int state_choose_flag = 0 ;



void EXTI5_9_IRQHandler(void)

{

    //判定是否是外部中断线5

   if (RESET != exti_interrupt_flag_get(EXTI_5))

   {

   state_choose_flag=5;

   Key_GPIO_IrqCallback();



   //清除中断标记

   state_choose_flag=0;

exti_interrupt_flag_clear(EXTI_5);

   }

   

 //判定是否是外部中断线6

   if (RESET != exti_interrupt_flag_get(EXTI_6))

   {

   state_choose_flag=6;

   Key_GPIO_IrqCallback();



   //清除中断标记

  state_choose_flag=0;

 exti_interrupt_flag_clear(EXTI_6);

   }



   

 //判定是否是外部中断线7

   if (RESET != exti_interrupt_flag_get(EXTI_7))

   {

   state_choose_flag=7;

   Key_GPIO_IrqCallback();



   //清除中断标记

state_choose_flag=0;  

exti_interrupt_flag_clear(EXTI_7);

   }





}

在外部重写中断处理函数:

void Key_GPIO_IrqCallback(void)

{

LED1_TOG;

}

以上为代码逻辑

接下来让我们新建中断外设文件,具体步骤可以参考上一章bsp_key.c以及bsp_key.h的建立

6ecad36f5a16444c9e1d4e93aae9bf2d.png

然后在bsp_exti.c文件中编写中断初始化代码以及放置中断处理函数

整体代码如下:

#include "gd32f10x.h"

#include "bsp_exti.h"





/*********************************************************************

*

*/

/**

@brief 按键外部中断初始化

@param 无

@return 无

*/

void Key_EXTI_Init(void)

{

// AFIO时钟使能

rcu_periph_clock_enable(RCU_AF);

// 设置优先级分组

nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

// 设置优先级

nvic_irq_enable(EXTI5_9_IRQn, 2U, 2U);

// 设置EXTI触发源

gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_5);

gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_6);

gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_7);



// 下降沿中断

exti_init(EXTI_5, EXTI_INTERRUPT, EXTI_TRIG_FALLING);

exti_init(EXTI_6, EXTI_INTERRUPT, EXTI_TRIG_FALLING);

exti_init(EXTI_7, EXTI_INTERRUPT, EXTI_TRIG_FALLING);



// 清中断标志

exti_interrupt_flag_clear(EXTI_5);

exti_interrupt_flag_clear(EXTI_6);

exti_interrupt_flag_clear(EXTI_7);







}



extern int state_choose_flag;

/**

@brief 按键中断回调函数

@param 无

@return 无

*/

void Key_GPIO_IrqCallback(void)

{

//如果来自中断线5

   if(state_choose_flag==5)

   {

   LED1_TOG;

   }

//如果来自中断线6

   else if(state_choose_flag==6)

   {

   LED2_TOG;

   }

   //如果来自中断线7

   else if(state_choose_flag==7)

   {

   LED3_TOG;

   }

}



然后在bsp_exti.c文件中放置声明文件

#ifndef _BSP_EXTI_H_

#define _BSP_EXTI_H_





#include "gd32f10x_exti.h"

#include "bsp_led.h"







/**函数声明

*

*

*/

void Key_EXTI_Init(void);









#endif

代码完成编写,现在烧录!

与实验预期相符合,完成!

具体代码请参考例程



群号:621154399

有问题欢迎大家加入我们一起交流,这个群是开源性技术交流群。

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不及你的温柔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值