STM32F103学习笔记(三) 外部中断(应用篇)

目录

1. 外部中断的常见应用场景

2. 外部中断的配置

3. 实例演示代码 

4. 总结

1. 外部中断的常见应用场景

        外部中断在嵌入式系统中具有广泛的应用场景,主要用于实时响应外部事件。下面介绍几种常见的应用场景:

        按键检测:外部中断常用于按键检测,例如在嵌入式系统中,我们经常需要检测按钮的按下或释放事件。通过将按钮连接到微控制器的外部中断引脚上,可以在按钮按下时触发外部中断,并在中断服务程序中处理相应的按键事件,如启动/停止操作、菜单切换等。

        传感器触发:外部中断也经常与传感器结合使用,用于实时监测外部环境的变化。例如,我们可以连接红外传感器、超声波传感器或光电传感器到外部中断引脚上,当传感器检测到特定事件(如物体接近、光线强度变化等)时,触发外部中断,从而及时处理相关事件,如报警、数据采集等。

        定时器中断扩展:外部中断与定时器结合使用,可以扩展定时器的功能。例如,我们可以利用定时器产生的定时中断来触发外部中断,从而实现定时采样、定时测量等功能。这种应用场景特别适用于需要定时执行某些任务的情况,如定时采集温湿度数据、定时发送数据等。

        外部设备触发:外部中断还常用于外部设备的触发和控制。例如,外部中断可以用于接收外部设备的触发信号,如外部传感器的报警信号、外部触发器的触发信号等,并据此执行相应的控制逻辑,如启动/停止设备、调整参数等。

        低功耗唤醒:外部中断还可用于实现低功耗唤醒功能。例如,在低功耗模式下,通过外部中断引脚接收外部事件的触发信号,可以唤醒微控制器,从而实现低功耗状态下的实时监测和响应。

2. 外部中断的配置

        配置外部中断是使用外部中断功能的关键步骤,它涉及到对外部中断引脚的配置、中断触发条件的设置以及中断服务程序的编写。以下是配置外部中断的基本步骤:

        引脚配置:首先,需要选择合适的引脚作为外部中断引脚,并将其配置为外部中断输入模式。在STM32F103系列微控制器中,每个引脚都可以作为外部中断引脚使用,需要根据具体的硬件连接和应用需求选择合适的引脚。然后,使用相应的寄存器设置将引脚配置为外部中断输入模式。

        中断触发模式设置:其次,需要根据具体的应用需求设置外部中断的触发模式。外部中断可以根据电平变化或边沿变化来触发中断,包括上升沿触发、下降沿触发、上升沿/下降沿触发等模式。在STM32F103系列微控制器中,可以通过配置外部中断触发控制寄存器来选择合适的触发模式。

        中断服务程序编写:最后,需要编写外部中断的中断服务程序。中断服务程序是一个特殊的函数,用于处理外部中断触发时的事件。在中断服务程序中,我们可以编写相应的处理逻辑,如更新状态标志、执行特定操作等。在编写中断服务程序时,需要注意保持程序的简洁高效,尽量避免使用延迟操作或阻塞式的代码,以确保系统的实时响应能力。

3. 实例演示代码 

        总结了开启所有外部中断的函数,通过简单的配置函数参数即可选定开启的外部中断通道

void EXITX_Tnit(GPIO_TypeDef* GPIOX,uint16_t PIN)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO时钟
	
	/*GPIO初始化*/
	if(GPIOX == GPIOA) gpio_init(RCC_APB2Periph_GPIOA,GPIO_Mode_IPU,GPIOA,PIN);
	if(GPIOX == GPIOB) gpio_init(RCC_APB2Periph_GPIOB,GPIO_Mode_IPU,GPIOB,PIN);
	if(GPIOX == GPIOC) gpio_init(RCC_APB2Periph_GPIOC,GPIO_Mode_IPU,GPIOC,PIN);
	
	if(GPIOX == GPIOA) GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GetPinSource(PIN));//将外部中断的N号线映射到GPIO
	if(GPIOX == GPIOB) GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GetPinSource(PIN));
	if(GPIOX == GPIOC) GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GetPinSource(PIN));

	/*EXTI初始化*/
	EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量
	EXTI_InitStructure.EXTI_Line = (uint32_t)PIN;					//选择配置外部中断的14号线
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发
	EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	if(PIN == 0x0001)	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;		//选择配置NVIC的EXTI0线
	if(PIN == 0x0002)	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;		//选择配置NVIC的EXTI1线
	if(PIN == 0x0004)	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;		//选择配置NVIC的EXTI2线
	if(PIN == 0x0008)	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;		//选择配置NVIC的EXTI3线
	if(PIN == 0x0010)	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;		//选择配置NVIC的EXTI4线
	if((PIN & 0x03E0) != 0x0000)	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;		//选择配置NVIC的EXTI9_5线
	if((PIN & 0xFC00) != 0x0000)	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;		//选择配置NVIC的EXTI15_10线
	
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
}

以下PIN口转换通道函数配合使用

uint8_t GetPinSource(uint16_t pin) 
{
	if (pin == GPIO_Pin_0) return GPIO_PinSource0;
	if (pin == GPIO_Pin_1) return GPIO_PinSource1;
	if (pin == GPIO_Pin_2) return GPIO_PinSource2;
	if (pin == GPIO_Pin_3) return GPIO_PinSource3;
	if (pin == GPIO_Pin_4) return GPIO_PinSource4;
	if (pin == GPIO_Pin_5) return GPIO_PinSource5;
	if (pin == GPIO_Pin_6) return GPIO_PinSource6;
	if (pin == GPIO_Pin_7) return GPIO_PinSource7;
	if (pin == GPIO_Pin_8) return GPIO_PinSource8;
	if (pin == GPIO_Pin_9) return GPIO_PinSource9;
	if (pin == GPIO_Pin_10) return GPIO_PinSource10;
	if (pin == GPIO_Pin_11) return GPIO_PinSource11;
	if (pin == GPIO_Pin_12) return GPIO_PinSource12;
	if (pin == GPIO_Pin_13) return GPIO_PinSource13;
	if (pin == GPIO_Pin_14) return GPIO_PinSource14;
	if (pin == GPIO_Pin_15) return GPIO_PinSource15;
	return 0xFF;
}

中断服务函数(可将触发条件后所需执行的代码替换进去)

void EXTI0_IRQHandler(void)
{
	cnt++;					//计数值自增一次
	EXTI_ClearITPendingBit(EXTI_Line0);		//清除外部中断0号线的中断标志位
}
void EXTI1_IRQHandler(void)
{
	cnt++;					//计数值自增一次
	EXTI_ClearITPendingBit(EXTI_Line1);		//清除外部中断1号线的中断标志位
}
void EXTI2_IRQHandler(void)
{
	cnt++;					//计数值自增一次
	EXTI_ClearITPendingBit(EXTI_Line2);		//清除外部中断2号线的中断标志位
}
void EXTI3_IRQHandler(void)
{
	cnt++;					//计数值自增一次
	EXTI_ClearITPendingBit(EXTI_Line3);		//清除外部中断3号线的中断标志位
}
void EXTI4_IRQHandler(void)
{
	cnt++;					//计数值自增一次
	EXTI_ClearITPendingBit(EXTI_Line4);		//清除外部中断4号线的中断标志位
}



void EXTI9_5_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line5) == SET)		//判断是否是外部中断5号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line5);		//清除外部中断5号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line6) == SET)		//判断是否是外部中断6号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line6);		//清除外部中断6号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line7) == SET)		//判断是否是外部中断7号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line7);		//清除外部中断7号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line8) == SET)		//判断是否是外部中断8号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line8);		//清除外部中断8号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line9) == SET)		//判断是否是外部中断9号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line9);		//清除外部中断9号线的中断标志位
	}
}


void EXTI15_10_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line10) == SET)		//判断是否是外部中断10号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line10);		//清除外部中断10号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line11) == SET)		//判断是否是外部中断11号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line11);		//清除外部中断11号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line12) == SET)		//判断是否是外部中断12号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line12);		//清除外部中断12号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line13) == SET)		//判断是否是外部中断13号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line13);		//清除外部中断13号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line14) == SET)		//判断是否是外部中断14号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line14);		//清除外部中断14号线的中断标志位
	}
	if (EXTI_GetITStatus(EXTI_Line15) == SET)		//判断是否是外部中断15号线触发的中断
	{
		cnt++;					//计数值自增一次
		EXTI_ClearITPendingBit(EXTI_Line15);		//清除外部中断15号线的中断标志位
	}
}

主函数开启初始化

EXITX_Tnit(GPIOX,GPIO_Pin_X);

        注意!!相同的PIN口不能一起使用,例如PA0与PB0,都是共享的外部中断通道0,故同时只能使用一个PIN口,防止程序逻辑错误的情况

4. 总结

        通过这篇学习笔记,我对外部中断的基础配置进行了学习。在整个学习过程中,我努力从多个通道的配置去理解外部中断的应用逻辑,并在撰写笔记的过程中,尽可能详细地呈现出来。然而,我也意识到在某些方面可能存在不足和错误,并希望通过后续的学习和实践来不断改进和完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值