对于嵌入式系统开发者而言,STM32系列微控制器是一个强大而灵活的选择,而外部中断作为其中一项重要的功能,为实时响应外部事件提供了关键支持。本文将带领初学者深入理解STM32外部中断的原理和应用,让你能够轻松地在你的项目中使用它。
1. 理解外部中断的原理
外部中断是一种特殊的中断类型,它允许外部信号触发微控制器的中断。在STM32中,外部中断通常用于实现来自外部设备(例如按钮、传感器等)的事件响应。其原理是基于GPIO的状态变化,当GPIO引脚上的电平发生变化(例如从高电平变为低电平或从低电平变为高电平),外部中断将被触发。
2. STM32外部中断的应用场景
- 按钮/开关控制: 当用户按下按钮或切换开关时,可以触发外部中断来响应用户的操作,例如控制LED的亮灭或执行特定功能。
- 传感器触发: 当传感器检测到特定事件或条件发生时,可以触发外部中断来及时处理传感器数据,例如温度传感器、光敏传感器等。
- 通信接口中断: 在串口通信或外部设备接口中,外部中断可以用于处理接收到的数据或监测通信状态的变化,例如UART、SPI、I2C等。
3. 如何在STM32中配置外部中断
在STM32中配置外部中断通常包括以下几个步骤:
- GPIO配置: 将外部中断对应的GPIO引脚配置为输入模式,并设置上拉或下拉电阻,以确保稳定的电平。
- 外部中断线配置: 配置外部中断线,将GPIO引脚与外部中断线关联起来,并设置触发方式(上升沿触发、下降沿触发等)。
- 中断优先级配置: 设置外部中断的抢占优先级和子优先级,以确保及时响应重要的外部事件。
- 编写中断服务程序: 编写外部中断的中断服务程序,处理外部中断事件,例如执行特定的功能或任务切换。
4.示例代码演示
以下是一个简单的示例代码,演示了如何在STM32中配置外部中断并实现LED的控制:
#include "stm32f4xx.h"
/* 外部中断服务程序 */
void EXTI0_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line0) != RESET) // 判断是否是PA0引脚的中断
{
GPIO_ToggleBits(GPIOA, GPIO_Pin_5); // 翻转PA5引脚的状态(LED)
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位
}
}
/* GPIO初始化函数 */
void GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO时钟使能 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* 配置PA5引脚为输出 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* 配置PA0引脚为输入并使能外部中断 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* 外部中断线0配置 */
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
/* 配置外部中断线0对应的GPIO引脚 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
/* 配置外部中断线0 */
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发中断
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
/* 中断优先级设置 */
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; // 抢占优先级为0
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00; // 子优先级为0
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
int main(void)
{
/* MCU初始化 */
SystemInit();
/* 初始化所有的GPIO引脚 */
GPIO_Init();
/* 死循环,等待外部中断触发 */
while (1)
{
}
}
5.特别注意事项
下图为STM32的中断配置表
这里要注意gpio9-gpio5,gpio15-gpio10是公用一根中断线,如果同时用到其中二个GPIO触发中断,需要在中断例程中判断,下面代码就是同时用到GPIO13和GPIO10的例子。
void EXTI15_10_IRQHandler(void)
{
ITStatus EXTI10_Status;
ITStatus EXTI13_Status;
EXTI10_Status = EXTI_GetITStatus(EXTI_Line10); //获得外部中断10的状态
EXTI13_Status = EXTI_GetITStatus(EXTI_Line13); //获得外部中断13的状态
if(EXTI10_Status == SET)
{
led_light_up(1);
}
if(EXTI13_Status == SET)
{
led_light_up(2);
}
EXTI_ClearFlag(EXTI_Line10 | EXTI_Line13); /*清除外部中断10或者13的挂起位 */
}
还需要注意,下图每组的GIPOX都公用一根线,所有系统中GPIOX只能配置一个为中断源,比如配置了PA0,其他PB0到PF0就不能配置,因为PA0到PG0都公用一根中断线,PA1,PA2。。。。都是一样原理。