【单片机】数字电位器(旋转编码器)检测程序

数字电位器(旋转编码器)就是下面这个,示波器等仪器上用的很多,手感很好。

这种编码器的原理和电机的AB相增量式编码器原理是一样的,参考之前文章《【机械自动化】旋转编码器》

这种编码器的检测不需要在意换向(旋转方向改变)时的抖动问题,这里只要检测到上图表中的A相跳变的情况,也就是第1/3/6/8四栏中的情况即可,为了不会漏检,可以使用中断检测A相的上升下降沿,同时判断B相的电平状态,如下程序为测试程序。需要注意的是这种数字电位器(旋转编码器)的每相信号的跳变是有抖动的(不是指换向过程的抖动,换向的抖动是正常抖动,这里的抖动是物理电气特性导致的无用甚至有害的“杂波”),和按键抖动一样,需要进行去抖操作,如下图。

程序中GPIO_Pin_5为A相,GPIO_Pin_6为B相,设置GPIO_Pin_5为上升下降沿中断触发,进入中断程序之后先进行去抖动,然后先判断A相是否有变化(上升沿或下降沿),然后在进行具体情形的检测。不需要检测B相的上升沿或下降沿,同时检测A相和B相的变化是为了检测到换向的抖动,多用于电机编码器,这里没必要。

void EXTI4_15_IRQHandler(void)
{
	if(EXTI->PR & EXTI_Line5)
	{
		//每一相脉冲都可能有抖动,类似于按键的抖动
		//需要在软件上将抖动过滤掉,延时放在最前面。
		delay_us(1000);	//去抖动,放在中断处理的最前面!
		
//		printf("r");
		now = GPIOA->IDR & (GPIO_Pin_5 | GPIO_Pin_6);
		if((last & GPIO_Pin_5) != (now & GPIO_Pin_5))	//A相变化
		{
//			printf("s");
			if((now & (GPIO_Pin_5 | GPIO_Pin_6)) == B00100000)
			{
//				printf("a");
				count++;
			}
			else if((now & (GPIO_Pin_5 | GPIO_Pin_6)) == B01100000)
			{
//				printf("b");
				count--;
			}
			else if((now & (GPIO_Pin_5 | GPIO_Pin_6)) == B01000000)
			{
//				printf("c");
				count++;
			}
			else if((now & (GPIO_Pin_5 | GPIO_Pin_6)) == B00000000)
			{
//				printf("d");
				count--;
			}
			last = now;
//			printf("%d\r\n",count);
		}
		
		EXTI->PR = EXTI_Line5;
		
	}
	else if(EXTI->PR & EXTI_Line6)
	{
		//B相不用检测,因为这里和电机编码器不同
		//不需要关心换向时的抖动,有点错误没关系
		EXTI->PR = EXTI_Line6;
	}
}

为了实现速率控制(velocity control),也就是转的越快,增长(降低)速度越快,绝大部分示波器都有这个功能,可以检测两次脉冲间的时间间隔,如果时间间隔较大,则增长速率为1,如果时间间隔较小,则可以根据时间间隔大小适当调整增长速率,如下测试程序中,使用一个1ms的定时器产生一个时钟计数器,定时器中断中简单地增加计数即可,不用管溢出情景,因为溢出对这里没什么大影响。

void EXTI4_15_IRQHandler(void)
{
	if(EXTI->PR & EXTI_Line5)
	{
		//每一相脉冲都可能有抖动,类似于按键的抖动
		//需要在软件上将抖动过滤掉,延时放在最前面。
		delay_us(1000);	//去抖动,放在中断处理的最前面!
		
		now = GPIOA->IDR & (GPIO_Pin_5 | GPIO_Pin_6);
		if((last & GPIO_Pin_5) != (now & GPIO_Pin_5))	//A相变化
		{
			int delta = syscount - syscount_last;	//计算两次有效脉冲的时间间隔
			if(delta > 10)	//根据时间间隔设置增长速率
				delta = 1;
			else
				delta = 20 - delta;    //修改这里的速率和时间间隔关系改变体验

			if((now & (GPIO_Pin_5 | GPIO_Pin_6)) == B00100000)
			{
				count += delta;
			}
			else if((now & (GPIO_Pin_5 | GPIO_Pin_6)) == B01100000)
			{
				count -= delta;
			}
			else if((now & (GPIO_Pin_5 | GPIO_Pin_6)) == B01000000)
			{
				count += delta;
			}
			else if((now & (GPIO_Pin_5 | GPIO_Pin_6)) == B00000000)
			{
				count -= delta;
			}
			last = now;
			syscount_last = syscount;
		}
		
		EXTI->PR = EXTI_Line5;
		
	}
	else if(EXTI->PR & EXTI_Line6)
	{
		//B相不用检测,因为这里和电机编码器不同
		//不需要关心换向时的抖动,有点错误没关系
		EXTI->PR = EXTI_Line6;
	}
}

//1ms中断定时器
void TIM16_IRQHandler(void)
{
	if (TIM16->SR & TIM_IT_Update)
	{
		syscount++;
	}

//	TIM16->SR = (uint16_t)~TIM_FLAG_Update;
	TIM16->SR = (uint16_t)0;	//清除所有标志位
}

测试主函数可以显示增长速度。

	int last = count;
	while(1)
	{
		if(last != count)
		{
			printf("%d,%d\r\n",count,count-last);
			last = count;
		}
	}

测试结果:

扫描二维码关注公众号,回复: 12921745 查看本文章

但是,这种检测方式还是比较复杂的,在中断中需要进行延时去抖动,还需要判断多种情形,这样会使得中断频率过快的时候丢步。为了简化检测程序,只需要检测在A相的上升沿中断产生的时候,判断B相的电平状态即可,这种做法虽然会丢失一些情况的检测,但是处理速度快,反而会提高检测速度,示例程序:

void EXTI0_1_IRQHandler(void)
{
	//每一相脉冲都可能有抖动,类似于按键的抖动
	//需要在软件上将抖动过滤掉,延时放在最前面。
//	delay_us(1000);	加上0.1uF滤波电容可以去掉抖动了//去抖动,放在中断处理的最前面!
	
	//尽量减少操作,减少丢步
		
	if(ENCODER_AB_PORT->IDR & ENCODER_B_PIN)
		encoder_count --;
	else 
		encoder_count ++;
	EXTI->PR = EXTI_Line0;
}

速率检测部分的代码也可以不在中断中做,可以在主程序中计算相邻两次计数值变化的时间差来推导速率。另外在编码器的A、B相和地端接上一个陶瓷电容,用于去除抖动,这样就无需在中断中做延时这样耗CPU的工作了,简化A、B电路为按键电路示意如下(使用的单片机内部上拉电阻约为40K):

C1取0.1uF,示波器测量IO的波形:​​

放大下降边沿波形,可以看出没有抖动了,而且下降时间也很短,因为按下按键是直接短路电容,放电时间短:

放大上升边沿波形,典型的RC充电波形:

RC = 40K * 0.1uF = 4ms;

当t= RC时,电容电压=0.63E;

当t= 2RC时,电容电压=0.86E;

当t= 3RC时,电容电压=0.95E;

当t= 4RC时,电容电压=0.98E;

当t= 5RC时,电容电压=0.99E;

所以当松开按键4ms之后,电容电压应该为 0.63E = 0.63 * 3.16 = 1.99V,如下图,△V = 1.96V,由于有抖动,可能会造成实际值和计算值有误差,但是这里差距很小了。

改变电容C1为1uF,测量波形,RC = 40K * 1uF = 40ms,测量结果很接近:

但是这个波形使用逻辑分析仪抓取出来的结果很奇怪:

上升沿尽然有毛刺出现:

可能是逻辑分析仪的采样方式和示波器不同导致RC充电曲线被逻辑分析仪误认为是毛刺信号,这时候看出来示波器的好处了。

如果C1的取值过大(或者内部上拉电阻过高),导致放电时间过长,这时候会导致连续按按键会检测不到,因为电容还没有充电至高电平电压的时候又按下按键,这时候并不会产生一个有效的下降沿中断,所以按键检测就会丢失。如果C1的取值过小,RC时间和按键抖动时间处于同一数量级的话,会导致抖动过滤效果不佳。

 

 

猜你喜欢

转载自blog.csdn.net/tq384998430/article/details/104542986