STM32F103(五)——关于EXIT外部中断介绍

前言

本节将会对 STM32(五)进行一个归纳

STM32 的每个 IO 都可以作为外部 中断的中断输入口,这点也是 STM32 的强大之处, STM32F103 的中断控制器支持 19 个外部中 断/ 事件请求。每个中断设有状态

位,每个中断 / 事件都有独立的触发和屏蔽设置

————————————————————————————————————————

目录

1. 对外部中断的描述

2. EXTI中断介绍

3. 以旋转编码器为历程进行代码介绍

——————————————————————————————————————-

一、 外部中断介绍

(1)中断系统

中断 :          在主程序运行过程中,出现特定的中断触发条件,使得CPU暂停当前正在运行的程                          序,而去处理中断程序,完成后,又返回原来被暂停的位置继续工作.

中断优先 :  当有多个中断开始时,CPU会根据事情的轻重响应更加紧急的中断

中断嵌套 :   一个中断正常进行,又来一个更高级的中断,会先去做刚来的高级的中断,然后依                         次返回
————————————————

(2)STM32的中断

1. 68个可屏蔽中断通道,包含 EXTI,TIM,ADC,USART,SPI,IIC,RTC 等多个外设

2. 使用  NVIC  统一管理中断,每个中断有16个可编程的优先等级,可对优先级分组

   (如果我们想要使用中断的话,我们就必须配置NVIC,这个在之后我们会进行说明)

————————————————

二、EXTI 外部中断介绍

1.   EXTI可监测指定GPIO口的电平信号,当GPIO口的电平变化时,EXTI就立刻向NVIC发出中断        申请,经过NVIC裁决后,让CPU执行中断程序

2.   触发方式 : 上升沿(低变高),下降沿(高变低),双边沿(前两个都可以),软件出发                              (写代码出发,和GPIO没关系)

4.   GPIO :       支持所有GPIO口,但是相同的Pin不能触发中断

5.   通道数 :     16个Pin(外加PVD输出,RTC闹钟,USB唤醒,以太网唤醒)

6.   触发响应方式: 中断响应,事件响应

我们来用下面这个照片帮助我们了解一下他的基本结构

需要注意的是,同一种引脚只能被使用一次,即 PA0 与 PB0 只有一个口被中断
————————————————

(2)AFIO 的简单介绍

AFIO口主要完成两个任务:复用功能引脚重映射,中断引脚选择

(我们同样参照上面的图)

————————————————

三、以旋转编码器为历程进行代码介绍

1. 什么是旋转编码器?

旋转编码器 : 一种可以用来测量 速度 方向 位置的工具,当它旋转时,他的输出端就可以输出与                         之对应速度方向的波形

而我们也正是通过这些波来进行编程

2. 旋转编码器的波形

知道旋转编码器的波形,是我们进行编程思路的关键

3.旋转编码器的配置

旋转编码器模块有5个引脚,分别是GND(-), VCC(+), SW, DT, CLK。其中VCC和GND用来接电源和地,按缩写SW应该是Switch(开关)、CLK是Clock(时钟)、DT是Data(数据)

4.编程的思路

这里我们将要使用单线程的方法——即用中断读取一个波的高低电平的同时,来读取另一个波电平的状态,以此来计算旋转的方向和次数

 当然和正常的机械按键一样,我们都要进行去抖

————————————————————————————————————

编程部分

老样子,我们还是先给出我们的总体的编程思路

1 ——  初始化 IO 口为输入。
2 ——  开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。
3 ——  初始化线上中断,设置触发条件等。
4 ——  配置中断分组( NVIC ),并使能中断。
5 ——  编写中断服务函数
————————————————

先设定我们的旋转编码器函数 ——   void Encoder_Init(void)

————————————-————

1.时钟使能,EXTI和NVIC的时钟是一直打开的,所以我们就不需要再打开了

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

——————————————

2.GPIO初始化

	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置为上拉模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

这里注意,我们前面说过我们的 旋转编码器 有 5个引脚,但是中间的按键引脚我们在这里不使用

————————————

3.配置 AFIO

 // GPIO_PinRemaConfig() 可以用来引脚重映射
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); //配置AFIO的数据选择器,来选择我们要的引脚,指定外部中断线

 即在这,我们选择 PB0 作为 中断口,选择 PB0作为中断源,并且设置我们的中断线

—————————————————

4.配置 EXIT

	EXTI_InitTypeDef EXTI_InitStructure;//结构体定义
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 ;//需要我们配置中断线,我们用PB0所在的line0
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;//开启中断
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
	EXTI_InitStructure.EXTI_Trigger =EXTI_Trigger_Rising_Falling ;//设置触发方式
	EXTI_Init(&EXTI_InitStructure);//调用这个参数,就可以根据这个结构体

我们的中断触发方式根据我们的使用来选择,这里我们选择上升/下降沿触发(其实选上升 或者下降都是可以的)

——————————————————

5.配置 NVIC

(写在前面)

1.   NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能

2.   NVIC跟内核紧密联系,是内核里的外设

我们把他分为 抢占响应 两种选择, 抢占大于响应,我们优先看抢占的大小(从0开始,越小越先开始),当抢占相同时,我们再看响应,比较方法也是一样的,高优先的抢占是可以打断低优先的抢占的,但是抢占相同时,高优先的响应是不能打断低优先响应的

(1)中断分组

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

(2)配置初始

	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //选择触发的通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级
	NVIC_Init(&NVIC_InitStructure);

——————————————————————

6. 中断函数的配置

我们要读取编码器的值,就需要把他返回回去,所以我们这边设了两个值,一个来记录,另一个用来返回

int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = Encoder_Count;
	Encoder_Count = 0;
	return Temp;
}

接下来进入我们的中断函数

void EXTI0_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line0) == SET)//进行一个中断标志位的判断,如果中断置1,中断触发(触发方式在上面选择),进入下面的if语句
	{	
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0) == 1)//先判断其中一个波的电平
		{
			Delay_ms(3);//去除抖动
			if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)//再判断第二波的电平状态
			{
				Encoder_Count --;
			}else{
				Encoder_Count ++;
			}
		
	}

——————————————————————————————————

写完中断函数后,就变得很简单了,我们接下来只要在OLED上面显示我们旋转出来的数字就好了
 

int16_t Num;

int main(void)
{
	OLED_Init();
	Encoder_Init();
	OLED_ShowString(1, 1, "Num:");
	
	while (1)
	{
		Num += Encoder_Get();
		OLED_ShowSignedNum(1, 5, Num, 3);
	}
}

——————————————————————————————————————-
 

猜你喜欢

转载自blog.csdn.net/ArtoriaLili/article/details/122530514