实验效果:用外部中断,实现PA1上接按键,选择上升沿触发中断,中断PB1上闪烁的LED,
先来看看配置外部中断的整体代码,然后再一个函数一个函数的解释
[color=#00FFFF]#include "exti.h"
/*
初始化总中断NVIC
*/
static void NVIC_Configur(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*************************/
/*
初始化GPIO口,GPIOA_PIN1
*/
void GPIO_Configur(void)
{
GPIO_InitTypeDef GPIO_InitStructure ; //命名GPIO初始化结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//选择PIN
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING; //悬浮输入
GPIO_Init(GPIOA,&GPIO_InitStructure);//调用初始化函数
}
/**************************/
/*
告诉GPIO那个引脚作为外部中断引脚
*/
void AFIO_Configur(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO的时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
}
/******************************/
/*
配置EXTI
*/
void EXTI_Configur(void)
{
NVIC_Configur();
GPIO_Configur();
AFIO_Configur();
EXTI_InitTypeDef EXTI_InitStructure;//命名ETTI初始化结构体
EXTI_InitStructure.EXTI_Line=EXTI_Line1;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
}[/color]
****************************************************************************************************
****************************************************************************************************
****************************************************************************************************
先来看看第一个函数
static void NVIC_Configur(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}[/align]
为什么要编写这段函数呢?
先来看看NVIC的全称(Nested vectoredinterrupt controller)即
嵌套向量中断控制器
由于STM32的中断系统非常强大,每个GPIO都能产生中断,所以需要一个能管理这些中断的控制器
下面是32的中断和事件,我只放出了一部分,还有很多可以在STM参考手册上看
那NVIC到底是怎么管理这些中断的,我们从函数一个一个看
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
32的中断优先级是可以自己设置的,所以我们要先给他配置优先级,所以这是给他的优先级选组的函数,为什么要选组先这个表
左边NVIC_IRQChannelPreemptionPriority是主优先级,右边NVIC_IRQChannelSubPriority是次优先级
每个组都有对应的主次优先级的选择范围,32会先比较主优先级,如果主优先级都一样,会比较次优先级,如果主次都一样,会用32自己配置的优先级。
NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
这四段函数,开始配置NVIC结构体的成员。
第一段函数,是选择你要用的中断的名字 ,
名字在stm32f10x.h文件中找(随便补充一下,关于NVIC的函数可以在misc.h中找到)
EXTI1有0-15个,分别对应16个IO口,我们要用PA1,所以就选EXTI1
第二,三段函数,就是选择中断的主次优先级
第四段使能NVIC
然后初始化结构体,命名初始化,这些库函数套路程序就不解释了
配置GPIO,凡是要用GPIO都要配置它,要注意输入的时候悬浮输入和不用配置频率
void GPIO_Configur(void)
{
GPIO_InitTypeDef GPIO_InitStructure ; //命名GPIO初始化结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//选择PIN
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING; //悬浮输入
GPIO_Init(GPIOA,&GPIO_InitStructure);//调用初始化函数
}
/**************************/
/*
告诉GPIO那个引脚作为外部中断引脚
*/
void AFIO_Configur(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO的时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
}
PS:记得使能AFIO的时钟
最后一步配置外部中断EXTI
void EXTI_Configur(void)
{
NVIC_Configur();
GPIO_Configur();
AFIO_Configur();
EXTI_InitTypeDef EXTI_InitStructure;//命名ETTI初始化结构体
EXTI_InitStructure.EXTI_Line=EXTI_Line1;//初始化那个EXTI
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//选择中断模式
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;//选择上升沿触发
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
然后在主函数中,写中断服务函数
在51中编写中断服务函数的名字可以直接编写,只要后面加个入口标志就行了
但是32已经有编好的中断服务函数,在启动文件里面可以找到
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1)==1) /*如果一条线上有PA0 PB0,如何判断是那个触发的中断?
{ 先判断总线,再判断IO口的电平(操作寄存器) */
Delay(3000000);
EXTI_ClearFlag(EXTI_Line1);/*清除触发标志*/
}
}
调用函数EXTI_GetITStatus(),如果有外部中断被触发,函数会返回一个1
/*如果一条线上有PA0 PB0,如何判断是那个触发的中断?这是野火教学视频留下的一个问题
我觉得 先判断总线,再判断IO口的电平(操作寄存器) 就可以了*/
这个题目就是让我们明白,不要只会调用库函数,还要懂得,这些库函数操作了那些寄存器。
还有就是EXTI_ClearFlag(EXTI_Line1);/*清除触发标志*/,这个函数,EXTI_GetITStatus()返回一个1本质是吧挂起寄存器置1了
然后它不会自动清0;所以要用EXTI_Clear