STM32中断系统

前言:想获得更好的阅读体验,可以跳转个人博客 ahoilc明的学习社区,学习过程中有任何问题欢迎加好友讨论

1、EXIT外部中断

使用中断系统可以加大的提高程序的运行效率,如果没有中断系统,为了防止外部中断被忽略或者串口数据被覆盖,主程序就只能不断地查询是否有这些事件发生。

比如如果没有定时器中断,主程序只能使用delay函数,才能实现定时的功能。

有了中断系统后,主程序就可以放心执行其他事情,有中断的时候再去处理。

img

img

1、抢占优先级和响应优先级

  • 抢占优先级用于确定中断的重要性,较高的抢占优先级意味着中断可以中断当前正在执行的较低优先级中断。
  • -响应优先级用于确定多个中断同时触发时的执行顺序。响应优先级高的中断会先执行,而响应优先级相同的中断会按照中断号顺序排队执行。

2、中断触发方式

  • 上升沿触发:中断在引脚电平由低到高变化时触发。
  • 下降沿触发:中断在引脚电平由高到低变化时触发。
  • 双边沿触发:中断在引脚电平由低到高或由高到低变化时触发。
  • 软件触发:通过执行一句特定的代码来触发中断,通常使用类似于 NVIC_SetPendingIRQ() 的函数。

3、触发响应方式

  • 中断响应:中断触发后,中断服务程序执行,通常用于需要立即响应的事件。
  • 事件响应:事件触发后,不会引发中断,而是触发其他外设操作,如启动ADC转换或启动DMA传输。

4、注意事项

  • 进入中断函数时,务必检查中断标志位以确定中断的原因。
  • 中断服务函数应该执行简短和高效的代码,以尽快释放中断,并允许更高优先级的中断执行。
  • 在中断服务函数退出时,通常需要清除中断标志位,以允许下一次中断触发

通道数:16个GPIO_PIN、外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒

img

NVIC用于统一管理中断和分配中断优先级,属于内核外设,是CPU的小助手,可以让CPU专注于运算。相当于医院里的叫号系统(给病人进行排号,CPU相当于医生,只负责看病)。

2、 NVIC优先级分组

优先级:抢占优先级、响应优先级。

NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级(插队)

抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队

img

img

如果中断不多,很难导致中断冲突时,可以随意选择优先级分组,那个都行。

3、 EXIT(Extern Interrupt)外部中断

1、基本功能

EXTI 的主要功能是检测连接到微控制器引脚的电平变化,并在特定条件下触发中断。它允许您实时响应外部事件,如按钮按下或传感器状态变化。

2、支持的GPIO口

EXTI 支持所有的 GPIO 口,但需要注意的是相同的引脚不能同时触发中断。例如,如果您将 PA0 配置为触发中断,那么其他引脚上的中断可能会被禁用。但是,PA0 和 PA1 这样的不同引脚可以同时触发中断。

3、通道数

EXTI 支持最多16个 GPIO 引脚作为中断触发源。除了 GPIO 引脚,它还可以监测其他事件,如电源电压监测(PVD)、RTC 闹钟、USB 唤醒和以太网唤醒。

4、EXTI 基本结构

您提供的示意图展示了 EXTI 的基本结构。它包括了多个通道,每个通道对应一个 GPIO 引脚。当引脚状态变化时,相应的 EXTI 通道会触发中断。

5、 AFIO 中断引脚选择

AFIO(Alternate Function Input Output)是用于配置微控制器引脚的外设。在配置 EXTI 时,您可以选择将特定的 GPIO 引脚连接到 EXTI 通道。这允许您灵活地选择要触发中断的引脚。

EXIT基本结构:

img

AFIO中断引脚选择:在GPIO(A~G)外设的16个GPIO_Pin中选择一个连接到后面的EXIT的通道里。

4、 常用的触发外部中断的硬件模块

对于STM32来说,想要获取的信号是外部驱动的很快的突发信号,但是又不需要一直进行检测。

不需要经常使用、不需要一直检测的模块:

  1. 按键(注意抖动问题),不推荐,可以使用定时器中断

  2. 旋转编码器

  3. 红外遥控接收器

5、 外部中断程序设计步骤

img

涉及到的外设:RCC、GPIO、AFIO、EXTI、NVIC

1、如何设置外部中断 (EXTI)

  1. 打开RCC时钟: 在使用任何外设之前,需要确保相应的外设时钟已打开。在这种情况下,您打开了RCC (Reset and Clock Control) 时钟,它是控制各种外设时钟的关键。没有时钟,外设无法正常工作。

  2. 配置GPIO: 在使用外部中断之前,需要选择一个GPIO端口,并将其配置为输入模式。输入模式的配置可以是浮空(不连接到任何电平)、上拉(连接到高电平)或下拉(连接到低电平),具体取决于应用的要求。

  3. 配置AFIO: AFIO (Alternate Function I/O) 控制着GPIO引脚的复用功能。在这一步中,您选择了使用的GPIO并将其连接到后面的EXTI模块,以允许GPIO引脚触发外部中断。

  4. 配置EXTI: 外部中断线 (EXTI) 控制着外部中断的触发和响应方式。您需要选择外部中断触发的方式,例如上升沿、下降沿或双边沿触发。通常,中断触发方式应根据应用的需求来选择。此外,您还可以选择中断响应方式,一般选择中断响应以触发中断处理函数。

  5. 配置NVIC: NVIC (Nested Vectored Interrupt Controller) 用于配置中断优先级和中断的全局控制。在这一步中,您可以为外部中断选择一个合适的优先级,以确定它在中断处理器中的相对重要性。抢占优先级和响应优先级的选择可以确保在多个中断同时发生时,系统可以正确地处理它们。

配置完之后,写中断执行函数

在STM32中,中断函数的名字都是固定的,每个中断通道都对应一个中断函数。

中断函数的名字可以参考启动文件中的“stratup_stm32f10x_md文件

配置AFIO相关函数

img

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

参数1:选择重映射方式

参数2:新的状态

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

配置AFIO的数据选择器,来选择想要的中断引脚

注意:主函数和中断函数不要操控同一个硬件(比如OLED显示),避免不必要的冲突,中断函数只执行突发的事件,需要快速的执行,如操作变量、中断标志位。

2、一般步骤:

要使用 EXTI(External Interrupt,外部中断)来检测和响应外部事件,您需要遵循以下一般步骤:

  1. 配置引脚

    • 首先,您需要选择要配置为 EXTI 中断触发源的 GPIO 引脚。这可以通过将引脚模式配置为输入和选择触发方式来实现。通常,上升沿或下降沿触发是常见的配置。
    • 如果您使用的是 STM32 系列的微控制器,通常需要使用 GPIO 初始化函数来配置引脚,如 GPIO_Init()
  2. 配置 EXTI

    • 接下来,您需要配置 EXTI 外部中断。在 STM32 等微控制器中,这通常涉及到以下步骤:
      • 选择 EXTI 通道,通常与要配置的引脚对应。
      • 配置触发方式,选择上升沿、下降沿或其他方式。
      • 使能 EXTI 中断。
  3. 编写中断处理程序

    • 为了响应 EXTI 中断触发,您需要编写中断处理程序。这个程序会在外部事件触发时执行。
    • 在中断处理程序中,您可以执行与事件相关的操作,例如读取传感器数据、处理按钮按下事件等。
  4. 配置中断优先级(可选):

    • 如果系统中有多个中断源,您可能需要配置中断优先级以确定执行顺序。通常,您可以使用中断控制器(如 NVIC,在 STM32 中)来配置中断优先级。
  5. 清除中断标志位

    • 在中断处理程序中,通常需要清除 EXTI 的中断标志位,以允许下一个触发。这可以通过写入特定的寄存器来实现。
  6. 启用全局中断

    • 最后,在主程序的入口点,通常需要启用全局中断以允许所有中断触发。这可以通过使用 __enable_irq() 或类似的函数来实现。

以下是一个典型的 STM32 的 EXTI 配置示例,假设要配置 PA0 引脚上升沿触发的外部中断:

// 步骤1: 配置引脚
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
// 使能 GPIOA 时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
// 输入浮空模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
// 配置 PA0 引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);

// 步骤2: 配置 EXTI
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 
// 使能 AFIO 时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); 
// 配置 EXTI 到 PA0
EXTI_InitStructure.EXTI_Line = EXTI_Line0; 
// EXTI0 通道
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 
// 中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; 
// 上升沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; 
// 使能 EXTI0
EXTI_Init(&EXTI_InitStructure);

// 步骤3: 编写中断处理程序
void EXTI0_IRQHandler(void) {
    // 在此处编写中断处理程序,响应外部事件
    // 例如,您可以执行读取传感器数据的操作

    EXTI_ClearITPendingBit(EXTI_Line0); 
    // 清除中断标志位
}

// 步骤4: 配置中断优先级 (可选)
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; 
// EXTI0 中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; 
// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; 
// 响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
// 使能中断通道
NVIC_Init(&NVIC_InitStructure);

// 步骤5: 启用全局中断
__enable_irq();

这个示例配置了 PA0 引脚上升沿触发的 EXTI 中断,当 PA0 引脚状态从低电平变为高电平时,将触发中断处理程序 EXTI0_IRQHandler。中断处理程序中的代码可根据外部事件的需要自定义。

3、GPIO中断输入输出函数

/**
  * @brief  锁定指定的GPIO引脚配置,防止进一步更改。
  * @param  GPIOx: 要锁定的GPIO端口。
  * @param  GPIO_Pin: 要锁定的GPIO引脚。
  * @retval 无
  */
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

/**
  * @brief  配置外部中断的事件输出功能,通常用于触发外部事件。
  * @param  GPIO_PortSource: 事件输出的源GPIO端口。
  * @param  GPIO_PinSource: 事件输出的源GPIO引脚。
  * @retval 无
  */
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

/**
  * @brief  启用或禁用外部中断的事件输出功能。
  * @param  NewState: 事件输出功能的新状态(ENABLE或DISABLE)。
  * @retval 无
  */
void GPIO_EventOutputCmd(FunctionalState NewState);

/**
  * @brief  配置GPIO引脚重映射,允许将一个引脚映射到另一个引脚。
  * @param  GPIO_Remap: GPIO引脚重映射配置。
  * @param  NewState: 重映射功能的新状态(ENABLE或DISABLE)。
  * @retval 无
  */
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

/**
  * @brief  配置外部中断线映射,将指定的GPIO引脚映射到外部中断线上。
  * @param  GPIO_PortSource: 外部中断线映射的源GPIO端口。
  * @param  GPIO_PinSource: 外部中断线映射的源GPIO引脚。
  * @retval 无
  */
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

/**
  * @brief  配置以太网接口的媒体类型(例如,RMII或MII)。
  * @param  GPIO_ETH_MediaInterface: 以太网媒体接口类型配置。
  * @retval 无
  */
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);

4、配置AFIO外部中断引脚选择

这段代码是用于配置外部中断线映射的函数。外部中断线映射允许将特定的GPIO引脚映射到外部中断线上,从而使这些引脚能够触发外部中断。以下是对该函数的注释和解释:

调用这个函数,就可以配置AFIO的数据选择器,来选择我们想要的中断引脚

/**
  * @brief  配置外部中断线映射,将指定的GPIO引脚映射到外部中断线上。
  * @param  GPIO_PortSource: 外部中断线映射的源GPIO端口。
  * @param  GPIO_PinSource: 外部中断线映射的源GPIO引脚。
  * @retval 无
  */
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
  • GPIO_PortSource 参数用于指定外部中断线映射的源GPIO端口。这是一个数字,表示GPIO端口,例如,如果要映射的引脚属于GPIOA,则该参数为 GPIO_PortSource = GPIO_PortSourceGPIOA
  • GPIO_PinSource 参数用于指定外部中断线映射的源GPIO引脚。这是一个数字,表示要映射的GPIO引脚的位置,例如,如果要映射的引脚是GPIOA的第2号引脚,则该参数为 GPIO_PinSource = GPIO_PinSource2

通过调用此函数,您可以配置外部中断线映射,以便将特定GPIO引脚与外部中断相关联。这使得在满足外部中断触发条件时,可以触发相应的中断处理程序。在配置外部中断时,通常需要使用此函数来设置引脚到外部中断线的映射关系。

6、配置EXTI

1、EXTI库函数

/**
  * @brief  将外部中断模块的配置恢复为默认值。
  */
void EXTI_DeInit(void);

/**
  * @brief  初始化外部中断模块。
  * @param  EXTI_InitStruct: 包含外部中断配置的结构体指针。
  */
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

/**
  * @brief  将外部中断配置结构体初始化为默认值。
  * @param  EXTI_InitStruct: 要初始化的外部中断配置结构体指针。
  */
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);

/**
  * @brief  生成软件触发的外部中断。
  * @param  EXTI_Line: 要生成中断的外部中断线。
  */
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
//主程序:
/**
  * @brief  检查指定外部中断线的中断标志位是否已设置。
  * @param  EXTI_Line: 要检查的外部中断线。
  * @retval 设置标志位的状态 (SET或RESET)。
  */
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);

/**
  * @brief  清除指定外部中断线的中断标志位。
  * @param  EXTI_Line: 要清除标志位的外部中断线。
  */
void EXTI_ClearFlag(uint32_t EXTI_Line);
//中断程序:
/**
  * @brief  检查指定外部中断线的中断挂起位是否已设置。
  * @param  EXTI_Line: 要检查的外部中断线。
  * @retval 挂起位的状态 (SET或RESET)。
  */
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);

/**
  * @brief  清除指定外部中断线的中断挂起位。
  * @param  EXTI_Line: 要清除挂起位的外部中断线。
  */
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

7、配置NVIC

以下是对这些函数的代码注释解释:

/**
  * @brief  配置中断优先级分组。
  * @param  NVIC_PriorityGroup: 中断优先级分组,可以是 NVIC_PriorityGroup_x 中的一个值。
  */
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

/**
  * @brief  初始化中断控制器 (NVIC) 寄存器。
  * @param  NVIC_InitStruct: 包含中断控制器配置信息的结构体指针。
  */
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

/**
  * @brief  配置向量表的基地址和偏移量。
  * @param  NVIC_VectTab: 向量表的基地址,可以是 NVIC_VectTab_RAM 或 NVIC_VectTab_FLASH。
  * @param  Offset: 向量表偏移量。
  */
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);

/**
  * @brief  配置系统低功耗模式。
  * @param  LowPowerMode: 低功耗模式,可以是 SysTick_CLKSource_HCLK_Div8 或 SysTick_CLKSource_HCLK。
  * @param  NewState: 新状态,可以是 ENABLE(启用)或 DISABLE(禁用)。
  */
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);

/**
  * @brief  配置SysTick定时器的时钟源。
  * @param  SysTick_CLKSource: SysTick定时器的时钟源,可以是 SysTick_CLKSource_HCLK 或 SysTick_CLKSource_HCLK_Div8。
  */
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);

这些函数用于配置和管理中断控制器 (NVIC) 和系统滴答定时器 (SysTick)。以下是它们的简要解释:

  • NVIC_PriorityGroupConfig 用于配置中断优先级分组,这是为了确定中断的优先级管理方式。
  • NVIC_Init 用于初始化中断控制器的寄存器,配置中断的优先级和其他设置。
  • NVIC_SetVectorTable 用于配置向量表的基地址和偏移量,这是中断处理程序的入口。
  • NVIC_SystemLPConfig 用于配置系统低功耗模式,以降低系统功耗。
  • SysTick_CLKSourceConfig 用于配置 SysTick 定时器的时钟源,以控制其工作时钟。

这些函数通常在初始化阶段用于配置系统的中断和定时器设置,以满足应用程序的需求。确保查阅您使用的STM32系列的参考手册和文档,以获取详细的配置信息和示例代码。

8、红外传感器中断计次

uint16_t CountSensor_Count; // 存储传感器计数值的变量

void CountSensor_Init(void)
{
    // 使能GPIOB和AFIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    // 配置GPIOB引脚14为上拉输入模式
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 配置外部中断线,将GPIOB引脚14与外部中断线14相关联
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
    
    // 配置外部中断线14,触发方式为下降沿触发
    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = EXTI_Line14;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_Init(&EXTI_InitStructure);
    
    // 配置中断分组为优先级组2
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    // 配置外部中断的中断处理函数和中断优先级
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; // 对应外部中断线15-10
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 响应优先级1
    NVIC_Init(&NVIC_InitStructure);
}

uint16_t CountSensor_Get(void)
{
    return CountSensor_Count; // 返回传感器计数值
}

void EXTI15_10_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line14) == SET)
    {
        // 如果外部中断14触发(引脚电平下降)
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
        {
            // 如果引脚电平为低(确保不是抖动),增加计数值
            CountSensor_Count++;
        }
        EXTI_ClearITPendingBit(EXTI_Line14); // 清除中断标志位
    }
}

1、实现逻辑

这段代码初始化了一个外部传感器计数功能。具体注释如下:

  • CountSensor_Count 是用来存储传感器计数值的变量。

  • CountSensor_Init 函数用于初始化外部传感器。它执行以下步骤:

    • 使能 GPIOBAFIO 时钟。
    • 配置 GPIOB 引脚14为上拉输入模式,这个引脚用于连接传感器。
    • 配置外部中断线,将 GPIOB 引脚14与外部中断线14关联起来。
    • 配置外部中断线14的触发方式为下降沿触发,表示当引脚电平从高变为低时触发中断。
    • 配置中断分组为优先级组2,允许设置中断的抢占优先级和响应优先级。
    • 配置外部中断的中断处理函数和中断优先级。
  • CountSensor_Get 函数用于获取传感器的计数值,并返回该值。

  • EXTI15_10_IRQHandler 是外部中断的中断处理函数。当外部中断14触发时(引脚电平下降),该函数会被调用。在函数内部,它会检查引脚的电平,如果电平为低(确保不是抖动),则增加 CountSensor_Count 计数值。最后,它会清除中断标志位,以表示已经处理了中断。

9、旋转编码器计次

这段代码是用于处理编码器的输入信号,并实时计算编码器的计数值。下面是对这段代码的详细注释:

#include "stm32f10x.h" // 包含STM32的库文件

int16_t Encoder_Count; // 定义一个16位整数用于存储编码器计数值

// 编码器初始化函数
void Encoder_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); 
    // 打开GPIOB时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 
    // 打开AFIO时钟

    GPIO_InitTypeDef GPIO_InitStructure; 
    // 定义GPIO初始化结构体
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
    // 配置GPIO引脚为上拉输入模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; 
    // 配置GPIO引脚0和1
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure); 
    // 初始化GPIOB

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); 
    // 配置GPIO引脚0连接到外部中断线
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1); 
    // 配置GPIO引脚1连接到外部中断线

    EXTI_InitTypeDef EXTI_InitStructure; 
    // 定义外部中断初始化结构体
    EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1; 
    // 配置外部中断线0和1
    EXTI_InitStructure.EXTI_LineCmd = ENABLE; 
    // 使能外部中断线0和1
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 
    // 配置中断模式
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; 
    // 配置下降沿触发
    EXTI_Init(&EXTI_InitStructure); 
    // 初始化外部中断

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
    // 配置中断优先级分组

    NVIC_InitTypeDef NVIC_InitStructure; 
    // 定义NVIC初始化结构体
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; 
    // 配置外部中断0通道
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    // 使能外部中断0通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 
    // 设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 
    // 设置响应优先级
    NVIC_Init(&NVIC_InitStructure); 
    // 初始化NVIC

    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; 
    // 配置外部中断1通道
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    // 使能外部中断1通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 
    // 设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 
    // 设置响应优先级
    NVIC_Init(&NVIC_InitStructure); 
    // 初始化NVIC
}

// 获取编码器计数值的函数
int16_t Encoder_Get(void)
{
    int16_t Temp;
    Temp = Encoder_Count;
    Encoder_Count = 0; 
    // 清零计数值并返回
    return Temp;
}

// 处理外部中断0的中断服务函数
void EXTI0_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line0) == SET)
    {
        // 如果外部中断0被触发
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
        {
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
            {
                Encoder_Count--; // 编码器逆时针旋转
            }
        }
        EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位
    }
}

// 处理外部中断1的中断服务函数
void EXTI1_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line1) == SET)
    {
        // 如果外部中断1被触发
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
        {
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
            {
                Encoder_Count++; // 编码器顺时针旋转
            }
        }
        EXTI_ClearITPendingBit(EXTI_Line1); // 清除中断标志位
    }
}

1、实现逻辑

这段代码设置了两个外部中断线,用于处理编码器的输入信号。在外部中断触发时,会根据按钮的状态(旋转编码器的状态为双向滞后九十度的电平信号,通过判断高低电平分辨正负)递增或递减编码器的计数值。外部中断0用于逆时针旋转,而外部中断1用于顺时针旋转。每次中断触发后,计数值会被清零,以便进行下一轮计数。这个示例展示了如何使用外部中断来处理实际硬件输入,并在中断服务函数中更新相关的计数值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ahoilc.明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值