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