Hallo, es gibt zwar einige Themen bezüglich Drehencoder, aber ich mach noch einen ;-). Nein, ich habe keine Antwort auf die Frage gefunden: Es geht darum, einen Drehencoder (den Pana von Pollin) an einem ATMEGA8515 auszuwerten. Das Ding hängt an PD6 und PD7, der gemeinsame Anschluss auf Masse. Pullups sind aktiv, das klappt alles. Ich hab ein SPeicherregister (encoder_state), welches den vorherigen Zustand speichern kann und 3 Temp Register (temp1, temp2, temp3) für den Fall zur verfügung. Prroblem an der Sache: Ich kann weder die Pins am µC ändern (auf einen IRQ Pin legen oder sowas) noch einen Timer verwenden, da alle beiden Timer bereits vergeben sind. Ich hab jetzt immer versucht, nachdem ich "11" oder "00" eingelesen habe, im nächsten Schritt zu schauen, welcher der beiden Pins ist als erstes gewechselt, dann gehts Zeittechnisch einfacher, da die Drehencodergeschichte nur ca 10x die Sekunde aufgerufen wird. Der Zustand, in der Rasterung muss eigentlich immer 11 oder 00 sein, leider ist das hier nicht immer so. Hat jemand einen Code, oder zumindest anregungen, wie man das ohne Hilfsmittel mit dem bloßen 2 Pins ohne Timer und IRQs lösen kann, eine links und rechtsdrehung zu unterscheiden und ein Unterprogramm aufzurufen? Wenns geht kein C Code.
Michael Juen schrieb: > Prroblem an der Sache: Ich kann weder die Pins am µC ändern (auf einen > IRQ Pin legen oder sowas) noch einen Timer verwenden, da alle beiden > Timer bereits vergeben sind. Darf ich fragen womit? Meistens kann man auch mehrere Funktionalitäten in eine Timer-ISR legen.
Du fragst jetzt nicht wirklich, wie man Drehencoder auswertet? Was bitteschön gefällt dir an den ungefähr 10000 Beschreibungen wie man Drehencoder auswertet nicht ? http://dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29 Nein, man braucht keinen Timer, man muss nur nicht zu schnell (sinnlos) und nicht zu langsam (man verliert Schritte) abfragen. Und geh nicht wie im psychotischen Zwang gerade den Weg, der nicht zum Erfolg führt, nämlich den Weg der Flankenerkennung.
Pins im Hauptprogramm in einer Endlosschleife pollen, um die Auswertung vorzunehmen. Dann brauchst du keinen Timer.
Timer bräuchte er wenn er die Drehgeschwindigkeit erfassen will, z.B. für schnelles Scrollen (wenn man schneller dreht werden pro realen Schritt mehrere in Software gemacht).
Michael Juen schrieb: > erstes gewechselt, dann gehts Zeittechnisch einfacher, da die > Drehencodergeschichte nur ca 10x die Sekunde aufgerufen wird. > Der Zustand, in der Rasterung muss eigentlich immer 11 oder 00 sein, Das ist definitiv zu wenig, gerade weil Du die Werte zwischen zwei Raststellungen sicher erkennen must, um die Drehrichtung zu erkennen. 100x pro Sekunde ist meiner Meinung nach immer noch zuwenig, wenn man halbwegs schnell drehen will. Ich verwende 1000x pro Sekunde...
Ich mach`s in einem Job der Mainloop, der 1000 mal pro Sekunde aufgerufen wird, natürlich von einem Timer synchronisiert, der nebenher noch andere Dinge erledigt. ...
Falls Du Bascom verwendest, probier mal: Dim Flag_dreh_flanke As Bit Dim Dreh_impulse As Integer Set Portd.6 ' Pullups einschalten Set Portd.7 Config Portd.6 = Input ' Drehgeber Config Portd.7 = Input Do ' Drehcoder auswerten und dann die Impulse zaehlen ' ... muss möglichst oft durchlaufen werden If Flag_dreh_flanke = 0 Then If Pind.6 = 1 Then Set Flag_dreh_flanke If Pind.7 = 1 Then Incr Dreh_impulse Else Decr Dreh_impulse End If End If Else If Pind.6 = 0 Then Reset Flag_dreh_flanke If Pind.7 = 0 Then Incr Dreh_impulse Else Decr Dreh_impulse End If End If End If ' und alle anderen Programmteile loop Gruß allu
Hallo, Mit Bascom kann ich nicht dienen, aber mit rein interruptgesteuerter Verarbeitung. Ich persönlich finde das mit dem Timer-Polling auch nicht so doll, oft versuche ich den uC so gut es geht schlafen zu lassen. Zugegeben hat man beim Prellen des Kontaktes einen Haufen "unnütze" Interrupts, aber halt auch nur wenn jemand dran dreht und nicht ständig. Bei der Auswertung ist der "Trick" gegen Prellen, dass man eine State-Machine mitführen muß. Flanken auf einem Kontakt erzeugen dann noch keine Schritte, sondern erst wenn ein Zyklus komplett ist. Oft sieht man die Primitivimplementierung: Bei Flanke an dem einen Kontakt nimm den anderen für die Richtung. Das funktioniert nicht zuverlässig! Den Code hier habe ich mit dem dem Panasonic-Encoder von Pollin erfolgreich im Einsatz. Ist aus dem Forum abgeguckt. Das Message-Senden an die Hauptschleife mag natürlich bei euch anders aussehen. Es gibt auch andere Encoder, mit Rastung nach 360° der Pulsfolge, nicht nach 180°. Dann wird es komplizierter. Habe ich auch, aber ist nicht so elegant.
1 | #include <stdint.h> |
2 | #include <avr/io.h> // for device register definitions |
3 | #include <avr/interrupt.h> // for interrupt handlers |
4 | #include <util/delay.h> // for delay loops |
5 | #include "msg.h" // messages waking up the main loop |
6 | #include "rotary.h" // own interface |
7 | |
8 | // define how the encoder is connected (Port B is hard coded)
|
9 | #define ENC_A PB4
|
10 | #define ENC_B PB1
|
11 | |
12 | static uint8_t rotary_status; |
13 | static uint8_t rotary_step; |
14 | |
15 | |
16 | void rotary_init(void) |
17 | {
|
18 | PORTB |= _BV(ENC_B) | _BV(ENC_A); // enable pullups |
19 | |
20 | _delay_us(10); // let the lines settle before reading the current status |
21 | |
22 | rotary_status = rotary_step = PINB & (_BV(ENC_A) | _BV(ENC_B)); |
23 | |
24 | PCMSK0 |= _BV(PCINT1) | _BV(PCINT4); // enable the line for pin change interrupt |
25 | PCICR |= _BV(PCIE0); // enable pin change interrupt 0, for port B |
26 | }
|
27 | |
28 | |
29 | SIGNAL(SIG_PIN_CHANGE0) |
30 | {
|
31 | uint8_t status_cur; |
32 | |
33 | status_cur = PINB & (_BV(ENC_A) | _BV(ENC_B)); // read the change |
34 | if ((status_cur ^ rotary_step) == (_BV(ENC_A) | _BV(ENC_B))) // both lines have changed? |
35 | { // full gray code cycle is done |
36 | struct msg message; // message for result |
37 | message.id = e_rotary; |
38 | |
39 | if ((status_cur ^ rotary_status) == _BV(ENC_A)) // contact A |
40 | { // turn towards the right |
41 | message.bdata = 1; |
42 | }
|
43 | else
|
44 | { // turn towards the left |
45 | message.bdata = -1; |
46 | }
|
47 | msg_post(&message); // send it |
48 | |
49 | rotary_step = status_cur; // remember stable state |
50 | }
|
51 | rotary_status = status_cur; // remember any state |
52 | }
|
Gruß Jörg
Hallo, hier noch eine Version in Assembler. Der Aufruf der Routine erfolgt alle 277µs. Die Rückgabewerte für L/R liegen in den Variablen ,countRIGHT' und ,countLEFT'. Gruß Marcus
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.