STM32F103ZET6+EXTI中断处理
STM32F103ZET6+EXTI中断处理一、 中断的相关概念
计算机在执行程序过程中(这里主要指单片机执行主程序),当出现异常情况(断电等)或特殊请求(数据传输等)时,计算机暂时停现行程序的运行,转向对这些异常情况或特殊请求的处理,调用相应的中断处理程序处理该事件),处理完毕后再返回到现行程序的中断处继续执行原程序,这就是中断
能够打断当前正常执行流程的事件有两种,一种是中断,一般由外部事件触发,一种是异常,由CPU内部事件产生。中断和异常其本质都是对主程序的中断,中断其实是异常的一种形式
中断处理流程
一个完整的中断处理过程分为4个步骤:中断请求、中断响应、中断服务和中断返回
中断请求
中断请求是中断源向CPU发出的中断请求信号,此时中断控制系统的中断请求寄存器被置位,向CPU请求中断 中断响应
中断响应是指CPU的中断系统判断中断源的中断请求是否符合中断响应条件,若符合条件,则暂时中断当前程序并控制程序跳转到中断服务程序,完成相应的中断服务操作。
CPU响应中断一般需要满足以下条件
(1)中断源发出中断请求
(2)系统允许中断提出中断请求,即中断没有被屏蔽
(3)无同级或更高级的中断正在被处理
CPU根据中断类型号进行中断优先级的判断,若无更高优先级的中断请求,则保护断点和现场,根据中断类型获得中断服务程序入口地址,转入相应的中断服务程序。
保护现场主要是只保护当前程序的断点和保存当前通用寄存器、状态寄存器的内容,即将这些寄存器的内容压入堆栈。这部分底层操作已经有硬件自动实现,不需要开发人员进行处理 中断服务
为处理中断而编写的程序称为中断服务程序,中断类型不同,其中断服务也不同。中断服务程序的入口地址称为中断向量,将所有中断的中断服务程序的入口地址汇成一张表,称为中断向量表 中断返回
中断返回是指CPU退出中断服务,返回到中断请求响应前中止的位置继续执行主程序。中断服务程序的最后一条指令通常是一条中断返回指令,使其返回到原来程序的断点处,以便继续执行原来的程序。若在中断处理过程中,又产生了一个优先级更高的中断。则CPU会暂停当前的中断服务,将断点和相关的寄存器入栈后,转而去处理优先级更高的中断,在中断服务完成后,需要将中断的现场(即断点)进行恢复,将压入堆栈的寄存器内容送回到原来的寄存器中(即出栈)。这部分操作同样由硬件来实现,不需要开发人员进行处理 STM32中断优先级
STM32通过Cortex-M3内核集成的NVIC实现中断优先级管理。理论上,除3个固定的高优先级(Reset、NMI、硬件失效)不可编程外,Cortex-M3支持256级中断,其优先级都是可以设置的
NVIC中断配置的相关函数存放在标准外设库misc.c文件和misc.h文件中,共定义了5个相关函数及NVIC初始化结构体
中断分组管理函数void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)用于设置中断的优先级分组,此函数只有一个参数NVIC_PriorityGroup,从源代码中可以看到其取值共有5组,每组的抢占优先级和响应优先级所占位数均不同,且取值范围也有不同,故每组可供设置优先级的数值不一样 通过函数void NVIC_PriorityGroupConfig()设置中断分组,对于具体的中断,其抢占优先级和响应优先级设置是通过中断初始化函数void NVIC_Init(NVIC_InitTypeDef *NVIC_InitStruct)实现的,其中NVIC_InitTypeDef是结构体,参数NVIC_InitStruct是指向NVIC_InitTypeDef结构体的指针 (1)NVIC_IRQChannel:用于指定某个具体的IRQ通道,即具体是哪个中断,在标准外设库stm32f10x.h文件中包含了所有中断所对应的名称
(2)NVIC_IRQChannelPreemptionPriority:用于设置NVIC_IRQChannel的抢占优先级
(3)NVIC_IRQChannelSubPriority:用于设置NVIC_IRQChannel的响应优先级
(4)NVIC_IRQChannelCmd:用于IRQ通道使能或失能,取值为ENABLE或者DISABLE
以上通过两个函数确定了具体中断的抢占优先级和响应优先级。若系统中存在多个中断,则一般遵循以下原则判断中断优先级。
(1)高抢先优先级的中断可以打断低抢先优先级的中断服务,构成中断嵌套。
(2)中断优先级的数值越小,优先级级别越高。
(3)抢占优先级的优先级总是高于响应优先级。
(4)中断优先级判断:先判断抢占优先级的大小;若抢占优先级相同,则比较响应优先级的大小;若抢占优先级和响应优先级均相同,则根据中断向量表中的顺序来决定。
(5)Reset NMI Hard Fault的优先级为负,且不可修改,高于其他普通的中断优先级。 STM32外部中断EXTI
1、 GPIO初始化
GPIO初始化配置的相关代码
开启I/O端口的时钟和复用时钟
GPIO不仅可以作为通用的输入/输出引脚,还可以用作片上外设(如USART、ADC等)的输入/输出引脚,称为复用I/O端口,当GPIO用作复用引脚时,必须开启AFIO时钟。这里I/O端口不是作为GPIO来使用的,而是用作EXTI外部中断功能引脚,所以必须开启复用功能,通过调用RCC_APB2PeriphClockCmd()函数打开相应引脚的AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO,ENABLE);
3、 设置I/O引脚与中断线路的映射关系
当GPIO引脚作为中断功能引脚用来触发外部中断时,需将GPIO引脚与相应的中断线关联在一起,使用库函数GPIO_EXTILineConfig来实现这种映射关系。如将PE3引脚与外部中断EXTI3_IRQn关联在一起
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3); 4、 初始化EXTI,配置EXTI相关参数并使能
如选择具体的中断引脚、中断线路、触发模式等,实例代码如下:
初始化NVIC,配置NVIC参数并使能
NVIC相关的配置主要包括配置中断优先级的中断分组,确定各具体中断的抢占优先级和响应优先级的大小,选择中断通道,在stm32f10x.h文件中通过IRQn_Type中断通道结构体定义所有的中断通道,不同的引脚对应不同的终端通道,使能相应的中断
在之前的LED灯工程上,新建两个文件,一个是exti.h文件,另一个是exti.c文件
exit.h文件的代码如下:
#ifndef __EXTI_KEY_H
#define __EXTI_KEY_H
#include "stm32f10x.h"
void EXTI_init(void);
#endif
exit.c文件的代码如下:
#include "exti.h"
#include "misc.h"
void EXTI_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO,ENABLE); //开启PE3的时钟,并开启复用时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //选择要使用的I/O引脚,此处选择PE3引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置引脚输入模式为浮空输入模式
GPIO_Init(GPIOE,&GPIO_InitStructure); //调用初始化库函数初始化GPIO端口
//初始化EXTI,外部中断
EXTI_ClearITPendingBit(EXTI_Line3); //清空外部中断3中断挂起,清空中断标志
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);//将PE3用作外部中断线路
EXTI_InitStructure.EXTI_Line = EXTI_Line3; //设置外部中断线3中断
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_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择中断优先级分组2
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //外部中断3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//设置抢占优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //设置响应优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //外部中断处理函数
NVIC_Init(&NVIC_InitStructure);
}
//外部中断处理函数
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3) != RESET)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_5,(BitAction)((1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5))));//PE5的电平状态翻转
EXTI_ClearITPendingBit(EXTI_Line3); //清除中断标志位
}
}
页:
[1]
2