- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 10 von 10

Thema: Drehgeber - Auswertung per polling

  1. #1
    henne
    Gast

    Drehgeber - Auswertung per polling

    Anzeige

    Praxistest und DIY Projekte
    Hallo zusammen,
    habe einen Drehgeber mit A und B Signal (2 Bit) an PD2 und PD3
    angeschlossen und möchte einen counter rauf oder runterzählen.
    Dafür wird die erste Stellung einmal eingelesen und der Gray-Code in
    Binär-Code umgewandelt, danach wird erneut die Position eingelesen und
    dann mit der alten verglichen.
    Bei der Gray/Binär-Umwandlung wird das MSB (Bit 1)so wie es ist
    übernommen und das LSB(Bit 0) durch XOR-Verknüpfung des LSB mit dem MSB
    bestimmt. Der Vergleich soll dann mit CP erfolgen.

    Der Code funktioniert aber nicht so, wie ich es möchte.
    Muss man einen Interrupt dafür starten ??
    Wenn ja, warum ?
    Kann man die Sprünge zu den "Unterprogrammen" so durchführen, oder
    muss das mir RCALL und RET erfolgen ??
    Bin davon ausgegangen, das bei einer Abfrage
    CP pos_klein,temp
    BRNE weiter
    ...
    bei Gleichheit der Code bei den drei Punkten weitergeht.
    Vielleicht kann mir jemand Verbesserungen vorschlagen
    oder die Fehler nennen.
    Danke schonmal

    code:

    .include "m8def.inc"

    .def temp = r16
    .def temp2= r17
    .def pos_klein = r18
    .def klein_alt = r19
    .def klein_neu = r20

    ;Stackpointer initialisieren

    ldi temp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
    out SPL, temp
    ldi temp, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
    out SPH, temp

    ;Aus/Eingänge festlegen

    ldi temp, 0b11000000 ;PD7,PD6 -Ausgang, Rest als Eingang
    out DDRD, temp

    ldi pos_klein,0b00000000 ;Positionscounter "leer" laden


    ;Stellung zum ersten mal einlesen
    ;und Signale A und B(PD2,PD3)
    ;ans Ende kopieren

    in temp, PIND ;an PIN D anliegende Werte einlesen
    BST temp,2 ;Bit 2 von temp in das T-Flag schreiben (Bit Store)
    BLD klein_alt,0 ;T-Flag in Bit 0 von klein_alt laden (Bit Load)
    BST temp,3
    BLD klein_alt,1

    ldi temp,0b00000000

    ;Conversion Gray--->Binary

    BST klein_alt,1
    BLD temp,1
    BST klein_alt,0
    BLD temp2,1

    EOR temp2,temp
    BST temp2,1
    BLD temp,0
    MOV klein_alt,temp

    nochange:

    ;counter pos_klein überprüfen

    ldi temp,0b00000100
    CP pos_klein,temp
    BRNE weiter
    ldi temp,0b10000000
    out PORTD,temp ;wenn zähler 4,dann soll LED 7 leuchten

    weiter:

    in temp, PIND ;an PIN D anliegende Werte einlesen
    BST temp,2 ;Bit 2 von temp in das T-Flag schreiben (Bit Store)
    BLD klein_neu,0 ;T-Flag in Bit 0 von klein_alt laden (Bit Load)
    BST temp,3
    BLD klein_neu,1

    ldi temp,0b00000000
    ;Conversion Gray--->Binary
    BST klein_neu,1
    BLD temp,1
    BST klein_neu,0
    BLD temp2,1

    EOR temp2,temp
    BST temp2,1
    BLD temp,0

    MOV klein_neu,temp

    CP klein_alt,klein_neu ;Vergleich von alter und neuer Position
    BRNE direction ;wenn ungleich, dann Richtung bestimmen -->direction
    RJMP nochange ;ansonsten neu überprüfen --->nochange

    direction:

    CP klein_alt, klein_neu
    BRLO right ;wenn kleiner dann ---->right
    RJMP left ;ansonsten ---->left

    right:
    INC pos_klein
    MOV klein_alt, klein_neu
    RJMP nochange

    left:
    DEC pos_klein
    MOV klein_alt, klein_neu
    RJMP nochange

  2. #2
    Neuer Benutzer Öfters hier
    Registriert seit
    02.12.2004
    Beiträge
    8
    So, habe mich mal registriert.

    Noch zum Verständnis - habe einen Atmega8 bei dem ich die Interrupts INT0 und INT1 nicht unbedingt dafür verwenden wollte, da ich später auch nicht nur einen, sondern zwei Drehgeber auswerten wollte.

    Gruß, Hanno

  3. #3
    JanB
    Gast
    Hi Hanno,
    ich bin nicht sicher, ob ich richtig verstanden habe,
    was du eigentlich machen willst, aber ich gebe dir hier
    mal ein Beispiel für eine Drehgeber-Abfrage.
    Kern dieser Methode ist die Tabelle dgtab.
    Jede der vier Zeilen steht für einen "alten" Drehgehber-Zustand.
    In jeder Zeile stehen die Additionswerte für den Zähler
    für jede der vier möglichen "neuen" Zustände.

    Vieleicht hilft dir das weiter.

    Gruß Jan


    Code:
    ;Codebeispiel zur Auswertung eins Drehgebers
    ;für Atmel ATTiny15L
    ;Signale A und B sind an PortB Bit0 und Bit1 angeschlossen
    ;Es wird 8 Bit weit gezählt mit dem Zähler cnt
    ;Jan Baare 12/2004
    
    .NOLIST
    .INCLUDE "C:\Programme\Atmel\Avr Tools\AvrAssembler\appnotes\tn15def.inc"
    .LIST
    
            .DEF temp = r16
            .DEF cnt  = r17   ;der Zähler
            .DEF ast  = r18   ;alter Zustand Drehgeber
    
    dgstart: ldi temp,0
             out ddrb,temp    ;Portb 0-7 auf Input setzen
             in ast,portb     ;einmal den aktuellen PortZustand holen
             andi ast,3       ;Drehgeber-Bits maskieren
    
    dgloop: in temp,portb     ;aktuellen PortZustand holen
            andi temp,3       ;Drehgeber-Bits maskieren
            cp temp,ast       ;mit altem Zustand vergleichen
            breq dgloop       ;Keine Änderung -> nix machen
            lsl ast           ;*2
            lsl ast           ;*2
            add ast,temp      ;alter Zustand mal 4 plus neuer Zustand
            ldi ZL,low(dgtab<<1) ;Zeiger Z auf Tabellenanfang setzen
            ldi ZH,high(dgtab<<1)
            add ZL,ast        ;zum Zeiger Addieren
            clr ast
            adc ZH,ast
            lpm               ;Tabelleneintrag holen
            add cnt,r0        ;auf Zähler draufaddieren
            mov ast,temp      ;neuer Zustand wird alter Zustand
            rjmp dgloop       ;fertig
    
    
    dgtab: .db 0,1,-1,0
           .db -1,0,0,1
           .db 1,0,0,-1
           .db 0,-1,1,0
    
    ;Ende

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    02.12.2004
    Beiträge
    8
    Hallo JanB,
    Ich habe den Code für den Atmega8 angepasst,
    und als Kontrolle für den Counter eine LED-Anzeige hinzugefügt.
    Leider funktioniert das ganze nicht - ich habe an PORTD 6 und 7 jeweils
    eine LED und beide leuchten,
    mehr passiert nicht.
    Das mit der Tabelle verstehe ich auch nicht so ganz--was und warum wird
    damit erreicht, den alten Zustand mit 4 zu multiplizieren und zum neuen hinzuzufügen??
    Was ist in den Spalten und Zeilen der Tabelle was ??
    Hier mal der Code

    Gruß, Hanno

    Code:
    ;Codebeispiel zur Auswertung eins Drehgebers 
    ;für Atmel AtMega8
    ;Signale A und B sind an PortD Bit2 und Bit3 angeschlossen 
    ;Es wird 8 Bit weit gezählt mit dem Zähler cnt 
    ;Hanno Monschan 12/2004 
    
    .NOLIST 
    .INCLUDE "m8def.inc" 
    .LIST 
    
            .DEF temp = r16 
            .DEF cnt  = r17   	;der Zähler 
            .DEF ast  = r18   	;alter Zustand Drehgeber 
            .DEF temp2 = r19
            
           
    
    dgstart: 
             ldi temp,0b11000000 
             out ddrd,temp    	         ;Portd 6/7 auf Ouput setzen, Rest Input 
             in ast,portd     	         ;einmal den aktuellen PortZustand holen 
             andi ast,0b00001100      ;Drehgeber-Bits maskieren 
             ldi temp2, 4		         ;bei Zählerstand 4 soll LED leuchten-->anzeige
    
    dgloop: in temp,portd    	         ;aktuellen PortZustand holen 
            andi temp, 0b00001100   ;Drehgeber-Bits maskieren 
            cp temp,ast       	         ;mit altem Zustand vergleichen 
            breq dgloop      	         ;Keine Änderung -> nix machen 
            
            
            lsl ast           	;*2 
            lsl ast           	;*2 
            add ast,temp      	         ;alter Zustand mal 4 plus neuer Zustand 
            ldi ZL,low(dgtab<<1)         ;Zeiger Z auf Tabellenanfang setzen 
            ldi ZH,high(dgtab<<1) 
            add ZL,ast        	         ;zum Zeiger Addieren 
            clr ast 
            adc ZH,ast 
            lpm               	                   ;Tabelleneintrag holen 
            add cnt,r0        	        ;auf Zähler draufaddieren 
            mov ast,temp      	        ;neuer Zustand wird alter Zustand
            
            cp temp2, cnt		        ;wenn Counter==4
            breq anzeige		        ;Ausgabe 
            
            rjmp dgloop       	        ;fertig 
    
    
    dgtab: .db 0,1,-1,0 
               .db -1,0,0,1 
               .db 1,0,0,-1 
              .db 0,-1,1,0 
           
           
    anzeige:
               ldi temp,0b10000000 ;Ausgabe an LED 7
    	out portd,temp
    	rjmp dgloop
    
    ;Ende

  5. #5
    JanB
    Gast
    Hallo Hanno,
    Ich habe den Code für den Atmega8 angepasst,
    Das Codefragment war als Beispiel gedacht um es zu analysieren,
    die Methode zu verstehen, und dann selbst zu verwenden.
    Und nicht, um es 1:1 zu übernehmen. Aber egal.

    Leider funktioniert das ganze nicht
    Das Beispiel hat den Anschluss des Drehgebers an den Bits 0 und 1 des Ports vorgesehen.
    Du hast sie jedoch an den Bits 2 und 3 angeschlossen.
    Da müssen die Bits im Register noch um zwei Bits nach rechts verschoben werden, damit es funktioniert.


    Das mit der Tabelle verstehe ich auch nicht so ganz
    Also diese Methode funktioniert folgendermassen:
    Die Signale A und B des Drehgebers können genau vier verschiedene
    Zustände annehmen: 00, 01, 10, 11.
    Das entspricht den Binärwerten 0 bis 3.
    Das Gleiche gilt natürlich auch für die "alten" Drehgeberwerte.
    Zur Auswertung müssen die "neuen" und die "alten" DG-Werte miteinander verglichen werden.
    Jeder der beiden Werte kann wie gesagt einen von vier verschiedenen Zuständen haben.
    Der Vergleich kann also genau 4 mal 4 also 16 Kombinationen ergeben.
    Für jede dieser 16 Kombinationen gilt es zu entscheiden,
    ob der Zähler stehen bleibt (+0), oder ob er vorwärts (+1), oder rückwärts (-1) zählen muss.
    Diese Entscheidungsmatrix ist die Tabelle dgtab.
    Sie besteht aus 4 Zeilen a' 4 Spalten, enthält also 16 Werte.
    Jede Zeile steht für einen "alten" DG-Zustand.
    Jede Spalte steht für einen "neuen".
    Der Tabelleneintrag (0 oder 1 oder -1) im Schnittpunkt
    von "alter Wert" und "neuer" Wert ist der Zählerschritt,
    der einfach auf den Zähler aufaddiert wird.
    Wie findet das Progrämmchen den richtigen Tabelleneintrag ?
    1. Es wird ein Zeiger (ZH,ZL) auf den Anfang der Tabelle gesetzt.
    2. Es wird der "alte" DG-Zustand mal 4 genommen und auf den Zeiger addiert.
    Der Zeiger zeigt jetzt auf den Anfang der richtigen Zeile.
    3. Es wird der "neue" DG-Wert auch auf den Zeiger addiert.
    Jetzt zeigt der Zeiger auch auf die richtige Spalte innerhalb der Zeile.
    Der Tabellenwert (0 oder 1 oder -1), auf den der Zeiger jetzt zeigt,
    wird ausgelesen (lpm) und zum Zähler addiert.
    Jetzt muss nur noch der "neue"DG-Wert zum "alten DG-Wert werden,
    und fertig.

    Das war jetzt wirklich ausführlich, meine ich.
    Diese Methode realisiert eine vollständige Auswertung des DG-Signales.
    D.h. Bei einem Drehgeber mit nominal 100 Imp/Umdrehung wird eine
    Umdrehung auf 400 Positionen aufgelöst.

    Ich nehme an, du bist noch Einsteiger in der Assembler-Programierung.
    Dann solltest dir das Beispiel ansehen, und versuchen zu verstehen,
    wie es funktioniert, dann kannst du es beliebig selbst anwenden.
    Nur Abtippen bringt dich nicht viel weiter.

    Ich habe deinen Code etwas angepasst so das er funktionieren müßte.
    Was ist das eigentlich für ein Drehgeber, den du da verwendest, und was
    willst du eigentlich damit machen ?
    Warum soll die LED gerade bei Zählerstand 4 leuchten ? Und nur da ?

    Gruß Jan


    Code:
    ;für Atmel AtMega8
    ;Signale A und B sind an PortD Bit2 und Bit3 angeschlossen
    ;Es wird 8 Bit weit gezählt mit dem Zähler cnt
    
    .NOLIST
    .INCLUDE "m8def.inc"
    .LIST
    
            .DEF temp = r16
            .DEF cnt  = r17      ;der Zähler
            .DEF ast  = r18      ;alter Zustand Drehgeber
            .DEF temp2 = r19
           
           
    
    dgstart:
            ldi temp,0b11000000
            out ddrd,temp                ;Portd 6/7 auf Ouput setzen, Rest Input
            in ast,portd                 ;einmal den aktuellen PortZustand holen
            andi ast,0b00001100          ;Drehgeber-Bits maskieren
            lsr ast                      ;DG-Bits in POsition 0 und 1 schieben
            lsr ast
    		      
    dgloop: in temp,portd                ;aktuellen PortZustand holen
            andi temp, 0b00001100        ;Drehgeber-Bits maskieren
    	lsr temp                     ;DB-Bits in Pos. 0 und 1 schieben
            lsr temp		     
            lsl ast                      ;*2
            lsl ast                      ;*2
            add ast,temp                 ;alter Zustand mal 4 plus neuer Zustand
            ldi ZL,low(dgtab<<1)         ;Zeiger Z auf Tabellenanfang setzen
            ldi ZH,high(dgtab<<1)
            add ZL,ast                   ;zum Zeiger Addieren
            clr ast
            adc ZH,ast
            lpm                          ;Tabelleneintrag holen
            add cnt,r0                   ;auf Zähler draufaddieren
            mov ast,temp                 ;neuer Zustand wird alter Zustand
    
            cpi cnt,4                    ;Counter==4 ?
            brne dgloop                  ;nee
            ldi temp,0b10000000          ;LED schalten  
    	out portc,temp
            rjmp dgloop                  ;fertig
    
    
    dgtab: .db 0,1,-1,0
           .db -1,0,0,1
           .db 1,0,0,-1
           .db 0,-1,1,0
           
           
    ;Ende

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    02.12.2004
    Beiträge
    8
    Hallo,
    bin erst jetzt dazu gekommen mich wieder näher mit dem Atmega zu beschäftigen.
    Den Code habe ich nun bis in letzte Detail verstanden, hoffe ich zumindest.
    Die Simulation mit AVR-Studio klappt astrein, wenn ich alte und neue Position manuell angebe, zählt der counter rauf oder runter, so wie`s sein soll.
    Nun läufts mit derm realen Drehgeber aber immer noch nicht--habe die Signale gecheckt, die Spg---alles fehlerfrei.
    Nun stellt sich mir die Frage, ob der Mikrocontroller zu schnell oder zu langsam für die Erkennung der Signale ist, oder ob es noch woanders dran liegen kann, das der counter immer gleich bleibt.

    @Jan: der Counter=4 soll nur ne Überprüfung sein, ob er zählt.

    wenn ich die Werte in der Tabelle alle auf 1 setze, dann leuchtet die Lampe sofort---weil ja immer 1 addiert wird und sofort die 4 erreicht wird.

  7. #7
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    10.12.2004
    Ort
    LEV
    Beiträge
    505
    Hallo,
    kann ich mir auch nicht erklären.
    Zu schnell ist der MC garantiert nicht.
    Zu langsam könnte er sein,
    er muss schneller pollen als die Signale wechseln.
    Ist ja logisch.

    Und wenn es in der Simu klappt, kannes eigentlich nur an der
    Hardware liegen.
    Hast du alle Ports richtig initialisiert und so ?

    Ahhh...Moment....Jaaaa!
    Sorry, Sorry
    Ich habe in der Routine meinen AVR-Lieblingsfehler eingebaut,
    auf den ich immer wieder reinfalle.

    Ein Port beim AVR kann man nicht mit IN PORTX lesen !!!
    ichidiotwannwerdeichdasendlichlernen
    Man muss IN PINX machen.

    Also in der dritten Zeile des Codes
    muss NICHT "in ast,PORTD" stehen,
    SONDERN da muss "in ast,PIND" stehen.
    Und in Zeile 7 (dgloop) natürlich genauso.
    da muss "in temp,PIND" hin.
    Wenn schon falsch, dann wenigstens konsequent.

    Das hab ich doch auch im Downloadbereich stehen.
    Das das bisher noch keiner gemerkt hat - komisch:
    da guckt wohl keiner so genau hin. Egal.

    Sagst du mir ob es klappt ?
    Oder sprichst du jetzt nicht mehr mit mir ?

    Gruß Jan

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    02.12.2004
    Beiträge
    8
    Die Antwort kam ja mal schneller als mein Atmega schaltet

    JAAAAA--es klappt!
    Habe ich gerade geändert, und siehe da----es funktioniert.
    Das hätte mir aber auch auffallen müssen, naja, bin ja noch ein Anfänger.

    Danke für deine Hilfe!
    Da ich mich ja jetzt den anderen Dingen wie z.B. ADC widmen werde, habe ich bestimmt nochmal die ein oder andere Frage an dich

    Gruß, Hanno

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    02.12.2004
    Beiträge
    8
    Halt,noch was.

    sollte die "Tabelle" nicht eigentlich so aussehen:
    .DB 0,-1,1,0
    .DB 1,0,0,-1
    .DB -1,0,0,1
    .DB 0,1,-1,0

    gehe ich richtig in der Annahme, das man sie auch so schreiben könnte ?
    .DB 0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0
    dabei sehe ich gerade das sich nur die Zählrichtung im Vergleich zu deiner ändert.(deine Tabelle invertiert).

    Woher kann es kommen, das der Drehgeber (100imp/Drehung) den counter schon bei ca.1/4 Umdrehung bei 100 hat ?? müsste doch eigentlich 25 sein!?

  10. #10
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    10.12.2004
    Ort
    LEV
    Beiträge
    505
    Hallo,
    Die Tabelle kann man schreiben wie man will,
    rückwärts oder vorwärts, ändert sich nur die Drehrichtung.

    Woher kann es kommen, das der Drehgeber (100imp/Drehung) den counter schon bei ca.1/4 Umdrehung bei 100 hat ?? müsste doch eigentlich 25 sein!?
    Das ist völlig richtig, und zeigt das es wie gewünscht funktioniert.
    Diese Methode ist eine "vollständige" Auswertung.
    2 mal 100 um 90 Grad versetze Signale ergibt
    genau 400 Zustandswechsel pro Umdrehung.
    Viele andere Verfahren verschenken 3/4 oder die Hälfte
    der möglichen Auflösung des Drehgebers.
    Da kommen dann nur 200 oder 100 Positionen pro Umdrehung raus.

    Gruß Jan

Benutzer, die dieses Thema gelesen haben: 0

Derzeit gibt es keine Benutzer zum Anzeigen.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests