Forum: Mikrocontroller und Digitale Elektronik Drehencoder in Bascom


von Gast (Gast)


Angehängte Dateien:

Lesenswert?

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

von Matthias (Gast)


Lesenswert?

wer soll denn das verstehen...
kannst du das mal in c übersetzen...

von Gast (Gast)


Lesenswert?

Wenn ich C könnte, hätte ich es gleich in C geschrieben....

von Matthias (Gast)


Lesenswert?

na ok, dann musst du mir halt erklären was die befehle machen (sollen)

von Gast (Gast)


Lesenswert?

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

von Matthias (Gast)


Lesenswert?

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
}

von Gast (Gast)


Lesenswert?

Ich weiss nicht, wie ich eine Flanke abfragen kann. Ich kann nur den 
zustand des Portpin´s abfragen.

von Matthias (Gast)


Lesenswert?

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
}

von Michael G. (glunzl)


Lesenswert?


von Hannes L. (hannes)


Lesenswert?

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.

...

von Reinhard (Gast)


Lesenswert?

@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 -

von Karl H. (kbuchegg)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Reinhard (Gast)


Lesenswert?

@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?

von Karl H. (kbuchegg)


Lesenswert?

~ 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.

von Hannes L. (hannes)


Lesenswert?

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. ;-)

...

von Reinhard (Gast)


Lesenswert?

@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 -


von Karl H. (kbuchegg)


Lesenswert?

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 ...

von Hannes L. (hannes)


Lesenswert?

>> 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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hannes L. (hannes)


Lesenswert?

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...

...

von Gast (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

> 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.

...

von Reinhard (Gast)


Angehängte Dateien:

Lesenswert?

@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 -


von Gast (Gast)


Lesenswert?

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

von Reinhard (Gast)


Lesenswert?

@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?

von Gast (Gast)


Lesenswert?

Es ist Hardwaremäßig mittels r/c entprellt. Ohne waitms läuft es auch 
einwandfrei.

von tobi (Gast)


Lesenswert?

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

von Kay R. (trafowickler)


Lesenswert?

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.

von r-u (Gast)


Lesenswert?

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

von Kay R. (trafowickler)


Lesenswert?

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)

von Hannes L. (hannes)


Lesenswert?

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...

...

von Kay R. (trafowickler)


Lesenswert?

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

von Klaus (Gast)


Lesenswert?

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

von Kay R. (trafowickler)


Lesenswert?

Das hatte ich versucht, hat leider nichts gebracht.

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.