stm32f103芯片多个IO配置成外部中断

根据引脚对应的EXTI线路来合理的组织代码。

引脚与EXTI线路对应关系分析:

PB12 → EXTI_Line12

PB13 → EXTI_Line13

PB14 → EXTI_Line14

PB15 → EXTI_Line15

PC6 → EXTI_Line6

PC7 → EXTI_Line7

PC8 → EXTI_Line8

PC9 → EXTI_Line9

PA8 → EXTI_Line8 (注意:与PC8冲突!)

重要发现:PA8和PC8都使用EXTI_Line8,不能同时配置为中断(需要二选一或者修改设计)。

方案1:使用PA8,不适用PC8(共8个引脚)

cpp 复制代码
#include "stm32f10x.h"
#include "misc.h"

/**
  * @brief  配置8个GPIO引脚为外部中断输入
  * @note   PB12, PB13, PB14, PB15, PC6, PC7, PC9, PA8
  *         PC8与PA8冲突,故只使用PA8
  * @param  无
  * @retval 无
  */
void EXTI_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    /* 1. 使能所有需要的时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | 
                          RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    
    /* 2. 配置GPIO引脚为输入模式 */
    
    // 配置PB12, PB13, PB14, PB15(建议下拉输入)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | 
                                  GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;  // 下拉输入
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 配置PC6, PC7, PC9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_9;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
    // 配置PA8
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    /* 3. 配置GPIO引脚与EXTI线路的映射关系 */
    
    // PB12 -> EXTI_Line12
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
    
    // PB13 -> EXTI_Line13
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource13);
    
    // PB14 -> EXTI_Line14
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
    
    // PB15 -> EXTI_Line15
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource15);
    
    // PC6 -> EXTI_Line6
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource6);
    
    // PC7 -> EXTI_Line7
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource7);
    
    // PC9 -> EXTI_Line9
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource9);
    
    // PA8 -> EXTI_Line8
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource8);
    
    /* 4. 配置EXTI线路参数 */
    
    // 配置EXTI_Line6,7,8,9 (共享中断向量)
    EXTI_InitStructure.EXTI_Line = EXTI_Line6 | EXTI_Line7 | EXTI_Line8 | EXTI_Line9;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
    
    // 配置EXTI_Line12,13,14,15 (共享中断向量)
    EXTI_InitStructure.EXTI_Line = EXTI_Line12 | EXTI_Line13 | 
                                   EXTI_Line14 | EXTI_Line15;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  // 下降沿触发
    EXTI_Init(&EXTI_InitStructure);
    
    /* 5. 配置NVIC中断优先级 */
    
    // 配置EXTI9_5中断 (包含EXTI5-EXTI9)
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  // 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;         // 响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    // 配置EXTI15_10中断 (包含EXTI10-EXTI15)
    NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
}

/**
  * @brief  EXTI9_5中断服务函数
  * @note   处理EXTI5-EXTI9的中断,需要判断具体是哪个引脚触发
  *         这里处理PC6(Line6), PC7(Line7), PA8(Line8), PC9(Line9)
  * @param  无
  * @retval 无
  */
void EXTI9_5_IRQHandler(void)
{
    /* 检查并处理PC6 (EXTI_Line6) 中断 */
    if (EXTI_GetITStatus(EXTI_Line6) != RESET)
    {
        // 在这里编写PC6中断处理代码
        // 例如:翻转LED,读取数据等
        
        // 清除中断标志位(必须!)
        EXTI_ClearITPendingBit(EXTI_Line6);
    }
    
    /* 检查并处理PC7 (EXTI_Line7) 中断 */
    if (EXTI_GetITStatus(EXTI_Line7) != RESET)
    {
        // 在这里编写PC7中断处理代码
        
        EXTI_ClearITPendingBit(EXTI_Line7);
    }
    
    /* 检查并处理PA8 (EXTI_Line8) 中断 */
    if (EXTI_GetITStatus(EXTI_Line8) != RESET)
    {
        // 在这里编写PA8中断处理代码
        
        EXTI_ClearITPendingBit(EXTI_Line8);
    }
    
    /* 检查并处理PC9 (EXTI_Line9) 中断 */
    if (EXTI_GetITStatus(EXTI_Line9) != RESET)
    {
        // 在这里编写PC9中断处理代码
        
        EXTI_ClearITPendingBit(EXTI_Line9);
    }
}

/**
  * @brief  EXTI15_10中断服务函数
  * @note   处理EXTI10-EXTI15的中断,需要判断具体是哪个引脚触发
  *         这里处理PB12(Line12), PB13(Line13), PB14(Line14), PB15(Line15)
  * @param  无
  * @retval 无
  */
void EXTI15_10_IRQHandler(void)
{
    /* 检查并处理PB12 (EXTI_Line12) 中断 */
    if (EXTI_GetITStatus(EXTI_Line12) != RESET)
    {
        // 在这里编写PB12中断处理代码
        // 例如:按键检测、传感器信号等
        
        EXTI_ClearITPendingBit(EXTI_Line12);
    }
    
    /* 检查并处理PB13 (EXTI_Line13) 中断 */
    if (EXTI_GetITStatus(EXTI_Line13) != RESET)
    {
        // 在这里编写PB13中断处理代码
        
        EXTI_ClearITPendingBit(EXTI_Line13);
    }
    
    /* 检查并处理PB14 (EXTI_Line14) 中断 */
    if (EXTI_GetITStatus(EXTI_Line14) != RESET)
    {
        // 在这里编写PB14中断处理代码
        
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
    
    /* 检查并处理PB15 (EXTI_Line15) 中断 */
    if (EXTI_GetITStatus(EXTI_Line15) != RESET)
    {
        // 在这里编写PB15中断处理代码
        
        EXTI_ClearITPendingBit(EXTI_Line15);
    }
}

方案2:如果需要9个引脚,重新设计引脚分配

如果确实需要9个独立的中断引脚,建议重新分配引脚,避免EXTI线路冲突:

cpp 复制代码
// 推荐使用以下不冲突的引脚组合(9个独立中断引脚):
// PB12 (Line12), PB13 (Line13), PB14 (Line14), PB15 (Line15)
// PC6 (Line6), PC7 (Line7), PC8 (Line8), PC9 (Line9)
// 替换PA8为:PA0 (Line0), PA1 (Line1), PA2 (Line2) 等不与前面冲突的引脚

// 例如改为:
// PB12, PB13, PB14, PB15, PC6, PC7, PC8, PC9, PA0
// 这样所有引脚使用不同的EXTI线路

关键注意事项:

1.EXTI线路冲突:

同一个时间,每个EXTI线路只能连接到一个GPIO引脚。

2.中断向量共享:

EXTI5~EXTI9,共享EXTI9_5_IRQHandler。

EXTI10~EXTI15,共享EXTI15_10_IRQHandler。

需要在中段服务函数中判断具体是哪个线路触发。

3.中断服务函数位置:

上述中断服务函数需要放在stm32f10x_it.c文件中。

或者在您的主文件中定义,但需要在stm32f10x_it.c中声明为弱定义。

4.输入模式选择:

GPIO_Mode_IPD:下拉输入,引脚默认低电平。

GPIO_Mode_IPU:上拉输入,引脚默认高电平。

根据实际电路选择,保证中断触发稳定。

5.触发边沿选择:

EXTI_Trigger_Rising:上升沿触发。

EXTI_Trigger_Falling:下降沿触发。

EXTI_Trigger_Rising_Falling:双边沿触发。

使用示例:

cpp 复制代码
int main(void)
{
    // 系统初始化
    SystemInit();
    
    // 配置外部中断
    EXTI_GPIO_Config();
    
    // 其他初始化...
    
    while(1)
    {
        // 主循环
    }
}

调试建议:

1.在每个中断处理函数中添加调试代码(如翻转LED)。

2.使用串口打印中断触发信息。

3.确保清除中断标志位,避免重复进入中断。

4.需要根据实际需求调整引脚配置,如果9个IO有冲突,需要重新分配引脚以使用不同的EXTI线路。

相关推荐
良许Linux3 小时前
IIC总线的硬件部分的两个关键点:开漏输出+上拉电阻
单片机·嵌入式硬件
✎ ﹏梦醒͜ღ҉繁华落℘3 小时前
单片机基础知识 -- ADC分辨率
单片机·嵌入式硬件
Q_21932764554 小时前
车灯控制与报警系统设计
人工智能·嵌入式硬件·无人机
雾削木4 小时前
树莓派部署 HomeAssistant 教程
stm32·单片机·嵌入式硬件
Q_21932764555 小时前
基于单片机的破壁机自动控制系统设计
单片机·嵌入式硬件
wjykp5 小时前
ESP32xxx烧录
stm32·单片机·嵌入式硬件
早起huo杯黑咖啡6 小时前
【NOR Flash】关于芯片的高耐久性分区的编程/擦除周期和最小保留时间的数据
单片机·嵌入式硬件
码农三叔6 小时前
(8-1)传感器系统与信息获取:运动与姿态传感
嵌入式硬件·机器人·人机交互·人形机器人
来可电子CAN青年6 小时前
《工业级 CAN 环网冗余架构设计与光纤长距离传输实践》
经验分享·笔记·单片机·物联网·网络协议