你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 外部中断

[复制链接]
STMCU小助手 发布时间:2022-4-1 15:19
01. 外部中断简介
外部中断的代码主要分布在固件库的 stm32f4xx_exti.h 和 stm32f4xx_exti.c 文件中。

STM32F4 的每个 IO 都可以作为外部中断的中断输入口,这点也是 STM32F4 的强大之处。STM32F407 的中断控制器支持 22
个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。

STM32F407 的 22 个外部中断为:

EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB OTG FS 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
EXTI 线 20:连接到 USB OTG HS(在 FS 中配置)唤醒事件。
EXTI 线 21:连接到 RTC 入侵和时间戳事件。
EXTI 线 22:连接到 RTC 唤醒事件。
从上面可以看出,STM32F4 供 IO 口使用的中断线只有 16 个,但是 STM32F4 的 IO 口却远远不止 16 个,那么 STM32F4 是怎么把 16 个中断线和 IO 口一一对应起来的呢?于是 STM32就这样设计,GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线 0~15。这样每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0,GPIOH.0,GPIOI.0。而中断线每次只能连接到 1 个 IO口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。下面我们看看 GPIO跟中断线的映射关系图:

20200824104147372.png

02. 外部中断配置
2.1 使能 IO口时钟,初始化 IO

我们要使用 IO 口作为中断输入,所以我们要使能相应的 IO 口时钟,以及初始化相应的 IO 口为输入模式

2.2 开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系

只要我们使用到外部中断,就必须打开 SYSCFG 时钟。

  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能 SYSCFG 时钟
复制代码

配置 GPIO 与中断线的映射关系。在库函数中,配置 GPIO 与中断线的映射关系的函数 SYSCFG_EXTILineConfig ()来实现的:

  1. void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
复制代码

该函数将 GPIO 端口与中断线映射起来,程序示例:

  1. SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
复制代码

2.3 初始化线上中断,设置触发条件

中断线上中断的初始化是通过函数 EXTI_Init()实现的。EXTI_Init()函数的定义是:

  1. void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
复制代码

程序示例

  1. EXTI_InitTypeDef EXTI_InitStructure;
  2. EXTI_InitStructure.EXTI_Line= EXTI_Line4;
  3. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  4. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  5. EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  6. EXTI_Init(&EXTI_InitStructure); //初始化外设 EXTI 寄存器
复制代码

2.4 配置中断分组(NVIC ),并使能中断

我们设置好中断线和 GPIO 映射关系,然后又设置好了中断的触发模式等初始化参数。既然是外部中断,涉及到中断我们当然还要设置 NVIC 中断优先级。

  1. NVIC_InitTypeDef NVIC_InitStructure;
  2. NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键外部中断通道
  3. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
  4. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;  //响应优先级 2
  5. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  6. NVIC_Init(&NVIC_InitStructure); //中断优先级分组初始化
复制代码

2.5 编写中断服务函数

我们配置完中断优先级之后,接着要做的就是编写中断服务函数。中断服务函数的名字是在 MDK 中事先有定义的。这里需要说明一下,STM32F4 的 IO 口外部中断函数只有 7 个,分别为:

  1. DCD     EXTI0_IRQHandler                  ; EXTI Line0                                             
  2. DCD     EXTI1_IRQHandler                  ; EXTI Line1                                             
  3. DCD     EXTI2_IRQHandler                  ; EXTI Line2                                             
  4. DCD     EXTI3_IRQHandler                  ; EXTI Line3                                             
  5. DCD     EXTI4_IRQHandler                  ; EXTI Line4   
  6. DCD     EXTI9_5_IRQHandler                ; External Line[9:5]s   
  7. DCD     EXTI15_10_IRQHandler              ; External Line[15:10]s  
复制代码

中断线 0-4 每个中断线对应一个中断函数,中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中断线 10-15 共用中断函数EXTI15_10_IRQHandler。在编写中断服务函数的时候会经常使用到两个函数,第一个函数是判断某个中断线上的中断是否发生(标志位是否置位)

  1. ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
复制代码

这个函数一般使用在中断服务函数的开头判断中断是否发生。另一个函数是清除某个中断线上的中断标志位:

  1. void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
复制代码

这个函数一般应用在中断服务函数结束之前,清除中断标志位。

03. 外部中断步骤
使用 IO 口外部中断的一般步骤:
1)使能 IO 口时钟,初始化 IO 口为输入。
2)使能 SYSCFG 时钟,设置 IO 口与中断线的映射关系。
3)初始化线上中断,设置触发条件等。
4)配置中断分组(NVIC),并使能中断。
5)编写中断服务函数。

04. 硬件设计
探索者 STM32F4 开发板上载有的 4 个按钮(KEY_UP、KEY0、KEY1 和 KEY2),来控制板上的 2 个 LED(DS0 和 DS1)和蜂鸣器,其中 KEY_UP 控制蜂鸣器,按一次叫,再按一次停;KEY0 控制 DS0,按一次亮,再按一次灭;KEY1 控制 DS1,
效果同 KEY2;KEY2 则同时控制 DS0 和 DS1,按一次,它们的状态就翻转一次。

20200824104205634.png

05. 程序示例一
KEY0控制LED1的翻转

exti.h文件
  1. #ifndef __EXTI_H__
  2. #define __EXTI_H__

  3. #include "sys.h"

  4. //中断初始化函数
  5. void EXTIX_Init(void);

  6. #endif /*__EXTI_H__*/
复制代码

exti.c文件

  1. #include "exti.h"
  2. #include "key.h"
  3. #include "led.h"
  4. #include "delay.h"
  5. #include "usart.h"

  6. //中断初始化函数
  7. void EXTIX_Init(void)
  8. {
  9.          EXTI_InitTypeDef EXTI_InitStruct;
  10.          
  11.          NVIC_InitTypeDef NVIC_InitStruct;
  12.          
  13.          //按键初始化
  14.          KEY_Init();
  15.          
  16.          //初始化SYSCFG时钟
  17.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  18.          
  19.          //KEY0 --> PE4
  20.          SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);
  21.          
  22.          //配置中断
  23.          EXTI_InitStruct.EXTI_Line = EXTI_Line4;
  24.          EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
  25.          EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
  26.          EXTI_InitStruct.EXTI_LineCmd = ENABLE;
  27.          EXTI_Init(&EXTI_InitStruct);
  28.          
  29.          //配置中断分组
  30.          NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;
  31.          NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
  32.          NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
  33.          NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

  34.          NVIC_Init(&NVIC_InitStruct);
  35. }

  36. //中断线4处理函数
  37. void EXTI4_IRQHandler(void)
  38. {
  39.         printf("KEY0按下啦....\r\n");
  40.         //消抖
  41.         delay_ms(10);
  42.         
  43.         if (0 == KEY0)
  44.         {
  45.                 LED1 = !LED1;
  46.         }

  47.         //清中断
  48.         EXTI_ClearITPendingBit(EXTI_Line4);
  49. }
复制代码

main.c文件

  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"
  4. #include "led.h"
  5. #include "beep.h"
  6. #include "key.h"
  7. #include "exti.h"

  8. int main(void)
  9. {
  10.         
  11.         BEEP = 0;
  12.         LED1 = 0;
  13.         
  14.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  15.         
  16.         BEEP_Init();
  17.         LED_Init();
  18.         
  19.         delay_init(168);
  20.         uart_init(115200);


  21.         //外部中断初始化
  22.         EXTIX_Init();
  23.         
  24.         while(1)
  25.         {
  26.                 printf("程序正在运行.....\r\n");
  27.                
  28.                 delay_ms(1000);
  29.         }        
  30. }
复制代码

06. 程序示例二
exti.h文件


  1. #ifndef __EXTI_H__
  2. #define __EXTI_H__

  3. #include "sys.h"

  4. //中断初始化函数
  5. void EXTIX_Init(void);

  6. #endif /*__EXTI_H__*/
复制代码

exti.c文件

  1. #include "exti.h"
  2. #include "key.h"
  3. #include "led.h"
  4. #include "beep.h"
  5. #include "delay.h"
  6. #include "usart.h"

  7. //中断初始化函数
  8. void EXTIX_Init(void)
  9. {
  10.          EXTI_InitTypeDef EXTI_InitStruct;
  11.          
  12.          NVIC_InitTypeDef NVIC_InitStruct;
  13.          
  14.          //按键初始化
  15.          KEY_Init();
  16.          
  17.          //初始化SYSCFG时钟
  18.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  19.          
  20.          //KEY0 --> PE4
  21.          SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);
  22.          
  23.          //KEY1 --> PE3
  24.          SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);
  25.          
  26.          //KEY1 --> PE2
  27.          SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);
  28.          
  29.          //KEY_UP --> PA0
  30.          SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
  31.          
  32.          //配置中断 KEY0 KEY1 KEY2
  33.          EXTI_InitStruct.EXTI_Line = EXTI_Line4 | EXTI_Line3 | EXTI_Line2;
  34.          EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
  35.          EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
  36.          EXTI_InitStruct.EXTI_LineCmd = ENABLE;
  37.          EXTI_Init(&EXTI_InitStruct);
  38.          

  39.          //配置中断 KEY_UP
  40.          EXTI_InitStruct.EXTI_Line = EXTI_Line0;
  41.          EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
  42.          EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
  43.          EXTI_InitStruct.EXTI_LineCmd = ENABLE;
  44.          EXTI_Init(&EXTI_InitStruct);
  45.          
  46.          
  47.          //配置中断分组 KEY0
  48.          NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;
  49.          NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
  50.          NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
  51.          NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

  52.          NVIC_Init(&NVIC_InitStruct);
  53.          
  54.          //配置中断分组 KEY1
  55.          NVIC_InitStruct.NVIC_IRQChannel = EXTI3_IRQn;
  56.          NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
  57.          NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
  58.          NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

  59.          NVIC_Init(&NVIC_InitStruct);
  60.          
  61.          //配置中断分组 KEY2
  62.          NVIC_InitStruct.NVIC_IRQChannel = EXTI2_IRQn;
  63.          NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
  64.          NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
  65.          NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

  66.          NVIC_Init(&NVIC_InitStruct);
  67.          
  68.          //配置中断分组 WK_UP
  69.          NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
  70.          NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
  71.          NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
  72.          NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

  73.          NVIC_Init(&NVIC_InitStruct);
  74. }

  75. //中断线4处理函数
  76. void EXTI4_IRQHandler(void)
  77. {
  78.         printf("KEY0按下啦....\r\n");
  79.         //消抖
  80.         delay_ms(10);
  81.         
  82.         if (0 == KEY0)
  83.         {
  84.                 LED1 = !LED1;
  85.         }

  86.         //清中断
  87.         EXTI_ClearITPendingBit(EXTI_Line4);
  88. }


  89. //中断线3处理函数
  90. void EXTI3_IRQHandler(void)
  91. {
  92.         printf("KEY1按下啦....\r\n");
  93.         //消抖
  94.         delay_ms(10);
  95.         
  96.         if (0 == KEY1)
  97.         {
  98.                 LED2 = !LED2;
  99.         }

  100.         //清中断
  101.         EXTI_ClearITPendingBit(EXTI_Line3);
  102. }


  103. //中断线2处理函数
  104. void EXTI2_IRQHandler(void)
  105. {
  106.         printf("KEY2按下啦....\r\n");
  107.         //消抖
  108.         delay_ms(10);
  109.         
  110.         if (0 == KEY2)
  111.         {
  112.                 LED1 = !LED1;
  113.                 LED2 = !LED2;
  114.         }

  115.         //清中断
  116.         EXTI_ClearITPendingBit(EXTI_Line2);
  117. }


  118. //中断线0处理函数
  119. void EXTI0_IRQHandler(void)
  120. {
  121.         printf("KEY_UP按下啦....\r\n");
  122.         //消抖
  123.         delay_ms(10);
  124.         
  125.         if (1 == WK_UP)
  126.         {
  127.                 BEEP = !BEEP;
  128.         }

  129.         //清中断
  130.         EXTI_ClearITPendingBit(EXTI_Line0);
  131. }
复制代码

main.c文件

  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"
  4. #include "led.h"
  5. #include "beep.h"
  6. #include "key.h"
  7. #include "exti.h"

  8. int main(void)
  9. {
  10.         
  11.         BEEP = 0;
  12.         LED1 = 0;
  13.         LED2 = 0;
  14.         
  15.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  16.         
  17.         BEEP_Init();
  18.         LED_Init();
  19.         
  20.         delay_init(168);
  21.         uart_init(115200);


  22.         //外部中断初始化
  23.         EXTIX_Init();
  24.         
  25.         while(1)
  26.         {
  27.                 printf("程序正在运行.....\r\n");
  28.                
  29.                 delay_ms(1000);
  30.         }        
  31. }
复制代码

收藏 评论0 发布时间:2022-4-1 15:19

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版