mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Trivial: LED blinken lassen mit C18 ?


Autor: Thorsten (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bin gerade am verzweifeln und hoffe auf ein Tip von euch. Ziemlich
triviale Sache eigentlich: ich möchte PB0 eines PIC18F2550 blinken
lassen, ich programmiere mit dem C18. Vorweg, TRISB etc. ist gesetzt,
der Controller läuft. Das blinken klappt (ca. 2Hz) auch mit folgendem
Code (Variante 1):

while(1)
{
  PORTB &= 0xf0;      // PB3..0 auf 0 setzen
  Delay10KTCYx(255);
  PORTB |= 0x01;      // PB0 auf 1
  Delay10KTCYx(255);
}

Soweit so gut. Wenn ich jetzt folgenden Code benutze, blinkt nichts
mehr (Variante 2):

while(1)
{
  PORTB ^= 0x01;     // PB0 toggeln
  Delay10KTCYx(255);
}

Im Simulator funktioniert jedoch alles einwandfrei. Im Anhang ist der
vom Compiler erzeugte Code. Der obere Teil zeigt den Assemblercode von
Variante 1, der untere Teil ist für Variante 2. Es ist offensichtlich
so, daß der Controler den BTG-Befehl (bit toggle) nicht ausführt. Hat
der etwa ne macke? Die Teile sind von eBay, der Datecode endet mit UD
(siehe http://www.mikrocontroller.net/forum/read-1-189045.html#new). Ob
es was damit zu tun hat?

Was meint ihr dazu?

Gruß
Thorsten

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab jetzt nochmal was anderes probiert:

...
PORTB &= 0b11110000;

_asm BTG PORTB, 0, 0 _endasm    // inline assembler
_asm BTG PORTB, 0, 0 _endasm

while(1);
...

Zuerst wird PB0 auf 0 gesetzt. Nach dem ersten BTG müßte PB0 auf 1
gehen, was auch geschieht. Nach dem zweiten BTG müßte PB0 wieder aif 0
gehen und genau das geschieht nicht. Es wird immer nur ein einziger
BTG-Befehl ausgeführt, alle weiteren ändern das Bit nicht mehr :(

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, hab den Fehler gefunden. Es liegt daran, daß der Compiler das
Banking nicht beachtet, mit "BTG PORTB, 0, 1" funktioniert es. Nur
wie macht man dem Compiler klar, daß er es eben genau so machen soll?

Autor: Bri (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kann dir leider nicht weiterhelfen. Aber das war einer der Gründe,
warum ich zu Atmels AVR's gewechselt habe. :-)

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und ich dachte immer, ein Compiler nimmt mir diese Probleme ab :(

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, es war doch nicht das Banking, der Compiler macht das schon richtig.
Es lag mal wieder (wie fast immer) am dummen Programmierer der das
Datenblatt nicht richtig lesen konnte. Die neueren PICs haben außer
z.B. TRISB und PORTB noch ein LATB. TRIS setzt die Richtung der Pins,
PORT dient zum lesen der Pins und LAT zur Ausgabe. Die älteren PICs
hatten dieses LAT-Register nicht :( Mit

while(1)
{
  LATB ^= 0x01;
  Delay();
}

ist die Welt wieder in Ordnung.

Gruß
Thorsten

Autor: Michi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wieso funktioniert dann oben Deine erste Variante?
Da kommt doch auch kein LATB vor.

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da hast du allerdings recht...

Autor: martinwisi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Es funktioniert deswegen, weil dort der Wert nicht in das PORT Register
geschrieben wird sondern der PIC direkt in das LAT Register schreibt,
auch wenn man im Programm PORTB schreibt...

Wenn man das Bit jedoch toggeln will dann wird der Wert der aktuell am
PORT anliegt ausgelesen und dann dort das jeweilige Bit getoggelt und
dann wieder ins LAT Register geschrieben!
Und eine Led reicht oft schon aus, dass der PIC bei High Ausgang Low
einliest....
Deswegen verwendet man dann zum toggeln das LAT Register, weil da die
Spannungswerte an den Pins keinen einfluss auf das LAT Register
haben...

MfG Martin W

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Und eine Led reicht oft schon aus, dass der PIC bei High Ausgang Low
einliest...."


Huch, wer macht denn bloß sowas, eine LED ohne Begrenzerwiderstand
anschließen ?


Bei nem AVR würden dann lt. Datenblatt mindestens 75mA fließen, schade
um die LED.


Peter

Autor: bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Pins schaffen maximal 29mA bei Kurzschluß, also bricht die
Ausgangsspannung entsprechend zusammen (und die LED möge überleben?).

Bernd

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab an dem Pin ne low current LED über nen 750 Ohm Widerstand
hängen. Hab ich vielleicht zu viel parasitäre Kapazität an dem Pin, so
das er beim einlesen noch den falschen Wert kriegt?

Autor: bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Thorsten:
Wieso, klappt das mit LATx nicht?

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Doch, denn bei LATx wird der Port ja nicht eingelesen nur mit PORTx
klappt es aber nicht, obwohl es ja eigentlich auch klappen müßte.
Martin meinte ja, daß evtl. die LED Schuld sein könnte. Ich hab auch
leider zur Zeit kein Scope da, um mir mal anzusehen was da am Pin so
abgeht.

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meine Güte, wie peinlich. Es funktioniert natürlich auch mit PORTB nur
ist das Problem, daß Port B auch als Input für den ADC fungiert und per
Default sind diese Portpins eben als ADC-Eingänge geschaltet und dies
bleibt auch so, obwohl durch TRISB diese Bits als Ausgang festgelegt
wurden. Und wenn die ADC-Eingänge aktiviert sind, so wird IMMER Null
vom Port gelesen, dies wird getoggelt, anschließend wird also der
entsprechende Pin IMMER auf High gesetzt (read-modify-write). Genau das
deckt sich auch mit meiner Beobachtung, nach der der Pin auf High geht
und so bleibt.

Man muß - wenn man diese Pins als digitale IOs nutzen will - dies noch
zusätzlich in ADCON1 einstellen. Alternativ kann man auch ein
Konfigurationsbit setzen, durch welches RB[4:0] per Default auf
digitale IOs gesetzt wird.

Zusammengefaßt läßt also folgender Code PB0 blinken:

...
ADCON1 = 0x0F;  // Alle Pins als digitale IOs nutzen

TRISB &= 0xF0;
PORTB &= 0b11110000;
LATB &= 0b11110000;

while(1)
{
   PORTB ^= 0x01;
   Delay10KTCYx(255);
}
...

So jetzt bin ich beruhigt und kann mich aufs Wochenende freuen :)

Gruß
Thorsten

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.