#include "../main/SystemInclude.h" /**------------------------------------------------------------------------ * @brief 配置 GPIO 引脚为外部中断输入 * @param EXTI_GPIOx: GPIO 端口 (pGPIO0/pGPIO1/pGPIO2) * @param EXTI_PINx: GPIO 引脚掩码,如 GPIO_PIN_3 * @param EXTI_LINEx: EXTI 线号,如 EXTI_LINE_3 * @param EXTI_IRQx: 对应的中断 IRQ 号,如 EXTI2_3_IRQn * @note 该函数将指定引脚配置为输入模式,并使能施密特触发器, * 连接到 EXTI 线,并配置为上升沿触发中断(触发边沿可修改代码)。 * 注意:中断的 NVIC 使能和优先级需在外部处理,函数内已注释。 * @example * GPIO_EXTI_Init(pGPIO0, GPIO_PIN_3, EXTI_LINE_3, EXTI2_3_IRQn); **/ void GPIO_EXTI_Init(GPIO_TypeDef* EXTI_GPIOx ,uint16_t EXTI_PINx ,EXTI_LINE_t EXTI_LINEx,IRQn_Type EXTI_IRQx) { GPIO_InitTypeDef GPIO_InitStructure;// GPIO配置结构体 EXTI_InitTypeDef EXTI_InitStructure;// EXTI配置结构体 /* 1. 配置引脚参数 */ GPIO_InitStructure.Pin = EXTI_PINx; // Pinx GPIO_InitStructure.Mode = GPIO_MODE_INPUT; // 输入模式 // GPIO_InitStructure.Pull = GPIO_NOPULL; // 无上拉/下拉电阻 GPIO_NOPULL GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.SchmittTrigger = ENABLE; // 开启施密特触发器输入 GPIO_InitStructure.Alternate = GPIOx_AF_GPIO; LHL_GPIO_Init(EXTI_GPIOx, &GPIO_InitStructure); // 初始化Pin为输入 LHL_GPIO_SetEXTILine(EXTI_GPIOx, EXTI_PINx); // 设置Pin为EXTI0 /* 2. 配置EXTI参数 */ EXTI_InitStructure.Line = EXTI_LINEx; EXTI_InitStructure.Mode = EXTI_MODE_INTERRUPT; // EXTI中断模式 EXTI_InitStructure.Trigger = EXTI_TRIGGER_RISING; // 上升下降沿触发 EXTI_TRIGGER_RISING EXTI_TRIGGER_FALLING EXTI_TRIGGER_RISING_FALLING EXTI_InitStructure.LineCmd = ENABLE; // 使能EXTI LHL_EXTI_Init(&EXTI_InitStructure); // 设置EXTI // NVIC_EnableIRQ(EXTI_IRQx); // 开启NVIC中断 // NVIC_SetPriority(EXTI_IRQx, 0); // 设置EXIT优先级 } /**------------------------------------------------------------------------ * @brief 配置 LPTIM 输出事件为 EXTI 中断源 * @param lptimer: LPTIM1 或 LPTIM2 * @note LPTIM1 对应 EXTI_LINE_10,LPTIM2 对应 EXTI_LINE_11, * 配置为上升沿触发中断模式。可用于将 LPTIM 事件作为唤醒源。 * @example LPTIM_EXTI_Init(LPTIM2); **/ void LPTIM_EXTI_Init(LPTIM_TypeDef *lptimer) { EXTI_InitTypeDef EXTI_InitStructure; if(lptimer == pLPTIM1) EXTI_InitStructure.Line = EXTI_LINE_10; else EXTI_InitStructure.Line = EXTI_LINE_11; EXTI_InitStructure.Mode = EXTI_MODE_INTERRUPT; EXTI_InitStructure.Trigger = EXTI_TRIGGER_RISING; EXTI_InitStructure.LineCmd = ENABLE; LHL_EXTI_Init(&EXTI_InitStructure); } /**------------------------------------------------------------------------ * @brief 配置 ADC 错误/数据就绪输出为 EXTI 中断源 * @note ADC0 和 ADC1 的共用 EXTI_LINE_12,配置为上升沿触发中断模式。 * 可用于在 ADC 转换完成或错误时产生中断。 * @example ADC_EXTI_Init(); **/ void ADC_EXTI_Init(void) { EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.Line = EXTI_LINE_12; EXTI_InitStructure.Mode = EXTI_MODE_INTERRUPT; // EXTI_MODE_EVENT EXTI_InitStructure.Trigger = EXTI_TRIGGER_RISING; EXTI_InitStructure.LineCmd = ENABLE; LHL_EXTI_Init(&EXTI_InitStructure); } /* (PVD、RTC、DMA 的 EXTI 初始化函数可根据需要自行实现) */ // EXTI_LINE_8 = 0x0100u, /*!< External interrupt line 8 PVD(电压低于阈值标记)输出 */ // EXTI_LINE_9 = 0x0200u, /*!< External interrupt line 9 RTC闹钟事件 */ // EXTI_LINE_13 = 0x2000u, /*!< External interrupt line 13 DMA所有通道中断的或 */ //(void)PVD_EXTI_Init(void) //(void)RTC_EXTI_Init(void) //(void)DMA_EXTI_Init(void) /*-===================================================================================================== //外部中断回调 -=====================================================================================================*/ static exti_irq_callback_t exti_callbacks[EXTI_MAX_LINES] = {NULL}; /**------------------------------------------------------------------------ * @brief 注册 EXTI 中断线的回调函数 * @param exti_linex: EXTI 线号,如 EXTI_LINE_3 * @param exti_irq_callback: 用户回调函数指针(无参数无返回值) * @note 同一 EXTI 线只能注册一个回调,重复注册将被忽略。 * 根据线号自动使能对应的 NVIC 中断(分组关系见代码) 。 * @example * void my_exti_callback(void) { ... } * Exti_register_irq_callback(EXTI_LINE_3, my_exti_callback); **/ void Exti_register_irq_callback(EXTI_LINE_t exti_linex, exti_irq_callback_t exti_irq_callback) { if (exti_linex == 0) return;//防止传0 或者不是EXTI_LINE_t的参数 uint8_t index = (uint8_t)__builtin_ctz((unsigned int)exti_linex); //获取exti_linex 索引编号 if(index >= EXTI_MAX_LINES) return; if(exti_callbacks[index] != NULL) return; exti_callbacks[index] = exti_irq_callback; switch (index) { //获取 EXTI 线对应的 IRQ 号 case 0: case 1: NVIC_EnableIRQ(EXTI0_1_IRQn); NVIC_SetPriority(EXTI0_1_IRQn,0); break; case 2: case 3: NVIC_EnableIRQ(EXTI2_3_IRQn); NVIC_SetPriority(EXTI2_3_IRQn,0); break; case 4: case 5: case 6: case 7: NVIC_EnableIRQ(EXTI4_7_IRQn); NVIC_SetPriority(EXTI4_7_IRQn,0); break; case 10: case 11: NVIC_EnableIRQ(EXTI10_11_IRQn); NVIC_SetPriority(EXTI10_11_IRQn,0); break; case 12: case 13: NVIC_EnableIRQ(EXTI12_13_IRQn); NVIC_SetPriority(EXTI12_13_IRQn,0); break; default: // 不支持的线 比如 8 9 break; } } /**------------------------------------------------------------------------ * @brief EXTI0 和 EXTI1 共享中断服务函数 * @note 分别检查 EXTI0 和 EXTI1 的中断标志,清除后调用对应线已注册的回调函数。 **/ void EXTI0_1_IRQHandler(void) { // 检查 EXTI0 和 EXTI1 if (LHL_EXTI_GetPending(EXTI_LINE_0) == SET) { LHL_EXTI_ClearPending(EXTI_LINE_0); if (exti_callbacks[0]) exti_callbacks[0](); } if (LHL_EXTI_GetPending(EXTI_LINE_1) == SET) { LHL_EXTI_ClearPending(EXTI_LINE_1); if (exti_callbacks[1]) exti_callbacks[1](); } } /**------------------------------------------------------------------------ * @brief EXTI2 和 EXTI3 共享中断服务函数 * @note 分别检查 EXTI2 和 EXTI3 的中断标志,清除后调用对应线已注册的回调函数。 **/ void EXTI2_3_IRQHandler(void) { if (LHL_EXTI_GetPending(EXTI_LINE_2) == SET) { LHL_EXTI_ClearPending(EXTI_LINE_2); if (exti_callbacks[2]) exti_callbacks[2](); } if (LHL_EXTI_GetPending(EXTI_LINE_3) == SET) { LHL_EXTI_ClearPending(EXTI_LINE_3); if (exti_callbacks[3]) exti_callbacks[3](); } } /**------------------------------------------------------------------------ * @brief EXTI4 至 EXTI7 共享中断服务函数 * @note 循环检查 EXTI4~7 的中断标志,清除后调用对应线已注册的回调函数。 **/ void EXTI4_7_IRQHandler(void) { for (int i = 4; i <= 7; i++) { EXTI_LINE_t line = (EXTI_LINE_t)(1U << i); if (LHL_EXTI_GetPending(line) == SET) { LHL_EXTI_ClearPending(line); if (exti_callbacks[i]) exti_callbacks[i](); } } } /**------------------------------------------------------------------------ * @brief EXTI10 和 EXTI11 共享中断服务函数 * @note 分别检查 EXTI10 和 EXTI11 的中断标志,清除后调用对应线已注册的回调函数。 **/ void EXTI10_11_IRQHandler(void) { // 检查 EXTI0 和 EXTI1 if (LHL_EXTI_GetPending(EXTI_LINE_10) == SET) { LHL_EXTI_ClearPending(EXTI_LINE_10); if (exti_callbacks[10]) exti_callbacks[10](); } if (LHL_EXTI_GetPending(EXTI_LINE_11) == SET) { LHL_EXTI_ClearPending(EXTI_LINE_11); if (exti_callbacks[11]) exti_callbacks[11](); } } /**------------------------------------------------------------------------ * @brief EXTI12 和 EXTI13 共享中断服务函数 * @note 分别检查 EXTI12 和 EXTI13 的中断标志,清除后调用对应线已注册的回调函数。 **/ void EXTI12_13_IRQHandler(void) { // 检查 EXTI0 和 EXTI1 if (LHL_EXTI_GetPending(EXTI_LINE_12) == SET) { if (exti_callbacks[12]) exti_callbacks[12](); LHL_EXTI_ClearPending(EXTI_LINE_12); } else if (LHL_EXTI_GetPending(EXTI_LINE_13) == SET) { LHL_EXTI_ClearPending(EXTI_LINE_13); if (exti_callbacks[13]) exti_callbacks[13](); } }