Forum: Compiler & IDEs Code auslagern mit #include und "globalem" #define


von Andreas P. (andreaspfau)


Lesenswert?

Hi Community,

mein erster Beitrag hier, nach langem googlen und suchen in diesem 
Forum. Ich bin am verzweifeln. Und ich weiß, dass bereits tausend 
ähnliche Fragen gestellt und beantworte wurdent, trotzdem hilft es mir 
nichts... :-(

Ich habe in AVRStudio+WinAVR ein wenig Code ausgelagert, welcher auf 
Konstanten zugreift, welche mit #define definiert wurden. Kurzer, 
zusammengefasster Abriss der Dateien:
1
// main.c
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include "Uart.h"
5
#define UART_Baud 9600
6
int main(void)
7
{
8
  UartInit();
9
}
10
11
// Uart.h
12
#ifndef _Uart_h_
13
#define _Uart_h_
14
void UartInit(void);
15
#endif
16
17
// Uart.c
18
#include <avr/io.h>
19
#include "Uart.h" 
20
void UartInit(void)
21
{
22
  UBRRH = (unsigned char)(((long)F_CPU / (16l * (long)UART_Baud) - 1l)>>8);
23
  UBRRL = (unsigned char)(((long)F_CPU / (16l * (long)UART_Baud) - 1l));
24
}

Beim compilieren des Projekts kommt nunt "error: 'UART_Baud' 
undeclared". Uart.C wurde natürlich schon in die Liste "Source Files" 
mitaufgenommen, klar. F_CPU sowie der AVR-Typ werden vom Projekt 
gesetzt.

Ich hoffe ihr versteht mein Problem: ich will eine allgemein gültige 
Uart.c schreiben, die ich aber in der übergeordneten Datei main.c über 
ein #define konfigurieren kann.

Alternativ könnte ich auch einen Parameter an UartInit übergeben, laufe 
aber in Gefahr, dass das die Artihmetik dahinter (also das "((long)F_CPU 
/ (16l * (long)UART_Baud) - 1l)>>8") in Assembler übersetzt wirdt, 
anstatt es wie beim #define vom Compiler ausgewertet wird. Außerdem 
erlaubt das #define die Ausgabe von Warnungen mittels #warning bei 
ungeeigneten Werten von UART_Baud (noch nicht implementiert).

Oder, anders formuliert: wie würdet ihr vorgehen???

von Stefan E. (sternst)


Lesenswert?

Andreas Pfau wrote:

> Ich hoffe ihr versteht mein Problem: ich will eine allgemein gültige
> Uart.c schreiben, die ich aber in der übergeordneten Datei main.c über
> ein #define konfigurieren kann.

Du musst dir bei solchen Sachen immer eines klar machen: der Compiler 
übersetzt jede C-Datei für sich alleine, unabhängig von den anderen 
C-Dateien. Wenn in main.c ein #define steht, dann ist das auch nur dort 
verfügbar.

> Alternativ könnte ich auch einen Parameter an UartInit übergeben, laufe
> aber in Gefahr, dass das die Artihmetik dahinter (also das "((long)F_CPU
> / (16l * (long)UART_Baud) - 1l)>>8") in Assembler übersetzt wirdt,
> anstatt es wie beim #define vom Compiler ausgewertet wird. Außerdem
> erlaubt das #define die Ausgabe von Warnungen mittels #warning bei
> ungeeigneten Werten von UART_Baud (noch nicht implementiert).
>
> Oder, anders formuliert: wie würdet ihr vorgehen???

Du übergibst den fertig berechneten UBR-Wert per Parameter und packst 
ein Makro zum berechnen in Uart.h. In main.c steht dann sowas:
1
#include "Uart.h"
2
#define UART_Baud 9600
3
...
4
UartInit(CALC_UBR(UART_Baud));

von main.h (Gast)


Lesenswert?

Oder du erstellst eine main.h und schreibst das
1
#define UART_Baud 9600
dort hinein. In der uart.c schreibst du dann
1
#include "main.h"

von Andreas P. (andreaspfau)


Lesenswert?

Hi,

>Du musst dir bei solchen Sachen immer eines klar machen: der Compiler
>übersetzt jede C-Datei für sich alleine, unabhängig von den anderen
>C-Dateien. Wenn in main.c ein #define steht, dann ist das auch nur dort
>verfügbar.

Ja, das war mir bewusst, aber ich hatte gehofft dass die #define-Werte 
irgendwie global mitgeschleift werden könnten...

>Du übergibst den fertig berechneten UBR-Wert per Parameter und packst
>ein Makro zum berechnen in Uart.h.

Das ist auch ne gute Idee! Ist zwar vom Aussehen her etwas holperig, 
aber so kann ich auf der Präprozessor-Ebene bleiben. Danke!

von Andreas P. (andreaspfau)


Lesenswert?

Hi @main.h

das würde auch funktionieren, aber dann wäre meine Unit ja nicht mehr 
universell einsetzbar, weil sie das Vorhandensein eine bestimmten 
Dateinamnes ("main.h") voraussetzt... OK, meine ursprüngliche Idee setzt 
das Vorhandensein eines bestimmten #include voraus ^^

von mork (Gast)


Lesenswert?

Du könntest das #define UART_Baud 9600 auch in die uart.h schreiben, die 
ja sowieso vorhanden sein muss ...

von Andreas P. (andreaspfau)


Lesenswert?

Hi @mork,

auf die Idee bin ich auch schon gekommen. Allerdings müsste man ja dann 
jedesmal die .h anpassen, das finde ich nicht allzu praktikabel...

von Wolfgang Mües (Gast)


Lesenswert?

Du schreibst in uart.h:

#define BAUD_9600 ((long)F_CPU / (16l * 9600) - 1l)
#define BAUD_19200 ((long)F_CPU / (16l * 19200) - 1l)

und so weiter....

in uart.c schreibst Du dann:

void UartInit(unsigned int baudrate)
{
  UBRRH = (unsigned char)(baudrate >>8);
  UBRRL = (unsigned char)(baudrate);
}

dann kannst Du in main schreiben:

UartInit(BAUD_9600);

Alles klar?

von Andreas P. (andreaspfau)


Lesenswert?

Alles klar! :-) Darauf bin ich auch noch nicht gekommen. Ist ne menge 
Fleißarbeit, aber ne sehr saubere Lösung wie ich finde!

von Falk B. (falk)


Lesenswert?

@ Wolfgang Mües (Gast)

>#define BAUD_9600 ((long)F_CPU / (16l * 9600) - 1l)
>#define BAUD_19200 ((long)F_CPU / (16l * 19200) - 1l)

Wozu? Eine allgemeine Formel reicht. Siehe

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#UART_initialisieren

MFG
Falk

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.