搜索
bottom↓
回复: 103

【开源项目】单片机在音响上的应用(一)旋转编码器的解码

  [复制链接]

出0入0汤圆

发表于 2010-8-25 20:36:53 | 显示全部楼层 |阅读模式
作者:sword__yang
      【导语】:高端的音响设备目前已经大量采用了先进的控制技术,其中使用单片机(MCU)控制是必不可少的,举凡遥控、显示、电子音量控制等都离不开单片机。本文拟通过几个单片机的应用实例来和大家分享一下自己的DIY心得。(文中所有的程序实例都已经在PIC16F873A单片机上通过实验的检验)。
     本文共有4个部分:
一、旋转编码器的解码
二、电子音量控制
三、荧光显示VFD、按键控制
四、红外遥控解码

音响应用之一:旋转编码器的解码
      旋转编码器(外形参见图II-1.0)在音响中多用于取代普通的滑动电阻电位器作为音量/音调控制的编码输入。它使用寿命长达100万次,比普通电位器长得多,而且不会因为机械磨损造成阻值的偏差,影响声道的平衡。其调节的精度仅仅取决于与MCU配合的音量控制芯片的控制级数,与本身的旋转角度无关,这也是普通电位器无法做到的,因此旋转编码器也大量地用于精密仪器的调节上。
      旋转编码器内部就是两个长寿命开关,可以根据旋转方向产生不同相位信号。电路如图II-1.1所示:当我们顺时针旋转时,开关A的输出信号A signal相位超前;如果我们逆时针旋转时,则是开关B的输出信号B signal相位超前,我们把A/B端分别接到MCU的两个输入端口,并在MCU内设置一个音量计数器;就可以用软件来判别是顺时针旋转还是逆时针旋转,以此判断是增加还是减少音量计数器的值,最后把这个计数值送到相应的电子音量控制芯片就可以实现音量(或者其他需要增量/减量的)控制了。
      由于旋转编码器是随时改变的,我们的软件也要能够跟踪各个瞬时的状态变化,为了判断旋转编码器的相位我们还需要用三个标志位(Bit变量)来记住开关A,B的“瞬时状态”。

(原文件名:1.jpg)


(原文件名:2.jpg)



      旋转编码器的解码例程如下:
     【说明】: Bit变量定义:状态1:FLG0,ECA 当开关A变高,B变低时,置位(设为1),为即将到来的增量做准备;状态2:FLG0,ECB 当开关A变低,B变高时,置位(设为1),为即将到来的减量做准备;状态3:FLG0,ECV: 当完成一次增加/减少时,置位(设为1),相位变动一次,只做一次增/减量;变量寄存器:VOLUE 用来保存音量变化数值。 16F873A的I/O端口B: VOA:连接到编码器的A端子; VOB:连接到编码器的B端子。
;======================================
VOLUME_CONTROL:
      BTFSC   FLG0,ECA                                      ; “状态1”检测:若已经满足了状态1,就去查看开关B是否变高
      GOTO    KE_1E
      BTFSC   FLG0,ECB                                      ; “状态2”检测:若已经满足了状态2,就去查看开关A是否变高
      GOTO    KE_1F
      BTFSS   PORTB,VOA                                   ; “IN A”检测   
      GOTO    KE_1B
KE_1A:
      BTFSC   PORTB,VOB                                  ; “IN B”检测
      GOTO    KE_1D
      BTFSC  FLG0,ECV
      GOTO   KE_EX
      BSF        FLG0,ECA                                      ; 满足“状态1”的设置条件
      GOTO    KE_EX
KE_1B:
      BTFSC   PORTB,VOB
      GOTO    KE_1C
      BCF        FLG0,ECV                                       ; 清除“状态3”
      GOTO     KE_1D
KE_1C:
      BTFSC   FLG0,ECV
      GOTO    KE_EX
      BSF        FLG0,ECB                                       ; 满足“状态2”的设置条件
      GOTO    KE_EX
KE_1D:
       BCF       FLG0,ECA
       BCF       FLG0,ECB
       GOTO    KE_EX
KE_1E:
        BTFSS  PORTB,VOB                                      ; “状态1”下,开关B变高?
        GOTO   KE_EX
INC_VOL:
        BCF       FLG0,ECA                                         ; 是的,完成一次增量, 清除“状态1”
        BCF       FLG0,ECB                                         ; 清除“状态2”
        BSF       FLG0,ECV                                         ; 设置“状态3”
        INCF      VOLUE,F                                           ; 音量寄存器加1
        GOTO   KE_EX
KE_1F:
        BTFSS   PORTB,VOA                                     ; “状态2”下,开关A变高?
        GOTO    KE_EX
DEC_VOL:
        BCF        FLG0,ECA                                        ; 是的,完成一次减量,清除“状态1”
        BCF        FLG0,ECB                                        ; 清除“状态2”
        BSF        FLG0,ECV                                        ; 设置“状态3”
        DECF VOLUE,F                                               ; 音量寄存器减1
KE_EX:
        RETURN
;=====================================
;开关的瞬时位置比较抽象,大家要对比波形图和软件的状态去加深理解。

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

发表于 2010-8-25 21:15:03 | 显示全部楼层
顶下杨老师~
前段时间有用过旋转编码器,在网上搜索到您的这篇文章

出0入0汤圆

 楼主| 发表于 2010-8-25 21:19:25 | 显示全部楼层
回复【1楼】spely 潮水的眼睛
顶下杨老师~
前段时间有用过旋转编码器,在网上搜索到您的这篇文章
-----------------------------------------------------------------------

呵呵,这是我原先为某杂志写的一篇专稿,如果能对你有点帮助就算不虚此举了。

出0入0汤圆

发表于 2010-8-25 21:19:38 | 显示全部楼层
这种旋转编码器还是机械结构的.
如果使用光电的话,寿命会更长,噪音会更小.不过就是价格会贵很多.

出0入0汤圆

发表于 2010-8-25 21:55:54 | 显示全部楼层
论坛曾经讨论过这个
我也用过,很不错,几元一个,比较便宜

出0入0汤圆

发表于 2010-8-25 23:03:29 | 显示全部楼层
好文章,谢谢杨老师。

出0入0汤圆

 楼主| 发表于 2010-8-26 10:00:23 | 显示全部楼层
回复【5楼】cjr82123
好文章,谢谢杨老师。
-----------------------------------------------------------------------

谢谢!

出0入0汤圆

发表于 2010-9-6 13:40:46 | 显示全部楼层
发现了胆艺轩。呵呵。

出0入0汤圆

发表于 2010-9-7 22:50:17 | 显示全部楼层
that's too complicated.

here is mine:

========code============
//determine increment / decrement of the encoder
unsigned char encoder_read(PORT_TYPE port, PORT_TYPE pins) {
        const signed char KEY_AB_states[]={0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
        static unsigned char encoder_output=0x00;
        static unsigned char KEY_AB=0x00; //AB key read out, Previous in the high 2 bits and current in the low two bits;
        unsigned char tmp;
       
        KEY_AB <<=2; //bit 2..3 now contain the previous AB key read-out;
        tmp=IO_GET(port, pins); //read ab pins
        if (tmp & KEY_A) KEY_AB |= 0x02; //set the 1st bit if A is high now;
        if (tmp & KEY_B) KEY_AB |= 0x01; //set the 0th bit if B is high;
        KEY_AB &= 0x0f; //only retain KEY_AB' last 4 bits (A_previous, B_previous, A_current, B_current)
        encoder_output += KEY_AB_states[KEY_AB];
        return encoder_output;                                //if you want to return absolute steps.
        //return KEY_AB_states[KEY_AB];                //if you want to return relative steps (+1=clock-wise, 0, -1=counter clock-wise).
}
=========end==============

出50入0汤圆

发表于 2010-10-20 09:45:21 | 显示全部楼层
好贴,mark备用。

出0入0汤圆

发表于 2010-10-25 03:51:09 | 显示全部楼层
上面的C 语言看不明白, 我还是菜鸟

出0入0汤圆

发表于 2010-10-25 04:56:05 | 显示全部楼层
//a相接单片机外部中断,下降沿触发
void __irq EINT0IRQ (void)
{

        UINT32 pina,pinb;       

       
          while((EXTINT & 0x01) != 0)
                EXTINT = 0x01;

        pina=pinb=0;
       
        delay();  //延迟是为了去抖动       
        pina =  fgpio_read(CODINGA);
        pinb = fgpio_read(CODINGB);


        if (pina) { //下降沿触发,如果反而读到高电平,则作为抖动处理
       
        //        printf("noise!\n ");
                VICVectAddr = 0;
                return;
        }
       
        if (0==pinb){     //如果b相为低电平,则是正向转动
                pulse++;
        }
        else if (pulse>0){ //如果b相为高电平,则是反向转动
                pulse--;
        }
        VICVectAddr = 0;
}


发源代码上来是为了让大家帮我看看,有错误没有?因为我在本站上看到的关于旋转编码器的源代码都比较复杂,导致我对自己的代码不相信了。
请大家帮我看看,我这个对么?
我将a相接到单片机的一个外部中断口线,设置为下降沿触发。
a相处于下降沿的时候,如果b相为低电平,则是正向转动,如果b相为高电平,则是反向转动。
我已经应用了,看起来好像是正确的。

出0入18汤圆

发表于 2010-10-25 09:44:01 | 显示全部楼层
这个旋转编码器我买了几个哟 感觉不错!!!

出0入97汤圆

发表于 2010-11-18 17:52:01 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-18 18:18:29 | 显示全部楼层
Make

出0入0汤圆

发表于 2010-11-18 21:42:10 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-27 09:54:59 | 显示全部楼层
旋转编码判断,不错

出0入0汤圆

发表于 2010-11-27 11:29:28 | 显示全部楼层
顶,正搞这个东西...记号..

出0入0汤圆

发表于 2010-11-27 12:16:07 | 显示全部楼层
顶起,最近在看春风电源,有用到这个,刚好买了两个回来,还没有开始研究呢,现在看到这贴,收益了。谢谢楼主。

出0入0汤圆

发表于 2010-11-27 12:37:49 | 显示全部楼层
马克.

出0入0汤圆

发表于 2010-11-27 12:46:39 | 显示全部楼层
学习一下,
有玩过,但出来的效果不好,
普通的旋转编码很容易坏,有看到过用普通42步进电机作编码开关用的,手感不错,寿命当然没话说了

出0入0汤圆

发表于 2010-11-27 13:25:29 | 显示全部楼层
我也和11楼一样用的

出0入0汤圆

发表于 2010-11-27 13:54:28 | 显示全部楼层
学习一下,

出0入4汤圆

发表于 2010-11-27 18:25:54 | 显示全部楼层
顶,好方法

出0入0汤圆

发表于 2011-1-6 12:09:55 | 显示全部楼层
请问这种可以倍频嘛???

出0入0汤圆

发表于 2011-1-6 12:29:18 | 显示全部楼层
mark!~

出0入0汤圆

发表于 2011-4-15 08:46:09 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-4-15 09:54:22 | 显示全部楼层
记号

出0入0汤圆

发表于 2011-4-15 18:33:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-15 20:43:50 | 显示全部楼层
记号~~

出0入0汤圆

发表于 2011-4-15 22:15:41 | 显示全部楼层
mark

出0入228汤圆

发表于 2011-4-15 22:44:01 | 显示全部楼层
回复【20楼】xiaowu191 小屋
学习一下,
有玩过,但出来的效果不好,
普通的旋转编码很容易坏,有看到过用普通42步进电机作编码开关用的,手感不错,寿命当然没话说了
-----------------------------------------------------------------------

今天还看到有人用步进电机做风力发电机呢

出0入0汤圆

发表于 2011-5-12 23:33:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-17 13:56:18 | 显示全部楼层
不错的资料,mark

出0入0汤圆

发表于 2011-5-17 14:10:35 | 显示全部楼层
收藏

出0入0汤圆

发表于 2011-5-17 17:23:22 | 显示全部楼层
shoucang

出0入42汤圆

发表于 2011-5-17 18:48:37 | 显示全部楼层
回复【20楼】xiaowu191  小屋
-----------------------------------------------------------------------
曾经在小批量的仪器上用过,好像没反馈多容易坏啊
他们是做学生仪器用的,环境应该比较严酷才是,学生各种乱拧之类的

步进电机就好多了,手感可真是没得说,尤其是配个超大的旋钮的时候,就是成本太高了点……

出0入0汤圆

发表于 2011-5-17 19:03:48 | 显示全部楼层
旋转编码器原理构析,直观

出0入0汤圆

发表于 2011-5-21 17:00:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-21 23:05:37 | 显示全部楼层
Mark.

出0入0汤圆

发表于 2011-5-22 00:19:19 | 显示全部楼层
mark

出0入4汤圆

发表于 2011-5-22 01:52:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-24 08:40:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-25 22:47:23 | 显示全部楼层
回复【8楼】millwood0
-----------------------------------------------------------------------

试用了8楼的代码,工作正常但未弄清楚原理,不管如何先谢谢了

出0入0汤圆

发表于 2011-5-25 23:09:40 | 显示全部楼层
学习

出0入0汤圆

发表于 2011-5-30 02:32:32 | 显示全部楼层
mark
头像被屏蔽

出0入0汤圆

发表于 2011-5-31 15:56:45 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-31 17:44:22 | 显示全部楼层
入门知识,好好学习.

出0入0汤圆

发表于 2011-5-31 17:58:35 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-3 12:12:44 | 显示全部楼层
回复【44楼】mowin 雾湾
-----------------------------------------------------------------------
试用了8楼的代码,工作正常但未弄清楚原理,不管如何先谢谢了
-----------------------------------------------------------------------

工作正常,怎样正常?例如高速、低速、极低速、快速正反转等效果怎样?

最近做收音机,想用编码器调频率,所以想研究研究。自己写的目前效果一般,还不满意。

出0入0汤圆

发表于 2011-6-3 12:34:06 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-7 15:19:20 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-21 12:49:21 | 显示全部楼层
学习!!!

出0入0汤圆

发表于 2011-6-24 18:09:39 | 显示全部楼层
Reading Rotary Encoders

here's my first contribution to this wiki. I hope this is the right place for it.

(原文件名:alps_stec12e07_encoder.jpg)
A rotary or "shaft" encoder is an angular measuring device. It is used to precisely measure rotation of motors or to create wheel controllers (knobs) that can turn infinitely (with no end stop like a potentiometer has). Some of them are also equipped with a pushbutton when you press on the axis (like the ones used for navigation on many music controllers). They come in all kinds of resolutions, from maybe 16 to at least 1024 steps per revolution, and cost from 2 to maybe 200 EUR.
I've written a little sketch to read a rotary controller and send it's readout via RS232.
It simply updates a counter (encoder0Pos) every time the encoder turns by one step, and sends it via serial to the PC.
This works fine with an ALPS STEC12E08 encoder which has 24 steps per turn. I can imagine it could fail with encoders with higher resolution, or when it rotates very quickly (think: motors), or when you extend it to accomodate multiple encoders. Please give it a try.
I learned about how to read the encoder from the file encoder.h included in the arduino distribution as part of the AVRLib. Thanks to its author, Pascal Stang, for the friendly and newbie-proof explanation of the functionings of encoders there. here you go:
/* Read Quadrature Encoder
  * Connect Encoder to Pins encoder0PinA, encoder0PinB, and +5V.
  *
  * Sketch by max wolf / www.meso.net
  * v. 0.1 - very basic functions - mw 20061220
  *
  */  


int val;
int encoder0PinA = 3;
int encoder0PinB = 4;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;

void setup() {
   pinMode (encoder0PinA,INPUT);
   pinMode (encoder0PinB,INPUT);
   Serial.begin (9600);
}

void loop() {
   n = digitalRead(encoder0PinA);
   if ((encoder0PinALast == LOW) && (n == HIGH)) {
     if (digitalRead(encoder0PinB) == LOW) {
       encoder0Pos--;
     } else {
       encoder0Pos++;
     }
     Serial.print (encoder0Pos);
     Serial.print ("/");
   }
   encoder0PinALast = n;
}
Oh, a few notes:
encoder0Pos will be counting forever, that means that if you keep turning into the same direction, the serial message will become longer (up to 6 characters), costing more time to transmit.
you need to make sure yourself (on the PC side) that nothing bad happens when encoder0Pos overflows - if the value becomes larger than the maximum size of an INT (32,767), it will flip to -32,768! and vice versa.
suggestion for improvement: make it spit out the counter only when it is polled from the PC. Count only the relative change of the encoder between two polls.
obviously, if you add more code to the loop(), or use higher resolution encoders, there is a possibility that this sketch will not see every individual step. The better way of counting encoder steps is to use an interrupt on every flank of the signal. The library I mentioned above does just that, but currently (2006-12) it doesn't compile under the arduino environment - or I just don't know how to do so...
I'm not sure about the etiquette of this, but I'm just going to add onto this tutorial. Paul Badger
Below is an image showing the waveforms of the A & B channels of an encoder.

(原文件名:RotaryEncoderWaveform.gif)

<a href=http://arduino.cc/playground/Main/RotaryEncoders>  更多

出0入0汤圆

发表于 2011-6-24 22:57:44 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-6-28 22:43:59 | 显示全部楼层
也准备上这个,但是一般是五个脚得嘛

出0入0汤圆

发表于 2011-6-28 22:52:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-3 15:56:53 | 显示全部楼层
void int1_isr(void)
{
//external interupt on INT1
unsigned char enc_b;
unsigned char i;
//delay_ms(1);
if((PIND&ENC_A_BIT)==0)
{
   delay_ms(50);
   enc_b=PIND&ENC_B_BIT;
   if (enc_b)
    {
           putchar(ENC_UP);
    }
   else
    {
          putchar(ENC_DOWN);
    }
};
}
汇编代码看不懂,自己写一个C的,用中断。比较简单的,能用了。

出0入0汤圆

发表于 2011-7-3 21:30:35 | 显示全部楼层
mark

出0入8汤圆

发表于 2011-7-3 23:01:35 | 显示全部楼层
回复【56楼】cgc_good  
也准备上这个,但是一般是五个脚得嘛
-----------------------------------------------------------------------

5个脚是多了向下按的按键

出0入0汤圆

发表于 2011-7-3 23:03:39 | 显示全部楼层
mark一下

出0入0汤圆

发表于 2011-7-25 16:34:51 | 显示全部楼层
我试验了上面几个旋转编码器的例子,包括16F的,汇编的,C语言的, 工作是能工作,但都没有去抖动.

出0入0汤圆

发表于 2011-7-25 17:09:49 | 显示全部楼层
//在24MHz下,延时常数, 51单片机, 如: STC89C52

#define TICKSCODE 100

sbit APIN = P3^3;
sbit BPIN = P3^7;



#define STA    0x10

#define CLKW   0x20
#define CCLKW  0x40
#define RDY    0x80

unsigned char flag=0;

/*
        flag:
                位0-3:        内部测试计数
                位4:         稳定标记
               
                位5:         正向旋转标记
                位6:        反向旋转标记
                位7:         应用标记         
*/


void VOLUME_CONTROL()  
{
        if (flag & CLKW)    //正向旋转,A低/B高
        {
                //连续测几次,防抖
                if ((flag & STA)==0)        //是否还不稳定
                {
                        if (APIN==0)        //脚A是低电平
                        {
                                flag++;
                                if (flag>=3)                //连续3次测试稳定(由于本程序使用环境包括键盘测试等,实际测试间隔比现在大)
                                        flag |= STA;        //置稳定标记,以防继续判断.
                                else
                                        return;                //继续测试
                        }
                        else                                //A脚变高电平,可能是抖动
                        {
                                flag &= 0xf0;                //清计数
                                 return;
                        }
               
                }
       
   
                if ( (flag & RDY)==0)                        //本次旋转还没有计数?
                {
                            //B脚变低了吗?

                        if (BPIN==1) return;                //没有反转,返回

                           //是的,一次增量

                        flag |= RDY;                         // 设置"状态"
                         
                        //安设定的音量间隔调整音量
                        /***
                        while (volume<VLEVELS-1)
                        {
                                volume++;
                                if (volInterval==1) break;
                                if (volumeDB[volume]/volInterval * volInterval==volumeDB[volume]) break;
                        }
                        vol_out();
                        ****/
                        volume++;

                }
                else  //等待B变高,完成一次完整的跳变
                {
                         if (APIN==0) return;
                         if (BPIN==0) return;
          
                        flag = RDY;
                }

                return;
        }

        if (flag & CCLKW)         //反向旋转,A高/B低
        {
                //连续测几次测试稳定,消抖
                if ((flag & STA)==0)
                {
                        if (BPIN==0)
                        {
                                flag++;
                                if (flag>=3)
                                        flag |= STA;
                                else
                                        return;
                        }
                        else
                        {
                                flag &= 0xf0;
                                 return;
                        }
                }

          
                if ((flag & RDY)==0)
                {
                        //A脚是否变低?
                        if ( APIN==1) return;                //没有反转,返回
       
                           // 是的,一次减量

                        flag |= RDY;                         // 设置"状态"  
                        /***
                        while (volume>0)
                        {
                                volume--;
                                if (volInterval==1) break;
                                if (volumeDB[volume]/volInterval * volInterval==volumeDB[volume]) break;
       
                        }
                        vol_out();
                        ***/

                }
                else        //等待A变高,完成一次完整的跳变
                {
                        if (APIN==0) return;
                         if (BPIN==0) return;

                        flag = RDY;
                }
                return;
            }  

        if (APIN==0)        //A脚检测
            {
                if (BPIN==1)
                {
                        if ((flag & RDY)==0)
                        {      
                                flag |= CLKW;         // A低,B高,正向旋转
                        }
                        return;
                }
             
                flag = 0;

                return;
        }
        else
        {
                if (BPIN == 0)                          //B脚检测
                {
                        if  ( (flag & RDY)==0)
                        {
                                flag |= CCLKW;          //B低, A高,反向旋转
                        }
                        return;
                }
                flag = 0;
                return;
        }         
}

void VOLUME_CONTROL() ;
void main()
{
        while(1)
        {
                scan_key();

                VOLUME_CONTROL();
        }
}

出0入0汤圆

发表于 2011-7-27 17:33:58 | 显示全部楼层
最近在用51单片机进行些爱好研究, 我在Taobao网上买了最小单片机系统, 矩阵键盘, LED数码管, LCD液晶屏, 旋转编码器, 想着设计我DIY的功放上的控制系统,本来是想用24档电阻音量电位器,但没有找到6声道的,于是就想用PGA2311,PGA4311等,或者用CS3310等, 为此也买了若干片IC, 但后来看到讨论,说这些IC有怎样怎样的不足,于是就想着自己DIY吧,反正DIY就是乐在行动的过程. 用CD4066? 自然不行,性能太差, SSM2404 又太贵, 最后查到了DG413, MAX314等, MAX314 还是很贵啊.最后在TB上买了60片DG413, 设计了20位 (2的20次方的控制级数)的音量控制板. 但在用CS51单片机时,发现I/O明显不足,当然换单片机是可以,但有得重新学习编程等, 想来想去,还是自己设计一个I/O扩展版吧,设计完了,希望以前我买过东东的TB店家能制作,供我辈来买,可是人家还得考虑利润和市场.

出0入0汤圆

发表于 2011-7-27 17:37:24 | 显示全部楼层
这个IO扩展版 7CM X 7CM, 用了6片CD4066, 一片74HC573, 若干排插, 成本几块钱, 要是个人单做,成本就比较高. 私下认为,这个IO版对开发单片机非常有帮助.

出0入0汤圆

发表于 2011-7-27 17:40:09 | 显示全部楼层

(原文件名:EI1.png)

出0入0汤圆

发表于 2011-7-27 17:55:00 | 显示全部楼层
有人在音响DIY上撰文, 说用16位(65536级)电子开关,实现了1分贝间隔,96级的音响音量控制,  且是用的 R-2R网络, 此说不正确或不当, 在开始的几级,其衰减分贝是:
1, i=     1,   -96  0.32960, -96.32960, 0.000015
  2, i=     2,   -90  0.30900, -90.30900, 0.000031
  3, i=     3,   -87  0.21283, -86.78717, 0.000046
  4, i=     4,   -84  0.28840, -84.28840, 0.000061
  5, i=     5,   -82  0.35020, -82.35020, 0.000076
  6, i=     6,   -81  0.23343, -80.76657, 0.000092
  7, i=     7,   -79  0.42764, -79.42764, 0.000107
  8, i=     8,   -78  0.26780, -78.26780, 0.000122
  9, i=     9,   -77  0.24475, -77.24475, 0.000137
10, i=     A,   -76  0.32960, -76.32960, 0.000153
11, i=     C,   -75  0.25403, -74.74597, 0.000183
12, i=     D,   -74  0.05073, -74.05073, 0.000198
13, i=     F,   -73  0.19223, -72.80777, 0.000229
14, i=    10,   -72  0.24720, -72.24720, 0.000244
15, i=    12,   -71  0.22415, -71.22415, 0.000275
16, i=    15,   -70  0.11479, -69.88521, 0.000320
17, i=    17,   -69  0.09504, -69.09504, 0.000351
18, i=    1A,   -68  0.03013, -68.03013, 0.000397
19, i=    1D,   -67  0.08164, -67.08164, 0.000443
只有在-68分贝后,才可实现-1分贝增量的衰减.

出0入0汤圆

发表于 2011-7-27 18:02:11 | 显示全部楼层
即使用20位电子开关, 实现-1 DB的衰减,在最初的几级也有0.1-0.2分贝的误差. 因此,如果不考虑在低端的几级音量跳跃,可以考虑用16位电子开关去控制R-2R网络, 如果想追求高精度,可以采用20位.  一片DG413 提供2个电子开关,20位就要10片 DG413, 这就是我说的用SSM2402/MAX314等很贵的原因. 如果是5声道,那就要 50片. 前几天去做了印板,还没到货.

出0入0汤圆

发表于 2011-9-20 10:15:17 | 显示全部楼层
回复【8楼】millwood0  
that's too complicated.
here is mine:
========code============
//determine increment / decrement of the encoder
unsigned char encoder_read(port_type port, port_type pins) {
        const signed char key_ab_states[]={0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
        static unsigned char encoder_output=0x00;
        static unsigned char key_ab=0x00; //ab key read out, previous in the high 2 bits and current i......
-----------------------------------------------------------------------

八楼 代码不错,简单明了。

A’ B’    A  B     
前1状态  当前状态    这4位二进制位 可表示16种状态,根据AB相相位,将判断结果预先存储在key_ab_states数组中,
                     1->顺时针,-1->逆时针,0->无效状态,再根据key_ab的值进行查找。

出0入0汤圆

发表于 2011-10-15 10:26:26 | 显示全部楼层
多谢楼主,刚买了几个旋转编码器,一直找不到应用资料,多谢楼主共享

出0入0汤圆

发表于 2011-12-6 09:33:02 | 显示全部楼层
8楼牛逼。

出0入0汤圆

发表于 2011-12-16 23:13:23 | 显示全部楼层
回复【11楼】drinker  
-----------------------------------------------------------------------

你们都太复杂了,mega16,8M,int1边沿触发,PD1用来做辅助的,用了一篇74HC14,

ISR(INT1_vect)
{        // PORTD 1,2,3 = Input,read PIND
        if (PIND & 0b00000010)
        {
                if (Volume > 0x00)
                        Volume -= Step ;
        }
        else
        {
                if (Volume < 0xFF)
                        Volume += Step ;
        }
        Int1_flag = TRUE;
}

出0入0汤圆

发表于 2012-1-12 10:19:37 | 显示全部楼层
学习一下

出0入0汤圆

发表于 2012-1-12 14:05:56 | 显示全部楼层
还可以使用AD功能实现

出0入0汤圆

发表于 2012-2-7 13:40:21 | 显示全部楼层
mark encoder

出0入0汤圆

发表于 2012-2-9 17:30:48 | 显示全部楼层
这个一定要顶,很好,

出0入0汤圆

发表于 2012-2-21 12:43:35 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-5-24 10:07:57 | 显示全部楼层
我正研究编码器呢。
编了段程序,但效果不好。
多学习。
谢谢分享

出0入0汤圆

发表于 2012-5-26 11:08:00 | 显示全部楼层
有C语言的么,汇编看不懂。初学者

出0入4汤圆

发表于 2012-5-26 13:46:42 | 显示全部楼层
旋转编码器顶一下,以后可能会用到

出0入0汤圆

 楼主| 发表于 2012-5-26 20:33:10 | 显示全部楼层
好老的帖子了。。。

出0入0汤圆

发表于 2012-5-26 20:39:31 | 显示全部楼层
mark  九楼的程序

出0入0汤圆

发表于 2012-5-26 21:15:01 | 显示全部楼层
本帖最后由 1ongquan 于 2012-5-26 21:18 编辑

that's too complicated.

here is mine:

========code============
//determine increment / decrement of the encoder
unsigned char encoder_read(PORT_TYPE port, PORT_TYPE pins) {
        const signed char KEY_AB_states[]={0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
        static unsigned char encoder_output=0x00;
        static unsigned char KEY_AB=0x00; //AB key read out, Previous in the high 2 bits and current in the low two bits;
/************************************************************************************************************/
        static long Tick_Cont_Sample;//抓取当前心跳计数
/************************************************************************************************************/
        unsigned char tmp;
        
        KEY_AB <<=2; //bit 2..3 now contain the previous AB key read-out;
        tmp=IO_GET(port, pins); //read ab pins
        if (tmp & KEY_A) KEY_AB |= 0x02; //set the 1st bit if A is high now;
        if (tmp & KEY_B) KEY_AB |= 0x01; //set the 0th bit if B is high;
        KEY_AB &= 0x0f; //only retain KEY_AB' last 4 bits (A_previous, B_previous, A_current, B_current)
        encoder_output += KEY_AB_states[KEY_AB];
        //return encoder_output;                                //if you want to return absolute steps.
        //return KEY_AB_states[KEY_AB];                //if you want to return relative steps (+1=clock-wise, 0, -1=counter clock-wise).

//下面是加入的加速键功能,有此函数科延长旋钮那可怜的寿命

        if(return KEY_AB_states[KEY_AB] != 0){
        tmp = Tick_Cont - Tick_Cont_Sample; //Tick_Cont 为系统节拍计数,或计时器,gloable variable
        Tick_Cont_Sample = Tick_Cont;       //刷新Tick_Cont_Sample
        if(tmp < Roltry_Fast_NUM)            //Roltry_Fast_Num为配置常量,当小于这个值时开始加速
            {return KEY_AB_states[KEY_AB]*Roltry_Fast_RATE; };//Roltry_Fast_RATE,加速的倍率
        else
             {return KEY_AB_states[KEY_AB]; };
        }
        else
             {return 0; };
}
=========end==============

出0入0汤圆

发表于 2012-6-15 16:22:18 | 显示全部楼层
从来未用过编码器,最近做的烘箱正好要用上,谢谢楼主的介绍

出330入0汤圆

发表于 2012-8-26 19:14:25 | 显示全部楼层
//下面是加入的加速键功能,有此函数科延长旋钮那可怜的寿命

        if(return KEY_AB_states[KEY_AB] != 0){
        tmp = Tick_Cont - Tick_Cont_Sample; //Tick_Cont 为系统节拍计数,或计时器,gloable variable
        Tick_Cont_Sample = Tick_Cont;       //刷新Tick_Cont_Sample
        if(tmp < Roltry_Fast_NUM)            //Roltry_Fast_Num为配置常量,当小于这个值时开始加速
            {return KEY_AB_states[KEY_AB]*Roltry_Fast_RATE; };//Roltry_Fast_RATE,加速的倍率
        else
             {return KEY_AB_states[KEY_AB]; };
        }
        else
             {return 0; };
}

===========================================
上面代码添加的符号错了很多,其中包括:1、()应该为().............2、;应该为;.......................3、if,else的括弧外面没必要再加;...................4、{}没有成对!这样不负责任放上来多不好啊。

出0入0汤圆

发表于 2012-8-27 09:43:28 | 显示全部楼层
zcllom 发表于 2012-8-26 19:14
//下面是加入的加速键功能,有此函数科延长旋钮那可怜的寿命

        if(return KEY_AB_states[KEY_AB]  ...


你这番言论,才是真的不负责任
第一:代码发上来,是为了让人看算法,不是copy paste
第二:{}配对是不完整的,但这只是他函数里面的一段代码而已,只是多了最后一个}而已啊

出0入0汤圆

发表于 2013-3-21 14:27:47 | 显示全部楼层
学习下

出0入0汤圆

发表于 2013-4-8 21:51:39 | 显示全部楼层
电源面板要用到旋转编码开关,标记个

出0入0汤圆

发表于 2013-4-9 07:53:49 来自手机 | 显示全部楼层
学习了,谢谢分享     

出0入0汤圆

发表于 2015-5-17 20:27:37 | 显示全部楼层
mark

出0入0汤圆

发表于 2015-9-11 19:44:42 | 显示全部楼层
本帖最后由 daiya 于 2015-9-11 19:45 编辑

具体算法见附件

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2015-10-21 18:02:55 | 显示全部楼层
谢谢分享!!

出0入0汤圆

发表于 2016-1-18 08:23:57 来自手机 | 显示全部楼层
我的代码和73楼的思想一样,不过有一些问题,不是很稳定,是不是因为没有去抖的原因,用逻辑分析仪抓了波形,的确是有抖动

出0入0汤圆

发表于 2016-8-25 19:59:30 | 显示全部楼层
谢谢分享,学习了,

出0入0汤圆

发表于 2016-10-11 14:28:52 | 显示全部楼层
今天仔细的看了一上午,8楼的算法,看明白了,
摘抄大致思路如下:

"a.两条线都是高电平时表示编码器无动作,退出.
                                                      
b.先检测测的两条线是01,后检测两条线是10时为正转.
                                                      
c.先检测测的两条线是10,后检测两条线是01时为反转.

d.两条线都是低电平时退出,不处理低电平区."

出0入0汤圆

发表于 2017-1-4 19:03:27 | 显示全部楼层
mark 一下下,每次都找。谢谢!

出0入0汤圆

发表于 2017-1-4 20:14:12 | 显示全部楼层
这个给力,旋转编码器好用

出0入0汤圆

发表于 2017-8-3 17:27:33 | 显示全部楼层
mark!!!!!!!

出0入0汤圆

发表于 2017-11-10 13:54:32 | 显示全部楼层
millwood0 发表于 2010-9-7 22:50
that's too complicated.

here is mine:

nice!                  

出0入0汤圆

发表于 2018-1-13 15:41:43 | 显示全部楼层
终于找到驱动旋转编码器的汇编代码了
谢谢楼主!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-19 19:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表