Forum: Mikrocontroller und Digitale Elektronik C-Programmierung/DCF77


von programmieren (Gast)


Lesenswert?

Heyho,

ich bin gerade dabei, an einen uController ein DCF77 Empfänger-Modul 
anzuschließen. Das klappt auch alles wunderbar. Über UART(meine 
Debug-Schnittstelle) sehe ich auch, dass ich die Daten richtig empfangen 
habe. Nur der entsprechende C-Code dazu schaut "schrecklich" aus. Gibt 
es irgendwelche Tipps, wie man den vereinfach könnte?

DCF77 sendet in 1min 59Bits, die ich in ein Array(dcf77_rx[59)] 
speichere.
Um jetzt z.B. die Parity-Bits bzw. feste Bitwerte zu überprüfen, ob ich 
alles Richtig empfangen habe, schaut mein Code so aus:
1
if((dcf77_rx[0] == 0) && (((dcf77_rx[29]+dcf77_rx[30]+dcf77_rx[31]+dcf77_rx[32]+dcf77_rx[33]+dcf77_rx[34]+dcf77_rx[35]) % 2) == 0) && (((dcf77_rx[21]+dcf77_rx[22]+dcf77_rx[23]+dcf77_rx[24]+dcf77_rx[25]+dcf77_rx[26]+dcf77_rx[27]+dcf77_rx[28]) % 2) == 0) && (dcf77_rx[20] == 1))
2
    {

Oder um das Datum(BCD-Codiert) in Dezimalzahl umzuwandeln
1
date_day = dcf77_rx[36] + 2*dcf77_rx[37] + 4*dcf77_rx[38]+ 8*dcf77_rx[39] + 10*dcf77_rx[40] + 20*dcf77_rx[41];

Kann man das irgendwie vereinfacht/leserlicher schreiben/darstellen?

von Jim M. (turboj)


Lesenswert?

programmieren schrieb:
> Kann man das irgendwie vereinfacht/leserlicher schreiben/darstellen?

Ja, man kann.

von Tom (Gast)


Lesenswert?

Als ersten Schritt: Berechnungen packt man jeweils in eine eigene 
Funktion, die man einmal erstellt und testet und danach (aus den Augen, 
aus dem Sinn) nur benutzt und die im Programmverlauf nicht stört, auch 
wenn sie intern etwas kompilzierter ist.
1
bool dcf_is_ok(const uint8_t[] buf)
2
{
3
    if ( (buf[0] != 0) || (buf[20] != 1) )
4
        return false;
5
    {
6
        uint8_t tmpsum_a = buf[21] + buf[22] + buf[23] + buf[24] + buf[25] + buf[26] + buf[27] + buf[28];
7
        if (tmpsum_a % 2 != 0)
8
            return false;
9
    }
10
    {
11
        uint8_t tmpsum_b = buf[29] + buf[30] + buf[31] + buf[32] + buf[33] + buf[34] + buf[35];
12
        if (tmpsum_b % 2 != 0)
13
            return false;
14
    }
15
    return true;
16
}
17
18
19
uint8_t calc_day(const uint8_t[] buf)
20
{
21
    uint8_t ones = buf[36] + 2 * buf[37] + 4 * buf[38]+ 8 * buf[39];
22
    uint8_t tens = buf[40] + 2 * buf[41];
23
    return ones + 10 * tens;
24
}
25
26
27
if(dcf_is_ok(dcf77_rx))
28
{
29
    date_day = calc_day(dcf77_rx);
30
}

Gleich werden die Optimierer kommen und wild Bytes sparen...

von Michael B. (laberkopp)


Lesenswert?

programmieren schrieb:
> Kann man das irgendwie vereinfacht/leserlicher schreiben/darstellen?
Tom schrieb:
> Berechnungen packt man jeweils in eine eigene Funktion

Eine Funktion ist gut, WENN man sie mehrmals aufruft.
Deine Funktionen sind Unsinn weil zu hoch spezialisiert.
dcf77_rx (Arrayanfangspointer) als Parameter zu übergeben
ist Quatsch weil als globale Adresse immer gleich, es
gibt keine zweite.

Wenn man ein sinnvolles Programm haben will, erfindet man z.B. eine 
Funktion
1
uint8_t bitvalue(uint8_t firstbit,uint8_t n)
2
{
3
  uint8_t value=0;
4
  while(n--) value=(value<<1)|dcf77_rx[firstbit+n];
5
  return value;
6
}
die kann man dann überall aufrufen, wo man aus dem bitstram Daten 
entnehmen will.
1
day=bitvalue(36,4)+10*bitvalue(40,2);
oder für Parity
1
uint8_t bitparity(uint8_t firstbit,uint8_t n)
2
{
3
  uint8_t value=0;
4
  while(n--) value^=dcf77_rx[firstbit++];
5
  return value;
6
}
7
8
valid=!dcf77_rx[0]&&dcf77_rx[20]&&!bitparity(21,8)&&!bitparity(29,7);

von Markus M. (adrock)


Lesenswert?

Michael B. schrieb:

> Eine Funktion ist gut, WENN man sie mehrmals aufruft.

Das kann man so alleine nicht stehenlassen. Aus Gründen der 
Übersichtlichkeit lagert man ja auch Programmteile in Funktionen aus, 
die nur einmal aufgerufen werden.

> Deine Funktionen sind Unsinn weil zu hoch spezialisiert.

Naja, Unsinn nicht, aber sie könnte weiter verbessert werden wenn sie 
die universelle Funktion von Dir aufrufen würde. Auch würde ich dennoch 
den Pointer zum Buffer übergeben, selbst wenn er in diesem Fall eine 
globale Variable ist. Vlt. schreibt er ja das Programm später um und der 
Buffer ist dann nur noch lokal (z.B. wenn er alles im Interrupt macht).

von A. S. (Gast)


Lesenswert?

Tom schrieb:
> kommen und wild Bytes sparen...

Bytes sparen wäre hier Dummheit.
Zeilen sparen, wie im UP ebenso.
Das einzige, was hier zählt ist Lesbarkeit. Also sinnvolle Namen, 
Formatierung, verständliche Operationen. Für Anfänger ist massives 
"eigene Funktion draus machen" manchmal klarer zu strukturieren.. Je 
lesbarer der Code mit Erfahrung wird, umso weniger ist das sinnvoll.

von Architekt (Gast)


Lesenswert?

Michael B. schrieb:
> Eine Funktion ist gut, WENN man sie mehrmals aufruft.

Die Vermeidung von Redundanz ist einer der Gründe, Funktionen zu 
schreiben (oft sicher auch der wichtigste und "einsichtigste"). Andere 
Gründe sind z.B. Lesbarkeit und Testbarkeit.

von Peter D. (peda)


Lesenswert?

Man muß die Bits nicht erst umständlich speichern, sondern kann sie 
direkt in knallharter Echtzeit (1Bit/s) auswerten. Am einfachsten geht 
das über eine Tabelle, die auf Byteadresse und Bitwertigkeit zeigt:

Beitrag "DCF77 Uhr in C mit ATtiny26"

Auch sollte man eine interne Uhr mitlaufen lassen, damit man bei 
Empfangsstörungen nicht im Regen steht.

von A. S. (Gast)


Lesenswert?

Architekt schrieb:
> Andere Gründe sind z.B. Lesbarkeit und Testbarkeit.

Genau hier entfacht sich ja der Streit, wohl unauflöslich, bei 
einmaligen Aufgaben:

Lesbarkeit: Der eine navigiert lieber über Listen von Anweisungen, der 
andere über Listen von Links.

Testbarkeit: Der eine favorisiert Unit-Test auf Einzeilern, dem anderen 
sind Test auf höheren Ebenen wichtig.

Das "gesunde Maß" hängt natürlich von Art und Umfang der Projekte ab. 
Für akademische Beispiele sind einzeiler-Funktionen immer positiv, bei 
größeren Projekten selbst in relativ kleiner Zahl tödlich.

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.