音响设备的音量调节,以往通常采用电位器,通过可调电位器阻值大小,调节电流的大小,控制音量大小;

而编码器 (encoder) 是将 **信号 **或 数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。更多用于频段选择,场景识别等应用。

目前,很多高端音响功放等设备都采用了 旋转编码器 来实现音量大小的调节。

那么, 编码器如何实现音量调节?

简而言之,旋转编码器 通过与 单片机(MCU) 的配合使用,可实现音量大小的调节。

原理如图所示:

当 顺时针旋转 编码器时,编码器 A端子 的输出信号A 信号相位超前;

当 **逆时针旋转 **编码器时,编码器 B端子 的输出信号B 信号相位超前;

我们把 A/B端信号 分别接到 MCU的 两个输入端口 ,同时在MCU内 设置一个音量计数器

就可以用软件来判别编码器是 顺时针旋转 还是 逆时针旋转;

通过此方法来识别是增加还是减少音量计数器的值,

最后把这个计数值送到相应的电子音量控制芯片即可实现音量(或者其他需要增量/减量的)控制。

编码器一般音量调节操作

1.机械的编码器要24脉冲/每转,牵强能够分辩3到4种速度(每隔100ms核算一次速度),机械的缺陷是有毛刺,并且寿命短,通常在1万转左右,不过LJV旋转编码器通常为30000次。

由于旋转编码器的寿命长达几十万次之多,比普通的电位器使用寿命长很多,还不会因为机械的磨损导致阻值偏差,影响音响设备声音正常输出,调节精度取决于与MCU配合的音量控制芯片的控制级数,与旋转编码器本身无关,这也是普通一般电位器无法做到的。2.期望编码器每转的脉冲越多越好,LJV的编码器和旋转编码器脉冲都许多,并且性价比很高。

编码器音量调节图

3.需求旋转编码器的旋转速度快,调理就快相反速度慢,调理就慢。

旋转编码器检测转变方向的电路,在检测转变方向时,用数字输出检测马达轴旋转,方向的传感器,输出相位相差90℃的两相(A相和B相)数字信号,使用两相信号检测出现在方向,对每个A相和B相信号的各沿(前沿和后沿)外加时标脉冲,脉冲的前沿同步输出旋转方向检测信号。

http://www.crystalradio.cn/thread-1419316-1-1.html



#include <reg52.h>


sbit     BMA    = P1^4;	// 编码开关A引脚


sbit     BMB    = P1^5;	// 编码开关B引脚


sbit     BMC    = P1^6;	// 编码开关 下按引脚





unsigned char  display[3];


unsigned char  code  LEDData[ ] = { 


   0xC0,0xF9,0xA4,0xB0,0x99,0x92,


   0x82,0xF8,0x80,0x90,0xff


}; 


unsigned char  counter = 0;     //编码器脉冲计数 


unsigned char  n,shift;





/**********************************************************	  


ms延时子函数


**********************************************************/


void delayms(unsigned int ms)


{


  	unsigned char k; 


	while (ms--)


	{


	    for (k = 0; k < 114; k++) 


		;


	}


}





/**********************************************************	 


扫描编码器子函数  


在编码器 引脚A 为 低电平期间:


  编码器 引脚B 从0到1为 正转,编码器引脚 B从1到0为 反转。


**********************************************************/


void scan_encoder(void) 


{ 


   	static  bit  Curr_b;  //定义一个变量来储存 当前B 信号 


   	static  bit  Last_b;  //定义一个变量来储存 上次B脚 信号 


   	static  bit  update= 0;





   	if( BMA && BMB)           //编码器无转动退出


   	{


     	update = 0; 


     	return;


   	}





   	Last_b = BMB;       	//记录B信号





   	while(!BMA)         	//等待 A由低变高


   	{ 


     	Curr_b = BMB;     	//记录等待期间的B信号(指当前B信号)


     	update = 1;


   


   	 	if(!BMC)           //当按下旋钮时


     	{


       		counter = 0;   //计数单元清零(归位)


       		delayms(10);


     	}   


   	} 





   	if(update)


   	{


   		update = 0 ;


	    if( (Last_b == 0)&&(Curr_b== 1) ) 		//B从0到1为正转


	    { 


	   		if(counter == 255)


	   		{


	   			return;


			}	   


	       counter++;          //正转计数加


	    } 


	    else if((Last_b == 1)&&(Curr_b == 0)) //B从1到0为反转


	    { 


		    if(counter == 0)


		    {


		       	return;


			}   


		    counter--;         //反转计数减


	    } 


   	}


}





/**********************************************************	 


主函数		 


**********************************************************/


void  main(void)


{


   P0 = 0xff;


   P1 = 0xff;


   P2 = 0xff;





   T2CON = 0x00;               	// 设置T2CON寄存器   


   TH2 = 0xfc;                 	// 1ms定时


   TL2 = 0x66;


   ET2 = 1;                    	// 启用Timer2中断


   EA = 1;                     	// 总中断允许


   TR2 = 1;                    	// 启动 定时器2


   counter = 0;                	// 计数单元清零





   while(1)


   { 


   	  scan_encoder();


      if(!BMC)                	//当按下旋钮时


      {


        counter = 0;            	//计数单元清零(归位)


        delayms(10);


      } 


    }


}





/*********************************************************	 


Timer2中断函数	   


**********************************************************/


void  timer2() interrupt 5 


{ 


	TR2 = 0;


   	TF2 = 0;                         //手工清中断标志  


   	TH2 = 0xfc;                      //1ms定时常数


   	TL2 = 0x66;





   	if(n >= 3)                       //3位数码管显示


   	{


     	n = 0;


     	shift = 0x7f;                  //送位码初值


     	P2 = 0xff;                     //关闭显示


   	}


   	else


   	{


     	display[0] = counter%10;       //个位数据


     	display[1] = (counter%100)/10; //十位数据


     	display[2] = counter/100;      //百位数据


   


     	if(display[2] == 0)


     	{


       		display[2] = 0x0a;           //百位为0,不显示


       		if(display[1] == 0)


       		{


       			display[1]  =0x0a;           //十位为0,不显示   


			}   


		}





     	P0 = LEDData[display[n++]];    //送段码


     	P2 = shift;                    //送位码


     	shift = (shift>>1)|0x80;       //调整位码


   	}


   	TR2 = 1;


}





/*********************************************************/