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 ?!
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
>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.
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?
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.
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?
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?
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
;-----------------------------------------------------------------------
-
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.
...
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..
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.
...
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.
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.
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.
...
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!
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...
...
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.
...