STM32微控制器器 | 复习五 | EXTI原理及应用

2021年6月23日 10点热度 0条评论 来源: 阿牛哥dd

一、中断源和中断通道

  1. 中断以及中断源:CPU执行程序时,由于发生了某种随机的事件(外部或内部),引起CPU暂时中断正在运行的程序,转去执行一段特殊的服务程序(中断服务子程序或中断处理程序),以处理该事件,该事件处理完后又返回被中断的程序继续执行,这一过程称为中断。可以引起中断的事件称为中断源。

  2. 中断通道:处理中断的信号通路,每个中断通道对应唯一的中断向量唯一的中断服务程序,但该中断可具有多个可以引起中断的中断源,这些中断源都能通过对应的中断通道向内核申请中断。

  3. STM32的外部中断/事件控制器(EXTI)对应19个中断通道,其中16个中断通道EXT0~EXT15对应GPIOx_Pin0-GPIOx_Pin15,另外3个是EXTI16连接PVD输出、EXTI17连接到RTC闹钟事件和EXTI18连接到USB唤醒事件。每个中断通道的输入线可以独立地配置输入类型和对应的触发事件。每个输入线都可以独立地被屏蔽。

二、NVIC、NVIC特点和NVIC设置

  1. NVIC:嵌套向量中断控制器,属于内核外设,管理着包括内核和片上所有外设的中断相关的功能。

  2. NVIC特点:
    △ 外部中断数量可配置为从 1 到 240 个
    △ 用来表示优先权等级的位数可配置为从 3 到 8
    △ 支持电平触发和脉冲触发中断
    △ 中断优先级可动态重置
    △ 支持优先权分组
    △ 支持尾链技术
    △ 进入和退出中断无需指令

  3. NVIC设置:
    (1)根据需要对中断优先级进行分组,确定抢占优先级和响应优先级的个数。
    (2)选择中断通道,不同的引脚对应不同的中断通道,在stm32f10x.h中定义了中断通道结构体IRQn_Type,包含了所有型号芯片的所有中断通道。
    (3)根据系统要求设置中断优先级,包括抢占优先级和响应优先级。
    (4)使能相应的中断,完成NVIC配置。

三、中断优先级

STM32(Cortex-M3)中有两个优先级的概念:抢占式优先级副优先级,每个中断源都需要被指定这两种优先级。

  1. 抢占式优先级:高占先式优先级的中断事件会打断当前的主程序/中断程序运行—抢断式优先响应,俗称中断嵌套

  2. 副优先级:在占先式优先级相同的情况下,高副优先级的中断优先被响应;在占先式优先级相同的情况下,如果有低副优先级中断正在执行,高副优先级的中断要等待已被响应的低副优先级中断执行结束后才能得到响应—非抢断式响应(不能嵌套)

  3. 判断中断是否会被响应的依据:首先是占先式优先级,其次是副优先级;占先式优先级决定是否会有中断嵌套;

  4. 优先级冲突的处理:具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断的嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。当相同占先优先级相同副优先级的中断同时申请服务,STM32首先响应中断通道所对应的中断向量地址低的那个中断。

  5. stm32中对中断优先级的定义:STM32中指定中断优先级的寄存器位有4位,这4个寄存器位的分组方式如下:
    第0组:所有4位用于指定副优先级;
    第1组:最高1位用于指定抢占式优先级,最低3位用于指定副优先级;
    第2组:最高2位用于指定抢占式优先级,最低2位用于指定副优先级;
    第3组:最高3位用于指定抢占式优先级,最低1位用于指定副优先级;
    第4组:所有4位用于指定抢占式优先级;

四、EXIT初始化

EXTI程序设计一般步骤:
1、配置GPIO端口工作方式
2、配置GPIO端口与EXTI映射关系
3、配置EXTI触发条件
4、配置相应的NVIC(中断控制器)
5、编写中断服务程序。

任务:按下PC1、PA8、PC4、PC2所接按键,触发中断,中断服务程序中相应PA0至PA3所接发光二极管状态改变。

void GPIO_Configuration(void)
{
		//将PC1、PA8、PC4、PC2设置成输入模式
		GPIO_InitTypeDef GPIO_InitStructure;
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTC时钟
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2 |GPIO_Pin_4;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    //设置成上拉输入
		GPIO_Init(GPIOC, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
		
		GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void EXTIX_Init(void)
{
 		EXTI_InitTypeDef EXTI_InitStructure;

  		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟

		//设置当前系统中使用哪个引脚作为触发外部中断的引脚
		GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource1); //Selects PC.01 as EXTI Line 1 
		GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2); //Selects PC.02 as EXTI Line 2 
		GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource4); //Selects PC.04 as EXTI Line 4
		GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource8); //Selects PA.08 as EXTI Line 8

		//设置外部中断结构体成员
		EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
		EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
		EXTI_InitStructure.EXTI_Line = EXTI_Line1 | EXTI_Line2 | EXTI_Line4| EXTI_Line8;
		EXTI_InitStructure.EXTI_LineCmd = ENABLE;
		EXTI_Init(&EXTI_InitStructure);
}

void NVIC_Init(void)
{
		NVIC_InitTypeDef NVIC_InitStructure;
		//配置NVIC
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);						//设置组别
		NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQChannel; 				//设置中断通道
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;			//设置抢占优先级
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 					//设置响应优先级
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;						//通道使能
		NVIC_Init(&NVIC_InitStructure);										//调用函数进行配置

		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	
		NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel; 
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);

		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	
		NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel; 
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);

		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	
		NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; 
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);
}

void EXTI1_IRQHandler(void) //通道1中断服务函数
{
   if ( EXTI_GetITStatus(EXTI_Line1) != RESET )//判断是否有键按下 
   {
		...
	}	
	EXTI_ClearITPendingBit(EXTI_Line1);//清中断
}

void EXTI2_IRQHandler(void)
{
   if ( EXTI_GetITStatus(EXTI_Line2) != RESET )//判断是否有键按下 
   {
		...
	}	
	EXTI_ClearITPendingBit(EXTI_Line2);//清中断
}

void EXTI4_IRQHandler(void)
{
   if ( EXTI_GetITStatus(EXTI_Line4) != RESET )//判断是否有键按下 
   {
		...
	}	
	EXTI_ClearITPendingBit(EXTI_Line4);//清中断
}

void EXTI9_5_IRQHandler(void)
{
   if ( EXTI_GetITStatus(EXTI_Line8) != RESET ) 
   {
		...
	}	
	EXTI_ClearITPendingBit(EXTI_Line8);//清中断
}


    原文作者:阿牛哥dd
    原文地址: https://blog.csdn.net/m0_46607832/article/details/118162923
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。