Forum: Mikrocontroller und Digitale Elektronik #define und #include Problem


You were forwarded to this site from EmbDev.net. Back to EmbDev.net
von Sef C. (sefco)


Lesenswert?

Hey,

ich würde gerne mit einem Atmega328P per UART mit einem USB-TTL Adapter 
kommunizieren. Hierbei stocke ich etwas bei folgendem Problem:

Ich möchte gerne in der main.c meine CPU Frequenz und Baudrate mit
1
#define F_CPU 8000000UL
2
#define UART_BAUD_RATE 19200
definieren. Danach folgt u.a.
1
#include <util/delay.h>
2
#include "uart.h"

In der uart.h wird das Baudregister entsprechend Datenblatt mit
1
#define MYUBRR F_CPU/16/UART_BAUD_RATE-1
berechnet.

Beim Kompilieren tritt ein Fehler auf, weil die uart.h weder F_CPU noch 
UART_BAUD_RATE kennt. Offenbar stört sich die ebenfalls inkludierte 
delay.h daran nicht, weil eine in der main.c blinkende LED problemlos 
mit der korrekten Verzögerung blinkt.
Wieso ist der delay.h meine defines bekannt, der uart.h aber nicht?

Danke schön!

von mitlesa (Gast)


Lesenswert?

Mit welcher Entwicklungsumgebung arbeitest du?

von einfach anschauen (Gast)


Lesenswert?

1
gcc -E filename.c

Und dann siehst du alle Preprocessorersetzungen.

Sef C. schrieb:
> #define MYUBRR F_CPU/16/UART_BAUD_RATE-1

Die Makros sollte man klammern.

von Stefan F. (Gast)


Lesenswert?

Deswegen stellt an solche Defines, die Datei-Übergreifend bekannt sein 
sollen, besser im Makefile oder Projekt als Kommandozeilen-Option für 
den Compiler ein. Dann spielt es keine Rolle, in welcher Beziehung die 
Dateien zueinander stehen und in welcher Reihenfolge der Compiler sie 
lädt.

gcc -D F_CPU=8000000 -DBAUD=38400

Die Werte für die Baudraten-Register berechnet man besser nicht selbst, 
sondern überlässt es den bewährten Algorithmen in der C Bibliothek 
setbaud.h.
1
#include <util/setbaud.h>
2
3
void init_serial()
4
{
5
    UBRRH = UBRRH_VALUE;
6
    UBRRL = UBRRL_VALUE;
7
    #if USE_2X
8
        UCSRA |= (1 << U2X);
9
    #else
10
        UCSRA &= ~(1 << U2X);
11
    #endif
12
}

von Sef C. (sefco)


Lesenswert?

mitlesa schrieb:
> Mit welcher Entwicklungsumgebung arbeitest du?

Microchip Studio.

Stefan ⛄ F. schrieb:
> gcc -D F_CPU=8000000 -DBAUD=38400

Wo soll ich das denn eingeben/definieren?

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Sef C. schrieb:
>> gcc -D F_CPU=8000000 -DBAUD=38400
> Wo soll ich das denn eingeben/definieren?

Ich bin mit deiner IDE nicht vertraut. Irgendwo wird es ein 
Dialogfenster geben, wo man die Parameter zum Compiler eingeben kann. 
Eventuell sogar grafisch aufbereitet unter dem Stichwort "Preprocessor" 
oder "Definitions".

Bei meiner IDE sieht das so aus, wie im Anhang gezeigt.

von Sef C. (sefco)


Lesenswert?

Stefan ⛄ F. schrieb:
> Sef C. schrieb:
>>> gcc -D F_CPU=8000000 -DBAUD=38400
>> Wo soll ich das denn eingeben/definieren?
>
> Ich bin mit deiner IDE nicht vertraut. Irgendwo wird es ein
> Dialogfenster geben, wo man die Parameter zum Compiler eingeben kann.
> Eventuell sogar grafisch aufbereitet unter dem Stichwort "Preprocessor"
> oder "Definitions".
>
> Bei meiner IDE sieht das so aus, wie im Anhang gezeigt.

Eine Möglichkeit das im Quellcode zu machen gibt es nicht sinnvoll? Ich 
wechsele ständig den uC und die Taktfrequenz :(

Danke dir für den Tipp mit setbaud.h, habe ich direkt so in meine uart.h 
integriert :)

von W.S. (Gast)


Lesenswert?

Sef C. schrieb:
> Ich möchte gerne in der main.c meine CPU Frequenz und Baudrate
> ...
> definieren.

Nö, lieber nicht. Sowas sollte man im zugehörigen Lowlevel-Treiber für 
den UART erledigen und nicht in main.c tun müssen.

Aber das klärt noch nicht dein momentanes Problem. Das besteht wohl 
darin, daß dein uart.c die zwei Zeilen mit F_CPU und UART_BAUD_RATE 
nicht kennt. Nun rate mal, woran das liegen mag, wenn du das lediglich 
in main.c geschrieben hast.

W.S.

von mitlesa (Gast)


Angehängte Dateien:

Lesenswert?

Sef C. schrieb:
> Eine Möglichkeit das im Quellcode zu machen gibt es nicht sinnvoll? Ich
> wechsele ständig den uC und die Taktfrequenz

Dann musst du das in den Project Settings sowieso machen.
Hier sind die richtigen Orte für Einstellungen.

von mitlesa (Gast)


Lesenswert?

Sef C. schrieb:
> Ich wechsele ständig den uC und die Taktfrequenz

Dazu legt man sich praktischerweise mehrere Projekte im
gleichen Arbeitsverzeichnis an und benutzt immer die gleichen
Sources. Das erzeugt im Studio keinen Widerspruch. So
"schaltet" man mit dem einfachen Laden eines anderen Projekts
schnell auf eine andere Konfiguration um ohne sein gedankliches
Sourcen-Gefüge ändern zu müssen.

Neues Anlegen eines Projekts ist nur einmal nötig, die
(veränderten) Projekteinstellungen erzeugt man indem man eine
Kopie der Projektdatei (*.cproj) erzeugt und diese Kopie dann
geeignet einstellt.

von Sef C. (sefco)


Lesenswert?

W.S. schrieb:
> Aber das klärt noch nicht dein momentanes Problem. Das besteht wohl
> darin, daß dein uart.c die zwei Zeilen mit F_CPU und UART_BAUD_RATE
> nicht kennt. Nun rate mal, woran das liegen mag, wenn du das lediglich
> in main.c geschrieben hast.

Und wieso kennt die delay.h die korrekte F_CPU (8 MHz)?
Das merke ich daran das eine LED in der main.c mit _delay_ms(1000) 
korrekt blinkt sowie der folgende Code keine Warning wirft:
1
#ifndef F_CPU
2
/* prevent compiler error by supplying a default */
3
# warning "F_CPU not defined for <util/delay.h>"
4
/** \ingroup util_delay
5
    \def F_CPU
6
    \brief CPU frequency in Hz
7
8
    The macro F_CPU specifies the CPU frequency to be considered by
9
    the delay macros.  This macro is normally supplied by the
10
    environment (e.g. from within a project header, or the project's
11
    Makefile).  The value 1 MHz here is only provided as a "vanilla"
12
    fallback if no such user-provided definition could be found.
13
14
    In terms of the delay functions, the CPU frequency can be given as
15
    a floating-point constant (e.g. 3.6864E6 for 3.6864 MHz).
16
    However, the macros in <util/setbaud.h> require it to be an
17
    integer value.
18
 */
19
# define F_CPU 1000000UL
20
#endif

von Wolfgang (Gast)


Lesenswert?

W.S. schrieb:
> Sef C. schrieb:
>> Ich möchte gerne in der main.c meine CPU Frequenz und Baudrate
>> ...
>> definieren.
>
> Nö, lieber nicht. Sowas sollte man im zugehörigen Lowlevel-Treiber für
> den UART erledigen und nicht in main.c tun müssen.

Du willst nicht wirklich in allen verwendeten Lowlevel-Treibern 
rumfummeln, nur weil du einen anderen Quarz in den Taktgenerator des µC 
gesteckt hast.

von mitlesa (Gast)


Lesenswert?

Wolfgang schrieb:
> Du willst nicht wirklich in allen verwendeten Lowlevel-Treibern
> rumfummeln, nur weil du einen anderen Quarz in den Taktgenerator des µC
> gesteckt hast.

Doch, Betonköpfe, die sich das einmal so eingerichtet haben,
wollen das so. Da hilft auch nichts mehr zu beschreiben wie
man es wirklich richtig macht.

von Stefan F. (Gast)


Lesenswert?

Sef C. schrieb:
> Eine Möglichkeit das im Quellcode zu machen gibt es nicht sinnvoll? Ich
> wechsele ständig den uC und die Taktfrequenz :(

Gerade dann solltest du besser Makefiles benutzen, damit du an einer 
zentralen Stelle alle relevanten Parameter konfigurieren kannst. So löst 
du dich auch von der Abhängigkeit zu einer bestimmten IDE.

Jede anständige IDE kann Makefile-Projekte öffnen.

Wo ich arbeite, steht jedem Entwickler frei, irgendeine IDE (oder gar 
keine) zu benutzen. Jeder soll verwenden, womit er am besten klar kommt. 
Aber jedes Projekt muss ein Makefile (oder etwas äquivalentes) haben, so 
dass es unabhängig von jeder IDE compiliert werden kann. Wir haben auch 
eine gewisse Unabhängigkeit vom Desktop Betriebssystem etabliert. Die 
Entwickler dürfen Linux, Windows oder Mac OS benutzen.

Ich müsste lügen wenn ich sagen würde dass das völlig ohne Probleme 
klappen würde. Aber diese waren bisher alle gut lösbar und die Vorteile 
überwiegen.

von Sef C. (sefco)


Lesenswert?

Das ist ein völlig unnötiger, beleidigender Kommentar der die hier 
gestellten Fragen nicht beantwortet:

mitlesa schrieb:
> Doch, Betonköpfe, die sich das einmal so eingerichtet haben,
> wollen das so. Da hilft auch nichts mehr zu beschreiben wie
> man es wirklich richtig macht.

Das ist ein sinnvoller, freundlicher und erklärender Kommentar der die 
hier gestellten Fragen sachlich beantwortet, sodass es auch anderen die 
über das selbe Problem stolpern weiter hilft:

Stefan ⛄ F. schrieb:
> Gerade dann solltest du besser Makefiles benutzen, damit du an einer
> zentralen Stelle alle relevanten Parameter konfigurieren kannst. So löst
> du dich auch von der Abhängigkeit zu einer bestimmten IDE.
>
> Jede anständige IDE kann Makefile-Projekte öffnen.
>
> Wo ich arbeite, steht jedem Entwickler frei, irgendeine IDE (oder gar
> keine) zu benutzen. Jeder soll verwenden, womit er am besten klar kommt.
> Aber jedes Projekt muss ein Makefile (oder etwas äquivalentes) haben, so
> dass es unabhängig von jeder IDE compiliert werden kann. Wir haben auch
> eine gewisse Unabhängigkeit vom Desktop Betriebssystem etabliert. Die
> Entwickler dürfen Linux, Windows oder Mac OS benutzen.
>
> Ich müsste lügen wenn ich sagen würde dass das völlig ohne Probleme
> klappen würde. Aber diese waren bisher alle gut lösbar und die Vorteile
> überwiegen.

Danke dir, tolle Erklärung die ich Betonkopf jetzt in Zukunft so 
umsetzen werden.

von STK500-Besitzer (Gast)


Lesenswert?

Nur so am Rande:
Defines sollte man in Header-Files schreiben, damit sie auch für andere 
Programmteile "global" verfügbar sind (, weil nur diese 
Quellcode-Dateien inkludiert werden sollten).
Schreibt man sie in die .c-Datei, ist das wie mit lokalen Dateien: Sie 
sind nur innerhalb der Datei verfügbar (kollidieren aber mit 
gleichnamigen Defines, die von "außerhalb" kommen.)

von W.S. (Gast)


Lesenswert?

mitlesa schrieb:
> Dann musst du das in den Project Settings sowieso machen.
> Hier sind die richtigen Orte für Einstellungen.

Sef C. schrieb:
> Und wieso kennt die delay.h die korrekte F_CPU (8 MHz)?

Sef C. schrieb:
> Eine Möglichkeit das im Quellcode zu machen gibt es nicht sinnvoll? Ich
> wechsele ständig den uC und die Taktfrequenz :(

Hmm... zuviele Mißverständnisse auf einem Haufen.
Also:
1. wenn man ständig den µC-Typ wechselt, dann darf man auch damit 
rechnen, daß unterschiedliche Hersteller/Produktreihen auch diverse 
Unterschiede in den Peripherie-Cores haben. Also ist einem mit nur einem 
UART-Treiber nicht wirklich gedient, da müssen an die jeweilige Hardware 
angepaßte Lowlevel-Treiber her. Das einzige, was für alle gleich sein 
sollte, ist der Inhalt der zugehörigen uart.h, damit all die höheren 
Programmschichten sich nicht um die jeweiligen Befindlichkeiten der 
Peripherie kümmern müssen. Das schließt auch die Berechnung von 
Teilerverhältnissen in main.c aus. Diese Berechnung gehört in den 
Lowlevel-Treiber. Allerdings ist es sinnvoll, die UART-Initialisierung 
mit der gewünschten Baudrate als Argument aufzurufen.
Beispiel:
[c]
 Uart0_init(9600);
{/c]
Und zur Frage, wo die betreffende uart0.c die Information über die 
aktuelle Taktfrequenz herkriegt: Diese Information sollte von dem 
Treiber kommen, der das Taktsystem aufsetzt. Das ist wiederum nicht 
main.c, sondern eine separate Quelle, die chipabhängig ist und deshalb 
bei Chipwechsel ebenfalls neu zu schreiben wäre. Und: mal bedenken, daß 
es durchaus sein kann, daß UART0 an einem anderen Peripherie-Bus sitzt 
als UART1, und die diversen Peripherie-Busse auch verschiedene Taktraten 
haben können.

2. Eine Header-Datei (xxx.h) soll nur zum Bekanntgeben von Dingen 
herhalten, die in der zugehörigen xxx.c vorhanden sind. So eine 
Headerdatei enthält zumeist selber keinen Code, sondern wird nur wie 
ein gewöhnliches Textstück in die inkludierende Datei aufgenommen. Eine 
Datei 'delay.h' kennt also keinerlei Taktfrequenz. Das ist Angelegenheit 
der Datei, wo die Inklude-Anweisung steht.

3. Irgendwelche programmrelevanten Einstellungen in der Projektdatei 
irgendeiner IDE oder in einem Makefile zu machen, ist eine drastische 
Einschränkung, denn dann kann das betreffende Projekt NUR mit genau 
dieser IDE bzw. diesem Make überhaupt übersetzt werden.

Also:
Alles, was für die zu erzeugende Firmware nötig ist, gehört auch in die 
Quelldateien dieser Firmware und nicht irgendwo anders hin. Wenn man das 
nicht genau so beachtet und es anders hält, dann nagelt man sich selbst 
auf eine bestimmte IDE bzw. Make fest.

W.S.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> 3. Irgendwelche programmrelevanten Einstellungen in der Projektdatei
> irgendeiner IDE oder in einem Makefile zu machen, ist eine drastische
> Einschränkung, denn dann kann das betreffende Projekt NUR mit genau
> dieser IDE bzw. diesem Make überhaupt übersetzt werden.

Was die IDE angeht stimme ich dir zu. Aber Makefiles sind seit Anbeginn 
der Programmiersprache bis heute Standard.

Was meinst du mit "NUR mit genau diesem Make"?

Wer ganz sicher gehen will, alte Quelltexte auch in Zukunft übersetzen 
zu können, sollte alle am Build beteiligten Programme samt 
Betriebssystem gut aufbewahren. make ist da allerdings meine geringste 
sorge. Ich musste noch nie ein Makefile an eine andere Version von Make 
anpassen.

von W.S. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Was meinst du mit "NUR mit genau diesem Make"?

Versuche mal, auf einem Windows PC, wo diverse Toolchains drauf sind, 
irgend etwas per Make zu machen. Das wird nix, weil es da diverse 
verschiedene make.exe gibt, die jeweils NUR ihr toolchainspezifisches 
Zeugs kennen und man folglich ein babylonisches Sprachproblem auf dem PC 
hat.

W.S.

von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
> Versuche mal, auf einem Windows PC, wo diverse Toolchains drauf sind,
> irgend etwas per Make zu machen. Das wird nix, weil es da diverse
> verschiedene make.exe gibt, die jeweils NUR ihr toolchainspezifisches
> Zeugs kennen und man folglich ein babylonisches Sprachproblem auf dem PC
> hat.

Hm. Wenn sich das Programm „make.exe“ nennt, dann ist die dortige 
Versionsvielfalt dann doch sehr überschaubar. Und vor allem lässt sich 
das in den meisten Fällen auf eine einzige Version vereinfachen.

Spielt aber alles keine Rolle, ein makefile ist natürlich Teil des 
Quelltextes, und gehört mit in die Versionsverwaltung, und später 
archiviert.

Oliver

: Bearbeitet durch User
von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

W.S. schrieb:
> Das wird nix, weil es da diverse
> verschiedene make.exe gibt, die jeweils NUR ihr toolchainspezifisches
> Zeugs kennen und man folglich ein babylonisches Sprachproblem auf dem PC
> hat.

Mal wieder keine Ahnung, aber sinnlos rumkrakelen?
Mit der selben make.exe kann ich makefiles für x64, AVR, ARM und MIPS 
durchnudeln. (Was ich eben so nutze, es kann eben alles was im makefile 
steht)
Man merkt, dass du echt von NICHTS auch nur die geringste Ahnung hast!

Alles außer deinem heißgeliebten Keil is zu hoch für dich ;)

von Klaus W. (mfgkw)


Lesenswert?

Tröste dich: hier hat genau genommen keiner Ahnung, weil niemand die 
Quelltexte kennt.
Da kann man nur wilrd spekulieren.

Kann es sein, daß die uart.h direkt oder indirekt schon vor dem #define 
mal verwendet wird?

Ansonsten halt mal die Quelltexte zeigen, sonst kann man nichts sagen 
(was viele aber nicht abhält).

von W.S. (Gast)


Lesenswert?

Klaus W. schrieb:
> Kann es sein, daß die uart.h direkt oder indirekt schon vor dem #define
> mal verwendet wird?

Spielt keine Rolle. Was in main.c definiert wurde, ist in uart.c 
höchstwahrscheinlich nicht bekannt. Deshalb geht blinky aber das 
Projekt mit uart.c geht nicht. Und der TO wundert sich darüber: "Und 
wieso kennt die delay.h die korrekte F_CPU (8 MHz)?"

W.S.

von W.S. (Gast)


Lesenswert?

Oliver S. schrieb:
> Hm. Wenn sich das Programm „make.exe“ nennt,...

Stell dir vor, du hast 3 oder mehr Dateien auf der Platte, die sich alle 
make.exe nennen, aber zu herzlich unterschiedlichen Programmiersystemen 
gehören. Selbst hier auf diesem Notebook findet sich ein make.exe, was 
aber zu Lazarus gehört und mit C rein garnix zu tun hat.

Also, wer sich wirklich niemals aus dem C-Gefilde heraus begibt und 
womöglich nur den GCC benutzt, der kommt nicht in die Verlegenheit, das 
verkehrte make zu benutzen, so daß er das Problem nicht kennt.

Das kann man aber nicht immer als gegeben annehmen. Deshalb sage ich: 
IDE-Projektdateien und Makefiles (also Make-Projektdateien) sind nicht 
die geeeigneten Orte, wo firmwarespezifisches Zeugs definiert werden 
soll. Diese Dateien sollen lediglich zum Übersetzen der zum Projekt 
gehörigen Dateien dienen, aber nicht (wie vorgeschlagen wurde) 
Festlegungen enthalten, ob der UART nun auf 9600 Baud oder einer anderen 
Rate laufen soll.

W.S.

von Stefan F. (Gast)


Lesenswert?

Ich denke es macht keinen Sinn mit W.S. über Programmierstil zu 
diskutieren. Der hat seinen eigenen Stil und kommt mit anderen Meinungen 
nicht klar. Selbst wo es technisch notwendig ist lästert er lieber über 
betroffene Produkte ab, anstatt die harten Fakten hin zu nehmen. Das 
hatten wir hier schon oft genug.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich denke es macht keinen Sinn mit W.S. über Programmierstil zu
> diskutieren.

Nicht nur beim Programmierstil ist das so.
Es fehlt auch immerwieder an Grundlagenwissen.
Haste ja eben gelesen, er lästert über make ab und aus seinem Geschwafel 
wird schnell klar, dass er absolut keine Ahnung vom Thema hat.

von Peter D. (peda)


Lesenswert?

Sef C. schrieb:
> weil die uart.h weder F_CPU noch
> UART_BAUD_RATE kennt

Muß sie auch nicht. Erst an der Stelle, wo das Macro expandiert wird, 
müssen alle verwendeten Defines bekannt sein.

von Sef C. (sefco)


Lesenswert?

W.S. schrieb:
> Aber das klärt noch nicht dein momentanes Problem. Das besteht wohl
> darin, daß dein uart.c die zwei Zeilen mit F_CPU und UART_BAUD_RATE
> nicht kennt. Nun rate mal, woran das liegen mag, wenn du das lediglich
> in main.c geschrieben hast.

W.S. schrieb:
> Spielt keine Rolle. Was in main.c definiert wurde, ist in uart.c
> höchstwahrscheinlich nicht bekannt. Deshalb geht blinky aber das
> Projekt mit uart.c geht nicht. Und der TO wundert sich darüber: "Und
> wieso kennt die delay.h die korrekte F_CPU (8 MHz)?"
>
> W.S.

Mir kommt es so vor, als würdest du einfach nicht verstehen was ich hier 
beschreibe.

Hier meine main.c:
1
#define F_CPU 8000000UL 
2
3
#define DDR_STATUS_LED DDRB
4
#define PORT_STATUS_LED PORTB
5
#define PIN_STATUS_LED 5
6
#define STATUS_LED_ON PORT_STATUS_LED |= (1<<PIN_STATUS_LED)
7
#define STATUS_LED_OFF PORT_STATUS_LED &= ~(1<<PIN_STATUS_LED)
8
#define STATUS_LED_TOGGLE PORT_STATUS_LED ^= (1<<PIN_STATUS_LED);
9
10
#include <avr/io.h>
11
#include <util/delay.h>
12
#include <avr/interrupt.h>
13
#include "uart.h"
14
#include "stdlib.h"
15
16
void init_gpio()
17
{
18
  // Init Status LED
19
  STATUS_LED_OFF;
20
  DDR_STATUS_LED |= (1<<PIN_STATUS_LED);  
21
}
22
23
void heartbeat()
24
{
25
  STATUS_LED_ON;
26
  _delay_ms(100);
27
  STATUS_LED_OFF;
28
  _delay_ms(100);
29
  STATUS_LED_ON;
30
  _delay_ms(100);
31
  STATUS_LED_OFF;
32
  _delay_ms(100);
33
}
34
35
int main(void)
36
{
37
  init_gpio();
38
39
  uart_init();
40
    
41
    while (1) 
42
    {
43
    uart_send_text("\r\n______________________________________\r\n");
44
    uart_send_text("ATMEGA328P ready.");
45
    uart_send_text("\r\n");
46
    
47
    _delay_ms(2000);
48
    heartbeat();
49
    }
50
}


Ich definiere vor den #includes die CPU Frequenz. Dieses #define ist der 
delay.h beim kompilieren bekannt. Das merkt man daran, dass sich die 
delay.h nicht mit der Warning "F_CPU not defined" beschwert und meine 
STATUS_LED korrekt blinkt.
Die uart.h beschwert sich aber darüber, dass sie F_CPU nicht kennt wenn 
ich es nicht zusätzlich dort reinschreiben.
Meine Frage ist einzig und alleine: Ein #define und darunter zwei 
inkludierte Files. Die eine inkludierte Datei kennt das #definde, die 
andere nicht. Wieso?

: Bearbeitet durch User
von Dyson (Gast)


Lesenswert?

Sef C. schrieb:
> Wieso?

Weil es deine uart.h einen Scheiss interessiert,was du irgendwo 
definiert hast. Die einzigen, die das interessiert, sind die Funktionen 
in uart.c. Die werden aber von der Information verschont, da die defines 
dafür in der uart.h drinstehen müssen und nicht irgendwo davor. Es sei 
denn, die Informationen stehen in den Projekteinstellungen. Das wurde 
hier aber auch schon mehrfach erwähnt.

von Sef C. (sefco)


Lesenswert?

Dyson schrieb:
> Weil es deine uart.h einen Scheiss interessiert,was du irgendwo
> definiert hast. Die einzigen, die das interessiert, sind die Funktionen
> in uart.c. Die werden aber von der Information verschont, da die defines
> dafür in der uart.h drinstehen müssen und nicht irgendwo davor. Es sei
> denn, die Informationen stehen in den Projekteinstellungen. Das wurde
> hier aber auch schon mehrfach erwähnt.

...und der Nächste der nicht erklärt, wieso der delay.h die in der 
main.c definierte CPU Frequenz bekannt ist...

von Stefan F. (Gast)


Lesenswert?

Bei delay ist das anders, weil der Quelltext der Funktion ausnahmsweise 
in der header Datei steht.

https://github.com/vancegroup-mirrors/avr-libc/blob/master/avr-libc/include/util/delay.h.in

Zeile 142.

Wärend der Compiler diesen Code übersetzt ist F_CPU bekannt. Denn die 
Datei wird ausschließlich in main.c inkludiert nachdem dort F_CPU 
definiert wurde.

Bei der uart.h ist das anders. Die wird nicht nur von main.c inkludiert 
(wo es kein Problem gibt) sondern auch von uart.c. Wenn der Compiler die 
uart.c compiliert, ist F_CPU undefiniert.

Bedenke: Der Compiler wird für jede *.c Datei einzeln aufgerufen, um 
eine gleichnamige *.o Datei zu erzeugen. Die main.c wird als letzte 
compiliert. Erst danach kombiniert der Linker die vielen *.o Dateien zu 
einem ausführbaren Programm.

von Sef C. (sefco)


Lesenswert?

Stefan ⛄ F. schrieb:
> Bei delay ist das anders, weil der Quelltext der Funktion ausnahmsweise
> in der header Datei steht.
>
> 
https://github.com/vancegroup-mirrors/avr-libc/blob/master/avr-libc/include/util/delay.h.in
>
> Zeile 142.
>
> Wärend der Compiler diesen Code übersetzt ist F_CPU bekannt. Denn die
> Datei wird ausschließlich in main.c inkludiert nachdem dort F_CPU
> definiert wurde.
>
> Bei der uart.h ist das anders. Die wird nicht nur von main.c inkludiert
> (wo es kein Problem gibt) sondern auch von uart.c. Wenn der Compiler die
> uart.c compiliert, ist F_CPU undefiniert.


Genau diesen Unterschied habe ich auch bemerkt und deswegen den Code aus 
der uart.c in die uart.h kopiert (und in der .c gelöscht) und es klappte 
trotzdem nicht. Wenigstens hast du meine Frage verstanden :)

: Bearbeitet durch User
von Dyson (Gast)


Lesenswert?

Sef C. schrieb:
> ...und der Nächste der nicht erklärt, wieso der delay.h die in der
> main.c definierte CPU Frequenz bekannt ist...

weil der gesamte delay-Kram in der delay.h drinsteht. Für delay gibt es 
keine delay.c. Die delay-Funktion, genau genommen ein Makro, steht in 
der delay.h. Die Texte von Header-Dateien werden da, wo sie inkludiert, 
welch ein Wort, werden, praktisch komplett hingeschrieben und stehen 
somit im Kontext dieser Datei. Deshalb wirft das delay-Makro keinen 
Fehler oder eine Warnung. Die uart.c, die die Funktionen enthält, kann 
das aber nicht sehen. Die kann nur in die uart.h gucken, da steht es 
aber nicht drin, sondern davor. Capito?

von Klaus W. (mfgkw)


Lesenswert?

Gibt es nur die main.c?

Sag doch mal, welche Dateien es alle gibt und wie die aussehen bitte.

von Gerald M. (gerald_m17)


Lesenswert?

Keine Ahnung wie "sauber" das ist, im Geschäft machen wir das einfach 
so, dass wir für jedes Gerät eine "device.h" haben und beispielsweise 
auch eine "typedef.h" in der wir genau solche spezifischen Sachen wie 
Clock-Frequenz oder auch Typen (bei kleinen Controllern wird ein float 
als float32 definiert, wenn eine Double Precision Einheit drauf ist 
entsprechend als Double) definiert werden.
So kann man Bibliotheken über alle Familien hinweg nutzen.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Sef C. schrieb:
> ...und der Nächste der nicht erklärt, wieso...

Das wurde dir bereits mehrfach erklärt. Der Fehler liegt also bei dir 
selber, der du nicht hast zuhören wollen.
Also:
Das in die Maschinensprache zu übersetzende Zeugs (Code,Konstanten usw.) 
wird normalerweise in Dateien geschrieben, die hier auf .c enden. Das 
mit der Endung ist bei anderen Programmiersprachen anders. Der Zweck von 
Dateien, die auf .h enden, ist üblicherweise, daß man dort all das Zeug 
hineinschreibt, was andere Quellen über die auf .c endende zugehörige 
Datei wissen müssen. Das wären mal ganz grob: Funktionsköpfe, 
Typdefinitionen und Verweise auf Variablen und Konstanten. Man muß dabei 
als Attribut das Wort 'extern' vor Variablen und Konstanten schreiben, 
bei Funktionsköpfen braucht man das nicht, aber man kann das. Ich wäre 
für ein generelles 'extern' in Headerdateien, dem menschlichen Verstehen 
zuliebe.

Hier ein paar Beispiele:

in der Datei emil.c
1
 int ottokar;
2
 char charlotte(void)
3
 { ...
4
 }

und in der zugehörigen Datei emil.h
1
 extern int ottokar;
2
 char charlotte(void);

Ich hoffe, daß dir das nun klar geworden ist und du selber merkst, was 
du bislang verkehrt gedacht hast.

W.S.

von Stefan F. (Gast)


Lesenswert?

Du hast mindestens zwei *.c Dateien in deinem Projekt, also wird der gcc 
mindestens zweimal aufgerufen.

> gcc -o main.o main.c
main.c definiert die benötigten Werte.
main.c inkludiert delay.h -> alles OK
main.c inkludiert uart.h  -> auch OK

> gcc -o uart.o uart.c
uart.c inkludiert uart.h  -> Werte fehlen

Ich hoffe jetzt macht es "Klick", sonst weiss ich nämlich auch nicht, 
wie man es sonst noch erklären kann.

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.