mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Atmega8, DCF an Interrupt. Ungültige Signaldauer mit externem Quarz


Autor: Dev Pap (dev_p)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Abend,

Ich habe es bereits erfolgreich geschafft ein DCF Modul mit einem 
Atmega8 anzusteuern und mir die Zeit korrekt ausgeben zu lassen. Im 
leichtesten Fall mittels UART.
In diesem Fall läuft der Controller mit dem internen RC-Oszillator auf 4 
MHz. Das Signal vom DCF Modul wird an Pin4 mit einem Interrupt 
getriggert.

Beispielhafte Debugausgabe im UART (Zahlen sind frei erfunden):
102, 213, 220, 112, 110, 105, 1838, 102 ...
Dieses Signal kann ich wunderbar verarbeiten. Gut!

Nun wollte ich einen externen Quarz ansteuern und mit wenigen 
Anpassungen im vorliegenden Code dasselbe Ergebnis erzielen. Ich habe 
einen 16 Mhz Quarz gewählt. Mein UART funktioniert weiterhin allerdings 
klappt es mit dem DCF Signal nicht mehr.

Folgende Änderungen habe ich durchgeführt:
Von
#define F_CPU 4000000L
nach
#define F_CPU 16000000L
in uart.c Zeile 13.

und von
 TCCR2 |= (1 << WGM21) | (1 << CS21) | (1 << CS20); 
nach
TCCR2 |= (1 << WGM21) | (1 << CS22) | (1 << CS20); 
in main.c Zeile 28.

Mehr Änderungen sollten nicht nötig sein. Programm auf den Atmega8 
programmiert. Nachdem ich die ersten Signale empfangen habe, bekomme ich 
folgende beispielhafte Ausgabe:
102, 213, 220, 112, 0, 110, 105, 1838, 102, 0, 210, 211, 113 ...
Jetzt kann ich leider nicht nachvollziehen woher die 0 Millis kommen?

Kann mir an dieser Stelle jemand weiterhelfen. Alternativ könnte ich es 
auch mit Polling der Impulse probieren, würde gerne aber meinen Fehler 
verstehen. Ich habe bereits verschiedene Intervalle für die ISR gewählt 
allerdings ohne Erfolg. Ich habe in dem Programmcode nur das wesentliche 
stehen, habe die Anbindung an die Anzeige für dieses Beispiel 
herausgenommen. Ich habe meine Schaltung auf dem Steckbrett gesteckt.

Mit freundlichem Gruß
devpap

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dev P. schrieb:
> Mehr Änderungen sollten nicht nötig sein.

Und wie hast Du die Fuses gesetzt?

Autor: Harald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kauf dir einen Logic Analyzer (z.B. einen Slaeae Clone mit freier 
Software Sigrok für <8€ (oder 17€ Prime)) und finde den Fehler mit 
Leichtigkeit. Ein Pin an die UART, ein Pin an das DCF Signal und lasse 
Dir durch die integrierten Decoder beide Signale in Klartext(!) 
anzeigen, wo es schiefgeht.
Vermutung sind kurze Spikes im DCF-Signal (evtl. höhere EMV durch 
Quarz-Einsatz)

Autor: Harald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich meinte "Saleae Clone"

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
Es folgt eine Kopie der Fuse Einstellungen aus dem Atmel Studio

[code]RSTDISBL = []
WTDON =[]
SPIEN =[X]
EESAVE =[]
BOOTSZ = 1024W_0C00
BOOTRST = []
CKOPT=[]
BODLEVEL=2V7
BODEN=[]
SUT_CKSEL=EXTHIFXTALRES_16KCK_64MS

Ich habe nicht viel Erfahrung mit den Fuses. Ich nahm an, dass alles 
richtig eingestellt ist, da ich keine Probleme mit UART habe.

Die Antwort von Harald muss ich noch prüfen.

Autor: Georg G. (df2au)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dev P. schrieb:
> weiterhelfen

Ein ZIP File aus unbekannter Hand öffne ich ungern. Der Code ist so 
klein, den kannst du auch ungezipt anhängen. Das macht das Lesen 
bequemer und senkt die Schwelle zum "mal drüber schauen".

Autor: H.Joachim Seifert (crazyhorse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich wollts nicht sagen :-)
Man sieht es auch an den mageren 3 downloads....

: Bearbeitet durch User
Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kein Problem, werde den Code anhängen. Habe mich versucht an die 
Richtlinien zu halten. Es dauert aber etwas, von meinem Mobiltelefon 
bekomme ich das nicht hin.

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
main.c
/*
 * DCF_Debugging
 *
 * Created: 19.09.2016 17:57:22
 * Author : devpap
 */ 

#include "uart.h"

#include <avr/io.h>
#include <avr/interrupt.h>

#include <stdlib.h>
#include <stdio.h>

volatile uint16_t g_millis; /* Zähler für Millisekunden der kurzen Signale 0 oder 1*/
volatile uint16_t g_breakMillis; /* Zähler für Millisekunden der Signalpause */
volatile uint8_t g_dcfInterrupt; /* Flag das angibt, dass ein Signal aktiv ist */

/**
 * @brief Initialisiert den Timer2 auf dem Atmega8 im CTC Modus mit dem Prescaler 128. Die ISR wird jede Millisekunde aufgerufen.
 * @param - 
 * @return - 
 */
void timer2_init()
{
  uart_puts_nl("Init Timer2");
  TCCR2 |= (1 << WGM21) | (1 << CS22) | (1 << CS20);
  OCR2 = 0x7C;
  TIMSK |= (1 << OCIE2);
  g_millis = g_breakMillis = 0;
  g_dcfInterrupt = 0;
}

/**
 * @brief Aktiviert den Interrupt an Pin4
 * @param - 
 * @return - 
 */
void dcf_interrupt0_init()
{
  uart_puts_nl("Init dcf_interrupt0");
  GICR |= (1 << INT0);
  MCUCR |= (1 << ISC01) | (1 << ISC00);
}

/**
 * @brief Zurücksetzen aller Status und Interrupt an Pin 4 wieder aktivieren
 * @param - 
 * @return - 
 */
void reinit()
{
  g_dcfInterrupt = 0;
  g_millis = 0;
  g_breakMillis = 0;
  GICR |= (1 << INT0);
}

/* Interrupt0 Pin 4*/
ISR(INT0_vect)
{
  /* Externen Interrupt zwischenzeitlich deaktiveren. Wird wieder aktiviert, wenn Signal verarbeitet wurde*/
  GICR &= ~(1 << INT0);
  PORTB |= (1 << PB1);
  TCNT2 = 0x00;
  g_millis = 0;
  g_dcfInterrupt = 1;
}

/**
 * @brief Ausgelößt jede Millisekunde
 * @param - 
 * @return - 
 */
ISR(TIMER2_COMP_vect)
{
  if (g_dcfInterrupt)
  {
    if(PIND & (1 << PD2))
    {/* Pin abfragen */
      ++g_millis;
    }  
    else
    {
      char time[5];
      if(g_breakMillis > 1500)
      {/* Lange Pause, bevor das neue Signal beginnt */
        itoa(g_breakMillis, time, 10);
        uart_puts_nl(time);
        reinit();
        return;
      }
      else
      {/* Hier muss der Impuls für eine 0 oder eine 1 verarbeitet werden */
        itoa(g_millis, time, 10);
        uart_puts_nl(time);
        PORTB &= ~(1 << PB1);
        reinit();
      }
    }
  }
  else
  {
    ++g_breakMillis;
  }
}

/**
 * @brief Los
 */
int main(void)
{
  uart_init();
  uart_puts_nl("Programmstart");
  dcf_interrupt0_init();
  timer2_init();
  
  /* globale Interrupts */
  sei();
  
  /* Status LED, damit man was sieht */
  DDRB = 0x03;
  PORTB |= (0 << PB1) | (1 << PB0);
      
    while (1) 
    {
    }
}

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Harald schrieb:
> Ich meinte "Saleae Clone"

Scheint mir jetzt für das vorliegende Problem nicht sehr zielführend zu 
sein. Kenne diese Geräte noch nicht und weiß auch nicht wie man sie 
nutzt. Vielleicht kann ich in Zukunft mal so etwas investieren, jetzt 
versuche es vorerst nur über das Forum und das Gespräch. Danke für den 
Tipp.

: Bearbeitet durch User
Autor: Georg G. (df2au)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine UART Ausgabe innerhalb einer ISR ist suboptimal.

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg G. schrieb:
> Eine UART Ausgabe innerhalb einer ISR ist suboptimal.

Gut, werde ich mir für die Zukunft merken und habe es schon umgebaut. 
Kenne noch keine andere Möglichkeit Code zu debuggen.

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Herausnehmen der UART Ausgaben aus der ISR hat leider keinen 
Unterschied gemacht. Bekomme weiterhin die Durchläufe mit 0 
Millisekunden.
Vielleicht finde ich es noch heraus. Wenn jemand Ideen hat, bin ich 
dafür offen.

: Bearbeitet durch User
Autor: Harald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dev P. schrieb:
> Kenne diese Geräte noch nicht und weiß auch nicht wie man sie
> nutzt

Investiere die 8€ doch mal und frage dich nach ca. 3h wie du jemals ohne 
entwickeln konntest...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein reinit() enabled nur den Interrupt, löscht aber nicht das 
Pending-Flag.

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Dein reinit() enabled nur den Interrupt, löscht aber nicht das
> Pending-Flag.

Wird das Pending-Flag nicht zurückgesetzt, wenn die ISR aufgerufen wird? 
Ich kann es natürlich auch setzen, indem ich eine 1 auf INTF0  setze.

Bezüglich des Logic Analyzers. Was genau kann ich damit sehen. Ich habe 
ein Angebot für unter 10 € bei Amazon gesehen.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dev P. schrieb:
> Wird das Pending-Flag nicht zurückgesetzt, wenn die ISR aufgerufen wird?

Kann die ISR aber erst direkt nach dem reinit().

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Dev P. schrieb:
>> Wird das Pending-Flag nicht zurückgesetzt, wenn die ISR aufgerufen wird?
>
> Kann die ISR aber erst direkt nach dem reinit().

So, hatte nun etwas Zeit mir das Problem wieder anzusehen. Auch wenn ich 
das Pending-Flag zurücksetze wird mein Ergebnis nicht besser. Irgendwie 
gehen Interrupts und/oder Zeit verloren. Die LED blinkt jede Sekunde 
unterschiedlich lang. Daraus schließe ich, dass die ISR aufgerufen wird.
Ich habe nun doch noch eine Ausgabe in der ISR. Ich lasse mir die Zeit 
g_millis und den Index ausgeben. In einigen  Interrupts ist die Zeit 
einfach 0ms. Ich übersehe sicher einfach etwas. Sollte am besten nochmal 
von Vorne anfangen.

: Bearbeitet durch User
Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht prellt das Signal.
Warum willst Du es so genau wissen?
Es reicht doch, wenn man es mit nem 10ms Timerinterrupt abtastet und die 
Dauer mitzählt.

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Vielleicht prellt das Signal.
> Warum willst Du es so genau wissen?
> Es reicht doch, wenn man es mit nem 10ms Timerinterrupt abtastet und die
> Dauer mitzählt.

Ich muss es natürlich nicht so genau wissen. Ich habe es einfach so 
versucht. Eventuell aus Unerfahrenheit. Werde die Zeit mal 
herunterschrauben.

Autor: Harald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Vielleicht prellt das Signal.

Genau das kann der Logic Analyzer, dann siehst Du den DCF-Datenstrom (in 
Klartext decodiert versteht sich) neben deiner UART Ausgabe. Mit 
weiteren Portpins könnte man sich im Bedarfsfall noch 6 weitere Pins 
ausgeben lassen, der LA hat 8 Eingänge (falls überhaupt notwendig).
Der LA kann große Dazenmengen in den PC einlesen, das sollte für min. 1 
Minute DCF reichen. Prellen erkennt man eben auch mit Leichtigkeit.

Autor: Harald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auf der Saleae Originalseite ist das etwas anschaulicher dargestellt, 
allerdings kann die OriginalSW kein DCF. Das kann aber die freie SW 
Sigrok.

Autor: MWS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei 16MHZ ist es empfehlenswert die CKOPT Fuse zu setzen.

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MWS schrieb:
> Bei 16MHZ ist es empfehlenswert die CKOPT Fuse zu setzen.

Jawohl, das habe ich nachträglich getan. Hatte es hier im Forum schon 
angedeutet gesehen. Ändert aber nichts.

: Bearbeitet durch User
Autor: Jakob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wozu ein Logik-Analysator?

Ich befürchte, dass dein Programm durch das An- und Abschalten
von INT0 bei kurzen Prellern den Signal-Überblick verliert.

Ob das Signal prellt, oder nicht, ist jedoch wurst, weil jede
DCF-Uhr damit klarkommen muss.

Aber auch um das DCF-Signal mit Aktiv- und Pausenlänge darzustellen,
darfst du dir mit dem INT0-An- und Abschalten nicht die Chance
verbauen, zu erkennen, dass es gleich wieder zurückspringt.


Mein Vorschlag:
(Dafür brauchst du auch nur 3 Variablen.)

Frage innerhalb der INT0-Routine ab, ob das Signal von PAUSE auf
AKTIV, oder umgekehrt geschaltet hat.
Damit kannst du die LED passend schalten. Weiterhin:

Wenn das DCF-Signal AKTIV geworden ist und (!) TCNT2 > 950 ist,
kannst du den Zählerstand in einer Variablen SKD_DAUER speichern
und dann TCNT2 auf NULL setzen.
Zusätzlich setzt du eine Variable NEUE_SEKUNDE auf 1.

Wenn das DCF-Signal PAUSE geworden ist und (!) TCNT2 > 50 ist,
(eventuell mit 25...75 experimentieren) speicherst du den Stand
von TCNT2 in einer Variable DCF_AKTIV.

Den Timer2-Interrupt brauchst du dafür garnicht. Hauptsache der
Timer läuft mit 1 kHz, um ms anzeigen zu können.

In der Hauptprogramm-Schleife prüfst du die Variable NEUE_SEKUNDE.
Ist sie 1, gibst du den Wert von DCF_AKTIV und
Pausendauer = SKD_DAUER - DCF_AKTIV aus.
Dann NEUE_SEKUNDE zurücksetzen.

Autor: Harald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jakob schrieb:
> Wozu ein Logik-Analysator?

Antwort hier:

Dev P. schrieb:
> Jetzt kann ich leider nicht nachvollziehen woher die 0 Millis kommen?
> Kann mir an dieser Stelle jemand weiterhelfen.

Autor: Jakob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Harald

Klar, bei der Verarbeitung komplizierterer Signale, als DCF,
wo es auch mal zeitlich knapp werden kann, ist dein Vorschlag
(für den Preis!) ein echt heißer Tipp.

Das Ding werde ich mir auch mal ansehen.

Aber bei DCF ist das (mit Einarbeitung) eher Overkill!
Noch dazu, wenn ein Blick auf den Programmcode zeigt, dass der
eher Fehler-einladend, als Fehler-abweisend geschrieben ist.

- Der INT0 für's DCF-Signal schaltet sich gleich mal selbst ab und
  wird erst irgendwann nach einer Serial-Ausgabe wieder eingeschaltet.
  Polaritäts-Auswertung, Plausibilitätserkennung und LED-Schaltung
  findet hier nicht statt, obwohl es zeitlich unproblematisch ist.

- Die Polarität des INT0-Signals wird irgendwann zum Timer-Interrupt
  erforscht - da sind viele Preller schon längst verschwunden.
  -> Falsche Polarität erfasst!
  -> Die Serial-Ausgabe, legt das System wahrscheinlich für
     etliche ms lahm...

- 4 MHz auf 16 MHz KÖNNTE auch erklären, dass es mal lief und
  jetzt nicht mehr: Für kurze Störpulse ist das Produkt nun
  4 mal so empfindlich.


Kurzen Störpulsen / unsauberen Flanken wird es hier leicht gemacht,
zur falschen Auswertung zu führen. Das kann man bestimmt mit dem
Analyzer sehen, aber ob das hilft, wenn man Fehlervermeidung einfach
noch nicht als Aufgabe für das Programm-Konzept erkannt hat?


Komisch, dass sich die DCF-nur-nicht-mit-Flankenerkennung-Warner
bisher nicht gemeldet haben!

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe es zwischenzeitlich mit aktivem Warten versucht und konnte auch bei 
16 MHz die Zeit korrekt ermitteln. Leider ist diese Lösung ziemlich 
grenzwertig. Ich habe 50 ms gewartet, bevor ich angefangen habe die 
Daten aufzuzeichnen. Aus diesem Grund würde ich auch den Ansatz von 
Jakob umsetzen.

Jakob schrieb:

> Mein Vorschlag:
> ...
>
> Wenn das DCF-Signal AKTIV geworden ist und (!) TCNT2 > 950 ist,

Wie kann denn TCTN2 diesen Wert erreichen? Kann TCNT2 nicht nur 8 Bit 
ausfüllen und beginnt wieder bei 0? Oder sollte ich ich doch 
Millisekunden zählen?

Habe mir auch die Kommentare die Du mehr oder weniger an Harald 
gerichtet hast zu Herzen genommen. Werde es nun umsetzen soweit ich es 
verstanden habe.
Das Thema mit der Ausgabe wurde aber auch schon weiter oben behandelt.

: Bearbeitet durch User
Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier mal ein Beispiel für eine einfache Pulsmessung des DCF77:
Beitrag "DCF77 Uhr in C mit ATtiny26"

Ob der Timerinterrupt 64Hz oder 100Hz hat, ist egal. Die 2s Synch 
sollten halt noch in ein uint8_t passen.

Wichtig ist aber, daß bei Empfangsstörungen (Z.B. Gewitter, Staubsauger) 
die Zeit intern weiter zählt.

Autor: Jakob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Dev Pap (dev_p)

Da hast du recht, der Timer2 des mega8 zählt nur 0...255.
Hatte in dem Moment übersehen, dass er nicht mit 1 kHz getaktet
wird, sondern jede ms beim Überlauf eine Variable hochzählt.

Dann musst du wohl deine Variable g_millis beibehalten,
(eine Variable mehr), solltest aber außer dem Hochzählen nichts
weiter in der TIMER2_COMP-ISR machen.

Die zusätzliche Variable NEUE_SEKUNDE soll dir auch nur den
Weg aufzeigen, wie zeitaufwändige Ausgabe-Routinen aus
IRS-Routinen an das Hauptprogramm übergeben werden.

Sowas nennt man Flag-Register: Wird benutzt, wie das Fähnchen
am amerikanischen Dorf-Briefkasten. Der Briefträger stellt es
auf, wenn was Neues drin ist - und wenn man Zeit hat, holt man
sich die Post, klappt das Fähnchen runter, und reagiert auf die
Post, indem man z.B. das Strafticket für falsches Parken bezahlt.

Also: Überall, wo ich TCNT2 geschrieben habe, muss eben
g_millis eingesetzt werden.

Probier mal, meine Vorschläge umzusetzen, um erstmal nur
die Anzeige von AKTIV- und PASSIV-Zeiten des DCF-Signals
hinzubekommen.

Der Vorschlag von Peter Dannegger (peda) ist bestimmt gut,
aber ich denke mal, du willst deine EIGENE (!) DCF-Auswertung
bauen, kein fremdes Programm kopieren.

Darum kommen von mir auch keine fertigen Programme, sondern
Vorschläge für den (hoffentlich!) besseren Programm-Ablauf.
DCF war jedenfalls MEIN (und auch von vielen anderen µC-Net-
Teilnehmern) das erste größere µC-Projekt! :-)

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe heute endlich wieder an dem Problem gearbeitet. Ich hoffe ich 
konnte deine Ratschläge, wie in dem angehängtem Code zu sehen ist, 
korrekt umsetzen?
Ich habe aber noch offene Fragen:

Ist es korrekt, dass ich nun auf steigenden und fallenden Flanken 
reagiere?

Jakob schrieb:
> ...
> Wenn das DCF-Signal AKTIV geworden ist und (!) TCNT2 > 950 ist, ...
> Wenn das DCF-Signal PAUSE geworden ist und (!) TCNT2 > 50 ist, ...

Mir ist leider nicht klar, wie du auf die Werte 950 und 50 kommst. 
Könntest du mir vielleicht eine kurze Erläuterung geben, während ich 
selber nochmal eine Skizze mache und darüber nachdenke.

/*
 * dcf_time_evaluation_2.c
 *
 * Created: 08.10.2016 15:26:48
 * Author : devpap
 */ 

#include "uart.h"

#include <avr/io.h>
#include <avr/interrupt.h>

#include <stdlib.h>
#include <stdio.h>

uint8_t g_dcfRegisterFlags[2];

#define DCFACTIVE 0
#define NEWSECOND 1

uint16_t g_millis; /* Zähler für Millisekunden */

uint16_t startTime; /* Start einer neuen Sekunde */
uint16_t activeTime; /* aktive Zeit */

/* Initialisierung des Interrupt 
 * Pin4, Interrupt 0
 * @param -
 * @return -
 */
void dcf_interrupt0_init()
{
  uart_puts_nl("Init dcf_interrupt0");
  g_dcfRegisterFlags[DCFACTIVE] = 0;
  
  GICR |= (1 << INT0);
  MCUCR |= (1 << ISC00);
}

/* Interrupt0 */
ISR(INT0_vect)
{
  if(PIND & (1 << PD2)) 
  {/* High Pegel */
    g_dcfRegisterFlags[DCFACTIVE] = 1;
  }
  else 
  {/* LOW Pegel */
    g_dcfRegisterFlags[DCFACTIVE] = 0;
  }
  
  if(1 == g_dcfRegisterFlags[DCFACTIVE])
  {
    PORTB |= (1 << PB1);
    if(950 < g_millis)
    {
      startTime = g_millis;
      g_millis = 0;
      g_dcfRegisterFlags[NEWSECOND] = 1;
    }
  }
  else
  {
    PORTB &= ~(1 << PB1);
    if(50 < g_millis)
    {
      activeTime = g_millis;
    }
  }
}

/* Initialisierung von Timer2 für das Aufsammeln der Zeitinformationen
 * @param -
 * @return -
 */
void dcf_timer2_init()
{
  uart_puts_nl("Init dcf_timer2");

  g_millis = 0;
  /* Timer2 in CTC Modus */
  TCCR2 |= (1 << WGM21) | (1 << CS22);
  TCNT2 = 0x00;
  OCR2 = 0xF9;
  /* Compare Match Interrupt aktivieren */
  TIMSK |= (1 << OCIE2);
}

/* Compare Match Interrupt an Timer2 für die Status LED */
ISR(TIMER2_COMP_vect)
{
  ++g_millis;
}

int main(void)
{
  uart_init();
  uart_puts_nl("Start dcf_time_evaluation_2");
  
  dcf_timer2_init();
  dcf_interrupt0_init();
  sei();
    
  /* Status LEDs intialisieren */
  DDRB = 0x02;
  /* DCF Status LED an PB1 */
  PORTB |= (0 << PB1) | (0 << PB0);

  uint16_t duration = 0;
  startTime = 0;
  activeTime = 0;
  

    while (1) 
    {
    if(g_dcfRegisterFlags[NEWSECOND])
    {
      char time[5];
      duration = startTime - activeTime;
      g_dcfRegisterFlags[NEWSECOND] = 0;
      
      /* Zeit für externes Testprogramm umrechnen */
      if(1500>duration)
        duration = 1000 - duration;
        
      itoa(duration, time, 10);
      uart_puts_nl(time);
    }
    }
}

Vielen Dank auch für die Hilfe. Ich habe einige Zeiten ermittelt und 
dabei noch einen weiteren Fehler in meiner Berechnungsroutine gefunden. 
Wäre toll, wenn wir noch die letzte Fragen klären können.

Grüße

Autor: Dev Pap (dev_p)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Abend,
nur um den Beitrag zu vervollständigen. Ich hatte in der Zwischenzeit 
Zugriff zu einem Oszilloskop und konnte sehen, warum mein ursprünglicher 
Code nicht lief. Da war ein kurzer Peak der mir alles durcheinander 
geworfen hat.
Damit ist nun alles geklärt. Konnte mir auch die restlichen offenen 
Fragen beantworten.

: Bearbeitet durch User
Autor: Jakob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, da hast du jetzt hoffentlich gelernt, dass man ein
Programm für die Signale "im echten Leben" immer
Fehler-abwehrend programmiern muss!

Das gilt nicht nur für DCF-Signale, sondern auch (und
besonders) für Eingaben des Benutzers!

Ansonsten sind deine Screenshots auch nicht sehr hilfreich,
da RIGOL es wohl vermeidet, so grundsätzliche Sachen, wie
V/div, oder t/div anzuzeigen.

WO (im DCF-Ablauf) IST DENN DER STÖRPULS?

Was bin ich froh, noch ein Scope mit althergebrachter
Technologie zu besitzen - da wird V/div und t/divs auch im
Screenshot an den PC übermittelt!

Autor: Dev Pap (dev_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jakob schrieb:
> ...
> Ansonsten sind deine Screenshots auch nicht sehr hilfreich,
> da RIGOL es wohl vermeidet, so grundsätzliche Sachen, wie
> V/div, oder t/div anzuzeigen.
>
> WO (im DCF-Ablauf) IST DENN DER STÖRPULS?
>
> Was bin ich froh, noch ein Scope mit althergebrachter
> Technologie zu besitzen - da wird V/div und t/divs auch im
> Screenshot an den PC übermittelt!

Hallo, es war schon sehr hilfreich, dass du mich darauf gestoßen hast. 
Schade um die Screenshots. Ich habe leider auch keine Erfahrung in der 
Bedienung. Der Störimpuls ist vor einer 100 ms oder 200 ms Absenkung die 
Am Anfang der Sekunde liegen. Das DCF Modul liefert ein invertiertes 
Signal. Ich habe dann einen Störimpuls am Ende einer Sekunde. Darauf 
folgt der Puls von 100ms /200ms. Da war mein Interrupt aber schon 
deaktiviert. Aus dieser Misere hast du mir sehr gut geholfen. Ich hoffe 
meine Erklärung ist zu verstehen.

Ich habe mir das so erklären lassen:
Unten links, ist die Anzeige der V/div. Ein Quadrat, vertikal gezählt, 
entspricht einem Volt unterschied. Oben links, neben STOP ist ein H. Das 
markiert die die Zeit die pro Quadrat verstrichen ist. Ich vermute nun 
einfach es steht für horizontal. Das würde dann t/div entsprechen. 
Korrigiere mich ruhig, wenn ich diese Thematik falsch verstehe. Habe 
vorher noch mit keinem Oszilloskop gearbeitet. Wahrscheinlich meinst du 
auch etwas anderes als ich erklärt habe.

Nochmals vielen Dank für deinen Tipp mit der Fehler-Kontrolle. In dem 
Punkt hast du natürlich recht.

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.