Forum: Mikrocontroller und Digitale Elektronik Versteh die Anweisung nicht..


von Progi (Gast)


Lesenswert?

#define ASC0_TBUF              (*((uword volatile *) 0xFEB0))

kann mir bitte jemand erklären, was dieser Befehl genau bedeutet?
danke schön

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Eine Anweisung an den Präprozessor, jedes Vorkommen des Bezeichners
ASC0_TBUF durch *((uword volatile *) 0xFEB0)) zu ersetzen.

Was das dann genau tut, hängt vom Kontext ab, in dem es benutzt wird.
Sieht aber sehr nach einem IO-Register aus, das sich über die
Speicheradresse 0xfeb0 ansprechen lässt.

von Rooney B. (rooney)


Lesenswert?

Das ist kein Befehl sondern eine Definition, deswegen auch #define

*((uword volatile *) ist ein Type-Cast.

Du weißt ASC0_TBUF Adresse 0xFEB0 zu.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das ist kein Befehl, sondern ein Makro des Präprozessors. Der ersetzt 
auf Textebene jedes Vorkommen von "ASC0_TBUF" durch den 
dahinterstehenden Text.

Und der erzeugt mit einem Typecast aus der Int-Konstante 0xFEB0 einen 
volatile uword-Pointer und dereferenziert diesen, so daß das einen 
syntaktisch korrekten lvalue, dem Werte zugewiesen werden können bzw. 
der auch Werte liefern kann.

Damit kannst Du im Programm also schreiben

  ASC0_TBUF = 1;

oder

  a = ASC0_TBUF;

In ersterem Falle wird in die Speicheradresse 0xFEB0 der Wert 1 
geschrieben, im anderen Falle wird der Wert, der in der Speicheradresse 
0xFEB0 liegt, der Variablen a zugewieden. Es findet in beiden Fällen ein 
16-Bit-Zugriff statt.

Solche Konstrukte werden verwendet, um "memory-mapped-I/O"-Zugriffe 
ausführen zu können, bei vielen Controllern kann so mit der eingebauten 
Peripherie kommuniziert werden.

von Karl H. (kbuchegg)


Lesenswert?

Progi wrote:
> #define ASC0_TBUF              (*((uword volatile *) 0xFEB0))
>
> kann mir bitte jemand erklären, was dieser Befehl genau bedeutet?
> danke schön

Wenn das erste Zeichen in einer Zeile in # ist, dann handelt
es sich um ein Präprozessor-Makro. In dem Fall also um ein #define

#define definiert eine Textersetzung. Überall wo im eigentlichen
Quelltext der Text "ASC0_TBUF" vorkommt, wird dieser Text durch den
Text "(*((uword volatile *) 0xFEB0))" ersetzt.

zb. hier

  ASCO_TBUF = 5;

die Textersetzung liefert

  (*((uword volatile *) 0xFEB0)) = 5

Worum handelt es sich? Da ist zunächst mal die Zahl

    0xFEB0

diese Zahl wird umgecastet zu einem uword volatile Pointer

    (uword volatile *) 0xFEB0

Damit hat man also einen Zeiger, der auf ein uword zeigt, und dessen
Zeigerwert die Adresse 0xFEB0 darstellt. Ugangssprachlich: Ein
Zeiger auf die Speicheradresse 0xFEB0, wobei angenommen wird,
dass sich an dieser Stelle im Speicher ein uword befindet.

Von dieser Speicherstelle wird gelesen/geschrieben indem der
Pointer dereferenziert wird. Ein Pointer wird dereferenziert
indem man ihm ein * voranstellt:

  *((uword volatile *) 0xFEB0)

Alles zusammen ergibt also:

    (*((uword volatile *) 0xFEB0)) = 5

und bedeudet: Schreibe an die Speicherstelle 0xFEB0 (und folgende)
den Wert 5, wobei beim Schreiben der Wert 5 zu einem uword (also
höchstwahrscheinlich ein unsigned word, also 2 Bytes) aufgeblasen
wird und demenstprechend 2 Bytes geschrieben werden.

Ach ja: Das volatile sorgt noch dafür, dass diese Operation nicht
wegoptimiert werden kann, sondern der Zugriff auf jeden Fall
gemacht werden muss. Ansonsten könnte der Optimizer bei sowas:

     ASCO_TBUF = 5;
     ASCO_TBUF = 7;

die erste Zuweisung weg optimieren, da deren Effekt scheinbar
durch die zweite Zuweisung sowieso zunichte gemacht wird.

von Progi (Gast)


Lesenswert?

ich habe da eine Funktion für die Ausgabe und zwar:
1
void ASC0_vSendData(uword uwData)
2
{
3
  ASC0_TBUF    = uwData; //  load transmit buffer register
4
5
}

bei:
1
ASC0_vSendData ('H');
hab ich auch eine Ausgabe beim Hyperterminal.

Wenn ich z.B. eine Variable ausgeben mag, z.B, int a = 3000;
und ich es so programmier: ASC=_vSendData (a), dann passiert nix und ich 
hab keine Ausgabe.
Ich dachte, dass es vllt. an der Diffinition von ASCO_TBUF liegt...also 
keine Ahnung

von die ??? (Gast)


Lesenswert?

Und was passiert bei

  ASC0_vSendData (0xa55a);

? Wenn du nur 3000 probiert hast, dann kann es sein, dass nur das 
untere Byte verarbeitet wird bzw. nicht verarbeitet wird da 0. 
Konfiguration der Hardware prüfen, etc.

von Progi (Gast)


Lesenswert?

also ich weiß, was mein Fehler war (ganz toll..) hatte beim Hyperterm, 
die ganze Zeit Pause eingestellt gehabt und wunder mich, warum ich 
nichts zu sehen bekommen habe...naja
Hätt da noch ne Frage und zwar werden bei mir nur die unteren 2 Bytes 
verarbeitet, also hab ich beim
int a = 3000;
ASC0_vSendData(a);
nur B8 statt BB8 auf dem Bildschirm, weiß vllt. jemand, wie ich das auf 
4 Bytes erweiter, denn ASC0_TBUF ist ja nur 16Bit breit..

von yalu (Gast)


Lesenswert?

Ich vermute mal, dass das ASC0_TBUF-Register an sich nur 8 Bit breit
ist. Es wird allerdings von der 16-Bit-CPU wie ein 16-Bit-Register
angesprochen, wobei die oberen 8 Bits einfach ins Leere laufen.

von die ??? (Gast)


Lesenswert?

yalu wrote:
> Es wird allerdings von der 16-Bit-CPU wie ein 16-Bit-Register
> angesprochen, wobei die oberen 8 Bits einfach ins Leere laufen.

...oder nette Seiteneffekte verursacht. Welchen Prozessor verwendest du?
1
#include <stdint.h>
2
3
#define ASC0_TBUF (*((uint8_t volatile *) 0xFEB0))
4
5
void ASC0_vSendData(uword uwData)
6
{
7
  ASC0_TBUF    = uwData % 0x100; //  load transmit buffer (lower byte)
8
9
  // Hier noch Warteanweisungen einfügen (wenn nötig).
10
11
  ASC0_TBUF    = uwData / 0x100; //  load transmit buffer (upper byte)
12
}

Du solltest mal nachschauen wie breit (8Bit oder 16Bit) dein 
ASC0-Register ist. Wenn es tatsächlich 16Bit breit ist, dann ist mein 
Vorschlag von oben suboptimal weil es in diesem Fall eine Möglichkeit 
geben muss 16Bit-Worte in einem Rutsch zu schreiben (und die Hardware 
sich dann um den Rest kümmert).

von die ??? (Gast)


Lesenswert?

1
  #define ASC0_TBUF (*((uint8_t volatile *) (0xFEB0 + 1)))
2
  //                                                ^^^

Edit: Evtl musst du - je nach Endianess - die Adresse modifizieren.

von yalu (Gast)


Lesenswert?

Auszug aus dem User Manual des C16x, um den (oder einen Ableger) es
sich hier zu drehen scheint:

  "Only the number of data bits which is determined by the selected
  operating mode will actually be transmitted, i.e. bits written to
  positions 9 through 15 of register S0TBUF are always insignificant."

Da über den UART bis zu 9 Bits/Datenwort übertragen werden können,
muss auch das ASC0_TBUF-Register mindestens so breit sein. Deswegen
wird ein 16-Bit-Register genommen, bei dem die obersten 7 ignoriert
werden.

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.