Forum: Mikrocontroller und Digitale Elektronik Entprellung


von Jochen (Gast)


Lesenswert?

Hallo,

ich habe noch eine Frage in Anlehnung an
Beitrag "erstes Programm, Binärzähler. Frage (Mega8)"

Und zwar geht es um das Entprellen.
Im Tutorial steht für die Verzögerung und die dann folgende Überprüfung:
wait1:
      ldi  temp2, $FF
wait2:
      dec  temp2
      brne wait2
      dec  temp1
      brne wait1
                                  ; ... und nachsehen, ob die Taste 
immer noch gedrückt ist
      in   temp1, key_pin
      and  temp1, key_now
      brne loop


Doch ich verstehe den Ablauf nicht.
In wait1 kommt man auf jeden Fall. Dann wird temp2 voller einsen 
geschrieben und man gelangt in wait2.
Es wird dann als erstes von temp2 die eins subtrahiert. brne wait 2, was 
dann folgt, heißt meines Wissens, dass er zur Marke wait2 springt, falls 
die Subtraktion 0 ist. Das ist sie beim ersten Durchlauf aber nicht und 
es geht weiter: von temp1 wird 1 abgezogen und es wird direkt, nach 
bereits einem Durchlauf geprüft ob die Taste noch gedrückt ist.
Was stimmt an meiner Überlegung nicht? Ich denke es liegt an meinem 
falschen Verständnis von brne ?!

von Christian Meurer (Gast)


Lesenswert?

Hallo,

brne heißt Branch (if) Not Equal. Somit wird dekrementiert, bis temp2 
auf 0 ist. Es werden 2 Loops verwendet um diese (wahrscheinlich wegen 
hoher Taktrate) zu verschachteln und eine größere Wartezeit zu 
erreichen.
Am Anfang steht wohl auch noch ein "ldi temp1, irgendwas", oder?

Gruß

Christian

von Michael U. (Gast)


Lesenswert?

Hallo,

brne -> Branch If Not Equal -> Springe, wenn das Ergebnis NICHT gleich 0 
ist.

Gruß aus Berlin
Michael

von Power (Gast)


Lesenswert?

>dass er zur Marke wait2 springt, falls die Subtraktion 0 ist
'brne' => branch not equal, also NICHT gleich. Er springt so lange zu 
wait2 (Zero-Flag NICHT gesetzt) bis die Subtraktion 0 ist (Zero-Flag 
gesetzt), also die Bedingung 'not equal' nicht mehr erfüllt ist.
Danach wird temp1 um 1 erniedrigt und die gleiche Abfrage erfolgt bei 
temp1.
Das sind zwei identische Zählschleifen von 255 bis 0 die ineinander 
verschachtelt sind.

von Jochen (Gast)


Lesenswert?

Ich danke Euch!
Muss ich die Schleifen so verschachteln oder kann ich theoretisch auch 
seperat zwei unabhängige Schleifen durchlaufen lassen? es geht doch hier 
nur um eine Zeitverzögerung, oder?

von Null (Gast)


Lesenswert?

Das ist Murks so. Man sollte einen Timertick nehmen wenn den sowies 
schon hat. Hat man doch eh schon. Nein ?

von Power (Gast)


Lesenswert?

In diesem Fall zählst du 255 x 255. Wenn du nacheinander zählst sind es 
nur 2 x 255. Die Verschachtelung musst du sowieso auf die geforderte 
Verzögerung anpassen, entweder Taktzyklen berechnen oder per Debugger 
und Stopwatch empirisch ermitteln.

von Power (Gast)


Lesenswert?

Null hat schon Recht, der Timer-INT ist vorzuziehen. Ich weiß aber nicht 
für welchen Zweck das Ganze gedacht ist, vielleicht ist die Anwendung so 
einfach dass es so genügt?

von Jochen (Gast)


Lesenswert?

Ich möchte es lernen, das ist der Zweck ;)
Also mein kleiner Binärzähler hat nun mit die Entprellung aus dem 
Tutorial, direkt die erste Lösung.
Jedoch muss ich die Tasten schon sehr kurz drücken, damit es richtig 
funktioiert.
Und gelegentlich zählt er auch durch, ohne dass ich irgendetwas drücke.
Was kann das sein?

von Jochen (Gast)


Lesenswert?

also es schaltet, wenn ich es z.B. nur bewege oder in der Hand halte. 
Wie unterdrückt man das?

von Jochen (Gast)


Lesenswert?

hier mal der Quelltext.
Ich habe vor dem Abziehen und ausgeben noch einen Counter reingebaut, 
das hilft zwar etwas aber ist auch nicht perfekt

  sbi DDRB,0
  sbi DDRB,1
  sbi DDRB,2
  cbi DDRD,2
  sbi PORTD,2
;----------------------------------------------------------------------- 
-
mainloop:  wdr
ldi r20, 0b00000000

loop:
in r18, PIND

mov r4,r18
eor r18,r22
mov r22,r4
breq loop
and r4,r18
brne loop

ldi r21, 0b11111111
wait1:
ldi r27, 0b11111111
wait2:
dec r27
brne wait2
dec r21
brne wait1



in r1, PIND
and r21, r18
brne loop

ldi r21, 0b11111111

wait3:
ldi r27, 0b11111111

wait4:
ldi r28, 0b00000111
wait5:
dec r28
brne wait5
dec r27

brne wait4
dec r21

brne wait3


inc r20
out PORTB, r20

  rjmp loop
;----------------------------------------------------------------------- 
-

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

So wird das nix...

Probiere mal das Programm im Anhang aus. Dann versuche mal zu 
analysieren, warum es funktioniert. Ich habe es bewusst sehr einfach 
gehalten, damit Du es verstehen kannst.

Schau es Dir auch im Simulator des AVR-Studios an, setze dazu (mit F9) 
einen Breakpoint auf den ersten Befehl der Interrupt-Routine des Timers, 
dann kannst Du mit F5 bis zum Breakpunkt laufen lassen und mit F11 im 
Einzelschritt weitermachen um zu analysieren, was da passiert. Klappe im 
Workspace PortB und PortD auf, bediene PIND 0..2 mit der Maus, schau was 
nach 4 Durchläufen passiert. Versuche zu verstehen.

...

von Hannes L. (hannes)


Lesenswert?

Natürlich hat sich ein Fehler eingeschlichen, in der Reset-Routine fehlt 
noch der Befehl:

 clr null    ;immer 0, braucht man immer mal

...

von Jochen (Gast)


Lesenswert?

Vielen vielen Dank!
Ich werde mir das ansehen und versuchen zu verstehen.
Woran liegt es denn, dass der Schalter offenbar schaltet, ohne dass ich 
ihn drücke? z.B . wenn alles ruhig auf dem Tisch liegt, gibt es 
gelegentlich Veränderungen in der Schaltung, so als würde ein Taster 
gedrückt.
Hat das auch was mit dem "nachprellen" zu tun? Aber der Taster wurde ja 
garnicht erst gedrückt..

von Hannes L. (hannes)


Lesenswert?

Sorry. Bitte verlange nicht von mir, dass ich versuche, Dein wirres 
Zeugs zu analysieren. Das tu ich mir nicht an. Das hat absolut nichts 
mit einem Programm zu tun. Etwas mehr Struktur solltest Du da schon 
reinbringen.

Tip am Rande: Benutze keine Codezeilen, die Du nicht verstehst. Schreib' 
zu jeder Zeile einen Kommentar, was Du damit bezwecken willst. Ansonsten 
blickst Du selbst nicht durch.

...

von Jochen (Gast)


Lesenswert?

Ok. Kein Problem.
Ich wollte nur wissen, wie es in der regel dazu kommt, dass eine 
Schaltung selber schaltet, ohne den entsprechenden Tastendruck und wie 
man das verhindern kann.

von Jochen (Gast)


Lesenswert?

wie gesagt, je nachdem wie ich dann die Platine halte, schaltet es 
manchmal selber. Manchmal auch nicht. Wenn ich sie z.B. in die Hand 
nehme, springen die Leds weiter, die Schaltung zählt.
Wenn ich sie so lege, dass sie automatisch nichts macht, dann 
funktioniert das Schalten über den Taster problemlos.

von Hannes L. (hannes)


Lesenswert?

Ich kann an Deinem Code nicht erkennen, wo Du auf das Bit, an dem der 
Taster angeschlossen ist (PD2?), reagierst, um fesrzustellen, ob er 
betätigt wurde. Du hast zwar ein 'breq loop' und ein 'brne loop' als 
bedingte Verzweigung drin, doch die prüfen nicht nur das Bit, an dem der 
Taster hängt, sondern den gesamten Port-Eingang. Da Du an den 
unbenutzten Bits keine PullUp-Widerstände aktiviert hast, wirken die 
(hochohmigen) Eingänge als Antenne und lesen Pegel ein, wie sie gerade 
Lust haben.

Und da Dein Programm nicht nur auf PD2 reagiert, sondern auf den 
gesamten PIND (in r18 eingelesen) macht es nunmal, was die Antennen so 
empfangen.

Die Dannegger-Routine hat den großen Vorteil, dass sie einen ganzen Port 
(bis zu 8 Bit breit) logisch mit dem vorherigen Zustand und zwei 
Prellzähler-Bytes verknüpft (ohne jede bedingte Verzweigung!!) und dabei 
jedes der 8 Bit des Ports getrennt behandelt. In jedem der beteiligten 
Bytes liegen parallel die Bits für die 8 Taster. Der Wert eines jeden 
Bytes ist also nicht als Zahlenwert zu interpretieren, sondern als 8 
unabhängige Boolsche Variablen (Bitwerte, ja/nein-Aussagen).

Die beiden Prellzähler-Bytes werden dabei nur lokal (aber statisch) 
gebraucht, das Register für den Tastenzustand ('key_state' bzw. bei mir 
'tas') stellt dem Hauptprogramm eine entprellte Kopie des 
Tastenzustandes aller 8 Tasten bereit, das Register mit den Tastenflags 
('key_press' bzw. 'tfl') stellt dem Hauptprogramm für jede der 8 Tasten 
ein Flag zur Verfügung, das anzeigt, ob diese Taste seit der letzten 
Abarbeitung erneut gedrückt wurde. Also komfortabler geht es eigentlich 
nicht mehr.

Durch einen ganz kleinen Zusatz zu dieser Routine lässt sich eine 
Wiederholfunktion einbauen, die bei Dauerdruck wirksam wird und auf 
einige der Tasten begrenzt werden kann (ist auch im Tutorial erklärt).

Auch die Störsicherheit ist enorm. Eine Pegeländerung wird erst dann 
akzeptiert und übernommen, wenn der neue Pegel 4 Durchläufe 
hintereinander stabil angelegen hat. Das überlistet sogar die 
laberigsten Billigtaster.

...

von Jochen (Gast)


Lesenswert?

Vielen, vielen Dank!
Ich war gestern am verzweifeln und hatte schon garkeine Lust mehr . Aber 
wenn ich die pullup Widerstd. aktiviere funktioniert es problemlos, 
lieben dank!

von Hannes L. (hannes)


Lesenswert?

Jochen wrote:
> Vielen, vielen Dank!
> Ich war gestern am verzweifeln und hatte schon garkeine Lust mehr . Aber
> wenn ich die pullup Widerstd. aktiviere funktioniert es problemlos,
> lieben dank!

Nein, es funktioniert nicht problemlos, es sieht nur so aus. Sobald Du 
die unbenutzten Portpins für andere Dinge nutzen willst, geht der Zirkus 
von vorn los...

...

von Gast (Gast)


Lesenswert?

> Sobald Du die unbenutzten Portpins für andere Dinge nutzen willst, geht
> der Zirkus von vorn los...
Inwiefern?

von Hannes L. (hannes)


Lesenswert?

Gast wrote:
>> Sobald Du die unbenutzten Portpins für andere Dinge nutzen willst, geht
>> der Zirkus von vorn los...
> Inwiefern?

Insofern, dass Jochens Programm nicht nur auf Änderung des Bits 
reagiert, an dem der Taster angeschlossen ist, sondern auf irgendeine 
Veränderung am gesamten Port.

...

von Jochen (Gast)


Lesenswert?

Vielen Dank, dass ihr mir soweit geholfen habt, ich schaue mal wie ich 
klar komme!

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.