重新开始学stm32(3)外部中断实验

今天来回顾外部中断。我个人外部中断很重要,又不那么重要,重要是因为外部中断是其他中断学习的基础,不重要是因为以后的使用其实很少,至少我用的是非常少甚至说不用外部中断。是不是有点废话文学了,那下面快速进入正题。 

实验目的

前面我们学习了IO口最基本的操作,现在我们来掌握IO口作为外部中断的使用方法。

实验内容

这里我们首先 STM32 IO 口中断的一些基础概念。STM32 的每个 IO 都可以作为外部中断的中断输入口,STM32F103 的中断控制器支持 19 个外部中断,每个中断设有状态位,每个中断都有独立的触发和屏蔽设置。STM32F103 的19 个外部中断为:
线 0~15:对应外部 IO 口的输入中断。
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB 唤醒事件。

在这个实验里面,我们只用到外部IO口的输入中断。中断线16、17、18的先放在一边。眼睑的小伙伴应该发现了,外部IO口中断线只有16条啊,但是我们的IO口可远远不止16个啊,那这些中断线怎么分配呢?我们来看一个图。

 没错,stm32的外部IO口的中断线每一条都是映射多个IO口的,但是中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。

下面我们开始来配置IO口的外部中断。

首先,毋庸置疑的当然就是要开启时钟了。在外部中断实验我们要开启的时钟是AFIO时钟。开启时钟的函数在前面就已经熟悉过了。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //开启复用功能时钟

在库函数中,配置 GPIO 与中断线的映射关系函数是 GPIO_EXTILineConfig(),该函数有两个参数,第一个参数是中断线的选择,有如下这些,被定义在头文件stm32f10x_gpio.h里面。

#define GPIO_PortSourceGPIOA       ((uint8_t)0x00)
#define GPIO_PortSourceGPIOB       ((uint8_t)0x01)
#define GPIO_PortSourceGPIOC       ((uint8_t)0x02)
#define GPIO_PortSourceGPIOD       ((uint8_t)0x03)
#define GPIO_PortSourceGPIOE       ((uint8_t)0x04)
#define GPIO_PortSourceGPIOF       ((uint8_t)0x05)
#define GPIO_PortSourceGPIOG       ((uint8_t)0x06)

第二个参数是IO口引脚序号的选择。有如下这些,同样定义在头文件stm32f10x_gpio.h里面。

#define GPIO_PinSource0            ((uint8_t)0x00)
#define GPIO_PinSource1            ((uint8_t)0x01)
#define GPIO_PinSource2            ((uint8_t)0x02)
#define GPIO_PinSource3            ((uint8_t)0x03)
#define GPIO_PinSource4            ((uint8_t)0x04)
#define GPIO_PinSource5            ((uint8_t)0x05)
#define GPIO_PinSource6            ((uint8_t)0x06)
#define GPIO_PinSource7            ((uint8_t)0x07)
#define GPIO_PinSource8            ((uint8_t)0x08)
#define GPIO_PinSource9            ((uint8_t)0x09)
#define GPIO_PinSource10           ((uint8_t)0x0A)
#define GPIO_PinSource11           ((uint8_t)0x0B)
#define GPIO_PinSource12           ((uint8_t)0x0C)
#define GPIO_PinSource13           ((uint8_t)0x0D)
#define GPIO_PinSource14           ((uint8_t)0x0E)
#define GPIO_PinSource15           ((uint8_t)0x0F)

本实验用到了PE3、PE4、PA0,配置如下。

GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

配置完了中断线映射,接下来就是要初始化中断了。这里的中断初始化使用的是EXTI_Init()函数来进行初始化。同样的,像前面说的一样所有的初始化函数的使用都是差不多的。下面是PE3的初始化配置。其他的以此类推。先来看EXTI_Init()函数使用到的结构体EXTI_InitTypeDef。

typedef struct
{
  uint32_t EXTI_Line;
  EXTIMode_TypeDef EXTI_Mode;
  EXTITrigger_TypeDef EXTI_Trigger;
  FunctionalState EXTI_LineCmd;
}EXTI_InitTypeDef;

 第一个成员变量是中断线选择;第二个成员变量是选择外部中断或事件请求;第三个成员变量是触发条件选择;第四个成员变量是是否使能外部中断或事件请求。在这个实验里面我们的配置如下。

EXTI_InitStructure.EXTI_Line = EXTI_Line3;                //中断线3(引脚3)
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;       //外部中断
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;   //下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;                 //使能外部中断
EXTI_Init(&EXTI_InitStructure);

既然是中断,那就必须要安排一波优先级配置啦。因为前面讲过优先级的配置,所以这里就不讲了,这给出来的是PA0的中断优先级配置。

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

配置完优先级,中断的配置就算是完成了。然后就要来写我们的中断服务函数了。这里的是PA0的外部中断服务函数。

void EXTI0_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line0)==RESET)    //判断中断标志位(判断中断是否发生)
    {
        EXTI_ClearITPendingBit(EXTI_Line0);    //清除中断标志位
	    delay_ms(10);
	    if(WK_UP==1)
	    {
		    LED0=LED1=0;
	    }
    }
}

有小伙伴就发现了,这里的中断标志位清除怎么放在前面,而正点原子的例程是放在最后的。其实,在正常情况下,中断标志位放在最后也是没问题的,但是总有个万一的。因为中断标志位清除也是需要一定的时间的,假设中断执行完了,但是中断标志位没有清除掉,就会一直进入中断,导致程序卡死,所以进入中断必须先清中断标志位,必须先清中断标志位,必须先清中断标志位

好了,今天就讲到这里了,再见!

如果喜欢的话就记得点个赞,关注关注呗!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值