Forum: Mikrocontroller und Digitale Elektronik Drehgeber mit Interrupts in Bascom auswerten


von praktiker (Gast)


Angehängte Dateien:

Lesenswert?

Guten Abend,

für ein aktuelles Projekt möchte ich das erste Mal in meinem 
Elektronikerleben einen Drehgeber einbauen. Bisher hat mich die 
Auswertung davon etwas abgeschreckt, heute habe ich mich doch mal 
reingearbeitet.
Wäre jemand so nett, meine Idee zu prüfen? Verwendet werden soll ein 
Attiny2313 mit INT0 und INT1.
Spur A hängt auf INT0 und Spur B auf INT1. Der Verständlichkeit halber 
nenne ich INT0 "INT A" und INT1 "INT B".

Das Problem mit dem Prellen möchte ich auf der Annahme lösen, dass nach 
einer Änderung auf einer Spur (z.B. A) immer erst eine Änderung auf der 
anderen Spur (z.B. B) passiert, bevor sich Spur A wieder ändern kann. 
Also kann ich nach dem Interrupt auf einer Spur für diese Spur den 
Interrupt abschalten und den für die andere Spur wieder aktivieren.

INT A und INT B werden als "changing" gesetzt.

Innerhalb von INT A und INT B gibt es ein if-else, mit dem ich zwischen 
LOW-HIGH (Pin=1) und HIGH-LOW (Pin=0) unterscheide.

Deshalb würde ich drei Fälle definieren:
1
1. INT A: LOW → HIGH
2
  a) INT A deaktivieren
3
  b) INT B aktivieren
4
  c) A = 1
5
6
2. INT A: HIGH → LOW
7
  a) INT A deaktivieren
8
  b) INT B aktivieren
9
  c) A = 0
10
11
3. INT B: HIGH → LOW
12
  a) INT B deaktivieren
13
  b) INT A aktivieren
14
  c) Wenn A = 1 dann RECHTS = 1 und LINKS = 0
15
     ELSE RECHTS = 0 und LINKS = 1
16
17
4. INT B: LOW → HIGH
18
  a) INT B deaktivieren
19
  b) INT A aktivieren
20
  c) Wenn A = 0 dann RECHTS = 0 und LINKS = 1
21
     ELSE RECHTS = 1 und LINKS = 0

Habe ich hier einen (groben) Denkfehler oder kann ich das (in Bascom) so 
umsetzen?

Danke und schönen Abend!

von Jobst M. (jobstens-de)


Lesenswert?

Einen Drehgeber mit Flankeninterrupts auszuwerten ist keine gute Idee, 
denn die Dinger prellen.
Starte einen Timer, welcher alle 0,1 - 1ms einen IRQ auslöst.
Lies die beiden Bits ein und zusammen mit den beiden Bits vom vorherigen 
IRQ hast Du 4 Bit, welche eine Zahl von 0-15 representiert.
In einem eindimensionalen Array hast Du eine Tabelle, welche entweder 0, 
1 oder -1 enthält. Diesen Wert summierst Du zu einer Variablen, welche 
dann außerhalb des IRQs ausgelesen werden kann. Sie enthält die Position 
des Gebers.


Gruß
Jobst

von praktiker (Gast)


Lesenswert?

Jobst M. schrieb:
> denn die Dinger prellen.

Deshalb die Idee, den prellenden Interrupt nach dem ersten Auslösen 
sofort zu deaktivieren und erst durch den anderen Interrupt (wenn also 
nichts mehr prellt) wieder zu aktivieren.

Dein Vorschlag klingt aber auch interessant. Ich versuche das mal zu 
verstehen.

von Jobst M. (jobstens-de)


Lesenswert?

praktiker schrieb:
> Deshalb die Idee, den prellenden Interrupt nach dem ersten Auslösen
> sofort zu deaktivieren und erst durch den anderen Interrupt (wenn also
> nichts mehr prellt) wieder zu aktivieren.

Und was passiert, wenn der Bediener gar nicht mehr so weit dreht und 
wieder zurück dreht? ;-)

Gruß
Jobst

von Bernd (Gast)


Lesenswert?

Wenn der Drehgeber sich in beide Richtungen drehen kann, ist die 
Annahme, dass erst auf dem anderen Interrupt was passieren muss, bevor 
sich auf dem ersten wieder etwas ändert, falsch. Man kann beispielsweise 
bei einer Rechtsdrehung die L/H-Flanke von Interrupt A überfahren und 
anschließend bei einer Linksdrehung kommt die H/L-Flanke von A ohne dass 
sich bei Interrupt B etwas geändert hat.
Eigentlich ist es ganz einfach. Man betrachtet die 4 Ereignisse L/H- 
oder H/L-Flanke auf Interrupt A und L/H- oder H/L-Flanke auf Interrupt 
B. In allen 4 Fällen schaut man ob der andere Interrupt gerade auf L 
oder H steht. Ergibt 8 Möglichkeiten, bei 4 von ihnen war es ein Schritt 
nach links und bei 4 ein Schritt nach rechts. Die Entprellung geschiet 
ganz automatisch dadurch, dass die Interruptbearbeitung etwas Zeit 
benötigt. Im schlimmsten Fall gibt es halt noch mal einen Schritt vor 
und einen zurück.
Ich hab das ganze mal für einen PIC programmiert.

Bernd

von Achim H. (pluto25)


Lesenswert?

Nur einen Interrupt benutzen, darin den Zweiten Pin abfragen um die 
Richtung zu bestimen und den Int sperren bis die Main es ausgewertet 
hat. (Oder ohne Auwertung rausspringen bis die Main es verarbeitet hat)

von Jobst M. (jobstens-de)


Lesenswert?

Pseudocode:
1
timerIRQ() {
2
  DGbits = DGbits + Pin1*8 + Pin2*4;
3
  DGvalue = DGvalue + DGArray[DGbits];
4
  DGbits = DGbits >> 2;
5
6
  (anderes timerIRQ Zeug)
7
};
8
9
10
DGArray = array(0,0,0,0,0,0,0,1, 0,0,0,0,0,-1,0,0);
11
12
; Oder, um jeden Übergang zu zählen:
13
DGArray = array(0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0);

Gruß
Jobst

von Jobst M. (jobstens-de)


Lesenswert?

A. H. schrieb:
> Int sperren bis die Main es ausgewertet
> hat

Wozu einen IRQ, wenn man anschließend sowieso pollt?

Gruß
Jobst

von Paul Angerlander (Gast)


Lesenswert?

praktiker schrieb:
> oder kann ich das (in Bascom) so
> umsetzen?

Mal eine Frage, würde das in Bascom mit der Funktion Encoder auch 
funktionieren.
Du verwendest allerdings einen Assbach Uralt Controller.
In der Bascom Hilfe steht.

Most new processors support the pin change  interrupt. This means that 
an interrupt occurs when the logic level of a pin changes. you can use 
this interrupt to call the encoder function. This way you can be sure 
you will

Das Beispiel dazu sieht so aus:

$regfile = "m128def.dat"                                   ' specify the 
used micro

$crystal = 4000000                                         ' used 
crystal frequency

$baud = 19200                                               ' use baud 
rate

$hwstack = 32                                               ' default 
use 32 for the hardware stack

$swstack = 10                                               ' default 
use 10 for the SW stack

$framesize = 40                                             ' default 
use 40 for the frame space



Print "Encoder test"

Dim B As Byte

'we have dimmed a byte because we need to maintain the state of the 
encoder



Portb = &B11                                               ' activate 
pull up registers



Do

  B = Encoder(pinb.0 , Pinb.1 , Links , Rechts , 1)

  '                                               ^--- 1 means wait for 
change which blocks programflow

  '                               ^--------^---------- labels which are 
called

  '              ^-------^---------------------------- port PINs

  Print B

Waitms 10

Loop

End



'so while you can choose PINB0 and PINB7,they must be both member of 
PINB

'this works on all PIN registers



Links:

Print "left rotation"

Return

Rechts:

Print "right rotation"

Return

End

Schau bitte in der Hilfe das an, hier gibt es wohl ein Problem mit Text 
einfügen.

von Gerald B. (geraldb)


Lesenswert?

praktiker schrieb:
> für ein aktuelles Projekt möchte ich das erste Mal in meinem
> Elektronikerleben einen Drehgeber einbauen. Bisher hat mich die
> Auswertung davon etwas abgeschreckt, heute habe ich mich doch mal
> reingearbeitet.
> Wäre jemand so nett, meine Idee zu prüfen? Verwendet werden soll ein
> Attiny2313 mit INT0 und INT1.

Warum?
RTFM!

Einfach das Kapitel 7.46 ENCODER lesen.

von MaWin (Gast)


Lesenswert?

praktiker schrieb:
> Deshalb die Idee, den prellenden Interrupt nach dem ersten Auslösen
> sofort zu deaktivieren und erst durch den anderen Interrupt (wenn also
> nichts mehr prellt) wieder zu aktivieren.

So so, den Unsinn hast du unter einem anderen Namen doch schon mal zu 
verbreiten gesucht:

Beitrag "Drehgeber an Arduino, external interrupt ISR wird doppelt ausgeführt"

Es war mühsam, aber nach dem man die Zählfehler der Routine aufgedeckt 
hatte, gab der Troll erstmal Ruhe.

Nun also schon wieder einer auf dem Holzweg.

von Harald W. (wilhelms)


Lesenswert?

praktiker schrieb:

> für ein aktuelles Projekt möchte ich das erste Mal in meinem
> Elektronikerleben einen Drehgeber einbauen.
> Das Problem mit dem Prellen möchte ich auf der Annahme lösen, dass nach
> einer Änderung auf einer Spur (z.B. A) immer erst eine Änderung auf der
> anderen Spur (z.B. B) passiert, bevor sich Spur A wieder ändern kann.
> Also kann ich nach dem Interrupt auf einer Spur für diese Spur den
> Interrupt abschalten und den für die andere Spur wieder aktivieren.

Warum nimmst Du nicht gleich die sog. Zustandsauswertung, bei der
das Prellen keine Rolle spielt? Siehe auch dse-faq.

von Peter D. (peda)


Lesenswert?

praktiker schrieb:
> Also kann ich nach dem Interrupt auf einer Spur für diese Spur den
> Interrupt abschalten und den für die andere Spur wieder aktivieren.

Das ist vermutlich die Variante, die in vielen kommerziellen Geräten 
implementiert ist und für maximalen Frust bei den Benutzern sorgt. Die 
prellt ohne Ende.

Wichtig ist, daß man sich den alten Zustand merkt und keinen Interrupt 
disabled. Dann kann bei einem Preller der nächste Flankeninterrupt 
sofort wieder zurück zählen, d.h. der Preller wird kompensiert.

von Falk B. (falk)


Lesenswert?

praktiker schrieb:
> Wäre jemand so nett, meine Idee zu prüfen? Verwendet werden soll ein
> Attiny2313 mit INT0 und INT1.
> Spur A hängt auf INT0 und Spur B auf INT1. Der Verständlichkeit halber
> nenne ich INT0 "INT A" und INT1 "INT B".

Nicht schon wieder! NEIN! Wie es richtig geht, siehe Drehgeber, das 
geht auch in BASCOM. Dort gibt es sogar schon einen Befehl dafür, den 
man nur periodisch in einem Timer-Tinerrupt aufrufen muss!

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


Lesenswert?

praktiker schrieb:
> Das Problem mit dem Prellen möchte ich auf der Annahme lösen, dass nach
> einer Änderung auf einer Spur (z.B. A) immer erst eine Änderung auf der
> anderen Spur (z.B. B) passiert, bevor sich Spur A wieder ändern kann.
Diese Annahme ist falsch. Also ist logischerweise das gesamte darauf 
aufbauende Konzept auch falsch.

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.