我无法让旋转编码器与AVR微控制器一起正常工作.编码器是机械ALPS编码器,我使用的是Atmega168.
澄清
我曾尝试使用外部中断来收听引脚,但看起来它太慢了.当引脚A变为高电平时,中断程序开始,然后检查引脚B是否为高电平.我们的想法是,如果引脚B变高,引脚A变高,那么它就会逆时针旋转.如果引脚B为低电平,则它按顺时针方向旋转.但似乎AVR检查引脚B需要太长时间,所以它总是读得很高.
我还尝试创建一个程序,只需阻塞直到引脚B或引脚A发生变化.但可能是旋转编码器时噪音太大,因为这也不起作用.我的最后一次尝试是有一个计时器,它将最后8个值存储在缓冲区中,并检查它是否从低到高.这也不起作用.
我已经尝试过对编码器进行范围设计,它似乎在第一个Pin的2到4ms之间使用,直到另一个Pin发生变化.
我有一个关于旋转编码器的网页以及如何使用它们,你可能会发现它们很有用.
很遗憾没有更多信息我无法解决您的特定问题.
哪些微控制器引脚连接到编码器,您目前用于解码脉冲的代码是什么?
好吧,你正在处理一些不同的问题,第一个问题是这是一个机械编码器,所以你必须处理开关噪声(反弹,颤振).该数据表指示它可能需要最多3毫秒的零件停止跳动和创建虚假输出.
你需要创建一个去抖动例程.最简单的是不断检查A是否变高.如果是,请启动计时器并在3 ms内再次检查.如果它仍然很高,那么你可以检查B - 如果它不高,那么你忽略了假脉冲并继续寻找A高.当你检查B时,你看它,启动一个3毫秒的计时器,然后再看看B. 如果两次都相同,则可以使用该值 - 如果它在3 ms内发生变化,则必须再次执行此操作(读取B,等待3 ms,然后再次读取它,看它是否匹配).
atmega足够快,你不必担心这些检查会慢慢进行,除非你的时钟速度很慢.
一旦你处理了机械噪声,那么你想看一个正确的灰色代码例程 - 你所遵循的算法将无法工作,除非你在A变低时A减小时减少.通常人们存储两个输入的最后一个值,然后将它与两个输入的新值进行比较,并使用一个小函数根据该值递增或递减.(请查看我在上面提到的表格中的"高分辨率阅读"标题).我将两个读数组合成一个四位数,并使用一个简单的数组告诉我是否增加或减少计数器,但有更高级的解决方案,并优化代码大小,速度或代码维护的简易性.
添加模拟低通滤波器可大大改善信号.使用低通滤波器,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#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; }
除非您快速旋转编码器,否则此代码有效.然后它可能会错过一两步,但这并不重要,因为使用编码器的人不会知道他们转了多少步.