- Akku Tests und Balkonkraftwerk Speicher         
Ergebnis 1 bis 10 von 26

Thema: Menüsteuerung mit Drehencoder ?

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #17
    Benutzer Stammmitglied
    Registriert seit
    12.12.2004
    Ort
    Trier
    Beiträge
    38
    Das Thema Drehgeber ließ mir nun doch keine Ruhe mehr. Also habe ich einen von diesen (Billig-)Drehgeber von Pollin (Best.Nr. 240 313) ausgekramt und an mein AVR-Bastelboard nach angehängtem Plan angeschlossen.

    R1 ist lediglich ein Schutzwiderstand, falls einer der Eingänge PD4..PD6 versehentlich doch mal als Ausgang konfiguriert ist. Es befinden sich bis auf die aktivierten internen PullUp-Widerstände des AVR keine weiteren Bauteile (zwecks Entprellung) im Signalweg des Dreh-Encoders.

    Wie ich schon im vorigen Post schrieb, setze ich diesen Drehgebertyp in einem Projekt in der von dort beschriebenen Weise mittels externem Interrupt ein. Das Prinzip und auch der Nachteil dieser Lösung ist, dass jeder Signalwechsel am Interrupteingang die zugehörige Interrupt-Service-Routine (ISR) ausführen lässt. Was heute noch scheinbar einwandfrei funktioniert, kann bei einem ausgelutschtem Drehgeber mit ggf. starkem Kontaktprellen zu einer unkontrollierbaren Prozessorlast führen. Aus diesem Grund werden in Expertenkreisen generell Kontakte mittels einer Timer-Interrupt gesteuerten Routine entprellt.

    Die Bascom-eigene Lösung mit dem Encoder-Befehl arbeitete bei mir noch nie zufriedenstellend - egal ob in der Hauptprogrammschleife oder per Timerinterrupt ausgeführt - traten immer Sprünge oder Impulsverluste am Drehgeber auf. Daraufhin habe ich die untenstehende Lösung ausgearbeitet. Beim Testen konnte ich bisher absolut keine Fehler erkennen. Kritik und Verbesserungsvorschläge sind gerne willkommen.

    Lösungsweg:
    Zur Entprellung werden die beiden Drehgebersignalpaar (A,B) alle 0.5ms in der Timer0-ISR abgefragt und im Schieberegister-Byte ROTARY im Format AAAABBBB abgelegt. Nur wenn alle A's und alle B's gleich sind, also (0000_0000), (0000_1111), (1111_1111) oder (1111_0000) gilt das Encodersignalpaar als stabil.

    Außer dem Kontaktprellen besitzt dieser Drehgebertyp aber noch ein weiteres zu beseitigendes Übel:
    Grundsätzlich stehen in den Rastungen des Drehknopfes die Signalpaarungen (A,B)=(0,0) bzw. (A,B)=(1,1) stabil an. Einige der 16 Rastungen sind aber so unpräzise, das schon durch bloßes Anfassen des Drehknopfes ein Signalwechsel zu (A,B)=(1,0) bzw. (A,B)=(0,1) und beim Loslassen wieder zurück nach (A,B)=(0,0) bzw. (A,B)=(1,1) erfolgt. Dies wird in vielen Routinen (so auch in meiner vom Externen Interrupt gesteuerten Routine) fälschlicherweise als Drehbewegung des Knopfes interpretiert.

    Um diesen Fehler zu beheben muß eine Encoderauswertung drei aufeinanderfolgende Signalpaarungen berücksichtigen. Bei mir geschieht das mittels den Variablen
    ROTARY: Signalpaarung (A,B) in der aktuellen Rastung
    ROTARY1: (A,B) im Übergang zwischen zwei Rastungen (Drehrichtungserkennung)
    ROTARY2: Signalpaarung (A,B) in der vorherigen Rastung

    Befindet sich der Drehknopf in der Rastung mit (A,B)=(0,0) bzw. (A,B)=(1,1) so muß bei einer Drehung um eine Rastung anschliessend genau die entgegengesetzte Signalpaarung vorliegen, nämlich (A,B)=(1,1) bzw. (A,B)=(0,0). D.h. eine Drehbewegung kann nur stattgefunden haben wenn ROTARY ungleich ROTARY2 ist. Abhängig von der Signalpaarung ROTARY1 beim Übergang zwischen den Rastungen (A,B)=(0,1) bzw. (A,B)=(1,0) wird die Drehrichtung erkannt.
    Zur Auswertung des Encoders werden nach vollzogener Rastung entsprechend der Drehrichtung die Flags R_Flag bei Rechtsdrehung und L_Flag bei Linksdrehung gesetzt und der Encoderwert ROTARY_VALUE bei Rechtsdrehung inkrementiert bzw. bei Linksdrehung dekrementiert und können in der Hauptprogrammschleife abgefragt und zurückgesetzt werden.

    Code:
    '*******************************************************************************
    '***   Testprogramm für POLLIN Dreh-Encoder PANASONIC EVEQDBRL416B           ***
    '***   Best.Nr. 240 313                                                      ***
    '*******************************************************************************
    '***   Author: Screwdriver                                                   ***
    '***   Datum:  28.06.2009                                                    ***
    '*******************************************************************************
    
    '*******************************************************************************
    '***   Konfiguration                                                         ***
    '*******************************************************************************
    'AVR
    $regfile = "m644def.dat"
    $crystal = 20e6
    
    'System-Timer für periodische Encoder-Abfrage
    Config Timer0 = Timer , Prescale = 256
    On Timer0 Isr_timer0
    Enable Timer0
    Const Timer0_reload = 217                                   'Wert für 0.5ms
    
    'Drehencoder
    Config Portd.4 = Input : Set Portd.4 : Rotary_button Alias Pind.4       'Taste
    Config Portd.5 = Input : Set Portd.5 : Ph_a Alias Pind.5    'Encoder Signal A
    Config Portd.6 = Input : Set Portd.6 : Ph_b Alias Pind.6    'Encoder Signal B
    
    '*******************************************************************************
    '***   Variablen                                                             ***
    '*******************************************************************************
    'Variablen
    Dim Rotary As Byte                                          'Aktuelles Rasterwert (A,B)
    Dim Rotary1 As Byte                                         'Übergangswert (A,B) zwischen Rastungen
    Dim Rotary2 As Byte                                         'Letzter Rasterwert (A,B)
    Dim R_flag As Bit , L_flag As Bit                           'Flags für Links- / Rechtsdrehung
    Dim Rotary_value As Byte                                    'Zahlenwert des Encoders
    
    Dim Rotary_key As Byte : Rotary_key = &HFF                  'Schieberegister Taste, &HFF: nicht gedrückt
    Dim Press_flag As Bit                                       'Flag Taste wurde gedrückt
    Dim Release_flag As Bit                                     'Flag Taste wurde losgelassen
    
    '*******************************************************************************
    '***   HAUPTPROGRAMM                                                         ***
    '*******************************************************************************
    
    Enable Interrupts
    
    Do
    'Beispiel zur Auswertung der Flags und des Encoder-Werts im Hauptprogramm
       If R_flag = 1 Then                                       'Drehung nach Rechts
          Reset R_flag
          Print "Rechts"
          Print Rotary_value
       End If
       If L_flag = 1 Then                                       'Drehung nach Links
          Reset L_flag
          Print "Links"
          Print Rotary_value
       End If
       If Press_flag = 1 Then                                   'Taste wurde gedrückt
          Reset Press_flag
          Print "gedrueckt"
       End If
       If Release_flag = 1 Then                                 'Taste wurde losgelassen
          Reset Release_flag
          Print "losgelassen"
       End If
    Loop
    End
    
    '*******************************************************************************
    '***   ISR_TIMER0                                                            ***
    '***   Periodische Auswertung des Dreh-Encoders                              ***
    '*******************************************************************************
    Isr_timer0:
    Timer0 = Timer0_reload
    
    Shift Rotary , Left , 1                                     'Schieberegister für Entprellung (A,B)
    Rotary.4 = Ph_a                                             'Phase A lesen -> Bit 4
    Rotary.0 = Ph_b                                             'Phase B lesen -> Bit 0
    
    If Rotary <> Rotary2 Then                                   'Neues Signalpaar (A,B) ?
       Select Case Rotary
          Case &B0000_0000                                      'Aktuell (A,B)= (0,0)
             If Rotary1 = &B1111_0000 Then                      'Übergang war (A,B)= (1,0), also
                Set R_flag                                      'Rechtsdrehung
                Incr Rotary_value                               'Encoder-Wert erhöhen
             Elseif Rotary1 = &B0000_1111 Then                  'Übergang (A,B)= (0,1), also
                Set L_flag                                      'Linksdrehung
                Decr Rotary_value                               'Encoder-Wert verringern
             End If
             Rotary2 = &B0000_0000                               'Aktuelles (A,B) in vorheriges (A,B)
          Case &B0000_1111                                      'Übergang (A,B)= (0,1) zwischen Rastungen
             Rotary1 = &B0000_1111                              'erkennen und in abspeichern
          Case &B1111_0000                                      'Übergang (A,B)= (1,0) zwischen Rastungen
             Rotary1 = &B1111_0000                              'erkennen und abspeichern
          Case &B1111_1111                                      'Aktuell (A,B)= (1,1)
             If Rotary1 = &B0000_1111 Then                      'Übergang war (A,B)= (0,1), also
                Set R_flag                                      'Rechtsdrehung
                Incr Rotary_value                               'Encoder-Wert erhöhen
             Elseif Rotary1 = &B1111_0000 Then                  'Übergang war (A,B)= (1,0), also
                Set L_flag                                      'Linksdrehung
                Decr Rotary_value                               'Encoder-Wert verringern
             End If
             Rotary2 = &B1111_1111                              'Aktuelles (A,B) in vorheriges (A,B)
       End Select
    End If
    
    Shift Rotary_key , Left , 1                                 'Schieberegister für Entprellung Taste Encoder
    Rotary_key.0 = Rotary_button                                'Taste lesen -> Bit 0
    
    If Rotary_key = &B1000_0000 Then                            'Taste wurde gedrückt
       Set Press_flag
    Elseif Rotary_key = &B0111_1111 Then                        'Taste wurde losgelassen
       Set Release_flag
    End If
    Return
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken encoder.png  

Berechtigungen

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

Solar Speicher und Akkus Tests