Forum: Mikrocontroller und Digitale Elektronik DCF77 Signalerfassung mit ATMega 328p in C


von Micha (Gast)


Lesenswert?

Hallo Zusammen,
ich benötige eure fachmännische Hilfe bei einem Problem mit dem DCF77 
Signal bei einem Atmel ATMega 328p.
Wie ihr euch denken könnt möchte ich das das DCF77 Signal empfangen. Der 
neg. Ausgang des DCF77-Sensor habe ich an den INT0 Eingang PD2 am Atmel 
angeschlossen. Mit einem Interrupt möchte ich nun im Sekundentakt ein 
Array hoch zählen. Die Signalzustandserkennung mache ich mit einem 
Timerinterrupt Timer0. Je nach Zustand schreibe ich dann die Werte in 
das Array.
Leider habe ich das Problem, dass der INT0- Interrupt nicht zuverlässig 
die fallende Flanke erkennt -> meistens wird er zweimal ausgelöst. Wie 
empfohlen habe ich einen Pull-Up Widerstand 5,2k zwischen + und neg. 
Ausgang geschalten.

Hier die Interrupt-Konfig:
  DDRD &= ~(1 << DDD2);
  PORTD |= (1 << PORTD2);


  DDRB |= (1 << 4);
  DDRB |= (1 << 5);

  EICRA |= (1 << ISC01);
  //EICRA |= (1 << ISC00);
  EIMSK |= (1 << INT0);


  TCCR0A |= (1 << WGM01);
  OCR0A = 160;
  TIMSK0 |= (1 << OCIE0A);
  TCCR0B |= (1 << CS02);
  TCCR0B |= (1 << CS00);

  sei();

Nachfolgend die beiden Interrupts:
ISR (TIMER0_COMPA_vect)
{


  if(PIND & (1 << PIND2))
  {
      dcf_interrupt_zaehler = 0;

      dcf_richtimpuls_zaehler++;

      if(dcf_richtimpuls_zaehler >= 110)
      {
        dcf_richtimpuls = 1;
        dcf_sekunde = 59;
        dcf_richtimpuls_startpuls++;
      }
  }
  else
  {
      dcf_richtimpuls_zaehler = 0;

      dcf_interrupt_zaehler++;

      if(dcf_interrupt_zaehler >= 11)
      {
        //char Test_PIN_1[] = "** PIN = 1 **";  //Zum Testen
        //USART_String_Ausgabe(Test_PIN_1);
        dcf_signalwert = 1;
      }
      else
      {
        //char Test_PIN_0[] = "** PIN = 0 **";  //Zum Testen
        //USART_String_Ausgabe(Test_PIN_0);
        dcf_signalwert = 0;
      }
  }

  if(dcf_signalwert == 1)
  {
    PORTB |= (1 << 5);
  }
  if(dcf_signalwert == 0)
  {
    PORTB &= ~(1 << 5);
  }

}

ISR (INT0_vect)
{

  PORTB ^= (1 << 4);

  if((dcf_richtimpuls == 0) && (dcf_richtimpuls_startpuls <= 1))
  {
    char wait[] = ".";
    USART_String_Ausgabe(wait);
  }
  else
  {
    Wochentag();
    char leer[]    = " ";
    USART_String_Ausgabe(leer);
    Tag();
    char punkt[]  = ".";
    USART_String_Ausgabe(punkt);
    Monat();
    USART_String_Ausgabe(punkt);
    Jahr();
    USART_String_Ausgabe(leer);
    Stunde();
    char dpunkt[]  = ":";
    USART_String_Ausgabe(dpunkt);
    Minute();
    USART_String_Ausgabe(dpunkt);
    Sekunde();
    char breakpoint[]  = "  ***  ";
    USART_String_Ausgabe(breakpoint);
  }

  DCF_Signalwerte[dcf_sekundenzaehler] = dcf_signalwert;

  dcf_signalwert = 0;

  dcf_sekundenzaehler++;


  if (dcf_sekunde < 58)
  {
    dcf_sekunde++;
  }

  if (dcf_sekunde == 59)
  {
    dcf_sekunde = 0;
    dcf_sekundenzaehler = 0;
  }

}


//////
Kann mir bitte jemand weiterhelfen oder hat jemand eine Idee was ich 
bessermachen sollte.

VIELEN DANK FÜR EURE HILFE.

Grüße Micha

von W.A. (Gast)


Lesenswert?

A. K. schrieb im Beitrag #4522762:
> Mit Timer alle N ms abfragen

N darf dabei gerne gleich 20 sein ...

Die ganzen Berechnungen und USART-Ausgabe sind völlig zeitunkritisch und 
haben in der ISR vom INT0 nichts zu suchen.

von (prx) A. K. (prx)


Lesenswert?

Manche DCF77 Receiver erzeugen ein instabiles quasi "prellendes" Signal 
im Übergang. Frag den Pin im Timer-Interrupt alle N msec ab, direkt ohne 
Pin-Interrupt, dann stört das nicht.

von (prx) A. K. (prx)


Lesenswert?

W.A. schrieb:
> Die ganzen Berechnungen und USART-Ausgabe sind völlig zeitunkritisch und
> haben in der ISR vom INT0 nichts zu suchen.

Nicht nur das, die UART-Asugabe ist für die Timer-ISR u.U. zu langsam.

von Micha (Gast)


Lesenswert?

@A.K. Danke für eine Hilfe soll ich dann den Eingang PD2 nur noch mit 
der _delayms() Funktion von delay.h abfragen. Ich hätte den Pininterrupt 
auch als Sekundenzähler genommen.

von (prx) A. K. (prx)


Lesenswert?

Micha schrieb:
> @A.K. Danke für eine Hilfe soll ich dann den Eingang PD2 nur noch mit
> der _delayms() Funktion von delay.h abfragen.

Nein. Timer auf 20msec programmieren und den Pin in dessen ISR abfragen. 
Mitzählen wie lang in low/high Zustand und das auswerten.

Komplexe Auswertung und Anzeige gehört ins Hauptprogramm.

> Ich hätte den Pininterrupt auch als Sekundenzähler genommen.

DCF77 taugt nicht als Interrupt-Quelle. Selbst im Idealfall fehlt jede 
Minute einer, von gestörtem Signal oder den beobachteten Effekten ganz 
abgesehen.

Im gleichen Timer eine Variable zählen, die alle 50x die Sekunde zählt.

: Bearbeitet durch User
von Micha (Gast)


Lesenswert?

@A.K. danke für deine Hilfe. Das ist eine gute Idee. Wie würdest du dann 
die Synchronisation machen ich muss ja immer wissen wann ein signal 
anfängt.

von (prx) A. K. (prx)


Lesenswert?

Den Wechsel des Zustands eines Pins gegenüber dem letzten Mal zu 
erkennnen wirst du hoffentlich selber schaffen. Dann mitzählen, wieviele 
Timer-Ticks dieser Zustand anhält. Der Rest ergibt sich direkt daraus.

Das Hauptprogramm braucht 2 Informationen:
- Pin hat den Zustand gewechselt, L=>H / H=>L
- Wieviele Ticks sind seit dem letzten Wechsel vergangen.

: Bearbeitet durch User
von Micha (Gast)


Lesenswert?

@A.K. Danke für deine Hilfe.

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.