Frage

Ich habe Probleme damit, dass ein Drehgeber ordnungsgemäß mit AVR-Mikrocontrollern funktioniert.Der Encoder ist mechanisch ALPS-Encoder, und ich benutze Atmega168.

Klärung

Ich habe versucht, einen externen Interrupt zu verwenden, um die Pins abzuhören, aber es scheint, dass es zu langsam ist.Wenn Pin A auf High geht, startet der Interrupt-Vorgang und prüft dann, ob Pin B High ist.Die Idee dahinter ist: Wenn Pin B in dem Moment, in dem Pin A auf High geht, High ist, dann dreht er sich gegen den Uhrzeigersinn.Wenn Pin B niedrig ist, dreht er sich im Uhrzeigersinn.Es scheint jedoch, dass der AVR zu lange braucht, um Pin B zu überprüfen, sodass dieser immer als hoch angezeigt wird.

Ich habe auch versucht, ein Programm zu erstellen, das einfach blockiert, bis sich Pin B oder Pin A ändert.Es könnte aber sein, dass es beim Drehen des Encoders zu viel Rauschen gibt, denn auch das funktioniert nicht.Mein letzter Versuch bestand darin, einen Timer zu haben, der die letzten 8 Werte in einem Puffer speichert und prüft, ob er von niedrig nach hoch wechselt.Auch das hat nicht funktioniert.

Ich habe versucht, den Encoder zu bestimmen, und es scheint zwischen 2 und 4 ms vom ersten Pin-Wechsel bis zum anderen Pin-Wechsel zu dauern.

War es hilfreich?

Lösung

Ich habe eine Webseite darüber Drehgeber und deren Verwendung, was für Sie nützlich sein könnte.

Ohne weitere Informationen kann ich Ihr spezielles Problem leider nicht beheben.

Welche Mikrocontroller-Pins sind mit dem Encoder verbunden und welchen Code verwenden Sie derzeit zum Dekodieren der Impulse?

Ok, Sie haben es mit ein paar verschiedenen Problemen zu tun. Das erste Problem ist, dass es sich um einen mechanischen Encoder handelt, sodass Sie mit Schaltergeräuschen (Bounce, Rattern) zu kämpfen haben.Der Datenblatt weist darauf hin, dass es bis zu 3 ms dauern kann, bis die Teile nicht mehr springen und falsche Ausgaben erzeugen.

Sie müssen eine Entprellroutine erstellen.Die einfachste davon besteht darin, kontinuierlich zu prüfen, ob A hoch geht.Wenn dies der Fall ist, starten Sie einen Timer und überprüfen Sie ihn in 3 ms erneut.Wenn er immer noch hoch ist, können Sie B überprüfen. Wenn er nicht hoch ist, ignorieren Sie den Störimpuls und suchen weiter nach A-Hoch.Wenn Sie B markieren, schauen Sie es sich an, starten einen Timer für 3 ms und schauen sich dann B erneut an.Wenn es beide Male derselbe war, können Sie diesen Wert verwenden – wenn er sich innerhalb von 3 ms ändert, müssen Sie es erneut tun (B lesen, 3 ms warten, dann erneut lesen und prüfen, ob er übereinstimmt).

Der Atmega ist schnell genug, sodass Sie sich keine Sorgen machen müssen, dass diese Überprüfungen langsam ablaufen, es sei denn, Sie verwenden auch eine langsame Taktrate.

Sobald Sie sich mit den mechanischen Geräuschen befasst haben, sollten Sie sich eine geeignete Gray-Code-Routine ansehen – der Algorithmus, dem Sie folgen, funktioniert nicht, es sei denn, Sie dekrementieren auch, wenn A hoch ist, wenn B niedrig wird.Im Allgemeinen speichern Benutzer den letzten Wert der beiden Eingaben, vergleichen ihn dann mit dem neuen Wert der beiden Eingaben und verwenden eine kleine Funktion, um auf dieser Grundlage zu erhöhen oder zu verringern.(Die Tabelle finden Sie unter der Überschrift „Hochauflösendes Lesen“ auf der Website, die ich oben erwähnt habe.)Ich kombiniere die beiden Messwerte zu einer Vier-Bit-Zahl und verwende ein einfaches Array, um mir mitzuteilen, ob ich den Zähler erhöhe oder dekrementiere. Es gibt jedoch Lösungen, die noch fortschrittlicher sind und die Codegröße, Geschwindigkeit oder einfache Codewartung optimieren.

Andere Tipps

Durch das Hinzufügen eines analogen Tiefpassfilters wird das Signal erheblich verbessert.Mit dem Tiefpassfilter war der Code auf dem AVR wirklich einfach.

       _________
        |         |
        | Encoder |
        |_________|
          |  |  |
          |  |  |
     100n |  O  | 100n  
 GND O-||-+ GND +-||-O GND
          |     | 
          \     /
      3K3 /     \ 3K3
          \     /
          |     |    
VCC O-/\/-+     +-\/\-O VCC
     15K  |     |  15K
          |     |
          O     O
          A     B

Ah, die Wunder der ASCII-Kunst :p

Hier ist das Programm auf dem AVR.Verbinden Sie A und B mit dem Eingang PORTB am Avr:

#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;
}

Dieser Code funktioniert, es sei denn, Sie drehen den Encoder sehr schnell.Dann könnte es sein, dass ein oder zwei Schritte fehlen, aber das ist nicht wichtig, da die Person, die den Encoder verwendet, nicht weiß, wie viele Schritte sie gedreht hat.

Geschwindigkeit sollte kein Problem sein.Fast alle mechanischen Schalter benötigen Entprellroutinen.Wenn Sie dies mit Interrupts tun möchten, schalten Sie den Interrupt aus, wenn er ausgelöst wird, und starten Sie einen Timer, der ihn nach ein paar ms wieder einschaltet.Hält Ihr Programm frei von Abfragen >:)

Womit genau hast du Probleme?Ich gehe davon aus, dass Sie die Pins des Encoders gemäß den auf der von Ihnen angegebenen Farnell-Seite verlinkten technischen Spezifikationen an Ihren PIC anschließen konnten. Liegt das Problem also beim Lesen der Daten?Erhalten Sie keine Daten vom Encoder?Wissen Sie nicht, wie Sie die zurückerhaltenen Daten interpretieren sollen?

/* 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)
 */
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top