STM32学习100步之第四十七-四十八步——旋转编码器驱动程序

旋转编码器

旋转编码器是一种可以左右旋转,同时也可以按下,也可以按下旋转的器件,通过左右旋转对应着内部不同开关的导通,同时按下也可以旋转,由此看来旋转编码器可以实现很复杂的功能,简单的通过左右旋转可以调节音量、亮暗等功能,按键可以发挥普通按键的作用,按下按键的同时左右旋转又可以区别普通旋转的按键,因此可以用一个旋转编码器同时调节音量和亮暗(举例),同时也可以通过不同的转速实现不同的功能,总之,功能很复杂,作为初学者,本次只介绍普通旋转和按键作用,同时分析卡死的问题。

开发板上的端口映射原理图如下:其中旋转编码器和模拟量摇杆线路复用,使用其中一个器件时,将对应的跳线帽断开即可。STM32学习100步之第四十七-四十八步——旋转编码器驱动程序_第1张图片

STM32学习100步之第四十七-四十八步——旋转编码器驱动程序_第2张图片

旋转编码器的具体原理图如下所示,我们开发板中的1和4接地,如上图所示,按键按下时,开关1闭合,1和2接通,当向左右旋转时,开关2和3以一定的先后顺序闭合,也可能同时闭合,时序电路如下图所示,另外卡死是由于旋转编码器内部的机械结构不灵敏,正常情况下,每旋转一次,旋转编码器都会正常的咔哒一声,但是极少数情况下,会卡在咔哒声之前,即旋钮停在了两个格段之间,使得K2一直保持低电平,单片机退不出循环,从而导致卡死。

STM32学习100步之第四十七-四十八步——旋转编码器驱动程序_第3张图片
STM32学习100步之第四十七-四十八步——旋转编码器驱动程序_第4张图片
STM32学习100步之第四十七-四十八步——旋转编码器驱动程序_第5张图片
STM32学习100步之第四十七-四十八步——旋转编码器驱动程序_第6张图片

具体的程序如下,其中读取旋钮旋转的方向的方法有两种。1、同时读取两个按键的状态,如果同时读到K2是高电平、K3是低电平,则是方向1,如果同时读到K2是低电平、K3是高电平,则是方向2。2、只读取K2的状态,当K2的状态是低电平的时候,取一段及短的时间再判断K3的状态,若K3的状态是低电平,则是方向1,若K3的状态是高电平,则是方向2。卡死的状态变化通过标志位KUO以及累加COUT来判断。

读取程序如下:

u8 ENCODER_READ(void){ //接口初始化
	u8 a;//存放按键的值
	u8 kt;
	a=0;
	if(GPIO_ReadInputDataBit(ENCODER_PORT_A,ENCODER_L))KUP=0;	//判断旋钮是否解除锁死
	if(!GPIO_ReadInputDataBit(ENCODER_PORT_A,ENCODER_L)&&KUP==0){ //判断是否旋转旋钮,同时判断是否有旋钮锁死
		delay_us(100);
		kt=GPIO_ReadInputDataBit(ENCODER_PORT_B,ENCODER_R);	//把旋钮另一端电平状态记录
		delay_ms(3); //延时
		if(!GPIO_ReadInputDataBit(ENCODER_PORT_A,ENCODER_L)){ //去抖
			if(kt==0){ //用另一端判断左或右旋转
				a=1;//右转
			}else{
				a=2;//左转
			}
			cou=0; //初始锁死判断计数器
			while(!GPIO_ReadInputDataBit(ENCODER_PORT_A,ENCODER_L)&&cou<60000){ //等待放开旋钮,同时累加判断锁死
				cou++;KUP=1;delay_us(20); //
			}
		}
	}
	if(!GPIO_ReadInputDataBit(ENCODER_PORT_A,ENCODER_D)&&KUP==0){ //判断旋钮是否按下  
		delay_ms(20);
		if(!GPIO_ReadInputDataBit(ENCODER_PORT_A,ENCODER_D)){ //去抖动
			a=3;//在按键按下时加上按键的状态值
			//while(ENCODER_D==0);	等等旋钮放开
		}
	}
	return a;
} 
其中delay_us(100)是等待一小段时间,等待稳定之后检测K3的按键值,另外delay_ms(3)是消抖函数,因为在电平的变化时,会产生抖动,消抖之后如果仍然有效,则给相应的按键赋值。其中最后一段的锁死判断程序用了两个&&,即同时起作用,第一个条件是等待旋转之后的自动弹起,当弹起时,直接退出while语句这时KUP标志位为1,注意此时是正常的状态,通过单片机的不断扫描,下一次再进入读取函数后会通过第一个判断语句,将KUP清为0,如果真的是锁死状态则第一个条件恒为真,执行第二个为真的条件,这时延时大概1.2秒之后退出了循环(正常情况下,旋转的弹起时间必然小于1.2秒),这时仍然是锁死状态,单片机再次进入读取函数时KUP不会被清为0(因为锁死状态不满足if语句),因为一个KUP=1,所以以后的读取函数所有的语句都不被执行,这时单片机处于不被卡死的状态,即完成了卡死的程序处理。

主函数实例如下:

int main (void){//主程序
	u8 a=0,b=0,c=0x01;
	RCC_Configuration(); //系统时钟初始化 
	RTC_Config();  //RTC初始化

	ENCODER_Init(); //旋转编码器初始化

	TM1640_Init(); //TM1640初始化
	TM1640_display(0,a/10); //显示数值
	TM1640_display(1,a%10);
	TM1640_display(2,20);
	TM1640_display(3,20);
	TM1640_display(4,20);
	TM1640_display(5,20);
	TM1640_display(6,20);
	TM1640_display(7,20);

	while(1){
		b=ENCODER_READ();	//读出旋转编码器值	
		if(b==1){a++;if(a>99)a=0;} //分析按键值,并加减计数器值。
		if(b==2){if(a==0)a=100;a--;}
		if(b==3)a=0;
		if(b!=0){ //如果有旋转器的操作
			TM1640_display(0,a/10); //显示数值
			TM1640_display(1,a%10);
		}

//		TM1640_led(c); //与TM1640连接的8个LED全亮
//		c<<=1; //数据左移 流水灯
//		if(c==0x00)c=0x01; //8个灯显示完后重新开始
//		delay_ms(150); //延时
	}
}
这里需要注意的是,如果同时将下面的流水灯程序打开之后,因为延时函数的存在,会使得旋转按钮便的不灵敏,这是因为延时函数占用了CPU空间,从而使得扫描的频率变慢,使得灵敏度降低,解决的方法有两种。1、在延时函数中加入读取按键旋转的函数,同时扫描读取显示即可。2、将K2开关接入外部中断触发,即将读取函数放入中断函数,一旦旋转按钮,则直接从延时函数进入中断读取,进而判断扫描显示,这也是方法2的优势,只占用了一个中断资源。

图中所有图片出自洋桃电子。

你可能感兴趣的:(STM32学习100步之第四十七-四十八步——旋转编码器驱动程序)