根据引脚对应的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线路。