STM32(五)——EXTI外部中断

文章笔记源于——江科大自化协的视频

一. 中断系统

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

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

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

STM32(五)——EXTI外部中断

一般中断函数都是在一个子函数里的,这个函数不需要我们调用,当中断来临时,自动由硬件调用这个函数

二. STM32的中断

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

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

STM32(五)——EXTI外部中断 

三 .  EXTI简介

1.  EXTI外部中断

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

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

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

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

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

STM32(五)——EXTI外部中断

 所以PA0 PB0 PC0只能有一个触发,不能同时触发

四. AFIO复用IO口

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

五. 旋转编码器介绍

STM32(五)——EXTI外部中断

 他是外部信号,这个信号是突发的,STM32只能被动读取,而且万一读取晚了,就会错过很多波形,所以我们就要考虑STM32的外部中断了

 

STM32(五)——EXTI外部中断

旋转编码器,是可以按下去的,这个时候他可以当作普通的按键来用

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

STM32(五)——EXTI外部中断

 A_CLK      B_DT ,我们没有接C,因为不用他的开关(当然也是可以使用的)

接下来进入代码部分

STM32(五)——EXTI外部中断

 

1.主函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Encoder.h"

//给了Num赋值
int16_t Num;

int main(void)
{
	//OLED ENCODER初始化,初始化完才能用
	OLED_Init();
	Encoder_Init();
	
	OLED_ShowString(1, 1, "Num:");
	
	while (1)
	{
		Num += Encoder_Get();
		OLED_ShowSignedNum(1, 5, Num, 5);
	}
}

2.Encode.c

#include "stm32f10x.h"     // Device header

//定义一个带符号变量
int16_t Encoder_Count;

void Encoder_Init(void)
{
	//两个中断的初始化代码,初始化时钟,GPIOB,AFIO
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	
	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);
	
	//AFIO的部分
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
	
	//指定的中断闲为EXTI_LINE1和EXTI_LINE0
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	//中断分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_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);

	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&NVIC_InitStructure);
}

//把变量返回回去,返回变化值,所以返回count(这里是用了一个技巧,间接返回了count(把值付给temp让temp回去))
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)
	{
		//判断一下另一个引脚的电平
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
		{
			//如果是就反转
			Encoder_Count --;
		}
		//清除中断标志位
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}
//下面这个也是一样的,只是换了线,如果是9——15就把两个放一起,用一个中断就行
void EXTI1_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line1) == SET)
	{
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
		{
			//正转
			Encoder_Count ++;
		}
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}

3.Encode.h

#ifndef __ENCODER_H
#define __ENCODER_H

void Encoder_Init(void);
int16_t Encoder_Get(void);

#endif

上一篇:FastAPI(28)- JSON Compatible Encoder 利器之 jsonable_encoder


下一篇:【自然语言处理三】SequenceToSequence 模型