以STM32F103为例,记录配置GPIO外部中断的一般方法与流程。
配置RCC时钟RCC时钟配置是STM32MCU顺利运行的必备步骤,笔者使用的参考代码如下:
void RCC_Config()
{
RCC_DeInit();
//使能HSE,并等待 HSE 稳定
RCC_HSEConfig(RCC_HSE_ON);
ErrorStatus HSEStartUpStatus;
HSEStartUpStatus = RCC_WaitForHSEStartUp();
//HSE启动成功
if (HSEStartUpStatus == SUCCESS)
{
//使能FLASH预存取缓冲区
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//SYSCLK周期与闪存访问时间的比例设置
FLASH_SetLatency(FLASH_Latency_2);
//Configures the AHB clock (HCLK): AHB clock = SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//Configures the High Speed APB clock (PCLK2): APB2 clock = HCLK
RCC_PCLK2Config(RCC_HCLK_Div1);
//Configures the High Speed APB clock (PCLK2): APB1 clock = HCLK/2
RCC_PCLK1Config(RCC_HCLK_Div2);
//Configures the PLL clock source and multiplication factor:
//HSE oscillator clock selected as PLL clock entry
//The PLL multiplication factor is 9
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//Enables the PLL.
RCC_PLLCmd(ENABLE);
//等待PLL时钟稳定
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
;
//Configures the system clock (SYSCLK): PLL selected as system clock
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//读取时钟切换状态位,确保PLLCLK被选为系统时钟
while (RCC_GetSYSCLKSource() != 0x08)
;
}
//HSE启动失败
else
{
while (1)
;
}
}
GPIO配置
以PB10, PB11, PB12, PB13作为外部中断输入口为例:
void GPIO_Config()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//选择EXTI的信号源
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource10);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource11);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource13);
}
EXTI配置
EXTI (External interrupt/event controller): 外部中断/事件控制器,管理了控制器的 20
个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿
检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为
中断或者事件,以及触发事件的属性。
void EXTI_Config()
{
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line10 | EXTI_Line11 | EXTI_Line12 | EXTI_Line13;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
NVIC配置
NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对 Cortex-M3内核里面的 NVIC进行裁剪,把不需要的部分去掉,所以说 STM32 的 NVIC 是 Cortex-M3 的 NVIC 的一个子集。
在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx,用来配置外部中断的
优先级,IPR 宽度为 8bit,原则上每个外部中断可配置的优先级为 0~255,数值越小,优先
级越高。
但是绝大多数CM3芯片都会精简设计,以致实际上支持的优先级数减少,在F103
中,只使用了高 4bit用于表达优先级的这 4bit,又被分组成抢占优先级和子优先级。
如果有多个中断同时响应,抢占优先级高的就会 抢占 抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。
void NVIC_Config()
{
NVIC_InitTypeDef NVIC_InitStructure;
//NVIC_PriorityGroup_2: 2 bits for pre-emption priority & 2 bits for subpriority
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
中断服务函数 IRQ_Handler
在启动文件 startup_stm32f10x_xd.s 中,我们已经初始化了中断向量表。实际的中断服务函数都需要重新编写,为了方便管理,可以把中断服务函数统一写在 stm32f10x_it.c 这个源文件中。关于中断服务函数的函数名必须跟启动文件里面预先设置的一样,否则系统就在中断向量表中找不到中断服务函数的入口,实现不了中断。
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line10)!=RESET)
{
DoSomething_Line10();
EXTI_ClearITPendingBit(EXTI_Line10);
}
else if(EXTI_GetITStatus(EXTI_Line11)!=RESET)
{
DoSomething_Line11();
EXTI_ClearITPendingBit(EXTI_Line11);
}
else if(EXTI_GetITStatus(EXTI_Line12)!=RESET)
{
DoSomething_Line12();
EXTI_ClearITPendingBit(EXTI_Line12);
}
else if(EXTI_GetITStatus(EXTI_Line13)!=RESET)
{
DoSomething_Line13();
EXTI_ClearITPendingBit(EXTI_Line13);
}
else if(EXTI_GetITStatus(EXTI_Line14)!=RESET)
{
DoSomething_Line14();
EXTI_ClearITPendingBit(EXTI_Line14);
}
else if(EXTI_GetITStatus(EXTI_Line15)!=RESET)
{
DoSomething_Line15();
EXTI_ClearITPendingBit(EXTI_Line15);
}
else
{
}
}
全能骑士涛锅锅
原创文章 9获赞 5访问量 403
关注
私信
展开阅读全文