我无法让旋转编码器与AVR微控制器一起正常工作。编码器是机械ALPS encoder,我正在使用Atmega168。
澄清
我尝试过使用外部中断来收听引脚,但看起来它太慢了。当引脚A变为高电平时,中断程序开始,然后检查引脚B是否为高电平。我们的想法是,如果引脚B变高,引脚A变高,那么它就会逆时针旋转。如果引脚B为低电平,则它按顺时针方向旋转。但似乎AVR检查引脚B需要太长时间,所以它总是读得很高。
我还尝试创建一个简单阻止的程序,直到Pin B或Pin A发生变化。但可能是旋转编码器时噪音太大,因为这也不起作用。我的最后一次尝试是有一个计时器,它将最后8个值存储在缓冲区中,并检查它是否从低到高。这也不起作用。
我尝试过对编码器进行范围设计,似乎在第一个Pin的2到4ms之间使用,直到另一个Pin发生变化。
答案 0 :(得分:10)
我有一个关于rotary encoders and how to use them的网页,您可能会发现它很有用。
不幸的是,如果没有更多信息,我无法解决您的特定问题。
哪些微控制器引脚连接到编码器,您目前用于解码脉冲的代码是什么?
好的,你正在处理一些不同的问题,第一个问题是这是一个机械编码器,所以你必须处理开关噪声(反弹,颤振)。 data sheet表示部件可能需要3mS才能停止弹跳并产生错误输出。
您需要创建一个去抖动例程。最简单的是不断检查A是否变高。如果是,请启动计时器并在3 ms内再次检查。如果它仍然很高,那么你可以检查B - 如果它不高,那么你忽略了假脉冲并继续寻找A高。当你检查B时,你看它,启动一个3毫秒的计时器,然后再看看B.如果两次都相同,则可以使用该值 - 如果它在3 ms内发生变化,则必须再次执行此操作(读取B,等待3 ms,然后再次读取它,看它是否匹配)。
atmega足够快,你不必担心这些检查会慢慢进行,除非你的时钟速度很慢。
一旦你处理了机械噪音,那么你想看一个正确的格雷码程序 - 你所遵循的算法将无法工作,除非你在B变低时A减小时也减少。通常人们存储两个输入的最后一个值,然后将它与两个输入的新值进行比较,并使用一个小函数根据该值递增或递减。 (请查看我在上面提到的表格中的“高分辨率阅读”标题)。我将两个读数组合成一个四位数,并使用一个简单的数组告诉我是否增加或减少计数器,但有更高级的解决方案,并优化代码大小,速度或代码维护的简易性。
答案 1 :(得分:5)
添加模拟低通滤波器可大大改善信号。使用低通滤波器,AVR上的代码非常简单。
_________
| |
| Encoder |
|_________|
| | |
| | |
100n | O | 100n
GND O-||-+ GND +-||-O GND
| |
\ /
3K3 / \ 3K3
\ /
| |
VCC O-/\/-+ +-\/\-O VCC
15K | | 15K
| |
O O
A B
啊,ASCII艺术的奇迹:p
以下是AVR上的程序。将A和B连接到avr上的输入PORTB:
#include <avr/io.h>
#define PIN_A (PINB&1)
#define PIN_B ((PINB>>1)&1)
int main(void){
uint8_t st0 = 0;
uint8_t st1 = 0;
uint8_t dir = 0;
uint8_t temp = 0;
uint8_t counter = 0;
DDRD = 0xFF;
DDRB = 0;
while(1){
if(dir == 0){
if(PIN_A & (!PIN_B)){
dir = 2;
}else if(PIN_B & (!PIN_A)){
dir = 4;
}else{
dir = 0;
}
}else if(dir == 2){
if(PIN_A & (!PIN_B)){
dir = 2;
}else if((!PIN_A) & (!PIN_B)){
counter--;
dir = 0;
}else{
dir = 0;
}
}else if(dir == 4){
if(PIN_B & (!PIN_A)){
dir = 4;
}else if((!PIN_A) & (!PIN_B)){
counter++;
dir = 0;
}else{
dir = 0;
}
}else if(PIN_B & PIN_A){
dir = 0;
}
PORTD = ~counter;
}
return 0;
}
除非您快速旋转编码器,否则此代码有效。然后它可能会错过一两步,但这并不重要,因为使用编码器的人不会知道他们转了多少步。
答案 2 :(得分:1)
速度应该不是问题。大多数机械开关都需要去抖动程序。如果您想通过中断执行此操作,请在触发时关闭中断,启动计时器,在几毫秒后将其重新打开。将保持您的程序无轮询&gt;:)
答案 3 :(得分:0)
你究竟遇到了什么问题?我假设您已经能够根据您提供的Farnell页面上链接的技术规范将编码器的引脚挂接到PIC,那么读取数据的问题是什么?你没有从编码器获得任何数据吗?你不知道如何解释你要回来的数据吗?
答案 4 :(得分:0)
/* into 0 service rutine */
if(CHB)
{
if(flagB)
Count++;
FlagB=0;
}
else
{
if(FlagB)
count--:
FlagB=0:
}
/* into 1 service rutine */
FlagB=1;
/* make this give to you a windows time of 1/4 of T of the encoder resolution
that is in angle term: 360/ (4*resolution)
*/