STM32F103(四)——中断系统与外部中断实例

中断系统与外部中断实例

  • 一. 中断系统
    • 1.1 抢占优先级和响应优先级的意义和区别
    • 1.2 中断管理方法
    • 1.3 中断优先级分组函数
    • 1.4 设置每个中断的抢占,响应优先级(相关寄存器)
    • 1.5 设置每个中断的抢占,响应优先级(具体的中断初始化函数)
    • 1.6 总结(中断优先级的设置步骤)
  • 二. 外部中断实例
    • 2.1 外部中断概述
    • 2.2 **外部中断配置的步骤**

参考资料:
《开发指南》P120,STM32 NVIC中断优先级管理
《参考手册》P130,中断和事件
《开发指南》P189,外部中断实验

一. 中断系统

STM32F103上有16个内核中断和60可外部中断,具有16级可编程的中断优先级(中断优先级由“抢占优先级”和“响应优先级”来控制)

1.1 抢占优先级和响应优先级的意义和区别

STM32F103的每一个中断都会被设置一个抢占优先级和一个响应优先级。

  1. 高优先级的抢占优先级可以打断正在进行的低抢占优先级中断
    例如:设A的抢占优先级是0,B的抢占优先级是1(数字越小,抢占优先级越高)。此时如果B正在执行中断内容,某时刻A突然发生中断,那么系统会先暂停B的中断内容,从而先执行A的中断内容,A的中断内容执行完后,再回到B的中断中。

  2. 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
    例如:设A,B的抢占优先级都是0,A的响应优先级为0,B的响应优先级为1。那么如果此时A,B中断同时发生,那么系统会先进入响应优先级高的中断,也就是说会先进入A的中断,后进入B的中断。

  3. 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级d的中断。
    例如:A,B的抢占优先级一样,而A的响应优先级是0,B的响应优先级是1。当B正在执行中断的时候,某时刻A的中断发生,此时系统会继续执行B的中断,不会进入A的中断。

  4. 如果两个中断的抢占优先级和响应优先级都一样,则看哪个中断先发生就先执行。

1.2 中断管理方法

首先,对STM32F103中断分成0~4组。同时对每个中断设置一个抢占优先级和一个响应优先级。
STM32F103(四)——中断系统与外部中断实例_第1张图片
如图:
分为0组时,没有抢占优先级,有4级的响应优先级
分为1组时,有1级的抢占优先级,有3级的响应优先级
分为2组时,有2级的抢占优先级,有2级的响应优先级
分为3组时,有3级的抢占优先级,有1级的响应优先级
分为4组是,有4级的抢占优先级,有0级的响应优先级

◉举例:设置中断优先级组为2(意味着有2级的抢占优先级,有2级的响应优先级);设置中断3的抢占优先级为2,响应优先级为1;设置中断6的抢占优先级为3,响应优先级为0;设置中断7的抢占优先级为2,响应优先级为0
此时这3个中断的优先级顺序为:中断7>中断3>中断6

1.3 中断优先级分组函数

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
     
  /* Check the parameters */
  assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
  
  /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
  SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}

函数参数是"分为几组"
参数的有效输入为:
NVIC_PriorityGroup_0 分为0组; NVIC_PriorityGroup_1分为1组;
NVIC_PriorityGroup_1分为2组; NVIC_PriorityGroup_3分为3组; NVIC_PriorityGroup_1分为4组

1.4 设置每个中断的抢占,响应优先级(相关寄存器)

STM32通过一系列的寄存器来配置每一个中断的抢占优先级和响应优先级,相关寄存器如下:STM32F103(四)——中断系统与外部中断实例_第2张图片

这些寄存器的作用如下:

  1. IP【240】寄存器
    全称:Interrupt Priority Registers
    作用:控制中断优先级

有240个8位寄存器,每个中断使用一个寄存器来确定优先级,STM32F103使用到IP【0】~IP【59】。

每个IP寄存器的高4位用来设置抢占和响应优先级,低4位没有用到 。

  1. ISER【8】寄存器
    作用:用来使能中断

32位寄存器,每个位控制一个中断的使能。STM32F103有60个屏蔽中断,所以只使用了其中的ISER【0】和ISER【1】

ISER【0】的位0~位31分别对应中断0-31,ISER【1】的位0-27 对应中断32-59。

  1. ICER【8】寄存器
    作用:用来失能中断

32位寄存器,每个位控制一个中断的失能。STM32F103有60个屏蔽中断,所以只使用了其中的ICER【0】和ICER【1】

ICER【0】的位0~位31分别对应中断0-31,ICER【1】的位0-27 对应中断32-59。

  1. ISPR【8】寄存器
    作用:用来挂起中断

  2. ICPR【8】寄存器
    作用: 用来解挂中断

  3. IABR【8】寄存器
    作用:通过它可以知道当前正在执行的中断是哪一个,如果对应位为1,说明该中断正在执行

1.5 设置每个中断的抢占,响应优先级(具体的中断初始化函数)

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

参数为一个结构体,该结构体的定义如下:
STM32F103(四)——中断系统与外部中断实例_第3张图片
其中的设置响应优先级和设置抢占优先级就是IP【240】寄存器的作用;其中的使能/失能就是ISER【8】和ICER【8】的作用

在使用时应该先new一个这样的结构体,具体如下:
STM32F103(四)——中断系统与外部中断实例_第4张图片

1.6 总结(中断优先级的设置步骤)

中断优先级的设置步骤:

  1. 设置优先级分组
  2. 针对每一个中断,设置对应的抢占优先级和响应优先级
  3. 如需挂起/解挂,查看中断当前的激活状态,可分别调用相应的函数

二. 外部中断实例

2.1 外部中断概述

  1. STM32F103每一个IO口都可以作为外部中断输入

  2. 中断控制器支持19个外部中断/事件请求
    线0~15:IO口的输入中断
    线16:连接到PVD输出
    线17:连接到RTC闹钟事件
    线18:连接到USB唤醒事件

  3. STM32F103有112个IO口,但只有16条中断线,它们之间的对应关系如下:STM32F103(四)——中断系统与外部中断实例_第5张图片
    如图,GPIOx.0映射到EXTI0;GPIOx.1映射到EXTI1…GPIOx.15映射到EXTI15

  4. 中断线只有16个,每一条中断线在同一时间只能被一个IO口所映射。也就是说GPIOx.0中同时只能存在一个IO是输入中断。

  5. 对于每一个中断线,都可以 设置相应的触发方式(上升沿触发,下降沿触发,边沿触发)以及使能

  6. 关于中断服务函数
    有16个中断线,但只有7个中断向量,也就是说只有7个中断服务函数

2.2 外部中断配置的步骤

以按键的外部中断为例.

  1. 使能IO口并将IO口配置为输入模式

跟“按键初始化函数类似”

	GPIO_InitTypeDef GPIO_InitStructure;
	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能GPIOA和GPIOE的时钟

	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4|GPIO_Pin_3;//KEY0-KEY1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置为上拉输入
 	GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE3,4
	//初始化 按键 WK_UP	  
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置为下拉输入  
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA0
  1. 开启相应IO口的复用时钟

使用到的库函数为void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

该实例中两个参数应为:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  1. 设置IO口与中断线的映射关系

使用到的库函数为void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
第一个参数是“哪一个端口”(例如GPIOE);第二个参数是端口号(例如GPIOE4)

该实例中两个参数为:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);在GPIO.c文件中

这样配置完成后,GPIOE4就已经映射到中断线4上了!!!!!!

  1. 初始化中断线,设置触发条件等
    使用到的库函数为void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); 在exti.c文件中

实例中:

EXTI_InitTypeDef EXIT_InitStrue;
	
EXIT_InitStrue.EXTI_Line=EXTI_Line4; 初始化的中断线
EXIT_InitStrue.EXTI_LineCmd=ENABLE;  ENABLE or DISABLE
EXIT_InitStrue.EXTI_Mode=EXTI_Mode_Interrupt;  中断触发或者事件触发,该模式是中断触发
EXIT_InitStrue.EXTI_Trigger=EXTI_Trigger_Falling;  触发中断的模式,该中断是下降沿触发
EXTI_Init(&EXIT_InitStrue);

这一步完成了中断线4的初始化!!!!!!

  1. 配置中断优先级分组,并且配置抢占优先级和响应优先级

中断优先级分组:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 设置中断分组22位抢占,2位响应; 在misc.c文件中

中断线4抢占,响应优先级配置:

NVIC_InitTypeDef NVIC_InitStrue;

NVIC_InitStrue.NVIC_IRQChannel=EXTI4_IRQn; 选择中断线4
NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;  使能
NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=2;  抢占优先级
NVIC_InitStrue.NVIC_IRQChannelSubPriority=2;   响应优先级
NVIC_Init(&NVIC_InitStrue);
  1. 编写中断服务函数

中断函数格式如下:
在这里插入图片描述
该实例中是中断线4,故:

void EXTI4_IRQHandler(void)   在startup_stm32f10x.hd.s文件中
{
     
}	
  1. 清除中断标志位

调用函数:void EXTI_ClearITPendingBit(uint32_t EXTI_Line); 在exti.h文件中
在实例中:

void EXTI4_IRQHandler(void)
{
     
	delay_ms(10);
	if(KEY0==0){
     
		LED0=!LED0;
		LED1=!LED1;
	}
	EXTI_ClearITPendingBit(EXTI_Line4);  清除中断线4标志位
}	

至此,以按键KEY_0为外部中断的相关配置就此完成。

你可能感兴趣的:(stm32,单片机)