今天上午加入一个功能时出现了问题,PB12~15配置外部中断失败,原因是操作AFIO前没有使能它的时钟。
我的目标是:
设置PA4 PA5 PA6 PA7 PB12 PB13 PB14 PB15为外部中断输入,每个引脚接收到一个上升沿就将引脚对应的计数加一。
配置代码如下(有问题):
//A4
#define Fre1_EXTI_PortSource GPIO_PortSourceGPIOA
#define Fre1_EXTI_PinSource GPIO_PinSource4
//A5
#define Fre2_EXTI_PortSource GPIO_PortSourceGPIOA
#define Fre2_EXTI_PinSource GPIO_PinSource5
//A6
#define Fre3_EXTI_PortSource GPIO_PortSourceGPIOA
#define Fre3_EXTI_PinSource GPIO_PinSource6
//A7
#define Fre4_EXTI_PortSource GPIO_PortSourceGPIOA
#define Fre4_EXTI_PinSource GPIO_PinSource7
//B12
#define Fre5_EXTI_PortSource GPIO_PortSourceGPIOB
#define Fre5_EXTI_PinSource GPIO_PinSource12
//B13
#define Fre6_EXTI_PortSource GPIO_PortSourceGPIOB
#define Fre6_EXTI_PinSource GPIO_PinSource13
//B14
#define Fre7_EXTI_PortSource GPIO_PortSourceGPIOB
#define Fre7_EXTI_PinSource GPIO_PinSource14
//B15
#define Fre8_EXTI_PortSource GPIO_PortSourceGPIOB
#define Fre8_EXTI_PinSource GPIO_PinSource15
#define EXTI_AFIO_CLK RCC_APB2Periph_AFIO
//GPIOA_4~7
#define FRE1_4_EXTI_PORT GPIOA
#define FRE1_EXTI_PIN GPIO_Pin_4
#define FRE2_EXTI_PIN GPIO_Pin_5
#define FRE3_EXTI_PIN GPIO_Pin_6
#define FRE4_EXTI_PIN GPIO_Pin_7
//GPIOB_12~15
#define FRE5_8_EXTI_PORT GPIOB
#define FRE5_EXTI_PIN GPIO_Pin_12
#define FRE6_EXTI_PIN GPIO_Pin_13
#define FRE7_EXTI_PIN GPIO_Pin_14
#define FRE8_EXTI_PIN GPIO_Pin_15
//EXTI_Line
#define Fre1_INT_EXTI_Line EXTI_Line4
#define Fre2_INT_EXTI_Line EXTI_Line5
#define Fre3_INT_EXTI_Line EXTI_Line6
#define Fre4_INT_EXTI_Line EXTI_Line7
#define Fre5_INT_EXTI_Line EXTI_Line12
#define Fre6_INT_EXTI_Line EXTI_Line13
#define Fre7_INT_EXTI_Line EXTI_Line14
#define Fre8_INT_EXTI_Line EXTI_Line15
//中断源们
#define FRE1_EXTI_IRQn EXTI4_IRQn
#define FRE2_4_EXTI_IRQn EXTI9_5_IRQn
#define FRE5_8_EXTI_IRQn EXTI15_10_IRQn
//中断输入GPIO时钟
#define FRE_GPIO_CLK RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB
//配置NVIC
static void NVIC_Configer(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
//优先级组在USART初始化时设置过了
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
//使能中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//配置中断源1
NVIC_InitStructure.NVIC_IRQChannel = FRE1_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
//配置中断源2
NVIC_InitStructure.NVIC_IRQChannel = FRE2_4_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
//配置中断源3
NVIC_InitStructure.NVIC_IRQChannel = FRE5_8_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_Init(&NVIC_InitStructure);
}
static void Fre_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//开启按键端口时钟
RCC_APB2PeriphClockCmd(FRE_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//下拉输入
//配置Fre1~4
GPIO_InitStructure.GPIO_Pin = FRE1_EXTI_PIN | FRE2_EXTI_PIN | FRE3_EXTI_PIN | FRE4_EXTI_PIN;
GPIO_Init(FRE1_4_EXTI_PORT,&GPIO_InitStructure);
//配置Fre5~8
GPIO_InitStructure.GPIO_Pin = FRE5_EXTI_PIN | FRE6_EXTI_PIN | FRE7_EXTI_PIN | FRE8_EXTI_PIN;
GPIO_Init(FRE5_8_EXTI_PORT,&GPIO_InitStructure);
//配置EXTI信号源
GPIO_EXTILineConfig(Fre1_EXTI_PortSource,Fre1_EXTI_PinSource);
GPIO_EXTILineConfig(Fre2_EXTI_PortSource,Fre2_EXTI_PinSource);
GPIO_EXTILineConfig(Fre3_EXTI_PortSource,Fre3_EXTI_PinSource);
GPIO_EXTILineConfig(Fre4_EXTI_PortSource,Fre4_EXTI_PinSource);
GPIO_EXTILineConfig(Fre5_EXTI_PortSource,Fre5_EXTI_PinSource);
GPIO_EXTILineConfig(Fre6_EXTI_PortSource,Fre6_EXTI_PinSource);
GPIO_EXTILineConfig(Fre7_EXTI_PortSource,Fre7_EXTI_PinSource);
GPIO_EXTILineConfig(Fre8_EXTI_PortSource,Fre8_EXTI_PinSource);
}
//初始化EXTI
void Fre_EXTI_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
//配置NVIC
NVIC_Configer();
//配置GPIO
Fre_GPIO_Init();
//开AFIO时钟
RCC_APB2PeriphClockCmd(EXTI_AFIO_CLK, ENABLE);
//中断模式
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
//上升沿中断
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
//使能中断
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
//选择EXTI信号源
EXTI_InitStructure.EXTI_Line = Fre1_INT_EXTI_Line;
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = Fre2_INT_EXTI_Line;
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = Fre3_INT_EXTI_Line;
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = Fre4_INT_EXTI_Line;
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = Fre5_INT_EXTI_Line;
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = Fre6_INT_EXTI_Line;
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = Fre7_INT_EXTI_Line;
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = Fre8_INT_EXTI_Line;
EXTI_Init(&EXTI_InitStructure);
}
发生的错误是PA4 PA5 PA6 PA7可以检测到上升沿并进入中断,但是PB12~PB15却死活进入不了中断,进入调试模式时发现PB13 PB14会无故检测到上升沿。
睡了一觉之后发现了问题的原因:
我在函数 Fre_GPIO_Init() 中调用了 GPIO_EXTILineConfig()
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
{
uint32_t tmp = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));
assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));
//这里包含了对AFIO_EXTICR的操作,但是我在这之前并没有使能AFIO,所以会出现异常
AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;
AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));
}
数据手册上说了
所以正确的写法应该是
static void Fre_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//开启按键端口时钟
RCC_APB2PeriphClockCmd(FRE_GPIO_CLK,ENABLE);
//开AFIO时钟
RCC_APB2PeriphClockCmd(EXTI_AFIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//下拉输入
//配置Fre1~4
GPIO_InitStructure.GPIO_Pin = FRE1_EXTI_PIN | FRE2_EXTI_PIN | FRE3_EXTI_PIN | FRE4_EXTI_PIN;
GPIO_Init(FRE1_4_EXTI_PORT,&GPIO_InitStructure);
//配置Fre5~8
GPIO_InitStructure.GPIO_Pin = FRE5_EXTI_PIN | FRE6_EXTI_PIN | FRE7_EXTI_PIN | FRE8_EXTI_PIN;
GPIO_Init(FRE5_8_EXTI_PORT,&GPIO_InitStructure);
//配置EXTI信号源
GPIO_EXTILineConfig(Fre1_EXTI_PortSource,Fre1_EXTI_PinSource);
GPIO_EXTILineConfig(Fre2_EXTI_PortSource,Fre2_EXTI_PinSource);
GPIO_EXTILineConfig(Fre3_EXTI_PortSource,Fre3_EXTI_PinSource);
GPIO_EXTILineConfig(Fre4_EXTI_PortSource,Fre4_EXTI_PinSource);
GPIO_EXTILineConfig(Fre5_EXTI_PortSource,Fre5_EXTI_PinSource);
GPIO_EXTILineConfig(Fre6_EXTI_PortSource,Fre6_EXTI_PinSource);
GPIO_EXTILineConfig(Fre7_EXTI_PortSource,Fre7_EXTI_PinSource);
GPIO_EXTILineConfig(Fre8_EXTI_PortSource,Fre8_EXTI_PinSource);
}