mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Inline Assembler in C


Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallöschen,

wie bekomme ich den
void setDdrLed( uint8_t x )
{
  asm (
      "ldi r16, %0\n\t"
      "out 0x17 , r16"  
      : "+r" ( x ) 
    );
}
Wie bekomme ich es hin das ich in "0x17" den Wert von "x" rein schreibe?

Autor: pointer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
uint8_t *ptr = 0x17;

... ptr, r123..

Autor: Thorsten K. (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
pointer schrieb:
> uint8_t *ptr = 0x17;
>
> ... ptr, r123..
Sollte möglichst alles in Inline geschehen..

Autor: Benjamin S. (recycler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich denke der Compiler optimiert das am besten:
uint8_t *ptr = 0x17;

wenn du die Funktion inline verwenden willst, dann definiere sie inline.
inline void setDdrLed( uint8_t x )
{
  asm (
      "ldi r16, %0\n\t"
      "out 0x17 , r16"  
      : "+r" ( x ) 
    );
}

Autor: Thorsten K. (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Benjamin S. schrieb:
> Ich denke der Compiler optimiert das am besten:uint8_t *ptr =
> 0x17;
> wenn du die Funktion inline verwenden willst, dann definiere sie inline.
> inline void setDdrLed( uint8_t x )
> {
>   asm (
>       "ldi r16, %0\n\t"
>       "out 0x17 , r16"
>       : "+r" ( x )
>     );
> }
Okay, habe ich übersehen.
Geht aber nach wie vor nicht.

Autor: Benjamin S. (recycler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst x mit 17 belegen beim Aufruf
setDdrLed(0x17)

oder willst du beim "out 0x17 , r16" das 17 dynmisch haben?
inline void setDdrLed( uint8_t x, uint8_t reg )
{
  asm (
      "ldi r16, %0\n\t"
      "out %1 , r16"  
      : "+r" ( x ) 
      : "+r" ( reg ) 
    );
}

weitere Info gibts u.a. hier:
https://rn-wissen.de/wiki/index.php?title=Inline-A...

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Benjamin S. schrieb:
> Du kannst x mit 17 belegen beim AufrufsetDdrLed(0x17)
> oder willst du beim "out 0x17 , r16" das 17 dynmisch haben?
> inline void setDdrLed( uint8_t x, uint8_t reg )
> {
>   asm (
>       "ldi r16, %0\n\t"
>       "out %1 , r16"
>       : "+r" ( x )
>       : "+r" ( reg )
>     );
> }
>
> weitere Info gibts u.a. hier:
> https://rn-wissen.de/wiki/index.php?title=Inline-A...

Ich würde gerne in das Register bzw. an die Adresse 0x17 den Wert den 
ich übergebe, rein schreiben.

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Ich würde gerne in das Register bzw. an die Adresse 0x17 den Wert den
> ich übergebe, rein schreiben.

Das kannst du auch ohne Assembler machen:
static func(uint8_t x) {
  *(uint8_t*)0x17 = x;
}

Oder besser lesbar, wie bereits geschrieben wurde:
static func(uint8_t x) {
  uint8_t *ptr = (uint8_t*)0x17;
  *ptr = x;
}

Wenn es dir darum geht, den Inline-Assembler von gcc besser zu 
verstehen, dann sage das bitte deutlich an.

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
S. R. schrieb:
> Thorsten K. schrieb
schrieben wurde:static func(uint8_t x)
> {
>   uint8_t *ptr = (uint8_t*)0x17;
>   *ptr = x;
> }
>
> Wenn es dir darum geht, den Inline-Assembler von gcc besser zu
> verstehen, dann sage das bitte deutlich an.

Ja ich würde es gerne in Inline Assembler machen, damit ich es auch 
besser verstehe..

Autor: Carl D. (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Benjamin S. schrieb:
> Du kannst x mit 17 belegen beim Aufruf
>
setDdrLed(0x17)
>
> oder willst du beim "out 0x17 , r16" das 17 dynmisch haben?
>
>
> inline void setDdrLed( uint8_t x, uint8_t reg )
> {
>   asm (
>       "ldi r16, %0\n\t"
>       "out %1 , r16"
>       : "+r" ( x )
>       : "+r" ( reg )
>     );
> }
> 

Welcher μC soll das denn sein? Aus dem ersten Post zu schließen ein 
AVR8.
Wo hat der ein OUT mit Port-Adresse in einem Register? Das geht nur über 
die MEM-Adresse (idR IO-Adresse+0x20 also 0x37) in einem 
Pointer-Register.

Autor: Mario M. (thelonging)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Wozu Inline-Assembler, wenn man auch "DDRB = x" schreiben kann?

Autor: Carl D. (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mario M. schrieb:
> Wozu Inline-Assembler, wenn man auch "DDRB = x" schreiben kann?

Weil "DDRB" hier "uint8_t reg" heißt?!

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde es halt mal gerne wissen wie man das damit macht. Es ist ein 
Tiny2313.

Eigentlich ist der Port mir egal.. Also welcher..

Autor: foobar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich würde es halt mal gerne wissen wie man das damit macht.

Wie wär's mit Google? Ne Suche nach "avr-gcc inline assembler" gibt als 
ersten deutschen[1] Treffer:

  https://rn-wissen.de/wiki/index.php?title=Inline-A...



[1] Wobei ich mir nicht sicher bin, ob Deutsch die passende Sprache ist 
;-)

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
foobar schrieb:
>> Ich würde es halt mal gerne wissen wie man das damit macht.
>
> Wie wär's mit Google? Ne Suche nach "avr-gcc inline assembler" gibt als
> ersten deutschen[1] Treffer:
>
>   https://rn-wissen.de/wiki/index.php?title=Inline-A...
>
> [1] Wobei ich mir nicht sicher bin, ob Deutsch die passende Sprache ist
> ;-)

Ja habe ich schon gegoogelt.. Diese Seite habe ich auch schon 
aufgerufen.. Bin nicht schlauer geworden..

Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Bin nicht schlauer geworden..

Das tut mir aber Leid.
Woran mangelt's denn?

Autor: foobar (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
> Diese Seite habe ich auch schon aufgerufen.. Bin nicht schlauer
> geworden..

Die Seite erklärt aber gut und ausführlich. Besser wirst du's hier auch 
nicht bekommen. Evtl solltest du dir nen anderes Thema suchen ...

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
foobar schrieb:
>> Diese Seite habe ich auch schon aufgerufen.. Bin nicht schlauer
>> geworden..
>
> Die Seite erklärt aber gut und ausführlich. Besser wirst du's hier auch
> nicht bekommen. Evtl solltest du dir nen anderes Thema suchen ...

Man könnte es jedoch wenigstens mal versuchen.
Ich kann auf den Port zugreifen. Das heißt wenn ich jetzt ne LED dran 
hänge fängt diese auch zu leuchten, je nach dem welches Bit ich setze.

Bei den Ausgängen jedoch funktioniert das eben nicht. Muss doch einen 
einfachen Grund haben..

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Geht aber nach wie vor nicht.

Was heißt "geht nicht"? Nimmt er Compiler es nicht an? Kommt der Wert 
nicht im Register an? Sollte es so sein: Woran hast du das erkannt?

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Thorsten K. schrieb:
>> Geht aber nach wie vor nicht.
>
> Was heißt "geht nicht"? Nimmt er Compiler es nicht an? Kommt der Wert
> nicht im Register an? Sollte es so sein: Woran hast du das erkannt?

Der Compiler zeigt mir keine warnings oder Fehlermeldungen an.
Ich vermute mal das der Wert nicht ins Register rein geschrieben wird.

Autor: Axel S. (a-za-z0-9)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> foobar schrieb:

>> Die Seite erklärt aber gut und ausführlich. Besser wirst du's hier auch
>> nicht bekommen. Evtl solltest du dir nen anderes Thema suchen ...
>
> Man könnte es jedoch wenigstens mal versuchen.
> Ich kann auf den Port zugreifen. Das heißt wenn ich jetzt ne LED dran
> hänge fängt diese auch zu leuchten, je nach dem welches Bit ich setze.
>
> Bei den Ausgängen jedoch funktioniert das eben nicht.

Du sprichst in Rätseln. Was meinst du denn bitte mit "den Ausgängen"? 
Inwiefern unterscheiden sich irgendwelche Ausgänge von Portpins, an 
denen LED hängen? Und was genau soll "funktioniert nicht" heißen?

Klingt gerade überhaupt nicht nach einem Softwareproblem, am wenigsten 
nach einem Problem mit Inline-Assembler.

Autor: Peter D. (peda)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Thorsten K. schrieb:
>
> void setDdrLed( uint8_t x )
> {
>   asm (
>       "ldi r16, %0\n\t"
>       "out 0x17 , r16"
>       : "+r" ( x )
>     );
> }
> 

Nun, x ist ja bereits im Register r24 (das macht der Aufrufer).
Das ldi ist somit falsch und gibt eine Fehlermeldung:
C:\Users\xxx\AppData\Local\Temp/cciQ1sp0.o: In function `setDdrLed1':
D:\AVR-C\Test2/asm.c:5: undefined reference to `r24'

Außerdem wird alles wegoptimiert, da nicht volatile.
So geht es:
void setDdrLed( uint8_t x )
{
  asm volatile (
      "mov r16, %0\n\t"
      "out %1 , r16\n\t"  
      : "+r" ( x ) 
      : "M" (_SFR_IO_ADDR (DDRB))
    );
}

Steht aber alles schön erklärt im:
https://rn-wissen.de/wiki/index.php?title=Inline-A...

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Nun, x ist ja bereits im Register r24 (das macht der Aufrufer).

In welchem Register das an die Funktion übergeben wird, muss deinem 
asm-Block egal sein. Wesentlich ist nur, dass das "+r" sagt, dass dein 
Code den Wert in einem (beliebigen) Register erwartet. ldi will aber 
einen Immediate-Wert und kein Register als zweiten Operanden.

Peter D. schrieb:
> void setDdrLed( uint8_t x )
> {
>   asm volatile (
>       "mov r16, %0\n\t"
>       "out %1 , r16\n\t"
>       : "+r" ( x )
>       : "M" (_SFR_IO_ADDR (DDRB))
>     );
> }

Warum ist x hier als Output-Operand aufgeführt? Es wird doch 
ausschließlich gelesen.
Man könnte sich den Umweg über r16 übrigens noch sparen. Und man kann 
den Operanden zur Übersicht auch Namen geben. Dann würde das ganze so 
aussehen:
  asm volatile (
      "out %[Register], %[Value]\n\t"
      : /* Leere Liste */
      : [Value]"r" ( x ), [Register]"M" (_SFR_IO_ADDR (DDRB))
    );

: Bearbeitet durch User
Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> Mario M. schrieb:
>> Wozu Inline-Assembler, wenn man auch "DDRB = x" schreiben kann?
>
> Weil "DDRB" hier "uint8_t reg" heißt?!

Genau darum kann es auch gar nicht gehen, C hin, Inline-Assembler her. 
Der Operand für OUT muss eine Compilezeit-Konstante sein, denn die 
Adresse des Ports wird in den Befehl hinein codiert.  Deshalb ist ja 
auch OUT auf einen vergleichsweise kleinen Portadressraum eingeschränkt.

Wenn es unbedingt zur Laufzeit einstellbar sein soll, kann man nur üben 
den (langsameren) Alias der Portadresse im Speicheradressraum gehen. Das 
ist in der avr-libc-FAQ beschrieben.

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> asm volatile (
>       "out %[Register], %[Value]\n\t"
>       : /* Leere Liste */
>       : [Value]"r" ( x ), [Register]"M" (_SFR_IO_ADDR (DDRB))
>     );

Das sieht viel versprechend aus ;) werde ich später mal testen.

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Das sieht viel versprechend aus

Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als 
Makro übergeben werden. Den kann man nicht durch einen Variablennamen 
ersetzen.

Ansonsten ist das aber wirklich nichts anderes, als gleich in C zu 
schreiben:
PORTB = x;

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als
> Makro übergeben werden. Den kann man nicht durch einen Variablennamen
> ersetzen.

Wo hat er das denn gewollt?

Thorsten K. schrieb:
> Ich würde gerne in das Register bzw. an die Adresse 0x17 den Wert den
> ich übergebe, rein schreiben.

Ich interpretiere das so, dass der Wert als dynamischer Parameter 
übergeben werden soll, aber nicht die Adresse des Registers.

> Ansonsten ist das aber wirklich nichts anderes, als gleich in C zu
> schreiben:
> PORTB = x;

Es geht ihm ja nur darum, inline assembler zu verstehen. Da ist es nicht 
von Nachteil, mit was einfachem anzufangen.

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Es geht ihm ja nur darum, inline assembler zu verstehen. Da ist es nicht
> von Nachteil, mit was einfachem anzufangen.

Dafür gibt's das Inline Assembler Cookbook.

https://www.nongnu.org/avr-libc/user-manual/inline_asm.html

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als
> Makro übergeben werden. Den kann man nicht durch einen Variablennamen
> ersetzen.
>
> Ansonsten ist das aber wirklich nichts anderes, als gleich in C zu
> schreiben:
> PORTB = x;

Das ist mir soweit auch klar -.-*
Ich möchte doch einfach nur mein Wissen in Inline ASM ein wenig 
verstärken.. Und durch das belesen, bin ich halt auch nicht weiter 
gekommen..

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als
> Makro übergeben werden. Den kann man nicht durch einen Variablennamen
> ersetzen.

Wie meinst du das? Die Adresse von PORTx? Welches Makro?

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Und durch das belesen, bin ich halt auch nicht weiter gekommen.

Dann schreib lieber mal, wo du nicht weiterkommst.

Das relativ simple Beispiel mit den IO-Port-Ausgaben steht im genannten 
Inline Asm Cookbook ja bereits ziemlich weit oben.  Nach unten wird's 
dann immer tiefgehender.

Diese Constraints mögen auf den ersten Blick ziemlich verwirrend 
aussehen. Letztlich bilden sie das ab, was der Compiler intern in seinen 
Zwischensprachen ebenfalls benutzt, um die einzelnen Operanden zu 
markieren. Dadurch kann man die Aufteilung, welche Daten beispielsweise 
in Registern gehalten werden und welche im Speicher bleiben (und dann 
temporär in Register kopiert werden müssen), bis zu einem Zeitpunkt nach 
hinten schieben, bei dem der Optimierer dann entscheiden kann, was wie 
zugegriffen wird, sodass der gesamte Code möglichst effizient wird. 
„Harte“ Registerzuteilungen sollte man folglich auch im Inline-Assembler 
vermeiden und stattdessen Variablen mit passendem Constraining benutzen.

Schau dir dein einleitendes Beispiel an: du hast Register r16 hart 
vorgegeben (und müsstest es in die "clobber"-Liste eintragen).  Wenn du 
stattdessen deinen OUT-Befehl mit einem Operanden versiehst, der 
passendes Constraining bekommt (OUT braucht ein beliebiges Register, 
also "r"), dann kann der Compiler sich darum kümmern, dass der 
auszugebende Wert gleich mal in einem solchen Register berechnet wird, 
sodass man nicht nochmal umkopieren muss.
void setled(uint8_t value)
{
   asm("out %[port], %[val]"
      :  /* no output operands 1) */
      : [port] "I" (_SFR_IO_ADDR(PORTB)),
        [val] "r" (value));
}

1) Natürlich wird aus dem Controller etwas ausgegeben, aber das 
Inline-Asm-Statement gibt in diesem Kontext nichts in seine C-Umgebung 
zurück. Daher gibt es hier nur input operands.

Obige Funktion compiliert zu:
.global setled
        .type   setled, @function
setled:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
/* #APP */
 ;  6 "setled.c" 1
        out 24, r24
 ;  0 "" 2
/* #NOAPP */
        ret

r24 ist hierbei das Register, in dem die Funktion den ersten Parameter 
übergeben bekommt. Der Compiler muss nichts extra umkopieren, er kann 
dieses Register gleich für den OUT-Befehl benutzen. Bei deiner Variante 
hätte er es erst (sinnlos) nach r16 umkopieren müssen.

: Bearbeitet durch Moderator
Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Die Adresse von PORTx? Welches Makro?

PORTx ist ein Makro.

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> : [port] "I" (_SFR_IO_ADDR(PORTB)),

Okay. Und kann ich meiner Funktion auch "PORTB" mitgeben?
Also quasie..
void setLed( uint8_t port , uint8_t bit )
{
  asm("out %[port], %[bit]"
  :  /* no output operands 1) */
  : [port]  "I" (_SFR_IO_ADDR( port ) ) , [bit] "r" ( bit) );
}

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Und kann ich meiner Funktion auch "PORTB" mitgeben?

Nein.  Schrieb ich doch weiter oben, sowas gibt die AVR-Architektur 
schlicht nicht her.

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Thorsten K. schrieb:
> Das sieht viel versprechend aus
>
> Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als
> Makro übergeben werden. Den kann man nicht durch einen Variablennamen
> ersetzen.
>
> Ansonsten ist das aber wirklich nichts anderes, als gleich in C zu
> schreiben:PORTB = x;

Also Makro übergeben. Kannst du mir bitte ein konkretes Beispiel 
posten..?
Wenn PORTB oder DDRB ein Makro ist, müsste ich das doch übergeben 
können?

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Wenn PORTB oder DDRB ein Makro ist, müsste ich das doch übergeben
> können?

Nein. Mach dich mal mit dem Konzept von Makros vertraut: das ist doch 
nur eine Textersetzung. Er würde ja bei der Übergabe aufgelöst werden 
müssen.

Unabhängig von Makro oder nicht, scheinst du immer noch nicht verstanden 
zu haben, dass beide Operanden eines OUT-Befehls zu dem Zeitpunkt, da 
es der Assembler vorgesetzt bekommt, feststehende Konstanten sein 
müssen. Das beißt sich mit deinem Wunsch, sie als Parameter einer 
Funktion zu übergeben, denn dann würde man ja den konkreten Port erst 
zur Laufzeit festlegen. Wenn du sowas willst, musst du über die 
Port-Aliase im Speicheradressbereich gehen. Wie das geht, ist hier 
beschrieben:

https://www.nongnu.org/avr-libc/user-manual/FAQ.ht...

Autor: Thorsten K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Unabhängig von Makro oder nicht, scheinst du immer noch nicht verstanden
> zu haben, dass beide Operanden eines OUT-Befehls zu dem Zeitpunkt, da es
> der Assembler vorgesetzt bekommt, feststehende Konstanten sein müssen.
> Das beißt sich mit deinem Wunsch, sie als Parameter einer Funktion zu
> übergeben, denn dann würde man ja den konkreten Port erst zur Laufzeit
> festlegen. Wenn du sowas willst, musst du über die Port-Aliase im
> Speicheradressbereich gehen. Wie das geht, ist hier beschrieben:
>
> https://www.nongnu.org/avr-libc/user-manual/FAQ.ht...

Das geht dann aber nur in C Code?

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten K. schrieb:
> Das geht dann aber nur in C Code?

Was geht nur in C-Code?  Zugriff auf IO-Ports über Speicherbereiche? 
Natürlich geht das auch direkt in Assemblercode, der C-Compiler erzeugt 
ja letztlich nur Assemblercode. Die Speicheradresse eines IO-Ports 
bekommt man mit _SFR_MEM_ADDR() – steht natürlich alles in der Doku. ;-)

Mir stellt sich trotzdem noch die Frage, warum du für simple Dinge, die 
in C völlig unproblematisch und einfach gehen, erst die Verrenkungen 
über inline asm machen willst. Wirklich lernen kann man an der Stelle 
nicht so viel …

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.

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