Hallo, ich hab ein problem mit einem Drehencoder von Panasonic. Das Datenblatt habe ich mal angehangen. Die Schaltung ist original aufgebaut. Die Signale habe ich an Pin D0 und Pin D1 angeschlossen. In Bascom habe ich folgendes kleine Programm geschrieben. Der wert b wechselt aber nur zwischen 1 und 2. Wenn ich Pin D2 und D3 nehme, läuft es. Kann mir jemand sagen warum es nicht an D0 und D1 geht ? Danke!! $regfile "m8def.dat" $crystal = 8000000 Cls Config Portd = Input Portd = 255 Dim A As Byte , B As Byte Do A = Encoder(pind.2 , Pind.3 , Links , Rechts , 0) Upperline Lcd B Waitms 20 Loop Links: B = B - 1 Return Rechts: B = B + 1 Return
Der Encoder-Befehl arbeitet wie folgt: B = Encoder(pinb.0 , Pinb.1 , Links , Rechts , 1) ' ^--- 1 means wait for change which blocks programflow ' ^--------^---------- labels which are called ' ^-------^---------------------------- port PINs
HÄ???? versuchs mal damit: (pseudocode, da ich kein basic kann): ENDLOSSCHLEIFE { IF (positive Flanke an PD0) THEN { IF ( PD1 == HIGH ) { A := A+1 } ELSE {A := A-1} } Anzeigen von A }
Ich weiss nicht, wie ich eine Flanke abfragen kann. Ich kann nur den zustand des Portpin´s abfragen.
so wirds in der sps-technik gemacht ok, dann machs so: (pseudocode) ENDLOSSCHLEIFE { IF ( bit_variable == PD0 ) THEN { IF ( PD1 == HIGH ) { A := A+1 } ELSE {A := A-1} } Anzeigen von A bit_variable := PD0 //zuweisung }
Gast wrote: > Ich weiss nicht, wie ich eine Flanke abfragen kann. Ich kann nur den > zustand des Portpin´s abfragen. Das ist traurig. Programmierst Du deshalb in BASCOM? Eine Flanke ist eine Änderung eines Eingangspegels. Um diese zu erkennen, liest man den Eingang zyklisch ein und vergleicht ihn mit dem zuvor eingelesenen Wert. Bei gleichem Wert ist keine Flanke aufgetreten, bei unterschiedlichem Wert ist eine Flanke aufgetreten, auf diese muss man dann reagieren. Vielleicht findet sich ja mal jemand von den wissenden BASCOM-Nutzern, der den genialen Algorithmus der PeDa-Bulletproof-Entprellung in BASCOM umsetzt. Dann können zukünftig zumindest die BASCOMer, die mit einem Timer umgehen können, bis zu 8 Tasten eines Ports vernünftig und effizient entprellen und auf die Flanken reagieren. ...
@Hannes, so ein Zufall, ich versuch gerade, das C-Beispiel von Peter nach Bascom zu übersetzen ... Mir sind ein paar C-Sachen aber unklar, da ich mit C nix am Hut habe: 1.) return get_key_press(~key_state & key_mask ); Was mach hier der Klammerausdruck, insbesondere ~key_state? 2.) 1<<KEY2 Ich denke mal, das ist ein einfaches Shift nach links. 3.) i << 1 Was wird hier geshifted? 4.) in get_key_short steht ein cli(). In get_key_long nicht. Warum? (in beziehe mich auf das hiesige Tutorial) Gruß: - Reinhard -
1) ~ ist das Einser-Komplement. Alle Bits umdrehen. Aus 0 wird 1 und umgekehrt. Auf Assembler-Ebene heist das COM Der ganze Klammerausdruck ist also key_state alle Bits umdrehen mit key_mask eine bitweise Und-Verknüpfung durchführen 2) ganz genau. Eine binäre 1 wird KEY2 mal nach links geschoben. Wenn KEY2 also den Wert 3 hat, dann ergibt das binär ein Byte (Word), bei dem das Bit 3 gesetzt ist. 3) der Inhalt von i wenn i zb. den Inhalt 3 hat, also binär 00000011, dann verschiebt i << 1 das um eine Stelle nach links. Also: 00000011 << 1 -> 00000110 Dezimal: 3 << 1 -> 6 das da 6 rauskommt ist kein Zufall. Solange kein Overflow im Spiel ist, ist ein einfaches Linksschieben eine Multiplikation mit 2 4) muss ich nachschauen. Melde mich gleich wieder
ad 4) Hier sind die Funktionen
1 | ///////////////////////////////////////////////////////////////////
|
2 | //
|
3 | uint8_t get_key_short( uint8_t key_mask ) |
4 | {
|
5 | cli(); // read key state and key press atomic ! |
6 | return get_key_press( ~key_state & key_mask ); |
7 | }
|
8 | |
9 | ///////////////////////////////////////////////////////////////////
|
10 | //
|
11 | uint8_t get_key_long( uint8_t key_mask ) |
12 | {
|
13 | return get_key_press( get_key_rpt( key_mask )); |
14 | }
|
in get_key_long werden nur Funktionen aufgerufen, die selbst die Steuerung des Interrupts übernehmen. in get_key_short wird aber auf key_state zugegriffen. Hier ist es aber notwendig, dass get_key_press dasselbe key_state auswertet, wie is im Argument zu der Funktion benutzt wird. Wenn zufällig nach der Auswertung von ~key_state, aber vor dem Aufruf der Funktion get_key_press ein Interrupt auftritt und dieser Interrupt key_state verändert, ist man in einem inkonsistenten Zustand. In get_key_long könnte man ebenfalls vor dem ganzen Return- Ausdruck einen cli() machen. Ich hab das jetzt nicht genauer durchdacht, wahrscheinlich würde ich das sogar tun.
@Karl Heinz Danke. Ich guck mal, ob ich das morgen ans Laufen bekomme. Eine Frage noch zu dem Thema "alle Bits umdrehen". Immer wenn ~ verwendet wird, also bspw. bei i = key_state ^ ~KEY_PIN; muss ich die Bits drehen? Hier also key_state XOR mit den "gedrehten" Bits von KEY_PIN?
~ ist ein unärer Operator, sowie es auch - (das Vorzeichen umdrehen,
nicht Subtraktion) einer ist.
> Hier also key_state XOR mit den "gedrehten" Bits von KEY_PIN?
Yep.
Reinhard wrote: > @Hannes, > > so ein Zufall, ich versuch gerade, das C-Beispiel von Peter nach Bascom > zu übersetzen ... Aua-ha, da habe ich ja was angerichtet. > > Mir sind ein paar C-Sachen aber unklar, da ich mit C nix am Hut habe: Sorry, mit C kann ich nicht dienen, aber da hilft ja Karl heinz weiter. Ich nutze den Algorithmus in ASM. Da ist jeder Schritt als ASM-Befehl exakt nachvollziehbar. Daher kann man/ich die Routine leicht an die Gegebenheiten anpassen. Denn mal brauche ich nur den entprellten Status, mal ist das Erkennen der "Drückflanke" erforderlich, mal die "Loslassflanke" und manchmal sogar beide Flanken. Es kommt zuweilen auch vor, dass ich die Entprellung deaktiviere, wenn es nur um die Flankenerkennung (elektronisch erzeugter Signale) geht. Ich halte es für eine gute Sache, den Algorithmus in BASCOM zu "gießen", habe aber Bedenken, dass da unterm Strich die Effizienz heraus kommt, die in ASM oder C vorhanden ist. Vielleicht wäre es ja effizienter, mit Inline-Assembler zu arbeiten. Dann spart sich der Compiler die Übersetzung, denn der AVR kann ja nur Maschinencode (1 zu 1 zu ASM)... Für das Entprellen von Tasten rufe ich die Routine im Timer-Int. etwa alle 10..20 ms auf. Auch für Drehgeber habe ich diese Routine schon benutzt, da habe ich sie alle 1 ms aufgerufen. Dabei habe ich in der Mainloop aud beide Flanken von einem Eingang reagiert und den (entprellten) Tastenstatus als Indiz für die Drehrichtung genommen. Das funktionierte recht gut. Es soll aber bessere Algorithmen zum Einlesen von Drehgebern geben, ich muss aber nicht alles können. ;-) ...
@Hannes sei beruhigt, ich hatte mich schon vor Deinem Post dazu entschlossen ;-). Der Grund für die Umstellung der C-Routine ist der, das dort mehr Möglichkeiten als in der ASM-Routine stecken (Repeat etc.). Mir geht es in erster Linie aber um das Verstehen von Peters Code. Ob der dann (in Bascom) so bleibt ist eine andere Frage, weil Peters Code glaube ich auf die Tasten an einem Port beschränkt ist (ich habe ein Projekt mit 4 Tastern an zwei unterschiedlichen Ports). Gruß: - Reinhard -
Reinhard wrote: > @Hannes > > sei beruhigt, ich hatte mich schon vor Deinem Post dazu entschlossen > ;-). > > Der Grund für die Umstellung der C-Routine ist der, das dort mehr > Möglichkeiten als in der ASM-Routine stecken (Repeat etc.). Schau in das Assembler Tutorial. Ich hab dort den C-Code als Vorlage benutzt um eine Assembler Version zu kreieren die auch Repeat kann. > > Mir geht es in erster Linie aber um das Verstehen von Peters Code. Viel Spass. Das ist ziemlich trickreich. > Ob > der dann (in Bascom) so bleibt ist eine andere Frage, weil Peters Code > glaube ich auf die Tasten an einem Port beschränkt ist Das stimmt allerdings. Irgendwo muss man Abstriche machen. Und wenn ich mir anschaue wie kompliziert Peter Fleurys LCD Code ist, der ja jeden Pin an jeden Port/Pin legen kann ...
>> Schau in das Assembler Tutorial. Ich hab dort den C-Code >> als Vorlage benutzt um eine Assembler Version zu kreieren >> die auch Repeat kann. Da muss ich wohl doch mal wieder reinschaun, hab' da lange nicht nachgesehen.
Hannes Lux wrote: >>> Schau in das Assembler Tutorial. Ich hab dort den C-Code >>> als Vorlage benutzt um eine Assembler Version zu kreieren >>> die auch Repeat kann. > > Da muss ich wohl doch mal wieder reinschaun, hab' da lange nicht > nachgesehen. Das wär mir sehr recht. So der Assembler-Spezi bin ich dann auch wieder nicht. Wär schon gut wenn mal jemand der was davon versteht über mein Machwerk drüber schauen würde.
Ich verstehe davon (von ASM) auch nicht viel. Ich beschränke mich halt immer auf das Wenige, das ich verstehe (es wird aber von mal zu mal mehr). Dein Beispiel ist aber völlig anders als die von mir genutzte Routine, da muss ich mich auch erst reinfinden. Das kann dauern... ...
Ich habe inzwischen den Interrupt Int0 mit eingebunden, der bei jeder drehung ein unterprogramm aufruft. Ich hab aber probleme mit der auswertung der Signale A und B, damit eine Variable hoch/runter gezählt wird. Der wert in Enc wechselt nur zwischen 0 und 255 ????? Der Code : Config Portd = Input Config Int0 = Change On Int0 _encoder Enable Int0 Enable Interrupts Dim Enc As Byte Enc_a Alias Pind.2 Enc_b Alias Pind.3 Cls Do Upperline Lcd Enc Loop _encoder: If Enc_b = 0 Then Enc = Enc + 1 Else Enc = Enc - 1 End If Return
> Ich habe inzwischen den Interrupt Int0 mit eingebunden, ...
Falls es sich um einen mechanischen Drehgeber handelt, so ist das keine
gute Idee, denn mechanische Kontakte prellen, was dazu führt, dass Dein
Interrupt mehrfach aufgerufen wird.
...
@Gast Hast Du nicht im ersten Beitrag geschrieben, das die Encoder-Funktion an D.2 bzw. D.3 mit Bascom funktionierte? Warum verwendest Du die denn nicht einfach? Ansonsten hat Hannes wohl Recht. Der Drehgeber prellt und Du müsstest das halt berücksichtigen. Im Tutorial steht ja, wie es mit Assembler und C geht. Für Bascom findest Du die adaptierte Routine im Anhang. Zwar nicht für einen Drehgeber, sondern für normale Tasten, aber das solltest Du umstellen können. HTH: - Reinhard -
So, nun läuft es. Jetzt wird pro Rastung auch einer hoch bzw. runter gezählt. Config Portd = Input Config Int0 = Change On Int0 _encoder Enable Int0 Enable Interrupts Dim Enc As Byte , A As Byte , B As Byte Enc_a Alias Pind.2 Enc_b Alias Pind.3 Cls Cursor Off Do Upperline Lcd Enc ; " " Waitms 60 Loop _encoder: If Enc_a = 1 And Enc_b = 0 Then Enc = Enc + 1 End If If Enc_a = 0 And Enc_b = 1 Then Enc = Enc + 1 End If If Enc_b = 1 And Enc_a = 1 Then Enc = Enc - 1 End If If Enc_b = 0 And Enc_a = 0 Then Enc = Enc - 1 End If Return
@Gast Schön, dass es nun läuft. Meines Erachtens ist aber das Prell-Problem damit noch vorhanden. Dein Waitms in der Main-Loop vertuscht das nur. Sobald Du dieses rausnimmst, wird das Prellen des Drehgebers deutlich werden. Oder hast Du das ganze hardwaremäßig entprellt?
Es ist Hardwaremäßig mittels r/c entprellt. Ohne waitms läuft es auch einwandfrei.
Also, ich mach das so, ist eine schnellere abfrage. Config Int0 = Change On Int0 Geber Enable Int0 Config Pind.3 = Input Config Pind.2 = Input Portd.2 = 1 Portd.3 = 1 :::::::::::::::: :::::::::::::::: geber: If Pind.3 = Pind.2 Then Decr Geber_zahl_haupt Else Incr Geber_zahl_haupt End If return
Muss ich die Interrupts nutzen oder kann ich die Abfrage auch in die Hauptschleife packen? (Die Int's sind schon belegt) Ich möchte 2 Encoder nutzen (Netzteil - Eigenbau, einer für U und einer für I) Sry, aber ich bin AVR - Neuling und in Basic hab ich auch nur Grundwissen.
Der Interrupt wurde ja nur benutzt, um die Flanke zu erkennen. Du kannst natürlich auch im Hauptprogramm eine Flankenänderung erkennen: merker=PinX.X do if merker <> PinX.X then Flanke_geändert merker=PinX.X loop
Soo, nach etlichem rumprobieren habe ich es nun ans laufen bekommen. Ich habe nicht die Interrupts genutzt, sondern mich des Encoder - Befehls bedient. Ein Problem habe ich trotzdem. Mein Encoder (mechanisch) gibt pro Rastung 4 Impulse bei 20 Rastungen, also 80 Impulse pro 360° Drehung. Wenn ich den Encoder langsam(!) drehe, funktioniert alles einwandfrei, nur bei schnellem drehen passiert nahezu nichts, d.h. der Wert ändert sich, wenn überhaupt, nur um eine Stufe. Kann man die Debounce - Time des Encoder - Befehls irgendwie ändern? In der Bascom - Hilfe ist davon jedenfalls nichts erwähnt. (Es muss an der Debounce Time liegen, denn wenn ich "$Crystal 1000000" setze, den Mega16 aber auf 4MHz fuse, dann funktioniert es auch bei schneller Drehung, nur spinnt mein LCD dann)
Kay R. schrieb: > Soo, nach etlichem rumprobieren habe ich es nun ans laufen bekommen. > Ich habe nicht die Interrupts genutzt, sondern mich des Encoder - > Befehls bedient. > Ein Problem habe ich trotzdem. > Mein Encoder (mechanisch) gibt pro Rastung 4 Impulse bei 20 Rastungen, > also 80 Impulse pro 360° Drehung. Wenn ich den Encoder langsam(!) drehe, > funktioniert alles einwandfrei, nur bei schnellem drehen passiert nahezu > nichts, d.h. der Wert ändert sich, wenn überhaupt, nur um eine Stufe. Beitrag "Re: Hilfe zu Drehencoder-Auswertung nach Wiki" > > Kann man die Debounce - Time des Encoder - Befehls irgendwie ändern? > In der Bascom - Hilfe ist davon jedenfalls nichts erwähnt. > > (Es muss an der Debounce Time liegen, denn wenn ich "$Crystal 1000000" > setze, den Mega16 aber auf 4MHz fuse, dann funktioniert es auch bei > schneller Drehung, nur spinnt mein LCD dann) Bascom halt... ...
Ich habs jetzt hinbekommen. Der Encoder wird nun "manuell" im Timerinterrupt abgefragt. Nun gibt es auch keine Probleme bei schnellem Drehen mehr. Trotzdem vielen Dank für die Hilfe, Gruß Kay
Kay R. schrieb: > Kann man die Debounce - Time des Encoder - Befehls irgendwie ändern? > In der Bascom - Hilfe ist davon jedenfalls nichts erwähnt. CONFIG DEBOUNCE = time
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.