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
;=====================================
【导语】:高端的音响设备目前已经大量采用了先进的控制技术,其中使用单片机(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的“瞬时状态”。
![](https://i-blog.csdnimg.cn/blog_migrate/9b7b5dcf814e4f6509dc5f1dccb19a2b.jpeg)
(原文件名:1.jpg)
![](https://i-blog.csdnimg.cn/blog_migrate/3383d9580570ce2c37c39a7e296bca18.jpeg)
(原文件名: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
;=====================================
;开关的瞬时位置比较抽象,大家要对比波形图和软件的状态去加深理解。
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. ![]()
|