Hallo,
ich muss für ein µC Labor etwas programmieren. Es handelt sich dabei um
den ersten Versuch und zwar sind am Port 4, vier Taster und vier LEDs
angeschlossen, alle Low Aktiv. Die ersten vier Bits sind die Taster und
die letzten vier die LEDs. Das Programm soll die Tasterinformationen auf
die LEDs ausgeben, also Taster 1 gedrückt -> LED 1 ein.
Hier mein Programm:
1
2
//Vorgabe:
3
mov A, PCA0MD;
4
anl A,#0BFh;
5
mov PCA0MD, A;
6
call Init_device;
7
8
main:
9
10
mov p4, #11111111b; Eingänge in Lesemodus, alle LEDs aus
11
loop:
12
mov a, p4; Inhalt von Port 4 in Akku
13
swap a; Taster Infos hoch
14
mov p4, a;
15
orl p4, #00001111b; Taster wieder in Lesemodus
16
17
jmp loop;
18
19
end
Das Problem ist das, wenn ich das Programm im Debuger Modus laufe lasse
und jeden Befehlt Step-by-Step ausführen lasse, funktioniert es. Wenn
ich es aber mit voller Geschwindigkeit laufen lasse, bleiben die LEDs an
auch wenn der entsprechende Taster nicht mehr gedrückt ist. Wenn man
hinter der ODER Verknüpfung ein paar nop Befehle einfügt funktioniert es
ebenfalls. Ich vermute das es etwas mit dem Ausgangslatch zu tun hat,
aber wie gesagt es ist mein erstes Programm. Es wäre nett, wenn mir
jemand einen Tipp geben könnte.
Es handelt sich um ein 8051F340 µC.
Gruß
Tom
Tom schrieb:
> mov p4, a;> orl p4, #00001111b; Taster wieder in Lesemodus
wenn du die Sequenz in:
orl a, #0x0fH ;low-swap des Akku zusätzlich in Lesemodus
mov p4, a ;und erst jetzt an p4 ausgeben
änderst?
Tom schrieb:> Ich vermute das es etwas mit dem Ausgangslatch zu tun hat
Hast du ein Oszilloskop? Dann könntest du dir mal ansehen, was der Pegel
an Pin macht.
So wie du es derzeit machst, muss der blitzschnell von 0 auf 1
ansteigen, damit du einen unbetätigten Taster erkennst.
Ich würde von den unteren 4 Bits am Port die Finger lassen und den
"neuen" Portzustand wie schon erwähnt erst mal im Akku so berechnen dass
sich der1-Pegel am Pin nicht ändert und diesen Wert dann ausgeben.
bei diversen "klassischen" 8051 sollte dein Code korrekt funktionieren,
weil dort beim Schreiben einer 1 auf einen IO-Port kurzeitig ein starker
High-Treiber aktiviert wird. Nach einigen Takten wird der starke
High-Treiber dann wieder deaktiviert und nur der schwache Pullup hält
den High-Pegel.
Beim 8051F340 scheint das etwas anders zu laufen: der hat ein
Steuerregister P4MDOUT, mit dem der Ausgang dauerhaft als Push-Pull
Treiber oder als Open-Drain Treiber konfiguriert werden kann. Der
Reset-State ist Open-Drain, und ich tippe drauf, dass damit auch das
kurzzeitige Aktivieren des Push-Pull bei diesem µC nicht stattfindet.
Damit bleibt nur der schwache Pullup und der High-Pegel wird erst
langsam erreicht.
Ansonsten schließe ich mich aber meinen Vorrednern an: mach die
Oder-Verknüpfung im Akku und schreibe erst danach auf den Port. Dann
bleibt das Nibble an den Tastern fest auf Highpegel.
Danke erstmal für die Tipps.
Ich habe jetzt, wie vorgeschlagen, die Oder Verknüpfung erst auf den
Akku angewandt und dann in den Port 4 geschrieben und es funktioniert!
Aber ich verstehe nicht ganz warum, es müsste doch egal sein ob ich
jetzt die Oder Verknüpfung direkt auf den Port anwende und somit direkt
schreibe oder ob ich erst den Akku verknüpfe und dann das Ergebnis in
den Port schreibe. Es wird sich doch in jedem Fall ein Bit ändern, oder?
Ich habe mal gelesen das es Befehle gibt die direkt auf den Port Pin
schreiben und welche die auf den Latch zugreifen, bin mir aber nicht
sicher ob ich das richtig verstanden habe.
Ich erinnere mich das ich vor ein paar Jahren ein ähnliches Problem bei
einem PIC hatte, damals habe ich ein High Signal an einem Ausgang
erzeugt und wollte das im nächsten Befehl an einem anderen Eingangspin
des PICs wieder einlesen, das hat auch nur mit einer Warteschleife
zwischen den Befehlen funktioniert.
Tom schrieb:> Danke erstmal für die Tipps.>> Ich habe jetzt, wie vorgeschlagen, die Oder Verknüpfung erst auf den> Akku angewandt und dann in den Port 4 geschrieben und es funktioniert!> Aber ich verstehe nicht ganz warum, es müsste doch egal sein ob ich> jetzt die Oder Verknüpfung direkt auf den Port anwende und somit direkt> schreibe oder ob ich erst den Akku verknüpfe und dann das Ergebnis in> den Port schreibe. Es wird sich doch in jedem Fall ein Bit ändern, oder?> Ich habe mal gelesen das es Befehle gibt die direkt auf den Port Pin> schreiben und welche die auf den Latch zugreifen, bin mir aber nicht> sicher ob ich das richtig verstanden habe.>> Ich erinnere mich das ich vor ein paar Jahren ein ähnliches Problem bei> einem PIC hatte, damals habe ich ein High Signal an einem Ausgang> erzeugt und wollte das im nächsten Befehl an einem anderen Eingangspin> des PICs wieder einlesen, das hat auch nur mit einer Warteschleife> zwischen den Befehlen funktioniert.
Sorry funktioniert doch nicht, ich habe jetzt folgendes gemacht:
1
main:
2
3
mov p4, #11111111b; Eingänge in Lesemodus, alle LEDs aus
4
loop:
5
mov a, p4; Inhalt von Port 4 in Akku
6
swap a; Taster Infos hoch
7
mov p4, a;
8
swap a;
9
orl a, #00001111b;
10
mov p4, a;
11
12
jmp loop;
das funktioniert zwar, nur hier wird ja jedes mal die LED wieder
abgeschalten. Man sieht das zwar nicht aber, so ganz richtig finde ich
es nicht.
Wenn ich den zweiten swap Befehl rausnehme. Dann funktioniert es wieder
nicht.
Tom schrieb:> Aber ich verstehe nicht ganz warum, es müsste doch egal sein ob ich> jetzt die Oder Verknüpfung direkt auf den Port anwende und somit direkt> schreibe oder ob ich erst den Akku verknüpfe und dann das Ergebnis in> den Port schreibe.
Nehmen wir an nur die LED an bit 7 des Ports war an:
- Du wirst also 0111 1111b einlesen.
- Nibble swap 1111 0111b
- Zurückschreiben 1111 0111b --> Port
- OR 1111 0111b
Der Eingang war kurz auf null und der Mosfet hat die Ausgangskapazität
entladen. Diese wir nach dem OR relativ langsam über den Pullup geladen.
Wenn du den Eingang abfragst, bevor die Kapazität geladen ist, wirst du
wieder '0' (Taste gedrückt) einlesen.
Jeztz mit dem OR im Akku:
- Du wirst also 0111 1111b einlesen.
- Nibble swap 1111 0111b
- OR 1111 0111b --> Akkua
- Zurückschreiben 1111 1111b
Jetzt war der Input nie auf '0', die Ausgangskapazität wurde also nicht
entladen und der Pin ist so lange ununterbrochen auf '1' bis du die
Taste drückst.
P.S. Ich hoffe ich es verständlich erklärt.
Tom schrieb:> Aber ich verstehe nicht ganz warum, es müsste doch egal sein ob ich> jetzt die Oder Verknüpfung direkt auf den Port anwende und somit direkt> schreibe oder ob ich erst den Akku verknüpfe und dann das Ergebnis in> den Port schreibe.
Nö: in deinem alten Code schreibst du selbst den IO am Taster immer
wieder kurz auf 0 (immer dann, wenn die zugehörige LED aktiv ist) und
erst mit dem folgenden Or-Befehl wieder auf 1. Da der Pullup den Pin nur
langsam auf 1 hochzieht, du aber schnell immer wieder die Null
"auffrischst", erreicht der Pin nie die Schwelle zur 1.
Wenn du das Oder im Akku durchführst schreibst du die Null gar nicht
erst auf den Taster-IO. Der kann nach dem Loslassen des Tasters beliebig
langsam nach oben laufen und wird nicht mehr von deinem Code auf Null
gezogen.
Tom schrieb:> Ich habe mal gelesen das es Befehle gibt die direkt auf den Port Pin> schreiben und welche die auf den Latch zugreifen
Den Effekt gibt es beim Einlesen: Read-Modify-Write-Befehle lesen das
Ausgangsregister, reine Read-Befehle lesen den Pinzustand. Aber der
spielt hier keine Rolle.
Tom schrieb:> Tom schrieb:>> Danke erstmal für die Tipps.>>>> Ich habe jetzt, wie vorgeschlagen, die Oder Verknüpfung erst auf den>> Akku angewandt und dann in den Port 4 geschrieben und es funktioniert!>> Aber ich verstehe nicht ganz warum, es müsste doch egal sein ob ich>> jetzt die Oder Verknüpfung direkt auf den Port anwende und somit direkt>> schreibe oder ob ich erst den Akku verknüpfe und dann das Ergebnis in>> den Port schreibe. Es wird sich doch in jedem Fall ein Bit ändern, oder?>> Ich habe mal gelesen das es Befehle gibt die direkt auf den Port Pin>> schreiben und welche die auf den Latch zugreifen, bin mir aber nicht>> sicher ob ich das richtig verstanden habe.>>>> Ich erinnere mich das ich vor ein paar Jahren ein ähnliches Problem bei>> einem PIC hatte, damals habe ich ein High Signal an einem Ausgang>> erzeugt und wollte das im nächsten Befehl an einem anderen Eingangspin>> des PICs wieder einlesen, das hat auch nur mit einer Warteschleife>> zwischen den Befehlen funktioniert.>> Sorry funktioniert doch nicht, ich habe jetzt folgendes gemacht:> main:>> mov p4, #11111111b; Eingänge in Lesemodus, alle LEDs aus> loop:> mov a, p4; Inhalt von Port 4 in Akku> swap a; Taster Infos hoch> mov p4, a;> swap a;> orl a, #00001111b;> mov p4, a;>> jmp loop;>> das funktioniert zwar, nur hier wird ja jedes mal die LED wieder> abgeschalten. Man sieht das zwar nicht aber, so ganz richtig finde ich> es nicht.>> Wenn ich den zweiten swap Befehl rausnehme. Dann funktioniert es wieder> nicht.
Ich könnte dann ja genauso gut auch folgendes machen:
1
main:
2
3
mov p4, #11111111b; Eingänge in Lesemodus, alle LEDs aus
Tom schrieb:> main:>> mov p4, #11111111b; Eingänge in Lesemodus, alle LEDs aus>> mov a, p4; Inhalt von Port 4 in Akku> swap a; Taster Infos hoch> mov p4, a;> jmp main;
Damit schaltest du tatsächlich immer wieder die LED aus, sie sollten
auch bei gedrücktem Taster nur mit viertel Helligkeit leuchten.
Hast du es folgendermaßen versucht? Was funktioniert dabei nicht?
mov p4,#11111111b
loop:
mov a,p4
swap a
orl a,#00001111b
mov p4,a
jmp loop
Tom schrieb:> main:>> mov p4, #11111111b; Eingänge in Lesemodus, alle LEDs aus>> mov a, p4; Inhalt von Port 4 in Akku> swap a; Taster Infos hoch> mov p4, a;> jmp main;>> Das funktioniert auch.
Wahrscheinlich, weil du die LEDs dann mit 1111 einließt und also nie 0
in die Eingänge schreibst.
Diese Lösung hatte ich auch gerade, so funktioniert es. Danke euch für
die Hilfe. Ich glaube bei der zweiten Lösung hat es nicht funktioniert,
weil ich erst eine Null (von der LED) an den Taster Pin geschrieben habe
und dann wieder eine eins (entstanden durch die ODER Verknüpfung). Und
gleich darauf den Taster Pin wieder eingelesen habe.
Achim S. schrieb:> Den Effekt gibt es beim Einlesen: Read-Modify-Write-Befehle lesen das> Ausgangsregister, reine Read-Befehle lesen den Pinzustand. Aber der> spielt hier keine Rolle.
Beim Standard-8051 sollte man sich auf jeden Fall genau die interne
Portstruktur anschauen, und was Read-Modify-Write macht, und welche
Befehle davon betroffen sind.
Es gibt Kuriositäten, die ich mal selbst heraus fand, aber bei korrektem
Betrieb normalerweise nicht auftreten:
Und zwar betrieb ich schon mal eine LED mit nur sehr kleinem
Vorwiderstand bzw. ganz ohne Vorwiderstand an einem I/O-Pin. Dazu hatte
ich einen alten 8051, wo ich bewußt in Kauf nahm, daß er kaputt geht.
Alter NMOS aus der Anfangszeit aus Schrott, ich hab auch genügend
modernere CMOS in Reserve. Deswegen macht es nichts, wenn einer über die
Wupper geht. Aber er überlebte. Der Pin kann mehrere 100mA treiben,
obwohl im Datenblatt nur ein TTL-Fanout (1,6mA Sinkstrom, 80µA
Sourcestrom) angegeben ist. Ich konnte es kaum glauben, aber die gelbe
LED leuchtete an dem immer für schwächlich gehaltenen I/O des 8051 auf
einmal orange. Das bedeutet ja Überlast. Der Ausgang wurde, während die
LED brennt, wieder eingelesen, und siehe da, im Portregister stand dann
an der Stelle der LED tatsächlich eine 1, weil die LED den Pinpegel
gewaltsam hoch zog. Die Spannung betrug fast wieder TTL-High, obwohl der
Pin auf Low gestellt war. Dann wird er auch mit 1 gelesen, auch wenn er
regulär immer 0 haben müßte. Sowas kann gerne auch passieren, wenn man
direkt ohne Vorwiderstand Kondensatoren an den Pin schaltet, aber das
sollte man halt nicht.
Ich meine, beim SiLabs-Derivat ist die Portstruktur nur in Bezug auf
Push-Pull-Betrieb etwas anders als beim Standard-8051. Die Unterschiede
kann man sich mal genauer anschauen. Ich habs bis jetzt nur mal schnell
überflogen.
@Tom:
Einen Taster gegen Masse kann man ohne weitere Bauteile normalerweise
direkt am 8051 anschließen. Da ist er sehr praktisch und ungefährlich.
Beim SiLabs darf dann aber kein Push-Pull für diesen Pin eingestellt
sein, dann wirkt nur der normale Weak-Pullup.