STM32学习笔记-如何使用GPIO的外部中断

以电眼检测的方式说明

1、参考《STM32学习笔记-如何操作GPIO》进行GPIO的初始化;

2、开启AFIO的时钟,AFIO时钟只有在外部中断和GPIO重映射的时候需要开启

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
/*APB2线上外设使能时钟函数,通过宏将各外设在RCC_APB2ENR寄存器上的对应使能位重新定义,通过函数传递宏定义操作寄存器实现外设使能*/

3、通过AFIO进行中断线路选择,调用void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)函数实现;

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
/*操作AFIO_EXTICR寄存器,配置AFIO的数据选择器来实现GPIO到中断的线路选择,第一个参数选择GPIO_PortSourceGPIOx,对应GPIOX,第二个参数选择GPIO_PinSourcex,对应GPIO_pingX*/

4、创建一个EXTI_InitTypeDef类型的结构体变量,并对其成员变量按需要赋值,具体操作方式与GPIO部分的类似,成员变量有:EXTI_Line选择中断对应GPIO_PIN的线路,EXTI_LineCmd使能外部中断,EXTI_Mode选择事件还是中断,EXTI_Trigger选择中断信号触发方式;

5、初始化外部中断,调用void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct),将上面创建的结构体传址给此函数;
/*外部中断初始化,库函数创建了EXTI_InitTypeDef的结构体类型,但未指向,需要用户自己创建一个结构体并赋值,并将结构体指针传递到函数,通过函数将结构体中的值赋值到对应寄存器上*/

6、进行中断分组,调用void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)函数配置抢占优先级和响应优先级;此函数在misc.h头文件中声明,不在Exti.h中;整个工程只能设置一次中断分组;

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
/*设置优先级分组:先占优先级和从优先级,操作SCB->AIRCR寄存器,此函数一个工程所有文件中只能用一次,及中断优先级分组只能设定一次*/

7、创建一个NVIC_InitTypeDef类型的结构体变量,并对其成员变量按需要赋值,具体操作方式与GPIO部分的类似,成员变量有:NVIC_IRQChannel确定NVIC线路,NVIC_IRQChannelCmd 使能NVIC,NVIC_IRQChannelPreemptionPriority和NVIC_IRQChannelSubPriority确定抢占优先级和响应优先级;

8、初始化NVIC,调用void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);将上面创建的结构体传址给此函数;

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
/*初始化NVIC,库函数已创建了一个NVIC_InitTypeDef的结构体类型,用户用此类型创建一个结构i,并对成员按需赋值后,传递指针给此函数,函数操作寄存器实现*/

9、到此,中断已经开始检测,若检测到对应GPIO有外部信号过来触发中断,就会进入中断函数操作

10、编写外部中断函数具体执行内容,中断函数名在库文件中已经有定义,不要自己编写,可以去startup_stm32f10x_md.s文件中查找,DCD开头的就是,例程是GPIO_PIN14,所以这里选择EXTI15_10_IRQHandler为中断函数名,并在中断函数中调用FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line)确认是否是PIN14的中断;因为PIN10~PIN15都会触发;执行完具体的操作后,需要调用void EXTI_ClearITPendingBit(uint32_t EXTI_Line)函数清除中断标志位;另外中断函数无返回值!

void EXTI15_10_IRQHandler(void)//中断函数不需要在头文件申明,系统文件已经生成
{
    if(EXTI_GetITStatus(EXTI_Line14)==SET)
    {
        count++;
        Delay_ms(200);//理论上中断函数内不能增加延迟,但是实验模块传感器有点问题,需要滤波
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
}

FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
/*获取指定的EXTI_Line标志位是否置1,通过EXTI->PR & EXTI_Line?的与运算!=0,确认EXTI_Line?是否被挂起,主程序中查看标志位建议用这个*/

void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
/*与void EXTI_ClearFlag(uint32_t EXTI_Line);功能一样,但在中断函数内,建议用这个*/

11、其他外部中断有关函数

在stm32f10x_exti.h和stm32f10x_exti.c文件中的

void EXTI_DeInit(void);
/*将EXTI相关所有寄存器恢复默认值*/


void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
/*外部中断初始化,库函数创建了EXTI_InitTypeDef的结构体类型,但未指向,需要用户自己创建一个结构体并赋值,并将结构体指针传递到函数,通过函数将结构体中的值赋值到对应寄存器上*/


void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
/*用户创建结构体后,可将结构体指针传递到此函数,进行结构体各成员变量赋默认值操作*/


void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
/*软件触发中断,操作的是EXTI_SWIER寄存器,函数传递值为EXTI_Linex,调用此函数就触发对应指定中断,当然前提要中断屏蔽寄存器(EXTI_IMR)或者事件屏蔽寄存器(EXTI_EMR)也设置的这条EXTI_Linex线*/


FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
/*获取指定的EXTI_Line标志位是否置1,通过EXTI->PR & EXTI_Line?的与运算!=0,确认EXTI_Line?是否被挂起,主程序中查看标志位建议用这个*/


void EXTI_ClearFlag(uint32_t EXTI_Line);
/*EXTI->PR = EXTI_Line,通过将对应EXTI_Line赋值到PR寄存器,即对应EXTI_Line的PR位置写1来清除标志位(PR寄存器,触发挂起后变1,写入1会清除标志位变0),主程序中清除标志位建议用这个*/


ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
/*与FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);功能一样,但在中断函数内,建议用这个,看函数内容,是多了一个EXTI->IMR寄存器是否启用中断的判断,即这两个可以判断中断是否允许及标志位,上面两个只能判断标志位*/


void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
/*与void EXTI_ClearFlag(uint32_t EXTI_Line);功能一样,但在中断函数内,建议用这个*/

在stm32f10x_gpio.h和stm32f10x_gpio.c文件中的

void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
/*看着像时GPIO的函数,其实操作的是AFIO_EVCR寄存器,用来配置对应的GPIO口的具体ping脚作为事件输出功能*/
/*GPIO_PortSource对应GPIO_PortSourceGPIOA~G,物理层的话可以理解为GPIOA~G, GPIO_PinSource对应GPIO_PinSource0~15,物理层的话可以理解为ping0~ping15*/


void GPIO_EventOutputCmd(FunctionalState NewState);
/*操作的也是AFIO_EVCR寄存器,事件输出功能的使能函数,与GPIO_EventOutputConfig配套使用*/


void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
/*操作AFIO_EXTICR寄存器,配置AFIO的数据选择器来实现GPIO到中断的线路选择,第一个参数选择GPIO_PortSourceGPIOx,对应GPIOX,第二个参数选择GPIO_PinSourcex,对应GPIO_pingX*/

#include "stm32f10x.h"
#include "Delay.h"

int16_t count=0;

void EXTI_TEST(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB时钟	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟	
	
	GPIO_InitTypeDef GPIO_Initstruction;//创建一个GPIO_InitTypeDef类型的结构体并对结构体成员进行初始化
	GPIO_Initstruction.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_Initstruction.GPIO_Pin=GPIO_Pin_14;
	GPIO_Initstruction.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_Initstruction);//GPIO-PIN14初始化
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);//通过AFIO中断线路选择,将GPIOB-PIN14与中断线14连接在一起
	
	EXTI_InitTypeDef EXTI_TEST14;//定义中断结构并对结构体成员初始化
	EXTI_TEST14.EXTI_Line=EXTI_Line14;//中断线14
	EXTI_TEST14.EXTI_LineCmd=ENABLE;
	EXTI_TEST14.EXTI_Mode=EXTI_Mode_Interrupt;//中断
	EXTI_TEST14.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿触发
	EXTI_Init(&EXTI_TEST14);//初始化中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//中断分组,配置抢占优先级和响应优先级
	//上面整个工程中断分组确定优先级只能一次,一般建议放到主函数开头
	NVIC_InitTypeDef NVIC_EXTI_TEST14;//创建NVIC结构体并对成员进行初始化
	NVIC_EXTI_TEST14.NVIC_IRQChannel=EXTI15_10_IRQn;//确定NVIC线
	NVIC_EXTI_TEST14.NVIC_IRQChannelCmd=ENABLE;
	NVIC_EXTI_TEST14.NVIC_IRQChannelPreemptionPriority=1;//确定抢占优先级和响应优先级
	NVIC_EXTI_TEST14.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_EXTI_TEST14);//初始化NVIC
}


//触发中断后进入中断函数,ST中断函数名称固定,参考启动文件中的DCD,并将进入中断后的操作编写好

int16_t GET_COUNT(void)
{
	return count;
}

void EXTI15_10_IRQHandler(void)//中断函数不需要在头文件申明,系统文件已经生成
{
	if(EXTI_GetITStatus(EXTI_Line14)==SET)
	{
		count++;
		Delay_ms(200);//理论上中断函数内不能增加延迟,但是实验模块传感器有点问题,需要滤波
		EXTI_ClearITPendingBit(EXTI_Line14);
	}
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值