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

news2024/11/24 12:28:05

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:优先级分组位长度     
返回值:
	无


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
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1415635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ribbon 体系架构解析

前面已经介绍了服务治理相关组件&#xff0c;接下来趁热打铁&#xff0c;快速通关Ribbon&#xff01;前面我们了解了负载均衡的含义&#xff0c;以及客户端和服务端负载均衡模型&#xff0c;接下来我们就来看下SpringCloud 下的客户端负载均衡组件Ribbon 的特点以及工作模型。 …

day04 两两交换链表中的节点、删除链表倒数第N个节点、链表相交、环形链表II

题目链接&#xff1a;leetcode24-两两交换链表中的节点, leetcode19-删除链表倒数第N个节点, leetcode160-链表相交, leetcode142-环形链表II 两两交换链表中的节点 基础题没有什么技巧 解题思路见代码注释 时间复杂度: O(n) 空间复杂度: O(1) Go func swapPairs(head *Li…

Android Handler完全解读

一&#xff0c;概述 Handler在Android中比较基础&#xff0c;本文笔者将对此机制做一个完全解读。读者可简单参考上述类图与时序图&#xff0c;便于后续理解。 二&#xff0c;源码解读 1&#xff0c;主线程伊始 众所周知&#xff0c;通过Zygote的fork方式&#xff0c;新创建…

腾讯云轻量应用Ubuntu服务器如何一键部署幻兽帕鲁Palworld私服?

幻兽帕鲁/Palworld是一款2024年Pocketpair开发的开放世界生存制作游戏&#xff0c;在帕鲁的世界&#xff0c;玩家可以选择与神奇的生物“帕鲁”一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。而帕鲁可以进行战斗、繁殖、协助玩家做农活&#xff0c;也…

网页转文件下载工具

为了更快捷copy博客 做了个 网页转文件下载工具 1.0.1 更新如下&#xff1a; javaphpjava提供页面转换文件的微服务APIphp调用接口&#xff0c;输出文件下载支持网页转md 1.0.2 更新如下&#xff1a; 样式表切换&#xff0c;白天or黑夜&#xff0c;cookie七天保质期 未…

全国首条智慧高速开通,“车牌付” 会取代传统 ETC 收费吗?

2024年1月19日&#xff0c;全国首条智慧高速--杭绍甬高速杭绍段正式建成通车&#xff01;项目全长约52.8公里&#xff0c;设计速度120公里/小时&#xff0c;是长三角智慧交通示范项目。 01 杭绍甬 “慧眼”感知系统 全国首条智慧高速公路--杭绍甬高速在视频AI算法、IoT物联网、…

SpringBoot系列之MybatisPlus实现分组查询

SpringBoot系列之MybatisPlus实现分组查询 我之前博主曾记写过一篇介绍SpringBoot2.0项目怎么集成MybatisPlus的教程&#xff0c;不过之前的博客只是介绍了怎么集成&#xff0c;并没有做详细的描述各种业务场景&#xff0c;本篇博客是对之前博客的补充&#xff0c;介绍在mybat…

mac裁剪图片

今天第一次用mac裁剪图片&#xff0c;记录一下过程&#xff0c;差点我还以为我要下载photoshop了&#xff0c; 首先准备好图片 裁剪的目的是把图片的标题给去掉&#xff0c;但是不能降低分辨率&#xff0c;否则直接截图就可以了 解决办法 打开原始图片(不要使用预览&#xf…

【机器学习笔记】0 基础知识之python基础

注&#xff1a;本文内容仅为个人学习笔记&#xff0c;教程为黄海广老师主讲的机器学习入门系列&#xff0c; 课程链接&#xff08;中国大学慕课&#xff0c;有习题和证书&#xff09; 课程资源&#xff08;pdf版本课件和代码&#xff09;公布在Github链接 课程视频也可以在b站观…

python10-Python的字符串之拼接字符串

如果直接将两个字符串紧挨着写在一起&#xff0c;Python就会自动拼接它们&#xff0c;例如如下代码。 s1 "软件测试划水老师傅&#xff0c;"软件测试老痞print(s1) 上面代码将会输出: 软件测试划水老师傅&#xff0c;软件测试老痞 上面这种写法只是书写字符串的一…

数学知识第三期 欧拉函数

前言 相信大家在高中的时候接触过欧拉函数&#xff0c;希望大家通过本篇文章能够进一步理解欧拉函数&#xff01;&#xff01;&#xff01; 一、什么是欧拉函数&#xff1f; 欧拉函数是一个在数论中用于描述特定正整数的互质数的概念。具体来说&#xff0c;对于一个正整数n&…

初识人工智能,一文读懂机器学习之逻辑回归知识文集(7)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

电商API接口|爬虫案例|采集某东商品评论信息

前言&#xff1a; 平常大家都有网上购物的习惯&#xff0c;在商品下面卖的好的产品基本都会有评论&#xff0c;当然也不排除有刷评论的情况&#xff0c;因为评论会影响我们的购物决策。今天主要分享用pythonre正则表达式获取京东商品评论。API接口获取京东平台商品详情SKU数据…

API网关-Apinto压缩包方式自动化安装配置教程

文章目录 前言一、Apinto安装教程1. 复制脚本2. 增加执行权限3. 执行脚本4. Apinto命令4.1 启动Apinto4.2 停止Apinto4.3 重启Apinto4.4 查看Apinto版本信息4.5 加入Apinto集群4.6 离开Apinto集群4.7 查看Apinto节点信息 5. 卸载Apinto 二、Apserver(Apinto Dashboard V3)安装教…

powermock: 一个支持 gRPC 的 Mock Server

文章目录 背景选型架构安装配置使用教程快速开始接口定义配置启动 Mock 规则redis 插件HTTP Mock高级配置前置准备场景一 特定 ID 返回特定用户信息场景二 通过脚本返回用户数据 总结参考资料 本文介绍的是如何基于 bilibili 的开源方案 powermock 搭建一套通用的适用于自己公司…

11. 双目视觉之立体视觉基础

目录 1. 深度恢复1.1 单目相机缺少深度信息1.2 如何恢复场景深度&#xff1f;1.3 深度恢复的思路 2. 对极几何约束2.1 直观感受2.2 数学上的描述 1. 深度恢复 1.1 单目相机缺少深度信息 之前学习过相机模型&#xff0c;最经典的就是小孔成像模型。我们知道相机通过小孔成像模…

uniapp scroll-view用法[下拉刷新,触底事件等等...](4)

前言:可滚动视图区域。用于区域滚动 话不多说 直接上官网属性 官网示例 讲一下常用的几个 scroll 滚动时触发 scrolltoupper 滚动到顶部或左边&#xff0c;会触发 scrolltoupper 事件 scrolltolower 滚动到底部或右边&#xff0c;会触发 scrolltolower 事件 1.纵向滚动…

【揭秘】RecursiveAction全面解析

内容概要 RecursiveAction是Java中一个强大的工具&#xff0c;它允许将复杂任务分解为更小的子任务&#xff0c;这些子任务可以并行执行&#xff0c;从而提高整体性能&#xff0c;其主要优点在于能够有效地利用多核处理器&#xff0c;减少任务执行时间&#xff0c;并简化并行编…

SQL注入:盲注

SQL注入系列文章&#xff1a; 初识SQL注入-CSDN博客 SQL注入&#xff1a;联合查询的三个绕过技巧-CSDN博客 SQL注入&#xff1a;报错注入-CSDN博客 目录 什么是盲注&#xff1f; 布尔盲注 手工注入 使用python脚本 使用sqlmap 时间盲注 手工注入 使用python脚本 使…

SpringBoot项目配置SSL后,WebSocket连接失败的解决方案

SpringBoot项目配置SSL后&#xff0c;WebSocket连接应使用wss协议&#xff0c;而不是ws协议。在前端配置WebSocket时&#xff0c;URL以wss://开头。