STM32标准库——(5)EXTI外部中断

目录

1.中断系统

2.中断执行流程

3.STM32中断

4.NVIC基本结构(嵌套中断向量控制器)

5.NVIC优先级分组

6.EXIT简介

7.EXIT基本结构

8.AFIO复用IO口

9.EXIT框图

10.相关API

10.1 GPIO_AFIODeInit

10.2 GPIO_PinLockConfig

10.3 GPIO_PinRemapConfig

10.4 GPIO_EXTILineConfig

10.5 EXTI_Init

10.6 EXTI_GetITStatus

10.7 EXTI_ClearITPendingBit

10.8 NVIC_PriorityGroupConfig

10.9 NVIC_Init

11.对射式红外传感器工程

11.1 对射式红外传感器模块

11.1.1 简介

11.1.2 特点

11.1.3 引脚说明

11.1.4 操作说明

11.1.5 电路原理图

11.2 接线图

11.3 相关代码

CountSensor.c

CountSensor.h

main.c

12.旋转编码器工程

12.1 旋转编码器模块

12.1.1 简介

12.2 硬件电路

12.2 接线图

12.3 相关代码

Encoder.c

Encoder.h

main.c


1.中断系统

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

中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源

中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回

2.中断执行流程

3.STM32中断

  • 68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设
  • 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级

  1. WWDG:窗口看门狗 用来监测程序运行状态的中断 比如程序卡死了 没有及时喂狗 窗口看门狗就会申请中断 让程序调到窗口看门狗的中断程序里 此时可以在中断程序里进行一些错误检查 看看出现什么问题
  2. PVD电源电压检测:如果供电电压不足 PVD电路就会申请中断 在中断里可知供电不足 此时便需要保存重要数据
  3. 地址:程序中的中断函数其地址是由编译器来分配的 是不固定的 但中断跳转由于硬件的限制 只能跳到固定的地址执行程序 所以为了能让硬件跳转到一个不固定的中断函数里 这里就需要在内存中定义一个地址的列表 这个列表地址是固定的 中断发生后 就跳到这个固定位置 在这个固定位置上 由编译器 再加上一条跳转到中断函数的代码 此时中断跳转就可以跳转到任意位置了 这个中断地址的列表 就是中断向量表 相当于中断跳转的一个跳板 但我们是用C语言编程的 不需要去管这个中断向量表

4.NVIC基本结构(嵌套中断向量控制器)

5.NVIC优先级分组

  • NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级

  • 抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队

6.EXIT简介

  1. 相同的Pin不能同时触发中断:比如PA0和PB0不能同时使用
  2. 通道数:加起来总共有20个中断线路 16个GPIO_Pin是外部中断的主要功能 后面四个主要是来外部中断”蹭网“的 外部中断有个功能 就是从低功耗模式的停止模式下唤醒STM32 对于PVD电源电压监测 当电源从电压过低恢复时 就需要PVD借助一下外部中断退出停止模式 对于RTC闹钟来说 有时候为了省电 RTC定了个闹钟后 STM32会进入停止模式 等到闹钟响的时候再唤醒 这也需要借助外部中断 USB唤醒、以太网唤醒也都是类似作用
  3. 中断响应:申请中断 让CPU执行中断函数
  4. 事件响应:是STM32对外部中断增加的一种额外的功能 当外部中断检测到引脚电平变化时 正常的流程是选择触发中断 但在STM32中 也可以选择触发一个事件 如果选择触发事件 那外部中断的信号就不会通向CPU 而是通向其他外设 用来触发其他外设的操作 比如触发ADC转换、触发DMA等
  5. 3、4对比总结:中断响应是正常流程 引脚电平变化触发中断 事件响应不会触发中断 而是触发别的外设操作 属于外设之间的联合工作

7.EXIT基本结构

  1. AFIO:数据选择器 可以在前面3个GPIO外设的16个引脚里选择其中一个连接到后面的EXIT的通道里
  2. 输入信号经过EXIT电路后分为了两种输出 上面的接到了NVIC 是用来触发中断的 本来20路输入 应该有20路中断的输出 可能开发板公司觉得20输出太多 比较占用NVIC的通道资源 所以把其中外部中断的9~5、15~10分到一个通道里 意思是外部中断的9~5会触发同一个中断函数 15~10也会触发同一个中断函数 在编程时 在这两个中断函数里  需要再根据标志位来区别到底是哪个中断进来的 下面有20条输出线路到了其他外设 这就是用来触发其他外设操作的 也就是我们上面说的事件响应

8.AFIO复用IO口

  • AFIO主要用于引脚复用功能的选择和重定义

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

9.EXIT框图

  • 触发信号通过或门之后 兵分两路 上一路是触发中断的 下一路是触发事件的 中断输出部分:触发中断首先会置一个挂起寄存器 相当于是一个中断标志位 可以读取这个寄存器判断是哪个通道触发的中断 如果中断挂起寄存器置1 继续向左走中断屏蔽寄存器共同进入一个与门 然后至NVIC中断控制器 这个与门相当于一个开关 中断屏蔽寄存器给1另一个就是直接输出 也就是允许中断 中断屏蔽寄存器给0 另一个无论输入什么 输出都是0 相当于屏蔽了这个中断 事件输出部分:事件屏蔽寄存器进行开关控制 最后通过一个脉冲发生器到其他外设 这个脉冲发生器就是给一个电平脉冲 用来触发其他外设的动作  

10.相关API

10.1 GPIO_AFIODeInit

void GPIO_AFIODeInit(void)(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
功能:
	用来复位AFIO外设 调用该函数后AFIO外设的配置就会全部清除
参数:
    无    
返回值:
	无    

10.2 GPIO_PinLockConfig

void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
功能:
	锁定GPIO引脚配置寄存器
参数:
    GPIOx:GPIOx:其中x可以为(A..G)选择GPIO外设
    GPIO_Pin:要写的端口位,该参数可以是GPIO_Pin_x的任意组合,其中x可以是(0..15)
返回值:
	无    

10.3 GPIO_PinRemapConfig

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
功能:
	更改指定引脚的映射
参数:
    GPIO_Remap: 选择要重新映射的引脚
    NewState:端口引脚重新映射的新状态,取值为:ENABLE或DISABLE 
返回值:
	无    

10.4 GPIO_EXTILineConfig

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
功能:
	选择 GPIO 管脚用作外部中断线路
参数:
    GPIO_PortSource: 选择用作外部中断线源的 GPIO 端口,取值为GPIO_PortSourceGPIOx,其中x为(A..G)
    GPIO_PinSource:待设置的外部中断线路,该参数可以是GPIO_PinSourcex,其中x可以是(0..15)  
返回值:
	无    

10.5 EXTI_Init

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
功能:
	根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器
参数:
    EXTI_InitStruct:指向结构 EXTI_InitTypeDef 的指针,包含了外设 EXTI 的配置信息 
返回值:
	无    

10.6 EXTI_GetITStatus

ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
功能:
	检查指定的 EXTI 线路触发请求发生与否
参数:
    EXTI_Line:待检查 EXTI 线路的挂起位 
返回值:
	EXTI_Line 的新状态(SET 或者 RESET) 
        
    

10.7 EXTI_ClearITPendingBit

void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
功能:
	清除 EXTI 线路挂起位
参数:
    EXTI_Line:待清除 EXTI 线路的挂起位 
返回值:
	无 
        
       

10.8 NVIC_PriorityGroupConfig

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
功能:
	设置优先级分组:先占优先级和从优先级(先占就是抢先优先级,从站就是响应优先级)
参数:
    NVIC_PriorityGroup:优先级分组位长度(本次代码选择的是2为抢占2位响应 比较平均)
返回值:
	无


PriorityGroup类型
/** @defgroup Preemption_Priority_Group 
  * @{
  */

#define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
                                                            4 bits for subpriority */
#define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
                                                            3 bits for subpriority */
#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
                                                            2 bits for subpriority */
#define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
                                                            1 bits for subpriority */
#define NVIC_PriorityGroup_4         ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
                                                            0 bits for subpriority */


10.9 NVIC_Init

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
功能:
	根据 NVIC_InitStruct 中指定的参数初始化外设 NVIC 寄存器
参数:
    NVIC_InitStruct:指向结构 NVIC_InitTypeDef 的指针,包含了外设 GPIO 的配置信息     
返回值:
	无    

11.对射式红外传感器工程

11.1 对射式红外传感器模块

11.1.1 简介

该产品采用FTR9606高灵敏度槽型光耦器件,槽宽5mm。它由一个红外发光二极管和NPN光电三极管组成,M3固定安装孔,有输出状态指示灯,输出高电平灯灭,输出低电平灯亮。有遮挡,输出高电平。无遮挡,输出低电平。使用3.3-5VDC 宽电压LM393比较器输出,信号干净,波形好,驱动能力强,超过15mA。输出形式:数字开关量输出(0和1)。广泛用于电机转速检测,脉冲计数,位置限位等。

11.1.2 特点

1、使用进口ITR9606高灵敏度槽型光耦传感器,槽宽度5mm。
2、有输出状态指示灯,输出高电平灯灭,输出低电平灯亮。
3、有遮挡,输出高电平;无遮挡,输出低电平。
4、比较器输出,信号干净,波形好,驱动能力强,超过15mA。
5、工作电压3.3V-5V
6、输出形式:数字开关量输出(0和1)
7、设有M3固定螺栓孔,方便安装
8、小板PCB尺寸:3.2cm x 1.4cm
9、使用宽电压LM393比较器
10、广泛用于电机转速检测,脉冲计数,位置限位等。

11.1.3 引脚说明

1、VCC 接电源正极3.3-5V

2、GND 接电源负极

3、DO TTL开关信号输出

4、AO 此模块不起作用

11.1.4 操作说明

1、接好VCC和GND,模块电源指示灯会亮
2、模块槽中无遮挡时,接收管导通,模块DO输出低电平,开关指示灯亮;遮挡时,DO输出高电平,开关指示灯灭。
3、模块DO可与继电器相连,组成限位开关等功能,也可以与有源蜂鸣器模块相连,组成报警器。
4、DO输出接口可以与单片机10口直接相连,一般接外部中断,检测传感器是否有遮档,如用电机码盘则可检测电机的转速。

11.1.5 电路原理图

11.2 接线图

11.3 相关代码

CountSensor.c
#include "stm32f10x.h"                  // Device header

uint16_t CountSensor_Count;				//全局变量,用于计数

/**
  * 函    数:计数传感器初始化
  * 参    数:无
  * 返 回 值:无
  */
void CountSensor_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB14引脚初始化为上拉输入
	
	/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚
	
	/*EXTI初始化*/
	EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量
	EXTI_InitStructure.EXTI_Line = EXTI_Line14;					//选择配置外部中断的14号线
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发
	EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;		//选择配置NVIC的EXTI15_10线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
}

/**
  * 函    数:获取计数传感器的计数值
  * 参    数:无
  * 返 回 值:计数值,范围:0~65535
  */
uint16_t CountSensor_Get(void)
{
	return CountSensor_Count;
}

/**
  * 函    数:EXTI15_10外部中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void EXTI15_10_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line14) == SET)		//判断是否是外部中断14号线触发的中断
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
		{
			CountSensor_Count ++;					//计数值自增一次
		}
		EXTI_ClearITPendingBit(EXTI_Line14);		//清除外部中断14号线的中断标志位
													//中断标志位必须清除
													//否则中断将连续不断地触发,导致主程序卡死
	}
}
CountSensor.h
#ifndef __COUNT_SENSOR_H
#define __COUNT_SENSOR_H

void CountSensor_Init(void);
uint16_t CountSensor_Get(void);

#endif
main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"

int main(void)
{
	/*模块初始化*/
	OLED_Init();			//OLED初始化
	CountSensor_Init();		//计数传感器初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Count:");	//1行1列显示字符串Count:
	
	while (1)
	{
		OLED_ShowNum(1, 7, CountSensor_Get(), 5);		//OLED不断刷新显示CountSensor_Get的返回值
	}
}

现象:这里给外部中断配置的是下降沿 所以每次遮挡传感器 在遮挡的那一瞬间计次加1 拿起的说话不变 再次遮挡计次再次加1

12.旋转编码器工程

12.1 旋转编码器模块

12.1.1 简介
  • 旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向

  • 类型:机械触点式/霍尔传感器式/光栅式

12.2 硬件电路

  1. 左边接了一个10的上拉电阻 默认没旋转的情况下 这个点被上拉为高电平 通过R3输出到A端口就是高电平 当旋转时 内部触电导通 这个点直接被拉低到GND 再通过R3输出 A端口就是低电平 
  2. R3:输出限流电阻 防止模块引脚电流过大
  3. C1:输出滤波电容 防止一些输出信号抖动 

12.2 接线图

12.3 相关代码

Encoder.c
#include "stm32f10x.h"                  // Device header

int16_t Encoder_Count;					//全局变量,用于计数旋转编码器的增量值

/**
  * 函    数:旋转编码器初始化
  * 参    数:无
  * 返 回 值:无
  */
void Encoder_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟
	
	/*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);						//将PB0和PB1引脚初始化为上拉输入
	
	/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//将外部中断的0号线映射到GPIOB,即选择PB0为外部中断引脚
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//将外部中断的1号线映射到GPIOB,即选择PB1为外部中断引脚
	
	/*EXTI初始化*/
	EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;		//选择配置外部中断的0号线和1号线
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发
	EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//选择配置NVIC的EXTI0线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设

	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;			//选择配置NVIC的EXTI1线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			//指定NVIC线路的响应优先级为2
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
}

/**
  * 函    数:旋转编码器获取增量值
  * 参    数:无
  * 返 回 值:自上此调用此函数后,旋转编码器的增量值
  */
int16_t Encoder_Get(void)
{
	/*使用Temp变量作为中继,目的是返回Encoder_Count后将其清零*/
	/*在这里,也可以直接返回Encoder_Count
	  但这样就不是获取增量值的操作方法了
	  也可以实现功能,只是思路不一样*/
	int16_t Temp;
	Temp = Encoder_Count;
	Encoder_Count = 0;
	return Temp;
}

/**
  * 函    数:EXTI0外部中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void EXTI0_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line0) == SET)		//判断是否是外部中断0号线触发的中断
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
		{
			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)		//PB0的下降沿触发中断,此时检测另一相PB1的电平,目的是判断旋转方向
			{
				Encoder_Count --;					//此方向定义为反转,计数变量自减
			}
		}
		EXTI_ClearITPendingBit(EXTI_Line0);			//清除外部中断0号线的中断标志位
													//中断标志位必须清除
													//否则中断将连续不断地触发,导致主程序卡死
	}
}

/**
  * 函    数:EXTI1外部中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void EXTI1_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line1) == SET)		//判断是否是外部中断1号线触发的中断
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
		{
			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)		//PB1的下降沿触发中断,此时检测另一相PB0的电平,目的是判断旋转方向
			{
				Encoder_Count ++;					//此方向定义为正转,计数变量自增
			}
		}
		EXTI_ClearITPendingBit(EXTI_Line1);			//清除外部中断1号线的中断标志位
													//中断标志位必须清除
													//否则中断将连续不断地触发,导致主程序卡死
	}
}
Encoder.h
#ifndef __ENCODER_H
#define __ENCODER_H

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

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

int16_t Num;			//定义待被旋转编码器调节的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Encoder_Init();		//旋转编码器初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Num:");			//1行1列显示字符串Num:
	
	while (1)
	{
		Num += Encoder_Get();				//获取自上此调用此函数后,旋转编码器的增量值,并将增量值加到Num上
		OLED_ShowSignedNum(1, 5, Num, 5);	//显示Num
	}
}
  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值