STM32F407中断学习笔记

中断与事件的区别

  • 相同点:中断和事件都是触发的一种,都是可以设置触发的;
  • 异同点:
  1. 中断触发后必须有中断处理子程序IRQ handle,例如比如按键中断触发,实现一个LED的闪烁,可以在按键按下后,在中断处理程序中实现某个LED的电平反转
  2. 但在事件中,事件是没有中断处理子程序的,事件发生后,会直接发出一个脉冲信号给与之联动的操作,也可以同样实现LED电平的反转,只要有事件发生,就会有一个脉冲信号,这样的好处是,不需要CPU干预了,可以节省CPU的处理资源,相比中断处理,速度还更快,因为硬件的速度总是比软件处理快。

EXTI 功能框图

在这里插入图片描述

  • EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所 不同。
  1. 红色虚线指示的电路流程。它是一个产生中断的线路,最终信号流入到NVIC 控制器内。
    (1)编号 1 是输入线,EXTI 控制器有 23 个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个 GPIO,也可以是一些外设的事件,这部分内容我们将在后面专门讲解。输入线一般是存在电平变化的信号。
    (2) 编号 2 是一个边沿检测电路,它会根据上升沿触发选择寄存器(EXTI_RTSR) 和下降沿触发选择寄存器 (EXTI_FTSR) 对应位的设置来控制信号触发。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号 1 给编号 3 电路,否则输出无效信号 0。而 EXTI_RTSR 和EXTIFTSR 两个寄存器可以控制器需要检测哪些类型的电平跳变过程,可以是只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发。
    (3)编号3电路实际就是一个或门电路,它一个输入来自编号2电路,另外一输入来自软件中断事件寄存器 (EXTI_SWIER)。EXTI_SWIER 允许我们通过程序控制就可以启动中断/事件线,这在某些地方非常有用。我们知道或门的作用就是有”就为 1,所以这两个输入随便一个有有效信号 1 就可以输出 1 给编号 4 和编号 6 电路。
    (4)编号 4 电路是一个与门电路,它一个输入编号 3 电路,另外一个输入来自中断屏蔽寄存器(EXTI_IMR)。与门电路要求输入都为 1 才输出 1,导致的结果EXTI_IMR 设置为 0 时,那不管编号 3 电路的输出信号是 1 还是 0,最终编号 4 电路输出的信号都为 0;如果 EXTI_IMR设置为 1 时,最终编号 4 电路输出的信号才由编号 3 电路的输出信号决定,这样我们可以简单的控制 EXTI_IMR 来实现是否产生中断的目的。编号 4 电路输出的信号会被保存到挂起寄存器(EXTI_PR) 内,如果确定编号 4 电路输出为 1 就会把 EXTI_PR 对应位置1。
    (5)编号 5 是将 EXTI_PR 寄存器内容输出到 NVIC 内,从而实现系统中断事件控制

  2. 接下来我们来看看绿色虚线指示的电路流程。它是一个产生事件的线路,最终输出一个脉冲信号。
    产生事件线路是在编号 3 电路之后与中断线路有所不同,之前电路都是共用的。编号 6 电路是一个与门,它一个输入编号 3 电路,另外一个输入来自事件屏蔽寄存器 (EXTI_EMR)。如果EXTI_EMR 设置为 0 时,那不管编号 3 电路的输出信号是 1 还是 0,最终编号 6 电路输出的信号都为 0;如果 EXTI_EMR 设置为 1 时,最终编号 6 电路输出的信号才由编号 3 电路的输出信号决定,这样我们可以简单的控制 EXTI_EMR 来实现是否产生事件的目的。
    (1)编号 7 是一个脉冲发生器电路,当它的输入端,即编号 6 电路的输出端,是一个有效信号 1 时就会产生一个脉冲;如果输入端是无效信号就不会输出脉冲。
    (2)编号 8 是一个脉冲信号,就是产生事件的线路最终的产物,这个脉冲信号可以给其他外设电路使用,比如定时器 TIM、模拟数字转换器 ADC 等等

中断程序的编写步骤

1.初始化需要连接到的EXTI的GPIO
2.初始化EXTI
3.配置NVIC中断优先级
4.编写中断服务函数

案例如下:

/*KEY1    宏定义*/
#define   KEY1_INIT_GPIO_CLK   		     RCC_AHB1Periph_GPIOA
#define   KEY1_INIT_GPIO_PORT   	     GPIOA
#define   KEY1_INIT_GPIO_PIN			 GPIO_Pin_0
#define   KEY1_INIT_GPIO_PORTSOURCE      EXTI_PortSourceGPIOA
#define   KEY1_INIT_GPIO_PINSOURCE       EXTI_PinSource0
#define   KEY1_INT_EXTI_LINE 			 EXTI_Line0
#define   KEY1_INT_EXTI_IRQ           	 EXTI0_IRQn
#define   KEY1_IRQHandler				 EXTI0_IRQHandler

/*KEY2    宏定义*/
#define   KEY2_INIT_GPIO_CLK   		     RCC_AHB1Periph_GPIOC
#define   KEY2_INIT_GPIO_PORT   	     GPIOC
#define   KEY2_INIT_GPIO_PIN			 GPIO_Pin_13
#define   KEY2_INIT_GPIO_PORTSOURCE      EXTI_PortSourceGPIOC
#define   KEY2_INIT_GPIO_PINSOURCE       EXTI_PinSource13
#define   KEY2_INT_EXTI_LINE 			 EXTI_Line13
#define   KEY2_INT_EXTI_IRQ           	 EXTI15_10_IRQn
#define   KEY2_IRQHandler				 EXTI15_10_IRQHandler


第一步:初始化需要连接到的EXTI的GPIO

void EXIT_KEY_Config(void){
	/*第一步:初始化需要连接到EXIT线的GPIO*/
	
	/*初始化GPIO时钟*/
	RCC_AHB1PeriphClockCmd(KEY1_INIT_GPIO_CLK|KEY2_INIT_GPIO_CLK,ENABLE);//打开key1,key2的GPIO时钟
	
	/*定义GPIO初始化结构体*/
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	/*配置KEY1_GPIO初始化结构体成员*/
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;//输入模式
	
	/*EXIT_KEY_Typedef.GPIO_OType=GPIO_OType_PP;    输入模式中用不到*/
	GPIO_InitStructure.GPIO_Pin=KEY1_INIT_GPIO_PIN; //定义引脚
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//无上下拉
	GPIO_InitStructure.GPIO_Speed=GPIO_Low_Speed;//速度:LOW
	
	/*调用GPIO初始化函数,把配置好的KEY1_GPIO初始化成员写入寄存器*/
	GPIO_Init(KEY1_INIT_GPIO_PORT, &GPIO_InitStructure);
	
	
	/*配置KEY2_GPIO初始化结构体成员,与KEY1_GPIO相一致,只需配置引脚*/
	GPIO_InitStructure.GPIO_Pin=KEY2_INIT_GPIO_PIN; //定义引脚

	/*调用GPIO初始化函数,把配置好的KEY2_GPIO初始化成员写入寄存器*/
	GPIO_Init(KEY2_INIT_GPIO_PORT, &GPIO_InitStructure);
	
	
	/*第二步:初始化EXIT*/
		EXTI_Config();

	/*第三步:配置NVIC中断优先级*/
		NVIC_Config();
	
	/*第四步:编写中断服务函数*/
	//在stm32f4xx_it.c文件中编写了
	
}

第二步:初始化EXTI

void EXTI_Config(void){
	/*使能 SYSCFG 时钟,使用GPIO外部中断时必须使能 SYSCFG 时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
	
	/*连接 EXIT 中断源到 key1 引脚*/
	SYSCFG_EXTILineConfig(KEY1_INIT_GPIO_PORTSOURCE,KEY1_INIT_GPIO_PINSOURCE);
	
	/*连接 EXIT 中断源到 key2 引脚*/
	SYSCFG_EXTILineConfig(KEY2_INIT_GPIO_PORTSOURCE,KEY2_INIT_GPIO_PINSOURCE);
	
	/*定义中断初始化结构体*/
	EXTI_InitTypeDef 	EXTI_InitStructure;
	
	/*配置EXTI初始化结构体成员*/
	//KEY1中断
	EXTI_InitStructure.EXTI_Line=KEY1_INT_EXTI_LINE; //选择EXTI中断源
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿触发
	
	/*使能中断/事件线*/
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	//KEY2中断,相同部分不许要配置
	EXTI_InitStructure.EXTI_Line=KEY2_INT_EXTI_LINE; //选择EXTI中断源
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
	/*使能中断/事件线*/
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_Init(&EXTI_InitStructure);

第三步:配置NVIC中断优先级

/*配置NVIC优先级*/
void NVIC_Config(void){
	/*定义NVIC初始化结构体*/
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/*配置NVIC优先级组1*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	/*配置中断源:KEY1*/
	NVIC_InitStructure.NVIC_IRQChannel=KEY1_INT_EXTI_IRQ;
	
	/*配置抢占优先级*/
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	
	/*配置子优先级*/
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	
	/*中断使能通道*/
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	
	
	
	/*配置中断源:KEY2*/
	NVIC_InitStructure.NVIC_IRQChannel=KEY2_INT_EXTI_IRQ;
	
	/*中断使能通道*/
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

第四步:编写中断服务函数

void	KEY1_IRQHandeler(void){
	
	/*确保是否产生了EXTI Line中断*/
	if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE)==SET)
	{
		/*灯翻转一次*/
	}
	/*清除中断标志位*/
	EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
}

void	KEY2_IRQHandeler(void){
	/*确保是否产生了EXTI Line中断*/
	if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE)==SET)
	{
		/*灯翻转一次*/
	}
	/*清除中断标志位*/
	EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值