Forum: Mikrocontroller und Digitale Elektronik 8051 Port zu langsam?


von Tom (Gast)


Lesenswert?

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

von Max H. (hartl192)


Lesenswert?

Mit dem 8051 kenn ich mich nicht aus, bei PIC gibt's ein ähnliches 
Verhalten:
http://www.sprut.de/electronic/pic/fallen/fallen.html#iospeed
Beim 8051 könnte es schlimmer sein, da die IOs Open Drain mit Pullup 
sind.

Kannst du das OR machen, bevor du die Zahl zurück in den Port schreibst?

: Bearbeitet durch User
von isnah (Gast)


Lesenswert?

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?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

von Achim S. (Gast)


Lesenswert?

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.

von Tom (Gast)


Lesenswert?

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.

von Tom (Gast)


Lesenswert?

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.

von Max H. (hartl192)


Lesenswert?

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.

von Achim S. (Gast)


Lesenswert?

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.

von Tom (Gast)


Lesenswert?

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
4
5
    mov a, p4;        Inhalt von Port 4 in Akku
6
    swap a;          Taster Infos hoch
7
    mov p4, a;
8
    jmp main;

Das funktioniert auch.

von Achim S. (Gast)


Lesenswert?

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

von Max H. (hartl192)


Lesenswert?

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.

von Tom (Gast)


Lesenswert?

1
   mov   p4,#11111111b
2
loop:
3
   mov   a,p4
4
   swap  a
5
   orl   a,#00001111b
6
   mov   p4,a
7
   jmp   loop

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.

von Ein Elektroniker (Gast)


Lesenswert?

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.

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.