2008-08-29 82 views
5

我無法使旋轉編碼器與AVR微控制器一起正常工作。編碼器是機械ALPS encoder,我使用的是Atmega168使用帶AVR微控制器的旋轉編碼器

澄清

我一直在使用一個外部中斷聽針試過,但是看起來實在是太慢了。當引腳A變高時,中斷程序開始,然後檢查引腳B是否爲高電平。這個想法是,如果引腳B爲高電平引腳A變高的時刻,那麼它逆時針旋轉。如果引腳B爲低電平,那麼它正在按照時鐘順序旋轉。但是看起來像AVR花費太長時間來檢查引腳B,所以它總是被讀取爲高。

我也試圖創建一個程序,只是阻止,直到引腳B或引腳A的變化。但是,編碼器旋轉時可能會有太多噪音,因爲這也不起作用。我最後一次嘗試是有一個計時器,它將最後8個值存儲在緩衝區中,並檢查它是否從低到高。這也沒有用。

我已經嘗試了編碼器的範圍,並且它似乎使用2到4ms之間從第一個引腳變化,直到其他引腳變化。

回答

10

我有一個關於rotary encoders and how to use them的網頁,您可能會覺得它有用。

不幸的是,沒有更多的信息,我無法解決您的特定問題。

哪個微控制器引腳連接到編碼器,以及當前用於解碼脈衝的代碼是什麼?

好的,你正在處理幾個不同的問題,第一個問題是這是一個機械編碼器,所以你必須處理開關噪聲(反彈,顫振)。 data sheet表示部件停止反彈併產生錯誤輸出可能需要3mS。

您需要創建一個去抖動程序。其中最簡單的就是不斷檢查A是否升高。如果是,請啓動計時器並在3 ms內再次檢查。如果它仍然很高,那麼你可以檢查B - 如果它不高,那麼你忽略虛假脈衝並繼續尋找A high。當你檢查B時,你看它,啓動一個計時器3 ms,然後再看看B.如果兩次都是相同的,那麼你可以使用該值 - 如果它在3毫秒內發生變化,那麼你必須重新做一次(讀取B,等待3毫秒,然後再次閱讀並查看它是否匹配)。

atmega速度足夠快,您不必擔心這些檢查進行得很慢,除非您的運行速度很慢。

一旦你處理了機械噪音,那麼你想看看一個合適的灰色代碼例程 - 你所遵循的算法將不起作用,除非當B變低時A也變小。通常人們存儲兩個輸入的最後一個值,然後將它與兩個輸入的新值進行比較,並使用一個小函數根據此值進行遞增或遞減。 (查看我在上面提到的網站上的標題「高分辨率閱讀」)。我將兩個讀數組合成一個四位數字,並使用一個簡單的數組來告訴我是遞增還是遞減計數器,但是有更高級的解決方案,並針對代碼大小,速度或易於維護的代碼進行了優化。

0

究竟是什麼問題?我假定您已經能夠根據您提供的Farnell頁面上鍊接的技術規範,將編碼器的引腳連接到PIC上,讀取數據時也存在問題?你沒有從編碼器得到任何數據嗎?你不知道如何解釋你回來的數據?

1

速度不應該是一個問題。大多數情況下,所有機械開關都需要去抖動程序。如果你想用中斷來做到這一點,當它觸發時關閉中斷,啓動一個定時器,在幾秒鐘後它將重新打開。將保持您的程序無輪詢> :)

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) 
*/ 
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; 
} 

此代碼的工作原理除非您真的快速旋轉編碼器。然後,它可能會錯過一兩步,但這並不重要,因爲使用編碼器的人不知道他們轉換了多少步。

+1

作爲一個「業餘愛好者」的解決方案可以。然而,額外的硬件(電阻器/電容器)不容小覷。這就是爲什麼軟件反彈是一個「更好」的解決方案(恕我直言)。 – 2009-02-02 22:45:23