Files
CHJ/user/MCU/lhl_exti.c
2026-03-20 21:19:53 +08:00

225 lines
8.5 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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_10LPTIM2 对应 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]();
}
}