中断详解
目录
一. NVIC要点分析
1. 为什么需要中断
- 程序中有很多不确定何时会发生的事情需要处理, 假如没有中断cpu就需要一直去等待, 这样会极大的消耗Cup的资源. 如图举例中断的优点以及应用场景

2. NVIC分组和响应优先级
- 由于中断的优点, 在STM32中预留了256个中断事件位, 不过在F103中只使用了70个. 其中10个是系统内部异常, 剩余60个是外部中断.这么多中断假如同时发送CUP该如何处理, 这时就引进了NVIC的概念, 用于控制所用中断是否响应以及响应优先级.
- 优先级分组将响应优先级分为抢占优先级和响应优先级, F103只使用了高4位用于优先级分组. 根据排列组合, 二者可以列出五种组合方式. 0000, 0001, 0011, 0111, 1111.
- 抢占优先级顾名思义拥有CPU抢夺权, 当CUP在执行A(抢占优先级2)中断事件时, B(抢占优先级1)中断来临CPU会优先执行B中断. 而响应优先级没有抢夺CPU的权利, 只有等待被优先选择的权利. 假如A, B的抢占优先级都为1, A的响应优先级为2, B为1. 当AB中断同时来临时会优先处理B. 但是如果A已经在执行, B不能将其打断. 如果AB抢占和响应优先级都一样, 当AB中断同时来临将比较二者的自然优先级, 参见中断向量表的先后顺序.

3. NVIC结构体分析
- 参考手册对NVIC描述很少, 有关寄存器详细需要参考M3权威指南. 对于NVIC我们只需要 设置分组, 配置好结构体并将其初始化即可.
*值得注意的是: 对于分组的设置整个程序只需要设置一次即可. 因此可以将这条函数放在main中.
/*
typedef struct {
uint8_t NVIC_IRQChannel; // 中断源
uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级
uint8_t NVIC_IRQChannelSubPriority; // 子优先级
FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能
} NVIC_InitTypeDef;
*/
//初始化示例
NVIC_InitTypeDef NVIC_InitStructures;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //最好放在main中配置.
NVIC_InitStructures.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructures.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructures.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructures.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructures);
二. 外部中断/事件控制器
1. EXTI简介以及功能框图
- EXTI可以由软件触发(设置触发条件), 或者由外部触发(外部设备为引脚提供信号). 每个EXTI支持20个中断/事件请求(每次只支持一个中断/事件). 分别为(EXTI0-EXTI19)

- 无论是由软件触发还是硬件触发, 经过或门后会使得请求挂起寄存器置1. 此时中断屏蔽寄存器和事件屏蔽寄存器控制着, 是否给到响应给NVIC或者发生脉冲.

2. EXTI结构体详解
- EXTI结构体主要是配置图中关键位. 通道选择, 上升/下降沿触发, 中断/事件模式选着, 使能. 值得注意的是这里用到的是GPIO的复用功能, 需要使能AFIO.
/*
typedef struct {
uint32_t EXTI_Line; // 中断/事件线
EXTIMode_TypeDef EXTI_Mode; // EXTI模式
EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
FunctionalState EXTI_LineCmd; // EXTI使能
} EXTI_InitTypeDef;
*/
void Key_EXIT_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructures;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //!!!注意这里不是使能EXTI, EXTI只是一个功能不算外设
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
EXTI_InitStructures.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructures.EXTI_Line = EXTI_Line0;
EXTI_InitStructures.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructures.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructures);
}
三. 外部中断控制实验
1. 按键控制外部中断
- 这个实验通过按键产生外部中断信号来控制灯的亮灭
- 值得注意的两个点是: 由于EXTI需要用到GPIO所以需要先使能并初始化GPIO.(使用任何外设都要先使能时钟再初始化) 中断服务函数尽量写在stm32f10x_it.c中.
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_exit.h"
static void Key_NVIC_Config(void);
void Key_EXIT_Config(void);
int main()
{
Led_GPIO_Config();
LED_OFF;
Key_EXIT_Config();
while(1){}
}
static void Key_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructures;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructures.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructures.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructures.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructures.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructures);
}
void Key_EXIT_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructures;
EXTI_InitTypeDef EXTI_InitStructures;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
Key_NVIC_Config();
GPIO_InitStructures.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructures.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructures);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
EXTI_InitStructures.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructures.EXTI_Line = EXTI_Line0;
EXTI_InitStructures.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructures.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructures);
}
//为了统一管理, 中断服务函数一般写在stmf10x_it.c中
void EXTI0_IRQHandler (void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
LED_TOGGLE;
EXTI_ClearITPendingBit(EXTI_Line0);
}
}


浙公网安备 33010602011771号