3.外部中断下的按键检测--EXTI

目录

库函数的使用

中断

中断的概念

中断的执行过程

中断的部分专业术语

STM32中的中断分类

STM32中的中断优先级和优先级分组

中断的使能和失能

中断使用的过程和相关函数接口

外部中断--EXTI

外部中断内部框图以及外部中断线路映像

外部中断线路映像

EXTI硬件中断选择过程

外部中断(EXTI)的配置过程

总结

代码


库函数的使用

1. 库函数是分为多个文件的,每个文件都有独立的功能

        Stm32f10x_rcc.c 就是和时钟相关的文件 

        Stm32f10x_gpio.c 就是和 GPIO 相关的文件 

        .c 文件存放函数的原型 

        .h 文件存放函数的声明或者宏定义等 

2. 函数的名字是什么意思?功能是什么?

        方法一:查看固件库中文翻译手册

        方法二:在工程中,查看函数的英文注释

3. 函数命名是有规律的

        中文固件库翻译手册,1.2 查看规则 

        RCC_APB2PeriphClockCmd 

        通过定义结构体,给结构体赋值,确定要设置的工作模式 

        GPIO_Init 将上面的结构体根据结构体内容,写入到寄存器中 

        GPIO_ResetBits 对应引脚输出低电平 

        GPIO_SetBits 对应引脚输出高电平 

        GPIO_ReadInputDataBit 读取对应引脚的电平

4. 结构体参数,填哪些值

        方法一:翻看中文固件库翻译手册 

        方法二:查看英文注释,一般都在对应的 stm32f10x_PPP.h 文件中。找到结构体原型,看后面的@ref,能跳转就跳转,不能跳转就搜索

中断

中断的概念

        中断:打断原有的执行过程,去执行临时的任务,执行完临时任务之后,再返回到原有的位置继续执行。

中断的执行过程

1、外设发出中断请求

2、处理器暂停当前执行的主程序,保护现场,将当前位置的 PC 地址压栈;

3、程序跳转到中断服务程序,执行中断服务程序;

4、恢复现场,将栈顶的值回送给 PC;

5、跳转到被中断的位置开始执行下一个指令

中断的部分专业术语

中断源:引起中断的原因,或者能够发出中断请求信号的来源统称为中断源

中断优先级:谁比较重要。Stm32 中数字越小,优先级越高。

中断响应:中断事件发生,Cortex-M3 内核准备执行该事件,即为中断响应。

中断嵌套:可嵌套的内核 -- 中断可以被其他中断打断。(Cortex-M3)不可嵌套的内核 -- 不可以打断。

中断挂起:中断事件发生了,但是 Cortex-M 内核还没准备去执行或者中断正在执行,有更高优先级的中断到来,就把原来的中断挂起。可嵌套内核中,高和低两个优先级的中断,低优先级正在执行中断服务程序,此时高优先级的中断也触发了,把低优先级的中断先挂起,等高优先级的执行完,再继续执行低优先级的。不可嵌套内核中,正在响应某个中断,有其他高优先级的中断到来,因为中断不能嵌套,所以新到来的中断,就要暂时被挂起,等原有中断执行完之后,再执行新到来的中断。

中断服务函数 中断发生后,要执行的程序。

中断通道:可以哪些响应的中断和该中断之间就有固定的中断通道

STM32中的中断分类

嵌套向量中断控制器(NVIC):作用是管理所有中断。

异常:内核内部的中断称为中断。

中断和异常向量表主要分为两部分:

        底色比较灰的部分:内核内部的中断,也称为异常 

        浅色部分:内核外部的中断。 

下面还有很多,内核外部的中断

总结:STM32 的中断分为内核的异常和内核外部的外设中断

STM32中的中断优先级和优先级分组

中断优先级寄存器如下图

内核提供 8 位用来标记各个通道的优先级(0-255)

STM32 在对内核封装之后,STM32 只用了 4 位 (0--15 -- 高四位

(1)NVIC_IPR[X]表示有好几个这样的寄存器,每 8 位管理 1 个通道的优先级

(2)ST 公司只有了 8 位中的高 4 位,低 4 位没有意义。

 优先级分组寄存器如下图

        利用系统控制块(SCB)中一个名为优先级分组的配置寄存器(属于 SCB 中的应用中断和复位控制寄存器)将每个具有可编程优先级的优先级配置寄存器可被分为两部分。上半部分(左边的位)为分组(抢占)优先级﹐而下半部分(右边的位)则为子(次级)优先级。事实上 stm32 只用了 4 位优先级,分组时从优先级高位向低位方向分组。

        SCB_AIRCR 的位 10:8 的三位决定了分组情况 ,三位中可填的值是二进制的 000 -- 111

 STM32 的中,分组寄存器实际使用情况

0b:二进制

X:表示抢占优先级位

Y:表示次级(子)优先级位

[7:4]:表示优先级寄存器中 8 位优先级的 bit4 到 bit7

Group priority bits:抢占优先级的位

Subpriority bit:子优先级(次级优先级)的位

Group priorities:表示抢占优先级可填的选择有几个 16 表示 16 种选择,0--15

Sub priorities:跟上面一样

特性:抢占优先级+次级优先级(子优先级)

                抢占优先级: 低优先级的中断正在执行,高优先级的可以打断低优先级运行 

                次级(子)优先级: 抢占优先级相同的多个中断同时请求,次级优先级越高先执行。 

正是抢占优先级的存在,才会发生中断嵌套。数字越小,优先级越高

至于选择哪个分组,是自己决定使用哪个分组,分组确定之后,抢占和次级占的位数就确定了。

        选择分组 5(2 位抢占,2 位次级) –SCB-AIRCR[10:8]填入 101 

        选择分组 6(1 位抢占,3 位次级) –SCB-AIRCR[10:8]填入 110

中断的使能和失能

外部中断或部分内部中断(异常),如果需要用中断,需要先在 NVIC 中使能中断。

中断使能寄存器如下图

中断失能寄存器如下图 

中断使用的过程和相关函数接口

内核提供的操作 NVIC 的函数说明:这一部分函数全部在 core_cm3.h 中

 

Core_cm3.h -- 内核提供的(ARM 公司)

NVIC_SetPriorityGrouping() -- 设置中断优先级分组,整个工程只需要一次分组就可以,一般放在主函数的最开头

NVIC_SetPriority(TIM6_IRQn, 0); -- 配置中断通道的优先级

NVIC_EnableIRQ(TIM6_IRQn); -- 使能中断通道

Misc.h -- ST 公司提供的(ST 公司)

NVIC_PriorityGroupConfig() -- 设置中断优先级分组

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //中断通道

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //次级优先级

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能

NVIC_Init(&NVIC_InitStructure);

外部中断--EXTI

外部中断内部框图以及外部中断线路映像

外部中断线路映像

通用 I/O 端口以下图的方式连接到 16 个外部中断/事件线上:

EXTI硬件中断选择过程

配置 20 个线路做为中断源:

1、配置 20 个中断线的屏蔽位(EXTI_IMR) ,中断屏蔽寄存器(EXTI_IMR)

2、配置所选中断线的触发选择位(EXTI_RTSR上升沿 和 EXTI_FTSR下降沿)

3、配置对应到外部中断控制器(EXTI)的 NVIC 中断通道的使能和屏蔽位,使得 20 个中断线中的请求可以被正确地响应。

外部中断(EXTI)的配置过程

 EXTI 的功能作用:

(1) 检测对应 IO 口是否产生上升沿、下降沿、双边沿

(2) 现在编程的例子中,通过按键产生对应的边沿

(3) 超声波测距模块也可以用 EXTI 实现

1、配置要中断检测的 IO 引脚模式为:浮空输入模式,

上升沿和下降沿是通过单片机外部的电路产生的,需要借助 GPIO 口输入进来,那么就需要配置 GPIO模式选择哪个 :

(1)看官方例程

(2)具体查阅参考手册 8.1.11 表格,同时结合自己的硬件电路来决定

我们的按键电路有高电平和低电平,所以选择浮空输入。如果按键电路只有低电平,选择上拉输入,如果只有高电平,选择下拉输入。 

2、把要中断检测的 IO 引脚映射到对应的 EXTI 中断线上,通过 AFIO 来设置(注意开 AFIO 时钟)。

        参考手册 9.2.5 描述, 

        开时钟:配置参考手册 6.3.7 

        配置 EXTI 线:配置参考手册 8.4.3—8.4.6 

3、配置对应的 EXTI 中断线触发的边沿

        配置参考手册 9.3.3 和 9.3.4 

4、配置对应的 EXTI 中断线,使能屏蔽位

        配置参考手册 9.3.1 

5、通过 NVIC 配置 EXTI 中断的优先级、使能 NVIC 的 EXTI 中断

6、编写中断服务函数:注意函数名、注意清中断等等。

        注:当把 GPIO 用作 EXTI 外部中断或使用重定义功能的时候,必须开启 AFIO 时钟,而在使用默认复用功能的时候,就不必开启 AFIO 时钟了。

总结

主要目的:学习中断(NVIC)--管理中断
关心的问题:
        中断优先级:数字越小,优先级越高
        中断的分组:SCB_AIRCR:位[10:8],填入000--111
        中断优先级分类:--优先级分组决定了抢占和次级可配置的范围
                抢占优先级:高优先级到来的时候,可以打断原有正在执行的中断
                次级(子)优先级:当抢占优先级相同的两个中断,同时到来,次级优先级高的先响应
        中断优先级的设置:通过操作IPRx寄存器,来设置中断的优先级,ARM公司预留的是8位,ST公司封装只用了高4位
        中断的使能:通过操作NVIC_ISER寄存器,来设置中断的打开。
代码层面实现:
        中断优先级分组:NVIC_SetPriorityGrouping(5);://中断优先级分组 core_cm3.h 1430行
        中断优先级的配置:NVIC_SetPriority(EXTI0_IRQn,9); //core_cm3.h 1439行
                9是如何来的:根据分组情况,2位抢占,2位次级。假如抢占是2,抢占两位填10,假如次级是1,次级两位填01,拼起来4位1001,填入IPR[X]寄存器中,所以传递9,该函数会自动左移4位。
中断的使能: NVIC_EnableIRQ(EXTIO_IRQn); //core_cm3.h 1432行
NVIC管理:..内核的异常+内核外部外设的中断
EXTI去练习中断如何使用
EXTI:检测20个通道,是否产生,上升沿下降沿或者双边沿

代码

exti.c

#include "exti.h"
#include "main.h"
#include "led.h"
#include "relay.h"

/*EXTI初始化
1、GPIO EXTI的上升沿和下降沿,需要借助GPIO输入到单片机内部
KEY PA0 PC4 PC5 PC6
*/

void EXIT_Confing()
{
#if (USB_STD_LIB==0)
	//1.开GPIO时钟
	RCC->APB2ENR |= (0x05 << 2);
	//2.设置KEY1工作模式
	GPIOA->CRL &= ~(0xF << 0);//先清0
	GPIOA->CRL |= (0x4 << 0);//在置1
	//3.设置KEY2 KEY3 KEY4工作模式
	GPIOC->CRL &= ~(0xFFF << 16);//先清0
	GPIOC->CRL |= (0x444<< 16);//在置1
	//4.开AFIO的时钟
	RCC->APB2ENR |= (0x01 << 0);
	//5.将PA0映射到EXTI0上 PC345映射到EXTI1
	AFIO->EXTICR[0] &= ~(0xF << 0);
	AFIO->EXTICR[0] |= (0x0 << 0);
	
	AFIO->EXTICR[1] &= ~(0xFFFF << 0);
	AFIO->EXTICR[1] |= (0x2222 << 0);
	
	/*uAFIO->EXTICR[1] &= ~(0xF << 4);
	AFIO->EXTICR[1] |= (0x2 << 4);
	
	AFIO->EXTICR[1] &= ~(0xF << 8);
	AFIO->EXTICR[1] |= (0x2 << 8);*/
	//6.设置触发方式
	EXTI->FTSR |= (0x01 << 0);//KEY1下降
	EXTI->RTSR |= (0x07 << 4);//345上升 
	/*EXTI->RTSR |= (0x01 << 5);
	EXTI->RTSR |= (0x01 << 6);*/
	//7.允许EXTI产生中断
	EXTI->IMR |= (0x01 << 0);//中断屏蔽寄存器
	EXTI->IMR |= (0x01 << 4);
	EXTI->IMR |= (0x01 << 5);
	EXTI->IMR |= (0x01 << 6);
	//8.中断层面配置:使能EXTI0、EXTI4、EXTI5、EXTI6中断
	NVIC_SetPriority(EXTI0_IRQn, 9);//抢占2次级1
	NVIC_SetPriority(EXTI4_IRQn, 9);//抢占2次级2
	NVIC_SetPriority(EXTI9_5_IRQn, 12);//抢占3次级0
	//9.允许NVIC层面的中断
	NVIC_EnableIRQ(EXTI0_IRQn);
	NVIC_EnableIRQ(EXTI4_IRQn);
	NVIC_EnableIRQ(EXTI9_5_IRQn);
	#elif (USB_STD_LIB==1)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);//开时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure = {0};//灯的模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//配置引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; 
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 |GPIO_Pin_5 |GPIO_Pin_6;
	GPIO_Init(GPIOC, &GPIO_InitStructure); 
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);//映射
	EXTI_InitTypeDef   EXTI_InitStructure = {0};
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;
	EXTI_Init(&EXTI_InitStructure);
		
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource4);//映射
	EXTI_InitStructure.EXTI_Line = EXTI_Line4;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿
	EXTI_Init(&EXTI_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5);//映射
	EXTI_InitStructure.EXTI_Line = EXTI_Line5;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿
	EXTI_Init(&EXTI_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource6);//映射
	EXTI_InitStructure.EXTI_Line = EXTI_Line6;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿
	EXTI_Init(&EXTI_InitStructure);

	
	NVIC_InitTypeDef   NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//次级优先级
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//次级优先级
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//次级优先级
	NVIC_Init(&NVIC_InitStructure);
	
	
	#endif
	
}

void EXTI0_IRQHandler()//当中断触发条件满足时,并且NVIC允许中断,内核会自动加载该函数
{
	#if (USB_STD_LIB==0)	
	//1.检测中断是否触发
	if((EXTI->PR & (0x01 << 0)) != 0)//挂起寄存器
	{
		//2.执行中断服务函数内容
		LED1_ON(); LED2_ON(); LED3_ON(); LED4_ON();
		//3.清楚中断表示位置
		EXTI->PR |= (0x01 << 0);
	}
	
	#elif (USB_STD_LIB==1)
	//1.检测中断是否触发
	if((EXTI_GetITStatus(EXTI_Line0) != RESET))
	{
		//2.执行中断服务函数内容
		LED1_ON(); LED2_ON(); LED3_ON(); LED4_ON();
		//3.清楚中断表示位置
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
	#endif
}
void EXTI4_IRQHandler()
{
	#if (USB_STD_LIB==0)	
	//1.检测中断是否触发
	if((EXTI->PR & (0x01 << 4)) != 0)
	{
		//2.执行中断服务函数内容
		LED1_OFF(); LED2_OFF(); LED3_OFF(); LED4_OFF();
		//3.清楚中断表示位置
		EXTI->PR |= (0x01 << 4);
	}
	#elif (USB_STD_LIB==1)
	//1.检测中断是否触发
	if((EXTI_GetITStatus(EXTI_Line4) != RESET))
	{
		//2.执行中断服务函数内容
		LED1_OFF(); LED2_OFF(); LED3_OFF(); LED4_OFF();
		//3.清楚中断表示位置
		EXTI_ClearITPendingBit(EXTI_Line4);
	}
	#endif
}
void EXTI9_5_IRQHandler()
{
	#if (USB_STD_LIB==0)	
	//1.检测中断是否触发
	if((EXTI->PR & (0x01 << 5))!= 0)
	{
		//2.执行中断服务函数内容
		Relay_ON();
		//3.清楚中断表示位置
		EXTI->PR |= (0x01 << 5);
	}
	else if((EXTI->PR & (0x01 << 6)) != 0)
	{
		Relay_OFF();
		//3.清楚中断表示位置
		EXTI->PR |= (0x01 << 6);
	}
	
	#elif (USB_STD_LIB==1)
	//1.检测中断是否触发
	if((EXTI_GetITStatus(EXTI_Line5) != RESET))
	{
		Relay_ON();
		EXTI_ClearITPendingBit(EXTI_Line5);
	}
	else if((EXTI_GetITStatus(EXTI_Line6) != RESET))
	{
		Relay_OFF();
		EXTI_ClearITPendingBit(EXTI_Line6);
	}
	#endif
}

exti.h

#ifndef __EXTI_H__
#define __EXTI_H__

#include "stm32f10x.h"


void EXIT_Confing();


#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力做小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值