Forum: Compiler & IDEs Anweisungen in Header Datei


von R. Q. (timebeast)


Lesenswert?

Hallo,
kann man in einer Header Datei auch Anweisungen direkt angeben, die 
dann, mit dem Abarbeiten der Header Datei, automatisch mit ausgeführt 
werden?
Ich will halt keinen zusätzlichen Funktionsaufruf der mir das 
Portregister auf Ausgang stellt. Und die main.c zumüllen wollte ich 
eigendlich auch nicht. Ziel ist halt, einfach Test.h includieren in 
main.c und *plopp fertig zum gebrauch, mit allen Port und Pin 
Definitionen...

Test.h
#define LED_1  PD3
#define PORT_LED_1  PORTD
#define DDR_LED_1  DDRD
.
.
/*hier fehlt was*/ DDR_LED_1 = (1<<LED_1)  ; LED1 wird Ausgang
/*hier fehlt was*/ PORT_LED_1 = (1<<LED_1); LED aus (neg. Logik)

Gruß
Ralf

von Karl H. (kbuchegg)


Lesenswert?

Du scheinst einem weit verbreitetem Irrtum zu erliegen, was den
Zweck und die Art der Verarbeitung einer Header-Datei angeht.

Da steckt nichts, aber auch gar nichts geheimnisvolles dahinter.
Der Präprozessor ersetzt die Zeile mit dem Include

#inlcude "blabla.h"

durch den Inhalt der Datei blabla.h und zwar bevor der eigentliche
Compiler den Quelltext zu Gesicht bekommt.
Das heist: Das ist ein reiner Editierschritt, so wie du ihn auch
händisch in deinem Editor mittels Cut&Paste machen könntest. Nur
macht es halt in diesem Fall der Präprozessor. Mehr steckt da
absolut nicht dahinter.

Wenn du wolltest, könntest du auch folgendes machen:

file1.h
*******

void foo()

file2.h
*******
{

file3.h
*******
  int i = 5;

file4.h
}

und eine zusammenfassende file.c:
                          ******

#include file1.h
#include file2.h
  int j = 7;
#include file3.h
#include file4.h


Nachdem sich der Präprozessor die Datei file.c vorgenommen
hat und alle includes durch den Inhalt der angegegeben Dateien
ersetzt hat, entsteht daraus (ohne die Kommentare, die sind
jetzt von mir)

void foo()     /* aus file1.h */
{              /* aus file2.h */
  int j = 7;   /* stand schon in file.c */
  int i = 5;   /* aus file3.h */
}              /* aus file4.h */

und erst dieses Ergebnis wird zum eigentlichen Compiler geschickt,
der es dann übersetzt.

Das heist aber auch im Umkehrschluss:
Überleg dir, wie du Funktionalität in einem *.c File
erledigen müsstest und gliedere dann diese Funktionalität
in eine eigene Datei aus.

> /*hier fehlt was*/ DDR_LED_1 = (1<<LED_1)  ; LED1 wird Ausgang
> /*hier fehlt was*/ PORT_LED_1 = (1<<LED_1); LED aus (neg. Logik)

Klar. Das wäre auch so kein gültiges C. Anweisungen stehen
(ausser bei Initialisierung) immer in Funktionen. Also wirst
du wohl eine Funktion dafür machen müssen. Das ist kein
Problem, denn du kannst dem Compiler den Hinweis geben, dass
du gerne möchtest, dass er die Funktionsaufrufe wegoptimiert
(Was er wahrscheinlich soweiso tun würde)

inline void SetLed1Ausgang()
{
  DDR_LED_1 = ( 1 << LED1 );
}

inline void SetLedAus()
{
  PORT_LED_1 = ( 1 << LED1 );
}

eine andere Möglichkeit (wenn du dich nicht auf den Optimierer
verlassen willst), ist die Verwendung von Makros (also der
Anweisung an den Präprozessor, eine Textersetzung im Quelltext
vorzunehmen):

#define LED1_AUSGANG    DDR_LED_1 = ( 1 << LED1 )
#define LED1_AUS        PORT_LED_1 = ( 1 << LED 1 )

und verwendest das ganze dann

int main()
{
   LED1_AUSGANG;
   LED1_AUS;
}

der Präprozessor ersetzt jeweils den Text LED1_AUSGANG bzw. LED1_AUS
durch den Text für den sie stehen, und heraus kommt:

int main()
{
  DDR_LED1 = ( 1 << LED1 );
  PORT_LED_1 = ( 1 << LED1 );
}

Damit aber nicht genug, für DDR_LED1, PORT_LED_1 bzw. LED1 gibt
es ja seinerseits Makros, so dass die Ersetzung jeweils weitergeht:

int main()
{
  DDRD = ( 1 << PD3 );
  PORTD = ( 1 << PD3 );
}

DDRD, PORTD und PD3 sind ihrerseits auch wieder Makros (die
über io.h eingebunden wurden) und die Ersetzung geht weiter.
Ich hab jetzt nicht im Kopf, wie die Zahlenwerte für DDRD
und PORTD lauten, PD3 wird durch eine ganz banale 3 ersetzt
Im Endeffekt vleibt dann aber sowas übrig:

int main()
{
  *(volatile unsigned char)0x23 = ( 1 << 3 );
  *(volatile unsigned char)0x24 = ( 1 << 4 );
}

und erst dieses wird jetzt, nachdem alle Textersetzungen durchgeführt
wurden, zum eigentlichen C-Compiler geschickt, der es übersetzt.

von Oliver (Gast)


Lesenswert?

Für gcc 3.x gibt es hier eine Anleitung, wie man code vor dem Start von 
main() ausführen knn:
http://www.roboternetz.de/wissen/index.php/Avr-gcc#Fr.C3.BChe_Codeausf.C3.BChrung_vor_main.28.29

Allerdings soll es ja viele Programme geben, die nur noch in ihrer 
debug-Version laufen, und keiner findet raus, warum. Solche (meiner 
Meinung nach unnötigen) Spielchen tragen dazu bei.

Oder du programmierst in c++. Dann brauchst du nur ein globales Objekt 
der Klasse "test" mit den Initialisierungsanweisungen im Konstruktor :-)

Oliver

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


Lesenswert?

> Ich will halt keinen zusätzlichen Funktionsaufruf der mir das
> Portregister auf Ausgang stellt.

C ist aber nun einmal funktionsorientiert, zumindest in seiner Syntax.
Das erste, was ein Controller daher in main() macht, ist die
Initialisierung seiner Hardware.  Wenn du dir technisch die paar
Takte für den Funktionsaufruf und die Rückkehr daraus sparen willst,
dann kannst du diese Funktion gern "static inline" deklarieren.  Dann
guck aber auch bitte nach, welche startup-time sich aus deinen Fuses
ergibt, oft genug liegt die im Bereich vieler Millisekunden (damit
der Quarzgenerator stabil werden kann), da stören die paar Takte für
die Funktion gar nicht.

von R. Q. (timebeast)


Lesenswert?

Vorweg, Danke für die Antworten...

@Karl heinz: ist schon erstaunlich, sämtliche einzel Informationen waren 
mir bekannt, aber sie mal alle auf einen Blick zu sehen rückt das ganze 
in ein für mich verständliches Licht, Danke...

@Oliver: Ich mag Vererbung nicht. Wie hab ich´s im Studium gelernt; Ein 
Mann ist ein Mensch, eine Frau ist eine Unterklasse von Mann, damit ist 
Frau aber noch lange kein Mensch,... oder so ähnlich ;-)

@Jörg: Nette Idee mit dem Einsparen von Zeit, aber das war nichtmal 
meine Absicht, ich wollte das Programm nur einfach einfacher machen. Um 
genau zu sein hab ich sogar eine kleine Verzögerungsschleife am Anfang, 
damit der Quarz Zeit zum einschwingen hat (falsche Kondensatoren >zu 
groß< am Quarz, aber für die ersten Versuche funktioniert es so)

Gruß und Danke

Ralf

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.