文章目录
EXTI_InitTypeDef的简单说明
结构体成员用于设置外设工作参数,并由外设初始化配置函数,比如 EXTI_Init()调用,这些设定参数将会设置外设相应的寄存器,达到配置外设工作环境的目的。初始化结构体和初始化库函数配合使用是标准库精髓所在,理解了初始化结构体每个成员意义基本上就可以对该外设运用自如了。初始化结构体定义在 stm32f4xx_exti.h 文件中,初始化库函数定义在 stm32f4xx_exti.c 文件中
EXTI_InitTypeDef的代码
typedef struct{
uint32_t EXTI_Line; //中断/事件线
EXTIMode_TypeDef EXTI_Mode; //EXTI 模式 可选 EXIT_Mode_Iterrupt
EXTITrigger_TypeDef EXIT_Trigger; //触发类型
FuntionalState EXIT_LineCmd; //EXTI 使能
} EXTI_InitTypeDef;
··············································································
对初始化结构体的介绍
1、EXTI_Line:可选EXTI0至EXTI19
2、EXTI_Mode:可选为产生中断EXIT_Mode_Iterrupt,或者产生事件EXTI_Mode_Event。
3、EXIT_Trigger:EXTI边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)。
下降沿触发(EXIT_Trigger_Falling)。或者上升沿,
和下降沿都触发EXIT_Trriger_Raising_Falling
4、EXTI_LineCmd:控制是否使能EXTI线,可选使能EXTI线使能(ENABLE),禁用(DISABLE)
NVIC_InitTypeDef结构体说明
typedef struct
{
uint8_t NVIC_IRQChannel; // 中断源
uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级
uint8_t NVIC_IRQChannelSubPriority; // 子优先级
FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能
} NVIC_InitTypeDe
1)NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即
使写错了程序也不会报错,只会导致不响应中断。具体的成员配置可参考 stm32f10x.h 头文件里面的 IRQn_Type 结构体定义,这个结构体包含了所有的中断源。
2)NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来
确定,具体参考表格 优先级分组真值表 。
3)NVIC_IRQChannelSubPriority:子优先级,具体的值要根据优先级分组来确定,具
体参考表格 优先级分组真值表 。
4)NVIC_IRQChannelCmd:中断使能(ENABLE)或者失能(DISABLE)。操作的
是 NVIC_ISER 和 NVIC_ICER 这两个寄存器。
真值表
编写中断服务函数
在启动文件 startup_stm32f10x_hd.s 中我们预先为每个中断都写了一个中断服务函数,
只是这些中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要我们重新编写,为了方便管理我们把中断服务函数统一写在 stm32f10x_it.c 这个库文件中。关于中断服务函数的函数名必须跟启动文件里面预先设置的一样,如果写错,系统就在中断向量表中找不到中断服务函数的入口,直接跳转到启动文件里面预先写好的空函数,并且在里面无限循环,实现不了中断。
外部中断示例代码
硬件基础
软件设计要点
*1 初始化用来产生中断的GPIO
*2 初始化EXTI
*3 配置NVIC
*4 编写中断服务函数
bsp_exti.h 头文件
#ifndef __BSP_EXIT_H
#define __BSP_EXIT_H
//引脚的定义
#define KEY1_INT_GPIO_PORT GPIOA
#define KEY1_INT_GPIO_CLK (RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE GPIO_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE GPIO_PinSource0
#define KEY1_INT_EXTI_LINE EXTI_Line0
#define KEY1_INT_EXTI_IRQ EXTI0_IRQn
#define KEY1_IRQHandler EXTI0_IRQHandler
#define KEY1_INT_GPIO_PORT GPIOC
#define KEY1_INT_GPIO_CLK (RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN GPIO_Pin_13
#define KEY1_INT_EXTI_PORTSOURCE GPIO_PortSourceGPIOC
#define KEY1_INT_EXTI_PINSOURCE GPIO_PinSource13
#define KEY1_INT_EXTI_LINE EXTI_Line13
#define KEY1_INT_EXTI_IRQ EXTI15_10_IRQn
/*
上面的宏定义中,我们除了开 GPIO 的端口时钟外,我们还打开了 AFIO 的时钟,
这 是 因 为 等 下 配 置 EXTI 信号源的时候需要用到 AFIO 的外部中断控制寄存器
AFIO_EXTICRx,具体见《STM32F10X-中文参考手册》8.4 章节 AFIO 寄存器描述。
*/
#endif
bsp_exti.c中断函数
#include"stm32f10x.h"
#include"bsp_exit.h"
//NVIC配置函数
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/*配置NVIC为优先级组1*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/*配置中断源:按键1*/
NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXIT_IRQ;
/*配置抢占优先级1*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/*配置子优先级1*/
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/*使能中断通道*/
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*配置中断源:按键2,其他使用上面相关配置*/
NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXIT_IRQ;
NVIC_Init(&NVIC_InitStructure);
}
//EXTI中断配置
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXIT_InitTypeDef EXTI_InitStructure;
/*配置NVIC 中断 */
NVIC_Configuration();
/*-----------KEY1配置-------*/
/*选择按键用到的GPIO*/
GPIO_InitStructure.GPIO_Pin = KEY1_INI_GPIO_PIN;
/* 配置为浮空输入 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_INT_GPIO_PORT,&GPIO_InitStructure);
/*选择EXIT的信号源*/
GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE,KEY1_INI_EXTI_PINSOURCE);
EXIT_InitStructure.EXIT_Line = KEY1_INT_EXTI_LINE;
/*EXTI 为中断模式*/
EXTI_InitStructure.EXIT_Mode = EXTI_Mode_Iterrupt;
/*上升沿中断*/
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
/*使能中断*/
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXIT_Init(&EXIT_InitStructure);
/*------------------KEY2配置----------*/
/*选择按键用到的GPIO*/
GPIO_InitStructure.GPIO_Pin = KEY2_INI_GPIO_PIN;
/* 配置为浮空输入 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_INT_GPIO_PORT,&GPIO_InitStructure);
/*选择EXIT的信号源*/
GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE,KEY2_INI_EXTI_PINSOURCE);
EXIT_InitStructure.EXIT_Line = KEY2_INT_EXTI_LINE;
/*EXTI 为中断模式*/
EXTI_InitStructure.EXIT_Mode = EXTI_Mode_Iterrupt;
/*上升沿中断*/
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
/*使能中断*/
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXIT_Init(&EXIT_InitStructure);
}
// EXTI中断服务函数按键1
void KEY1_IRQHandler(void)
{
//确保是否产生了EXTI_Line中断
if(EXTI_GetITStstus(KEY1_INT_EXTI_LINE) != RESET)
{
//LED1 取反
LED1_TOGGLE;
//清除中断标志位
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
}
}
// EXTI中断服务函数按键2
void KEY2_IRQHandler(void)
{
//确保是否产生了EXTI_Line中断
if(EXTI_GetITStstus(KEY2_INT_EXTI_LINE) != RESET)
{
//LED1 取反
LED1_TOGGLE;
//清除中断标志位
EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
}
}
/*
EXTI_GetITStatus 函数用来获取 EXTI 的中断标志位状态,如果 EXTI 线有中断发生函
数返回“SET”否则返回“RESET”。实际上,EXTI_GetITStatus 函数是通过读取
EXTI_PR 寄存器值来判断 EXTI 线状态的。
按键 1 的中断服务函数我们让 LED1 翻转其状态,按键 2 的中断服务函数我们让 LED2
翻转其状态。执行任务后需要调用 EXTI_ClearITPendingBit 函数清除 EXTI 线的中断标志
位。
*/
主函数main()
//主函数
int main(void)
{
/*LED端口初始化*/
LED_GPIO_Config();
/*
*初始化EXIT中断,按下按键就会触发中断
*触发中断就会进入stm32f1xx_it.c文件中的函数
*KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯。
*/
EXIT_Key_Config();
/*等待中断,由于使用中断方式,CPU不用轮询按键*/
while(1)
;
}
主函数中的LED_GPIO_Config()是在其他函数里面写好的。
要点记录
当出现异常或者中断被触发的时候,程序计数器指针PC将跳转到异常或中断地址处执行,该地址处存放一条跳转指令,跳转到异常或中断的服务函数处执行相应的功能。异常与中断向量表只能是汇编指令编写的,在启动文件startup_stm32f10x_hd.s
中可以找到。