Forum: Mikrocontroller und Digitale Elektronik Problem mit selbstgemachter header datei


von Oliver D. (highspeed-oliver)


Angehängte Dateien:

Lesenswert?

Also, im Anhang mal das Programm.
Ich würde gerne hingehen und den ganzen krams, bis auf die 
Hauptfunktion, in eine .h datei auslagern.
Sowas habe ich bisher noch nie gemacht und mit einem einfachen billigen 
printf befehle, ausgelagert in einer Funktion, die wiederrum in einer .h 
datei steht, klappt das einwandfrei.


Mein Sourcecode läuft ebenfalls einwandfrei, allerdings lässt er sich 
nicht auslagern.

Ich habe einfach alles, bis auf Programm hauptteil in eine .h datei 
gepackt.
Natürlich oben schön include "displayinit.h".

Dann zeigt mir der Compiler aber in allen funktionsaufrufen beim 
compilieren das an: ERROR 104: MULTIPLE PUBLIC DEFINITIONS SYMBOL: 
delay(DISPLAYINIT)


Woran liegt es und wo mache ich da den fehler?

von Johannes M. (johnny-m)


Lesenswert?

Vielleicht wäre es sinnvoll, Deinen Header-Versuch auch mal zu posten. 
Ich vermute aber stark, dass Du da was falsch verstanden hast: In eine 
Header-Datei werden keine Funktionen an sich ausgelagert. Die 
Header-Datei enthält ausschließlich Variablen- und 
Funktions-(Prototypen) Deklarationen. Die eigentlichen Funktionen kommen 
in eine .c-Datei, die separat kompiliert wird. Und drauf achten, dass in 
der Header-Datei "extern"-Deklarationen verwendet werden.

von Johannes M. (johnny-m)


Lesenswert?

Beispiel anhand der Funktion timer_init:
Es gibt drei Dateien: "main.c", "functions.h" und "functions.c".

In "functions.c" steht
1
void timer_init(void)  
2
{
3
  // Timer 0 initialisieren
4
  TMOD = 0x01;          // 0000 0001B    Timer 0: Mode 1 (16-Bit Z�hler)
5
  TH0  =  0xAF;      //Ultra short couting time
6
  TL0  =  0xFF;    
7
8
  // Interruptsystem
9
  ET0  = 1;             // Timer 0, Interruptfreigabe
10
  EA   = 1;             // generelle Interruptfreigabe
11
}

In "functions.h" steht
1
extern void timer_init(void);

In main.c:
1
#include "functions.c"
2
//[...]
3
timer_init();
4
//[...]

main.c und functions.c werden dem Compiler bekanntgegeben (bei einer IDE 
dem Projekt hinzugefügt).

von I_ H. (i_h)


Lesenswert?

Das extern weg, das gehört da net hin. Ganz oben in die .h

#ifndef _FUNCTIONS_H
#define

und ganz unden

#endif

rein, sonst knallts wenn du das mehrfach einbindest.

von Oliver D. (highspeed-oliver)


Lesenswert?

Ah ok. Danke.


Also ist es zwingend erfoderlich eine weitere .C datei anzulegen, in die 
ich den C Code packe?!?

von Oliver D. (highspeed-oliver)


Lesenswert?

Alles klar. Habs gemacht. Die fehlaaas sind weg,

dafür aber MISSING MACRO NAME AFTER DEFINE in der .h datei.

von Oliver D. (highspeed-oliver)


Lesenswert?

So habe einfach mal functions dafür eingetippt und meine probleme 
BLEIBEN BESTEHEN!

von I_ H. (i_h)


Lesenswert?

sorry,

#ifndef _FUNCTIONS_H
#define _FUNCTIONS_H

sollte das werden. Kannst du mal die genaue Fehlermeldung schreiben?

von Oliver D. (highspeed-oliver)


Angehängte Dateien:

Lesenswert?

HAllo,

ich hab mal nen Screenshot gemacht.

von I_ H. (i_h)


Lesenswert?

Bei den letzten beiden Funktionen hast du keinen Rückgabetyp angegeben, 
sowas kann zu merkwürdigen Fehlermeldungen führen. Und zeig mal die 
beiden anderen Dateien, so wie das aussieht kommt das nicht (nur) von 
der functions.h.

von Oliver D. (highspeed-oliver)


Lesenswert?

Also wenn ich bei den letzten beiden ein void davor setze, erhalte ich 
nurnoch den fehler
Type error in second_byte redeclaration
und put_to_lcd redeclaration.

Der Fehler tritt dann also bei den beiden Funktionen auf.

von Oliver D. (highspeed-oliver)


Lesenswert?

Das ist die test.c

#include "functions.c"
#include <reg51.h>
#include "displayinit.h"
sfr leds=0x80; //Hier ist die led low activ verschaltet.
sbit  DB4=0xB0;// Die Bezeichnungen der Ports des Displays
sbit  DB5=0xB1;//1 zu 1 verkabel wie der Name, also DB5 an D5
sbit  DB6=0xB2;
sbit  DB7=0xB3;
sbit  RS=0xB4;
sbit   EN=0xB5;
sfr port_B0=0xB0;
void main (void)
{
char display_ausgabe[12];
int i=0,length=12;
timer_init(); //Zuerst timer initialisieren!
display_init(); //Display init ausführen!
clear_display();
strcpy(display_ausgabe, "Hello World!");//SPEICHERRAUBEND und schreibt 
müll in leere Zeichen bei length 20
do{
put_to_lcd(display_ausgabe[i]);
i++;
}
while (i<length);
while(1);
{
}
}

von Oliver D. (highspeed-oliver)


Lesenswert?

Das ist die functions.h

#ifndef _FUNCTIONS_H
#define _FUNCTIONS_H
void delay(unsigned int delay_multi);
 void enable_routine(void)  ;
 void turnoff_display(void);
 void turnon_display(void);
 void clear_display(void);
 void timer_init(void);
 void display_init (void);
 second_byte(char uebergabewert);
 put_to_lcd (char uebergabewert);
#endif

von I_ H. (i_h)


Lesenswert?

Aaalso:

> Das ist die test.c

#include "functions.c"

macht man üblicherweise nicht, geht aber. Normalerweise wird das beides 
getrennt kompiliert (.o) und dann erst zusammengelinkt. Geht aber auch 
so.

> Type error in second_byte redeclaration
und put_to_lcd redeclaration.

Guck mal in die functions.c welchen Rückgabetyp du den beiden funktionen 
dort gegeben hast. Der muss mit dem in der functions.h übereinstimmen.

von Oliver D. (highspeed-oliver)


Lesenswert?

Ja die haben selbstverständlich keinen rückgabewert.
Habe ja auch return 0; reingegeschrieben.


Das Problem bleibt also bestehen.

von I_ H. (i_h)


Lesenswert?

Also mal langsam, kein Rückgabewert bedeutet "void" (das ist dann der 
Rückgabetyp) und dann schreibst du in den Code "return;" ohne irgend'nen 
Wert. Funktionen ohne Angabe vom Rückgabetyp gibt es nämlich nicht, das 
läuft dann zwangsläufig auf einen Fehler hinaus.
Und "return 0;" könnte alles mögliche sein. Poste doch mal die 
functions.c, die fehlt.

Vielleicht solltest du dich erstmal ein bisschen mit C beschäftigen, das 
gehört schon zu den grundlegendsten Grundlagen.

von Rooney B. (rooney)


Lesenswert?

displayInit.h != displayinit.h
Also probiers mal mit gleicher Schreibweise... Der findet vielleicht 
nicht mal die Datei.

Wenn du keinen Rückgabewert hast, muss die Funktion als void deklariert 
werden, jeder anständige Compiler würde da meckern.

von Johannes M. (johnny-m)


Lesenswert?

I_ H. wrote:
> Das extern weg, das gehört da net hin.
Stimmt natürlich, bei Funktionsprototypen ist es überflüssig (schadet 
aber auch nicht)...

Hab grad gesehen, dass der gute Karl Heinz einen Wiki-Artikel zu dem 
Thema verfasst hat: 
http://www.mikrocontroller.net/articles/Funktionen_auslagern_%28C%29

von Oliver D. (highspeed-oliver)


Lesenswert?

Ich habe mir den wiki artikel durchgelesen und danach gearbeitet.

In meinem C buch steht übrigens garnichts zu header datein!

von Karl H. (kbuchegg)


Lesenswert?

I_ H. wrote:
> Also mal langsam, kein Rückgabewert bedeutet "void" (das ist dann der
> Rückgabetyp)

Fast.
Kein angegebener Rückgabetyp bedeutet 'int'

@Oliver
Es ist aber trotzdem besser, man nutzt dieses 'Feature' nicht aus,
sondern gewöhnt sich gleich guten Stil an:

Wenn eine Funktion einen int retourniert, dann lautet das

int foo()
{
   return 0;
}

Wenn eine Funktion keinen Rückgabewert hat, dann lautet das

void foo()
{
  // eventuell ein mglw. vorzeitiger return;
}


Lass den Compiler sowenig Annahmen wie möglich treffen.

von Karl H. (kbuchegg)


Lesenswert?

Oliver D. wrote:
> Ich habe mir den wiki artikel durchgelesen und danach gearbeitet.

Der Artikel ist nicht besonders gut, weil er eigentlic aus
einer Anfrage, bei der es um 'extern' gegangen ist stammt.

Hat es denn trotzdem funktioniert?

>
> In meinem C buch steht übrigens garnichts zu header datein!

In deinem C-Buch stehen wahrscheinlich noch viele anderen
Praxistips zu C nicht drinnen :-)

Ich versuch mal eine Wette:
Ich wette, dass in deinem Buch eine Fahrenheit / Celsius umrechnung
drinnen ist und in dieser Umrechnung der Datentyp float vorkommt,
während double da drinn überhaupt nicht vorkommt. Generell
kann man sagen, dass im Buch als Standard-Gleitkommatyp meistens
float verwendet wird.

(Die Chancen für ein gewinnen der Wette stehen bei ca. 60%)

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.