Forum: Projekte & Code Mehrere Drehgeber verarbeiten (ungetestet)


von Rene B. (themason) Benutzerseite


Angehängte Dateien:

Lesenswert?

In Anlehnung an den hochkompakten Tastatur-Abfrage-Code von Peter 
Dannegger habe ich mir etwas überlegt um mehrere Drehgeber (vielfaches 
von 8) auslesen und verarbeiten zu können. Dieser Code ist erstmal nur 
ein Grundgerüst welches ich mangels Drehgeber (habe gerade keine 
8/16/24/32 Drehegeber zur Hand :-)) noch nicht testen konnte. Die 
eigentliche Drehgeber-Routine verwende ich (in leicht veränderter Form) 
in einem meiner Projekte und stammt z.T. aus der Code-Beschreibung von 
Peter Dannegers Drehgeber-Routine (wobei die von Peter noch deutlich 
kompakter ist als meine Lösung, da ich die Eingänge entprelle, in einen 
Gray-Wert konvertiere und mit dem aktuellen und dem letzten Gray-Wert 
ein Increment bzw Decrement einer Variablen auslöse).
Auf Basis dieser Vorgehensweise (und weil ich so fasziniert von der 
Byte-Weisen verarbeitung des Tastatur-Ports in PeDa's Code-Beispiel war) 
habe ich diesen Code geschrieben.
Damit kann ein vielfaches von 8 Drehgebern ausgelesen werden. Die 
Anpassung an die jeweilige Hardware (wie die Port-Pins eingelesen werden 
ist der Drehgeber Routine eig. egal, es muß nur eine möglichkeit geben 
einen Port X für die 8 A und 8 B Pins auswählen zu können sofern mehr 
als 8 Drehgeber angeschlossen sind) passiert nur in dem Makro ENC_A und 
ENC_B. Mit ENC_BYTES wird bestimmt wieviele Drehgeber-Ports vorhanden 
sind (wie gesagt : wie die ports ausgelesen werden ist zweitrangig, da 
je nach hardware die ports per SPI, I2C, Parallel oder sonstwie 
angebunden sein können).

Zur Funktionsweise :

Über die Makros ENC_A und ENC_B wird der aktuelle zustand eines Ports 
für
die A und B Pins des Drehgebers ausgelesen. In jeweils 3 Variablen für A 
und B werden die letzten 3 Werte gespeichert. Über eine UND-Verknüpfung 
wird die positive oder negative Flanke erkannt (entprellen). Aus dem 
Entprellten A und B Signal wird der Gray-Code gebildet. Mit dem letzten 
und dem aktuellen Gray-Wert wird ein Inkrement-Puls und ein 
Richtungs-Puls berechnet. Diese beiden Pulse verändern letztendlich den 
Inhalt der Drehgeber Variablen.

Ich hoffe das mal jemand über den Code drüberschauen kann und bei 
gelegenheit auch mal testen kann (sofern ich entsprechend Drehgeber habe 
werde ich dies auch mal tun und ggf code änderungen hier posten).

von Marc H. (bauerpilot)


Lesenswert?

Hallo Rene,
gibt es Neuigkeiten in Deinem Projekt? Das ist genau das, was ich suche. 
Allerdings reicht mit eine Version, in der nur so viele Drehgeber 
angeschlossen sind, wie Eingabepins vorhanden sind.
Ich habe die Originalversion von Peter für einen Drehgeber am laufen und 
bin begeistert. Jetzt suche ich nach einer Version für 3-4 Drehgeber. 
Zum Einsatz kommt aktuell ein Attiny 2313, später vielleicht ein 
ATMega8.

Gruß Marc

von Peter D. (peda)


Lesenswert?

Marc Höner schrieb:
> Jetzt suche ich nach einer Version für 3-4 Drehgeber.

Schreibste eben die Funktion 4-mal in den Interrupthandler, jeweils mit 
anderen Pins und Variablen.


Peter

von Marc H. (bauerpilot)


Lesenswert?

Danke für den Tipp, werde ich versuchen.
Bin aber gerade auf ein anderes Problem gestossen. Ich habe einfach ein 
neues Projekt erstellt und den Quelltext hineinkopiert. Wenn ich jetzt 
den gleichen Quelltext kompiliere, bekomme ich folgende Warnmeldung:

"c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:85:3: 
warning: #warning "F_CPU not defined for <util/delay.h>""

Wieso bekomme ich die bei der Kopie und nicht beim Original?
Was muss ich tun um die Warnung zu vermeiden?

Gruß Marc

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Marc Höner schrieb:
> Wieso bekomme ich die bei der Kopie und nicht beim Original?
Darum:
> Ich habe einfach ein neues Projekt erstellt

> Was muss ich tun um die Warnung zu vermeiden?
Gib in deinem neuen Projekt einfach auch eine F_CPU an.

von Marc H. (bauerpilot)


Lesenswert?

Dumme Frage, was ist eine F_CPU, die Quarzfrequenz?

Gruß Marc

von TheMason (Gast)


Lesenswert?

Jups

Zu deiner Frage. Habe es mangels Drehgebern (und passendem Projekt) noch 
nicht getestet. Habe zwar ein projekt dazu im Kopf, aber momentan keine 
Lust und kein Geld 22 Drehgeber und 5 Displays für meinen Synthesizer 
zusammenzuschrauben :-)

Wäre dankbar wenn jemand den Code mal testen könnte. Für Fragen und 
Feedback bin ich jederzeit offen.

von Marc H. (bauerpilot)


Lesenswert?

Hallo Peter
und natürlich auch alle anderen,

so richtig komme ich nicht weiter. Ich habe jetzt alle aus meiner Sicht 
notwendigen Teile kopiert und mit anderen PINs und Variablen versehen.
Leider funktioniert nur ein Drehgeber. Beim anderen geht eine LED an und 
nichts weiter.
Hier der Code:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>


                // target: ATTiny2313
//---------------------------------------------------------------------- 
--

#define XTAL        8e6         // 8MHz

#define PHASE_A     (PIND & 1<<PD0)
#define PHASE_B     (PIND & 1<<PD1)
#define PHASE_C      (PIND & 1<<PD3)
#define PHASE_D    (PIND & 1<<PD4)

#define LEDS_DDR    DDRB
#define LEDS        PORTB           // LEDs against VCC



volatile int8_t enc_delta_1, enc_delta_2;          // -128 ... 127
static int8_t last_1, last_2;


void encode_init( void )
{
  int8_t new_1, new_2;

  new_1 = 0;
  new_2 = 0;

  if( PHASE_A )
    new_1 = 3;
  if( PHASE_B )
    new_1 ^= 1;                   // convert gray to binary
  last_1 = new_1;                   // power on state
  enc_delta_1 = 0;

  if( PHASE_C )
    new_2 = 3;
  if( PHASE_D )
    new_2 ^= 1;                   // convert gray to binary
  last_2 = new_2;                   // power on state
  enc_delta_2 = 0;

  TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10);     // CTC, XTAL / 64
  OCR1A = (uint16_t)(XTAL / 64.0 * 1e-3 - 0.5);   // 1ms
  TIMSK |= 1<<OCIE1A;
}


ISR( TIMER1_COMPA_vect )             // 1ms for manual movement
{
  int8_t neu_1, neu_2, diff_1, diff_2;

  neu_1 = 0;
  if( PHASE_A )
    neu_1 = 3;
  if( PHASE_B )
    neu_1 ^= 1;                             // convert gray to binary
  diff_1 = last_1 - neu_1;                  // difference last - new
  if( diff_1 & 1 ){                         // bit 0 = value (1)
    last_1 = neu_1;                         // store new as next last
    enc_delta_1 += (diff_1 & 2) - 1;        // bit 1 = direction (+/-)
  }


  neu_2 = 0;
  if( PHASE_C )
    neu_2 = 3;
  if( PHASE_D )
    neu_2 ^= 1;                             // convert gray to binary
  diff_2 = last_2 - neu_2;                  // difference last - new
  if( diff_2 & 2 ){                         // bit 0 = value (1)
    last_2 = neu_2;                         // store new as next last
    enc_delta_2 += (diff_2 & 2) - 1;        // bit 1 = direction (+/-)

  }



}

int8_t encode_read_1( void )         // read two step encoders
{
  int8_t val;


  cli();
  val = enc_delta_1;
  enc_delta_1 = val & 1;
  sei();
  return val >> 1;
}

int8_t encode_read_2( void )         // read two step encoders
{
  int8_t val;


  cli();
  val = enc_delta_2;
  enc_delta_2 = val & 1;
  sei();
  return val >> 1;
}

 int main( void )
{

  int8_t richt_1, richt_2, cnt_1, cnt_2, cnt;
  cnt = 80;
  cnt_1 = 0;
  cnt_2 = 0;
  PORTD = 0xFF;
  DDRD = 0x00;
  LEDS_DDR = 0xFF;
  LEDS = 0x0F;
  encode_init();
  sei();

  for(;;){
     richt_1 = encode_read_1();
     richt_2 = encode_read_2();
    if (richt_1 > 0) {
      LEDS = 0b00001011;
      cnt_1 = cnt;
    }
    else if (richt_1 < 0) {
      LEDS = 0b00000111;
      cnt_1 = cnt;
    }
    else if (richt_2 > 0) {
      LEDS = 0b00001110;
      cnt_2 = cnt;
    }
    else if (richt_2 < 0) {
      LEDS = 0b00001101;
      cnt_2 = cnt;
    }

    if (cnt_1 >0) cnt_1--;
    if (cnt_2 >0) cnt_1--;
    if (cnt_1 == 0) LEDS |= 0b00001100;
    if (cnt_2 == 0) LEDS |= 0b00000011;
    _delay_ms(1);

  }
}

Hat einer eine Idee?

Gruß Marc

von Marc H. (bauerpilot)


Lesenswert?

Hat sich erledigt, habe meine Tippfehler gefunden.
Gruß Marc

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.