学习资料:《野火零死角玩转STM32——F103》
EXTI——外部中断/事件控制器。可单独配置中断或者事件,及触发事件的属性(?)。
当GPIO作为中断的输入源时(如按键按下产生中断),需要初始化GPIO,配置为输入模式。如配置GPIOC13作为输入源:
GPIO_InitTypeDef GPIO_InitStruct;
//初始化GPIO
RCC_APB2PeriphClockCmd(KEY2_INT_GPIO_CLK, ENABLE);
//KEY2_INT_GPIO_CLK为宏,即RCC_APB2Periph_GPIOC ,该库函数使能GPIOC的时钟
GPIO_InitStruct.GPIO_Pin = KEY2_INT_GPIO_PIN;
//KEY2_INT_GPIO_PIN为宏,即GPIO_Pin_13,指定GPIO指针
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//配置GPIO为浮点输入模式
GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStruct);
//输入GPIO配置
类似于GPIO的初始化,EXTI的初始化也有相应的初始化结构体 EXTI_InitTypeDef,用于设置EXTI的中断/事件线、EXTI模式、触发类型。
由于EXTI有20个中断/事件线(EXTI0~EXTI19),根据不同的输入源选择不同的EXTI事件线,如下表:
EXTI模式可选择为中断或事件,中断触发类型可配置为上升沿触发、下降沿触发、或上升沿下降沿都触发。
EXTI初始化结构体如下:
EXTI_InitTypeDef EXTI_InitStruct;
//配置中断优先级
EXTI_NVIC_Config();
//初始化EXTI
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//AFIO_EXTICRx,外部中断配置寄存器,用于选择EXTI外部中断的输入源,因此需要使能AFIO时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource13);
//选择GPIO指针作为中断/事件线
EXTI_InitStruct.EXTI_Line = EXTI_Line13;
//选择中断/事件线
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
//选择中断模式
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
//选择下降沿触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
//使能中断
EXTI_Init(&EXTI_InitStruct);
//输入配置
NVIC是嵌套向量中断控制器,控制芯片中断相关的功能,是内核中的外设。主要配置中断的中断源、抢占优先级、子优先级、使能中断请求。
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
//设置中断源频道,不同中断源的中断频道不一样,其成员配置可参考 stm32f10x.h 头文件里面的 IRQn_Type 结构体定义
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //优先级分组
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //主优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //子优先级
/*根据下表格设按需要设置优先级
--------------------------------------------------------------------------
| 优先级分组 | 主优先级 | 子优先级 | 描述 |
--------------------------------------------------------------------------
| NVIC_PriorityGroup_0 | 0 | 0-15 | 主-0bit,子-4bit |
| NVIC_PriorityGroup_1 | 0-1 | 0-7 | 主-1bit,子-3bit |
| NVIC_PriorityGroup_2 | 0-3 | 0-3 | 主-2bit,子-2bit |
| NVIC_PriorityGroup_3 | 0-7 | 0-1 | 主-3bit,子-1bit |
| NVIC_PriorityGroup_4 | 0-15 | 0 | 主-4bit,子-0bit |
--------------------------------------------------------------------------*/
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
//使能中断请求
NVIC_Init(&NVIC_InitStruct);
//输入配置
在启动文件 startup_stm32f10x_hd.s 中初始化了中断向量表。中断服务函数统一写在stm32f10x——it.c库文件中,函数名称根据中断向量表选择。
在stm32f10x_it.c文件最下方编写中断服务函数,如使用EXTI13作为中断/事件线:
void EXTI15_10_IRQHandler(void)/*EXTI15_10_IRQHandler是根据启动文件中的向量表进行选择的,
选择不对尽管编译无错误,但中断无效*/
{
/*确保是否产生了 EXTI Line 中断,该库函数用于获取EXTI的中断标志位状态,如果EXTI线有中断,返回SET(1),否则返回RESET(0)
实际上该库函数是读取EXTI_PR寄存器来判断EXTI线的状态*/
if (EXTI_GetITStatus(EXTI_Line13) != RESET)
{
//中断后关闭所有LED灯
LED_ALL(OFF);
//清除中断标志位
EXTI_ClearITPendingBit(EXTI_Line13);
}
}
在编程时,第1-3点在自定义的c文件中编写,并在其头文件中声明;第4点在stm32f10x_it.c文件中编写;主函数中包含所需要的头文件,并调用。
main.c
#include "stm32f10x.h"
#include "bsp_led.h" //led的控制头文件
#include "bsp_key.h" //key的控制头文件
#include "bsp_exti.h"
int main(void)
{
LED_GPIO_Config();
KEY1_GPIO_Config();
EXTI_KEY2_Config();
LED_ALL(OFF);
here:
while(1)
{
if (KEY1_SCAN(KEY1_GPIO_PORT , KEY1_GPIO_PIN) == KEY_ON)
{
LED_ALL(OFF);
LED_R(ON);
while(1)
{
if (KEY1_SCAN(KEY1_GPIO_PORT , KEY1_GPIO_PIN) == KEY_ON)
{
LED_ALL(OFF);
LED_G(ON);
while(1)
{
if (KEY1_SCAN(KEY1_GPIO_PORT , KEY1_GPIO_PIN) == KEY_ON)
{
LED_ALL(OFF);
LED_B(ON);
goto here;
}
}
}
}
}
}
}//main
bsp_exti.c
#include "bsp_exti.h"
static void EXTI_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
//设置中断源频道,不同中断源的中断频道不一样,其成员配置可参考 stm32f10x.h 头文件里面的 IRQn_Type 结构体定义
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //优先级分组
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //主优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //子优先级
/*根据下表格设按需要设置优先级
--------------------------------------------------------------------------
| 优先级分组 | 主优先级 | 子优先级 | 描述 |
--------------------------------------------------------------------------
| NVIC_PriorityGroup_0 | 0 | 0-15 | 主-0bit,子-4bit |
| NVIC_PriorityGroup_1 | 0-1 | 0-7 | 主-1bit,子-3bit |
| NVIC_PriorityGroup_2 | 0-3 | 0-3 | 主-2bit,子-2bit |
| NVIC_PriorityGroup_3 | 0-7 | 0-1 | 主-3bit,子-1bit |
| NVIC_PriorityGroup_4 | 0-15 | 0 | 主-4bit,子-0bit |
--------------------------------------------------------------------------*/
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
//使能中断请求
NVIC_Init(&NVIC_InitStruct);
//输入配置
}
void EXTI_KEY2_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
//配置中断优先级
EXTI_NVIC_Config();
//初始化GPIO
RCC_APB2PeriphClockCmd(KEY2_INT_GPIO_CLK, ENABLE); //APB2外设时钟使能库函数,打开GPIOA时钟使能
GPIO_InitStruct.GPIO_Pin = KEY2_INT_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStruct); //调用库函数初始化GPIOC,&表示取结构体的地址
//初始化EXTI
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource13);
EXTI_InitStruct.EXTI_Line = EXTI_Line13;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
}
bsp_exti.h
#ifndef __BSP_EXTI_H
#define __BSP_EXTI_H
#include "stm32f10x.h"
#define KEY2_INT_GPIO_PORT GPIOC
#define KEY2_INT_GPIO_CLK RCC_APB2Periph_GPIOC
#define KEY2_INT_GPIO_PIN GPIO_Pin_13
void EXTI_KEY2_Config(void);
#endif /*__BSP_EXTI_H*/