这个实验展示了如何在STM32F10x系列单片机上使用外部中断(EXTI)来检测按钮按下事件。通过配置GPIO引脚和EXTI控制器,我们可以实现当按钮被按下时触发中断,在中断服务程序(ISR)中控制LED灯的亮灭状态。
实验使用了两个按钮分别连接到GPIOA的Pin5和Pin6,当任一按钮被按下时,会触发对应的外部中断线(EXTI_Line5或EXTI_Line6)。中断服务程序会根据触发的中断线来设置或重置GPIOC的Pin13(连接LED)的状态。
code复制按钮1 -> PA5
按钮2 -> PA6
LED阳极 -> PC13
LED阴极 -> GND(通过220Ω电阻)
注意:按钮连接应采用上拉或下拉电阻配置,本实验代码中使用内部上拉模式(GPIO_Mode_IPU),因此硬件上可以不接外部上拉电阻。
主程序主要完成以下几项初始化工作:
c复制int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
Init_LED();
Init_Button();
while(1)
{
// 主循环为空,所有工作由中断处理
}
}
LED初始化将PC13配置为开漏输出模式,初始状态由硬件决定。
c复制void Init_LED(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
}
这是实验的核心配置部分,分为四个步骤:
将PA5和PA6配置为上拉输入模式:
c复制GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
将GPIO引脚映射到对应的EXTI线:
c复制GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);
配置EXTI线5和6为上升沿触发的中断模式:
c复制EXTI_InitTypeDef EXTI_Structure;
EXTI_Structure.EXTI_Line=EXTI_Line5;
EXTI_Structure.EXTI_LineCmd=ENABLE;
EXTI_Structure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_Structure.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_Init(&EXTI_Structure);
// 同样配置EXTI_Line6
配置EXTI9_5中断通道的优先级并使能:
c复制NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn;
NVIC_Init(&NVIC_InitStruct);
当EXTI5或EXTI6触发中断时,会进入这个中断处理函数:
c复制void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line5)==SET)
{
EXTI_ClearFlag(EXTI_Line5);
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); // 熄灭LED
}
else if(EXTI_GetFlagStatus(EXTI_Line6)==SET)
{
EXTI_ClearFlag(EXTI_Line6);
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); // 点亮LED
}
}
外部中断/事件控制器(EXTI)管理了20个中断/事件线,每个中断线可以独立配置为中断或事件模式,并可以单独使能/禁用。EXTI的主要特点包括:
本实验使用了NVIC_PriorityGroup_2优先级分组方式,这意味着:
当按钮按下产生上升沿时,完整的处理流程如下:
可能原因及解决方法:
可能原因:
可能原因:
可以在中断服务程序中增加简单的延时去抖动:
c复制if(EXTI_GetFlagStatus(EXTI_Line5)==SET)
{
EXTI_ClearFlag(EXTI_Line5);
Delay_ms(20); // 20ms去抖动延时
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5) == Bit_SET)
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
}
}
修改EXTI配置为双边沿触发:
c复制EXTI_Structure.EXTI_Trigger=EXTI_Trigger_Rising_Falling;
扩展电路和代码,实现不同按钮控制不同LED:
c复制void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line5)==SET)
{
EXTI_ClearFlag(EXTI_Line5);
GPIO_WriteBit(GPIOC,GPIO_Pin_13, !GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13));
}
else if(EXTI_GetFlagStatus(EXTI_Line6)==SET)
{
EXTI_ClearFlag(EXTI_Line6);
GPIO_WriteBit(GPIOC,GPIO_Pin_14, !GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_14));
}
}
通过这个实验,我们掌握了STM32外部中断的基本使用方法。在实际项目中,EXTI广泛应用于按钮检测、限位开关、外部信号触发等场景。理解EXTI的工作原理和配置方法,是STM32开发的重要基础。