Code auslagern mit #include und "globalem" #define

OP #993264
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???
#993288
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));
OP #993329
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!
Gast #994296
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren