STM32 外部中断

发布于: 2018年05月13日 21:41:39 | 分类: STM32 | 浏览: 191

STM32 外部中断简介

    原子哥说:STM32所有的IO口都可以作为外部中断的中断输入口,这让我不经感到STM32非常强大。STM32F103的中断控制器支持 19 个外部中断/事件请求 每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。

    线0~15:对应外部 IO 口的输入中断。
    线 16:连接到 PVD 输出。
    线 17:连接到 RTC 闹钟事件。
    线 18:连接到 USB唤醒事件

STM32F103的 19 个外部中断

    STM32供给IO口使用的中断线只有16,所以STM32将IO分组分别为:GPIOA,GPIOB,GPIOC,GPIOD,GPIOE,GPIOF,GPIOG。每组IO的16个口分别对应0~15个中断线,于是每个中断线对应了最多7个IO口。终端每次只能连接在一个IO口上,所以STM32通过下图来映射:

在库函数中,配置 GPIO 与中断线的映射关系的函数 GPIO_EXTILineConfig() 来实现的。该函数将 GPIO 端口与中断线映射起来,使用范例是:GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2); 将中断线 2 与 GPIOA 映射起来,那么很显然是PIOA.2 与 EXTI2 中断线连接了 。通过刚刚的函数设置好中断线映射之后,接下来就要设置该中断线上中断的初始化参数了。中断线上中断的初始化是通过函数 EXTI_Init()实现的。该函数的定义是:void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); EXTI_InitTypeDef是一个结构体:

 typedef struct {
    uint32_t EXTI_Line;               //   中断线
    EXTIMode_TypeDef EXTI_Mode;       //   EXTI_Mode_Interrupt:设置为中断请求 EXTI_Mode_Event:事件请求
    EXTITrigger_TypeDef EXTI_Trigger; //   设置触发方式
    FunctionalState EXTI_LineCmd;     //   使能
} EXTI_InitTypeDef;

typedef enum {
    EXTI_Mode_Interrupt = 0x00,
    EXTI_Mode_Event 	= 0x04
}EXTIMode_TypeDef;

typedef enum { //触发方式
    EXTI_Trigger_Rising 	= 0x08,
    EXTI_Trigger_Falling 	= 0x0C,
    EXTI_Trigger_Rising_Falling = 0x10
}EXTITrigger_TypeDef;

typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; //使能

    从以上结构体定义可以看出,有 4个参数需要设置。第一个参数是中断线的标号,取值范围为EXTI_Line0~EXTI_Line15。这个在上面已经讲过中断线的概念。也就是说,这个函数配置的是某个中断线上的中断参数。第二个参数是中断模式,可选值为中断 EXTI_Mode_Interrupt和事件 EXTI_Mode_Event。第三个参数是触发方式,可以是下降沿触发 EXTI_Trigger_Falling,上升沿触发 EXTI_Trigger_Rising,或者任意电平(上升沿和下降沿)触发EXTI_Trigger_Rising_Falling。最后一个参数就是使能中断线了  。设置好结构体之后调用EXTI_Init(&EXTI_InitTypeDef); 

    设置好中断线和GPIO映射关系之后,就要设置中断优先级,以前学过51的都知道中断优先级的概念,在STM32中我们还要配置NVIC中断优先级,设置NVIC中断优先级也涉及到一个结构体:NVIC_InitTypeDef

typedef struct {
    uint8_t NVIC_IRQChannel; 					//指定要启用或禁用的IRQ通道
    uint8_t NVIC_IRQChannelPreemptionPriority; 	//指定IRQ信道的优先级
    uint8_t NVIC_IRQChannelSubPriority;   		//指定IRQ通道中指定的IRQ通道的子优先级。
    FunctionalState NVIC_IRQChannelCmd;   		//使能
}  NVIC_InitTypeDef;

ITStatus EXTI_GetITStatus(uint32_t EXTI_Line); 该函数是判断某个中断线上的中断是否发生,一般使用在中断服务函数的开头判断中断是否发生。而void EXTI_ClearITPendingBit(uint32_t EXTI_Line); 函数是清除某个中断线上的中断标志位,这个函数一般应用在中断服务函数结束之前,清除中断标志位。在启动文件:startup_stm32.s 中定义好了中断服务函数:

固件库还提供了两个函数用来判断外部中断状态以及清除外部状态标志位的函数 EXTI_GetFlagStatus()EXTI_ClearFlag()他们的作用和前面两个函数的作用类似。只是在 EXTI_GetITStatus()函数中会先判断这种中断是否使能,使能了才去判断中断标志位,而EXTI_GetFlagStatus()直接用来判断状态标志位。

    有了理论基础开始敲代码

1)初始化 IO 口为输入。
2)开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。
3)初始化线上中断,设置触发条件等。
4)配置中断分组(NVIC),并使能中断。
5)编写中断服务函数。

一般步骤

硬件设计

    使用GPIOB组IO口,PIN_0用作外部中断输入源(按键)PIN_15外接LED。

软件设计

    exti.h

#ifndef EXTI_EXTI_H_
#define EXTI_EXTI_H_

void EXTI_INIT();    /初始化中断

#endif /* EXTI_EXTI_H_ */

    exti.c

#include "exti.h"

#include <misc.h>
#include <stm32f10x.h>
#include <stm32f10x_exti.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#include <sys/_stdint.h>

#include "../delay/delay.h"
#include "../led/led.h"

void EXTI_INIT() {

	EXTI_InitTypeDef EXTI_InitTypeDef;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);

	EXTI_InitTypeDef.EXTI_Line 	   	= EXTI_Line0;
	EXTI_InitTypeDef.EXTI_LineCmd 	= ENABLE;
	EXTI_InitTypeDef.EXTI_Mode 	   	= EXTI_Mode_Interrupt;
	EXTI_InitTypeDef.EXTI_Trigger 	= EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitTypeDef);

	NVIC_InitTypeDef NVIC_InitType;

	NVIC_InitType.NVIC_IRQChannel 				  	= EXTI0_IRQn;
	NVIC_InitType.NVIC_IRQChannelPreemptionPriority = 3;		//抢占优先级3
	NVIC_InitType.NVIC_IRQChannelSubPriority		= 3;		//子优先级3
	NVIC_InitType.NVIC_IRQChannelCmd 			   	= ENABLE;	//IRQ通道使能
	NVIC_Init(&NVIC_InitType);		//根据指定的参数初始化VIC寄存器

}

void EXTI0_IRQHandler() {
	delay_ms(20);				//GPIO_ReadInputDataBit 低电平有效时取反
	if (!GPIO_ReadInputDataBit(GPIOB, KEY_0)) {
		GPIO_WriteBit(GPIOB, GPIO_Pin_15, (BitAction) (1 - GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15)));
		while (!GPIO_ReadInputDataBit(GPIOB, KEY_0));
	}
	EXTI_ClearITPendingBit(EXTI_Line0);//清楚中断标志
}

    main.c

#include <misc.h>
#include <stm32f10x.h>
#include <stm32f10x_gpio.h>

#include "delay/delay.h"
#include "exti/exti.h"
#include "led/led.h"

int main(int argc, char **argv) {

	LED_Init();		//led初始化
	delay_init();	//延时初始化
	EXTI_INIT();	//外部中断初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组,两位抢占优先级,两位响应优先级

	GPIO_WriteBit(GPIOB, GPIO_Pin_14, (BitAction) 0);
	while(1);
}

效果
上电后LED不亮按下按键之后LED一直亮,再按一次LED熄灭。

标签: STM32
本文为作者原创文章,转载时请务必声明出处并添加指向此页面的链接。
分享:
发表评论

目前您尚未登录,请 登录 后进行评论

评论信息