Ich versuche einen einfachen Drehencoder für meine Navigation im Menü
abzufragen und verzweifle an dieser einfachen aufgabe.
Der Code ist Simpel:
INT0 wird von pin 1 ausgelößt und pin 2 wird abgefragt um festzustellen
ob vor- oder rückwärts gedreht wird.
Das Funktioniert aber extrem schlecht. Warum verstehe ich nicht.
Habe mit dem Oszi schon Geschaut, ob da was Prellt oder ähnliches.
Herunter zählt er relativ gut bis auf dass er gerne zahlen überspringt.
vorwärts zählt er fast gar nicht, egal ob schnell oder langsahm gedreht
wird.
Hardware:
Mega328P in TQFP Gehäuse
Display
China Drehencoder (Prellt laut oszi nicht)
Code Komplett:
Wenn dein Programm anders aufgebaut ist als hier
https://www.mikrocontroller.net/articles/Drehgeber beschrieben, solltest
du besser erklären, wie deins funktioniert/funktionieren soll. Viele
Kommentare im Programm erleichtern das Verständnis.
Ich sehe nicht, daß die Pull-up Widerstände an den Eingängen für den
Encoder eingeschaltet sind. Das ist wichtig, um eindeutige Pegelwechsel
zu produzieren.
Also hier:
Config Pind.3 = Input 'Button
(int0)
Config Pind.2 = Input 'Input A
(int1)
Config Pind.4 = Input 'Input B
noch ergänzen:
Port.d = &B00011100
Herbert
Andy _. schrieb:> Der Code ist Simpel:> INT0 wird von pin 1 ausgelößt und pin 2 wird abgefragt um festzustellen> ob vor- oder rückwärts gedreht wird.>> Das Funktioniert aber extrem schlecht.
Natürlich.
> Warum verstehe ich nicht.
Das liegt am Prinzip den flankengetriggerten Interrupts.
Frage es nach
http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29
ab und es funktioniert schlicht und einfach.
Andy _. schrieb:> 'Pin wird 1000 mal abgefragt um ein prelen auszuschließen> 'Sollte unter 2ms dauern
Also, erstmal eines: deinen Basic-Dialekt verstehe ich nicht wirklich,
hab zuletzt in den 80er Jahren Basic angefaßt.
Aber so, wie ich es mir aus deinem Code herauszulesen glaube, machst du
sehr seltsame und mir nicht nachvollziehbare Aktionen. Ich versuche mal,
hier einen für die allermeisten Drehgeber passenden Pseudo-Code zu
formulieren:
portbit A; COMMENT: Eines der beiden Drehgebersignale
portbit B; COMMENT: das andere Drehgebersignal
boolean R; COMMENT: die aktuelle Drehrichtung
integer Z; COMMENT: eben ein Auf- und Abwärtszähler
if detected (Flanke(A) = (H to L) or Flanke(A)= (L to H))
then do
begin
LET R = A xor B;
COMMENT: R enthält jetzt die Richtung
if R = true
then LET Z = Z + 1;
else LET Z = Z - 1;
COMMENT: Z enthält den aktuellen Zählerstand
end
end;
So, vielleicht nützt es ja was..
W.S.
Klar ist es ein Mechanischer Drehencoder..
soweit ich das gesehen hab sind nur die teuersten optisch.
Ich werde sicher nicht mehr als 10€ für so einen blöden knopf ausgeben.
Diese China dinger haben ~50ct pro stk gekostet.
Pullups hab ich je einen 5,1k Widerstand nach GND
Wenn man meinen Code gründlich ließt sollte die Funktion schon Leicht
erkennbar sein, da der Code ja minimal ist.
Hier die Funktion einmal erklärt:
Das Programm Läuft in der Schleife und Zeigt die Werte der Variable an,
die mit dem Encoder Verändert werden kann.
Der Encoder ist an INT0 angeschlossen und lößt beim Drehen einen
Interrupt aus.
Dieser Inerrupt Arbeitet ein Unterprogramm ab, welches zu Testzwecken
den 2. Pin Des Drehencoders 1000mal abfragt.
Ist Pin2(Encoder) ein mal in allen Abfragen "High" wird die Variable um
1 erhöt.
Ist Pin2(Encoder) "low" wird die Variable um 1 verringert.
Ende vom Interrupt
Nocheinmal einfach:
Encoder 1 = 1 & Encoder 2 = 1
Addieren (+)
Encoder1 = 1 & Endoder 2 = 0
Subtrahieren (-)
Meistens ist das signal vom Encoder 1000 von 1000 "High" nur selten 900
von 1000.
Trotzdem zählt er oft gar nicht(trotz ausgeführten interrupts) oder nur
sehr unzuverlässig aufwärts (+)
Runter (-) geht zielich gut.
Auf dem Oszi sehen die Signale wie auf der Zeichnung aus !!!
Sehr steile Flanken.
Deshalb ist es für mich völlig unklar, warum es nicht funktioniert.
Naja, dein Code fragt ja 1000 mal ab, sobald aber ein einziges Mal PIND4
1 ist, wird X auf 1 gesetzt. Wenn du runterzählst, wird der Wert ja auch
übernommen, wenn Tc entsprechend hoch ist. Zählst du aber hoch, reicht
ein einziges Prellen aus, damit die Eingabe komplett verworfen wird.
Böse gesagt ist das kein Entprellen, sondern ein "Verprellen" ;-)
Ja genau wie dein Code Funktioniert auch meiner.
Ich könnte da eine menge weg lassen, was aber nichts ändert.
Die 1000 abfragen waren nur um zu testen ob der encoder prellt.
Das tut er aber nicht.
Hier nochmal abgespeckt:
Das hast du Falsch verstanden :-)
Wenn Pind.4 einmal "high" gewesen ist soll er ja hoch zählen...
Das Geht aber eben nicht.
Runter geht immer heißt wenn Pind.4 alle 1000 abfragen brav "low" war.
Genau das gegenteil was man erwarten würde :/
Ich kann den Code auch weg lassen...
Ändert überhaupt nichts :(
Dachte halt das der andere Pin Prellt und eventuell "low" ist , wenn er
"high" sein sollte.
Andy _. schrieb:> Pullups hab ich je einen 5,1k Widerstand nach GND
Dann sind es Pull-Down. Das aber nur nebenbei. Wenn der Encoder aber
auch (wie normalerweise üblich) zwischen GND und den Eingängen liegt,
dann schließt Du mit ihm lediglich die Pulldown-Widerstände kurz und
sonst Nichts.
Herbert
Herbert B. schrieb:> Andy _. schrieb:>> Pullups hab ich je einen 5,1k Widerstand nach GND>> Dann sind es Pull-Down. Das aber nur nebenbei. Wenn der Encoder aber> auch (wie normalerweise üblich) zwischen GND und den Eingängen liegt,> dann schließt Du mit ihm lediglich die Pulldown-Widerstände kurz und> sonst Nichts.>> Herbert
Das ganze ist ein größeres Projekt und ich habe von Schaltplan über
Platine bis zur Software selber gemacht.
Die Widerstände halten die Eingänge des Controllers low.
Der Drehencoder bekommt dann die Versorgungsspannung und gibt die dann
weiter.
Hab wie gesagt alles schom mit dem Oszi gemaessen.
Passt alles was an den Pins ankommt.
Andy _. schrieb:> Die Widerstände halten die Eingänge des Controllers low.
Die mir bekannten China-Drehencoder auf Platinchen haben 10k gegen Plus,
der Encoder zieht nach GND.
Andy _. schrieb:> Hat niemand eine idee woran es liegen könnte ?
Natürlich. Es liegt an Deiner ungeeigneten Flankenabfrage. Wenn Du
eine Zustandsabfrage machst, so wie alle vernünftigen Programmierer,
wirds auch richtig funktionieren, selbst mit etwas älteren Drehgebern.
Wie soll das überhaupt mit zig ms Blockierzeiten im Code funktionieren?
Zwischen 2 Rasten machen manche Drehencoder 4 Takte und die warten da
nicht auf ein Basicprogramm.
Die ISR werden vermutlich zu lange verzögert bekommen dann einen eher
zufälligen Pegel zur Auswertung.
Andy _HV & µC schrieb
>Ist Pin2(Encoder) ein mal in allen Abfragen "High" wird die Variable um>1 erhöt.>Ist Pin2(Encoder) "low" wird die Variable um 1 verringert.>Ende vom Interrupt
Ob es ein Vorwärts oder Rückwärtsschritt ist, läst sich
eigentlich nur erkennen wenn man sich das vorhergehende
Bitmuster gemerkt hat und mit dem aktuellen vergleicht,
siehe Tabelle.
Schritt Vorwärts Rückwärts
0 00 00
1 10 01
2 11 11
3 01 10
4 00 00
5 10 01
6 11 11
7 01 10
8 00 00
9 10 01
10 11 11
11 01 10
Nur der Verständnis halber:
Bascom hat einen integrierten Befehl, um Drehgeber auszuwerten.
https://avrhelp.mcselec.com/index.html?encoder.htm
Der Beispiel-Code ruft das ohne Interrupt einfach zyklisch in seiner
Hauptschleife auf, und es finden sich haufenweise andere Beispiele, die
einen Timer-Interrupt verwenden, um den "ENCODER"-Befehl zyklisch
aufzurufen.
Mir ist kein einziges Bascom-Beispiel über den Weg gelaufen, das da auf
die Idee kommt einen Flanken-Interrupt mit dranzumogeln.
Warum versuchst du das? NIH-Syndrom? Angst vor den fertigen
Bascom-Routinen, oder dass du sonst nicht schnell genug drehen kannst?
batman schrieb:> Ein IRQ zeigt ja einen Zustandswechsel von 0->1 eines Pins an und der> Zustand des anderen zu diesem Zeitpunkt(!) entscheidet die Richtung.
Ja, eine typische Methode, die in der Theorie wesentlich
besser funktioniert wie in der Praxis.
Andy _. schrieb:> Passt alles was an den Pins ankommt.
Schön.
Und nach Deiner eigenen Ansicht ist Dein Softwarekonzept auch ganz toll
und nicht etwa der letzte Dreck. Dann ist ja auch hier alles in Ordnung.
Also wird Deine Lösung wohl auch richtig funktionieren. Herzlichen
Glückwunsch!
Andreas S. schrieb:> Andy _. schrieb:>> Passt alles was an den Pins ankommt.>> Schön.>> Und nach Deiner eigenen Ansicht ist Dein Softwarekonzept auch ganz toll> und nicht etwa der letzte Dreck. Dann ist ja auch hier alles in Ordnung.> Also wird Deine Lösung wohl auch richtig funktionieren. Herzlichen> Glückwunsch!
Eine vernünftige Antwort währe auch schön, aber vernünftige sowie
höfliche beiträge kann sich ja nicht jeder leisten.
So eine Hilfeeinstellung und unhöflichkeit braucht kein Forum.
Nun zu meiner Problemlösung:
Der Encoder hat wohl tatsächlich minimal geprellt, aber schneller als
mein Altes Oszi messen kann (wenifer als ein paar uS).
Zusätzlich habe ich die Software so abgeändert, das das ganze jetzt
Funktioniert.
Neuer Code:
batman schrieb:> Jepp, die langen Blockierzeiten rausgeschmissen, Glückwunsch.
Die Wartezeiten waren nicht so das grundlegende problem eher die art wie
ich den encoder abgefragt hab.
Ich habe den Vorgang mit dem ersten Bitwait komplett umgedreht und messe
nun den zustand, wenn der erste pin "low" geht.
So ist genügend zeit für den Controller das Unterprogramm anzuspringen.
Der 2 pin fällt allerdingens schon 0,5ms nach dem ersten was bei 8Mhz
Taktrate aber noch nicht allzu zeitkritisch ist.
Andy _. schrieb:> Die Wartezeiten waren nicht so das grundlegende problem eher die art wie> ich den encoder abgefragt hab.
Die Wartezeiten verstehe ich nicht.
Wenn Interrupt, dann solle das Teil hardwaremäßig entprellt sein!
(Schaltungsvorschläge meist in den Datenblättern enthalten)
Die Verarbeitung im IR sieht dann bei mir (in C) so aus:
1
if(ENC_IR){
2
if(ENC_DIR==ENC_DIR_UP)flags.encUp=1;
3
elseflags.encDown=1;
4
5
mENC_IR_RST();// clear IR flag
6
return;
7
}
Mehr braucht man meiner Meinung nach nicht.
(ENC_DIR ist der Pin, ENC_DIR_UP der Pegel und flags ein Bitfeld)
(((if(ENC_IR) weil nur ein Vector für viele IR)))
Wenn das Entprellen nicht in der Hardware gemacht werden soll,
dann besser gleich die hier schon mehrfach verlinkte Polling Methode...
Volker S. schrieb:> Wenn Interrupt,
Nochmal:
Warum Interrupt, wenn doch BASCOM schon einen fertigen "ENCODER"-Befehl
mitliefert, der das Problem direkt erschlägt?
Was ist an der integrierten Lösung so schlecht, dass man das unbedingt
selber implementieren will?
Εrnst B. schrieb:> Was ist an der integrierten Lösung so schlecht, dass man das unbedingt> selber implementieren will?
Die schon integrierte Lösung funktioniert wahrscheinlich zu gut. Und der
TE hätte keinen Grund gehabt, seine gequirlte Scheiße hier abzusondern
und als tolles Softwarekonzept anzupreisen.
Andreas S. schrieb:> Und der> TE hätte keinen Grund gehabt, seine gequirlte Scheiße hier abzusondern...
Läufst Du noch ganz rund? Diesen Ton kannst Du im Betrieb auf der
Weihnachtsfeier anschlagen, dann gibts den Weihnachtsstollen quer in die
Fresse.
:(
Εrnst B schrieb:
>Was ist an der integrierten Lösung so schlecht, dass man das unbedingt>selber implementieren will?
Manchmal will man etwas Lernen, man will Spielen und Experimentieren.
Man möchte herausfinden warum etwas funktioniert oder auch
nicht funktioniert. Es sind nicht alle Experten und die Experten waren
auch nicht von Anfang an Experten.
Günter Lenz schrieb:> Manchmal will man etwas Lernen, man will Spielen und Experimentieren.> Man möchte herausfinden warum etwas funktioniert oder auch> nicht funktioniert. Es sind nicht alle Experten und die Experten waren> auch nicht von Anfang an Experten.
Zum Lernen könnte man ja auch den Artikel vom Drehencoder lesen. Es wird
seit Jahren immer wieder versucht den Int für Flankenwechsel zu utzen.
Es wird seit Jahren immer wieder davon abgeraten. Er hat dan Fehler
durch try and error zufällig beseitigt. Ich bezweifel das er gelernt hat
was da in Hardware passiert. PullUP sind ja auch keine PullDown, die er
benutzt.
Stephan schrieb:> Zum Lernen könnte man ja auch den Artikel vom Drehencoder lesen.
Dazu müßte dieser Artikel aber erstmal aufgeräumt und in Ordnung
gebracht werden.
Wer einen Artikel schreibt und dort zum Besten gibt, daß er nicht
versteht, warum heutige Drehgeber so aufgebaut sind, wie sie sind
(zitat: "Umso merkwürdiger ist es, dass hier die Rastpunkte oft genau
auf dem Pegelwechsel einer Spur liegen, meist Spur B."), oder gar sowas
schreibt (noch ein Zitat: "Es wird bisweilen die Auffassung vertreten,
dass mit Hilfe von sog. Pin Change Interrupts Rechenzeit gespart werden
kann."), der hat mit seinen Darstellungen wohl kaum einem Leser wirklich
die nötigen Erkenntnisse gebracht.
W.S.
Stephan schrieb:> Zum Lernen könnte man ja auch den Artikel vom Drehencoder lesen. Es wird> seit Jahren immer wieder versucht ...
... Engstirnigkeit zu predigen: "Du mußt das genau so machen, sonst
biste doof!"
W.S. schrieb:> der hat mit seinen Darstellungen wohl kaum einem Leser wirklich> die nötigen Erkenntnisse gebracht.
Wo er Recht hat, hat er Recht!