Forum: Compiler & IDEs Uhrzeit Stellen/ externe Variablen im Struct


von Ein Fest a. (einfest_a)


Lesenswert?

Hallo,
ich möchte die Uhrzeit in meiner main.c einstellen. Der Code für die Uhr 
befindet sich in einer externen Datei RTC.c.
Ich vermute mal, dass es mit "extern" funktionieren sollte, aber 
irgendwie bekomme ich es nicht hin bei dem "struct".
Ich würde mich freuen, wenn mir jemand helfen könnte.
1
C-Code
2
//RTC.c
3
typedef struct
4
{
5
    volatile unsigned char Sekunden;
6
    volatile unsigned char Minuten;
7
    volatile unsigned char Stunden;
8
} datestruct;
9
10
 volatile datestruct Uhrzeit;
1
C-Code.c
2
//main.c
3
Uhrzeit.Minuten = EinstellwertMinuten; //usw.

Grüße, Tobi

von Walter S. (avatar)


Lesenswert?

Wie war noch Mal die Frage bzw. das Problem?

Na ja, eine Vision sagt mir, dass du die struct Definition in einen 
h-File packen solltest und den dann sowohl in rtc.c als auch in main.c 
includen solltest.

von Karl H. (kbuchegg)


Lesenswert?

Das wichtigste Prinzip ist wohl das hier:

 C an sich, hat keine Projektverwaltung!

Wenn sich der Compiler eine C-Datei vornimmt, dann interessiert ihn 
nicht, was in anderen C-Dateien steht. Jede C-Datei wird für sich und 
unabhängig von allen anderen übersetzt. Jede Datei muss in sich 
vollständig sein.

Da der Compiler bei diesem Quelltext
1
int main(){
2
{
3
  Uhrzeit.Minuten = 5;
4
}

weder jemals irgendetwas von einer Variable 'Uhrzeit', noch deren 
Aufbau, noch dass sie einen Member 'Minuten' hat gehört hat, setzt es 
einen Fehler.

Also musst du ihm erst mal klar machen, dass es eine Variable Uhrzeit 
gibt. Du brauchst eine Deklaration dafür
1
extern volatile datestruct Uhrzeit;
2
3
int main(){
4
{
5
  Uhrzeit.Minuten = 5;
6
}

Tja. Alles schön gut. Aber was ist jetzt wieder ein 'datestruct'?

Da der Compiler das nur durch betrachten dieses Textes nicht wissen 
kann, muss man ihm das mitteilen
1
typedef struct
2
{
3
    volatile unsigned char Sekunden;
4
    volatile unsigned char Minuten;
5
    volatile unsigned char Stunden;
6
} datestruct;
7
8
extern volatile datestruct Uhrzeit;
9
10
int main(){
11
{
12
  Uhrzeit.Minuten = 5;
13
}


Und jetzt ist man in der unschönen und unglücklichen Lage, dass man in 2 
C-Files dieselbe Strukturdefinition hat. Das will man auf alle Fälle 
vermeiden!
Die Lösung: Man verbannt die Strukturdefinition (und die extern 
Deklaration gleich mit) in ein Header File

rtc.h
*****
1
typedef struct
2
{
3
    volatile unsigned char Sekunden;
4
    volatile unsigned char Minuten;
5
    volatile unsigned char Stunden;
6
} datestruct;
7
8
extern volatile datestruct Uhrzeit;

wird dieses in main.c inkludiert
1
#include "rtc.h"
2
3
int main(){
4
{
5
  Uhrzeit.Minuten = 5;
6
}
dann ist alles paletti. Durch den include wird die Definition von 
'datestruct' hereingezogen und auch gleich noch die extern-Deklaration 
von Uhrzeit.

Und in rtc.c mach ich (fast) dasselbe
1
#include "rtc.h"
2
3
volatile datestruct Uhrzeit;
4
5
void foo()
6
{
7
}

Damit hab ich erreicht, dass es die Strukturdefinition nur einmal in 
Textform gibt und somit ist sichergestellt, dass sie an allen Stellen 
gleich aussieht.


Eigentlich ganz einfach.

von Ein Fest a. (einfest_a)


Lesenswert?

Vielen Dank für die Antworten!

So hatte ich es eigentlich auch schon versucht...ich werde es nochmal 
probieren.

Danke!
Gruß, Tobi

von Ein Fest a. (einfest_a)


Lesenswert?

Wenn ich es so mache wie oben beschrieben, bekomme ich 4 Fehler vom 
Compiler:
Drei für die datei rtc.h:
Error  1  conflicting types for 'datestruct'
Error  2  previous declaration of 'datestruct' was here
Error  3  conflicting types for 'Uhrzeit'
und eine für rtc.c:
Error  4  previous declaration of 'Uhrzeit' was here

Kann damit jemand mehr anfangen als ich?

von Karl H. (kbuchegg)


Lesenswert?

Zeig mal deine Source Files.

(Im Prinzip fehlen noch Include Guards. Allerdings solltest du die jetzt 
noch nicht brauchen, wenn die Includes richtig sind)

Ich hab da so einen Verdacht, was du gemacht haben könntest :-)

von Karl H. (kbuchegg)


Lesenswert?

> Kann damit jemand mehr anfangen als ich?


> Error  1  conflicting types for 'datestruct'
Es gibt eine 2-te Definition für datestruct, nicht nur die auf die in 
der Fehlermeldung verwiesen wird.

> Error  2  previous declaration of 'datestruct' was here
Nämlich hier ist sie. An der Stelle, auf die diese Fehlermeldung 
verweist.

> Error  3  conflicting types for 'Uhrzeit'
Das ist dann ein Folgefehler, weil datestruct ein Problem hat.

und eine für rtc.c:
> Error  4  previous declaration of 'Uhrzeit' was here
Ebenfalls ein Folgefehler

von Karl H. (kbuchegg)


Lesenswert?

OK. Du willst den Code nicht posten.

Dann frage ich direkt:

Du hast nicht zufällig in deiner Hauptdatei ein

#include "rtc.c"

stehen?

von Ein Fest a. (einfest_a)


Lesenswert?

Ihr seit ja wirkich unglaublich schnell! :-)

Also hier nochmal die relevanten Teile der einzelnen Dateien:

rtc.h:
*****
c]C-Code
typedef struct
{
    volatile unsigned char Sekunden;
    volatile unsigned char Minuten;
    volatile unsigned char Stunden;
} datestruct;


extern volatile datestruct Uhrzeit;
[/c]

rtc.c
*****
c]C-Code
#include <avr/io.h>
#include <avr/interrupt.h>
#include "rtc.h"
#define fosc 12288000
/*
typedef struct
{
    volatile unsigned char Sekunden;
    volatile unsigned char Minuten;
    volatile unsigned char Stunden;
} datestruct;
*/
 volatile datestruct Uhrzeit;


void init_Timer1(void)
{
  OCR1A = 0xBB7F;       // TOP = 47999
  TIMSK |= (1<<OCIE1A); // CTC-Interrupt zulassen
  TCCR1B = (1<<CS12) | (1<<WGM12); // Mode 4 (CTC; OCR), Timer starten 
PSC = 256
}


// Uhrzeit-Timer-Interrupt
#pragma vector = TIMER1_COMPA_vect
//Anmerkung 1) Heir gibt der Compiler eine Warnung aus: "ignoring 
#pragma vector"
void TIMER1_COMPA_Interrupt(void)
{

  if (++Uhrzeit.Sekunden >59)
  {
    Uhrzeit.Sekunden = 0;
    if (++Uhrzeit.Minuten > 59)
    {
      Uhrzeit.Minuten = 0;
      if (++Uhrzeit.Stunden >23)
      {
        Uhrzeit.Stunden = 0;
      }
    }
  }
}
[/c]

main.c
*****
c]C-Code
#include <avr/io.h>
#include <avr/interrupt.h>
#include "rtc.c"
#include "rtc.h"
//#include "pid.c"

  unsigned char EnterUhrzeit = 0;
  unsigned char EnterUhrzeitMin;
  unsigned char EnterUhrzeitStund;



int main( void )
{
  init_Timer1();
  sei();
  while(1)
  {
    if(EnterUhrzeit)
    {
     Uhrzeit.Minuten = EnterUhrzeitMin;  //Uhr einstellen
     Uhrzeit.Stunden = EnterUhrzeitStund;
    }

  return 0;
}
[/c]


Ich habe jetzt alle nicht relevanten Teile der main.c gelöscht.

Das ist jetzt natürlich OT, aber wo wir schon dabei sind...in der rtc.c 
gibt es noch eine warnung (Anmerkung 1)) und ich vermute mal, dass die 
Uhr so noch nicht ganz funktioniert. Hat dazu noch jemand einen Tip?

von Ein Fest a. (einfest_a)


Lesenswert?

Doch, ich habe da eine #include "rtc.c"
wenn ich das nicht darf, müsste ich einiges umbauen ;-(

von Karl H. (kbuchegg)


Lesenswert?

1
main.c
2
*****
3
c]C-Code
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include "rtc.c"

und da haben wirs schon.

C-Files werden nicht inkludiert!

von Karl H. (kbuchegg)


Lesenswert?

Ein Fest a. schrieb:
> Doch, ich habe da eine #include "rtc.c"
> wenn ich das nicht darf, müsste ich einiges umbauen ;-(

musst du nicht.

Du musst nur nach den Regeln spielen und nicht jeder scheinbaren 
Vereinfachung nachlaufen, die du irgendwo siehst.

Bau dir als erstes mal eine vernünftige Projektstruktur auf. Sonst 
brauchst du erst gar nicht damit anfangen, Dinge in einzelne C-Files zu 
verpacken, wenn du dann sowieso alles wieder mittels #include in einen 
Topf wirfst.

Die C-Files werden (im AVR-Studio) zum Projekt hinzugefügt!
Und nicht alle mitsammen in ein C-File per #include hineingezogen.

FAQ Punkt 7

von EGS_TI (Gast)


Lesenswert?

Definitionen in C Dateien (niemals in Header-Dateien), und Deklarationen 
in Header-Dateien.
Nachzulesen in der sehr guten C-FAQ: http://c-faq.com/decl/decldef.html

von Karl H. (kbuchegg)


Lesenswert?

Ein Fest a. schrieb:

> Das ist jetzt natürlich OT, aber wo wir schon dabei sind...in der rtc.c
> gibt es noch eine warnung (Anmerkung 1)) und ich vermute mal, dass die
> Uhr so noch nicht ganz funktioniert. Hat dazu noch jemand einen Tip?

1
#pragma vector = TIMER1_COMPA_vect
2
//Anmerkung 1) Heir gibt der Compiler eine Warnung aus: "ignoring
3
#pragma vector"
4
void TIMER1_COMPA_Interrupt(void)
5
{
6
7
  if (++Uhrzeit.Sekunden >59)

Ja. Klau nicht Code, welcher mit dem IAR Compiler gemacht wurde. Und 
wenn du das tust, dann pass die Nicht-Standard Syntax der Interrupt 
Vektoren vom IAR Compiler auf die Nicht-Standard-Syntax vom GCC an.

von Ein Fest a. (einfest_a)


Lesenswert?

Da scheitert es wieder an den einfachsten Grundlagen :-(
es ist schon zu lange her, dass ich an der Uni C gelernt habe.

Danke trotzdem!

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.