Hi Leute, folgendes struct/union habe ich angelegt:
1
// DCF77 Data Struct
2
typedefstructDCF77_DATA_STREAM_struct
3
{
4
union{
5
6
unsignedlonglongintRaw_Stream;
7
8
struct{
9
unsignedintMinute_Mark:1;// LSB of Long_Int_Def
10
unsignedintBBK_Meteo:14;
11
unsignedintR:1;
12
unsignedintA1:1;
13
unsignedintZ1:1;
14
unsignedintZ2:1;
15
unsignedintA2:1;
16
unsignedintS:1;
17
unsignedintMin_Ones:4;
18
unsignedintMin_Tens:3;
19
unsignedintMin_Par:1;
20
unsignedintHour_Ones:4;
21
unsignedintHour_Tens:2;
22
unsignedintHour_Par:1;
23
unsignedintDay_Ones:4;
24
unsignedintDay_Tens:2;
25
unsignedintWeekday:3;
26
unsignedintMonth_Ones:4;
27
unsignedintMonth_Tens:1;
28
unsignedintYear_Ones:4;
29
unsignedintYear_Tens:4;
30
unsignedintDate_Par:1;
31
unsignedintNo_Mark:1;
32
unsignedint:4;
33
};
34
};
35
}DCF77_DATA_STREAM;
Wenn ich nun mit "sizeof" die Größe bestimme erhalte ich 10 Bytes,
obwohl sowhl unsigned long long int 8 Bytes groß sein müsste, als auch
das gesamte Bitfeld. Wo is'n da der Fehler???
Hinweis: MPLAB C30
Michael S. schrieb:> Hi Leute, folgendes struct/union habe ich angelegt:
Dem Compiler steht es frei zwischen die einzelnen Teile eines struct
noch zusätzliche Padding Bytes einzufügen um zb irgendwelche
Alignment-Anforderungen zu erfüllen. Und das wird er wohl getan haben
Und damit sind dann Bitfelder in Strukturen gleich gar nicht mehr so
elegant wie ursprünglich gedacht.
Schreib dir Zugriffsfunktionen um dir aus dem ull mit den DCF Daten die
relevanten Bits zu extrahieren und zurecht zu schieben. Was anderes
macht der Compiler ja auch nicht.
Michael S. schrieb:> Wenn ich nun mit "sizeof" die Größe bestimme erhalte ich 10 Bytes,> obwohl sowhl unsigned long long int 8 Bytes groß sein müsste, als auch> das gesamte Bitfeld. Wo is'n da der Fehler???
Das Problem ist wohl, dass Deine Bits - wenn man sie von oben nach unten
zusammenzählt - nicht immer genau in 16-Bit-Integer reinpassen. Dann
muss der Compiler Padding-Bits einfügen, damit sowas wie
unsigned int Min_Ones :4 ;
nicht auf zwei Integers aufgesplittet werden muss.
Ich finde Bitfelder höchst unportabel. Ich würde an Deiner Stelle davon
Abstand nehmen.
Im DCF-Signal gibt es doch nur 59 Bits. Was liegt näher, erstmal den
ganzen Frame in eine 64bit Variable reinzutakten und mit Maskieren und
geeignetem Schieben die Einzelinformationen zu extrahieren?
mfg mf
Hallo, ich habe ähnliches vor.
Bei mir ist es eine 32bit Zahl die ich zerstückeln möchte.
Der Code ist mit dem von Michael identisch.
Funktioniert leider nicht. Hat jemand eine Ahnung woran das liegt?
Verwende ebefalls den C30.
Gruß Max
Mini Float schrieb:> Im DCF-Signal gibt es doch nur 59 Bits. Was liegt näher, erstmal den> ganzen Frame in eine 64bit Variable reinzutakten und mit Maskieren und> geeignetem Schieben die Einzelinformationen zu extrahieren?
Warum sollte man diesen hohen Aufwand treiben?
Die Bit kommen mit ner Wahsinns-Geschwindigkeit von einem Baud rein. Da
hat man alle Zeit der Welt, die sofort auszuwerten. Dann wird der Code
auch sehr schön klein und übersichtlich.
Hier ein Beispiel für die Auswertung in "Echtzeit":
Beitrag "DCF77 Uhr in C mit ATtiny26"
Peter
Max Pohl schrieb:> In meinem Fall geht dies leider nicht.
Warum nicht?
Es ist egal, wo die Bits herkommen.
Es ist einfacher, wenn es eine Regel gibt, was die Bits bedeuten.
Ansonsten nimmt man eben ein Switch mit 32 Case.
Peter
Ich bekomme per SPI zwei 16bit Werte, diese kann ich nur als ganze Zahl
aus dem Eingangspuffer nehmen. Dann muss ich diese 32bit Zahl wie oben
gezeigt aufspliten um damit weiter arbeiten zu können.
Hallo,
Frank M. hat das Problem ja schon genannt. Deine Felder schneiden nicht
exakt an den int Grenzen. Wenn Du jetzt trotzdem Bitfelder benutzen
willst, musst Du eben Teilfelder bilden, z.B.
unsigned int Hour_Ones :4 ;
wird aufgesplittet in
unsigned int Hour_Ones_a :2 ;
unsigned int Hour_Ones_b :2 ;
und dann wieder bei der Auswertung zusammensetzen:
unsigned int Hour_Ones = (x.Hour_Ones_b << 2) | x.Hour_Ones_a;
Gruß,
Andreas
Max Pohl schrieb:> Ich bekomme per SPI zwei 16bit Werte, diese kann ich nur als ganze Zahl> aus dem Eingangspuffer nehmen. Dann muss ich diese 32bit Zahl wie oben> gezeigt aufspliten um damit weiter arbeiten zu können.
Das gleiche hier: Bis unsigned int empty:2; sinds 10bit
Dann müssen die Daten eben in 6 und 10 bit geteilt werden
Alternativ auf 32bit alignen (compiler option), das kostet aber size
(also nicht so praktikabel)
Vielen Dank Andreas das wars, jetzt geht alles.
Ich bin noch recht neu bei der C Programmierung mit C30 was ist dieses
Alignment? Ich brauche maximale Geschwindigkeit wenn deswegen etwas mehr
Speicher für dies verlogen geht ist mir das recht egal, solange es
schneller geht.
Max Pohl schrieb:> Eine struct müsste doch wesentlich schneller sein oder etwa nicht?
Nur wenn die CPU spezielle Bitbefehle hat und der Compiler diese auch
unterstützt.
Ansonsten sind Bit-Structs deutlich langsamer und erzeugen größeren Code
als alles andere.
C ist für Bytes und größer optimiert.
Peter
Max Pohl schrieb:> Eine struct müsste doch wesentlich schneller sein oder etwa nicht?
Du meinst eine struct, die auf Bitfields beruht? Man kann jede
Bitfiled-Präsentation bzw. -Operation auch "per Hand" in C machen. Peter
Dannegger hat es Dir oben gezeigt wie. Bitfields sind vielleicht für den
Programmierer etwas "bequemer", aber letztendlich macht der Compiler
beim Bitfriemeln nichts anderes als Du selbst mit Maskieren und
Schieben, um die entsprechenden Daten zu extrahieren.
Fazit: Von der Geschwindigkeit/Codegröße ist es kaum ein Unterschied
(tatsächlich sind Bitfields sogar oft "schlechter"). Dabei sind
Bitfields auch noch höchst unportabel. Nicht machen.
Hallo Max,
es gibt beim gcc zwei Options in dieser Richtung: -fpack-struct und
-funsigned-bitfields.
IMHO wird aber sowieso auf 16bit aligned. Ich würde jetzt mal probieren,
ob
1
typedefunionGYRODATA
2
{
3
uint32_tData;
4
struct
5
{
6
uint32_tP1:1;
7
uint32_tCHK:1;
8
uint32_tCST:1;
9
uint32_tPWR:1;
10
uint32_tPOR:1;
11
uint32_tNVM:1;
12
uint32_tQ:1;
13
uint32_tPLL:1;
14
uint32_tempty:2;
15
uint32_tDaten:16;
16
uint32_tST:2;
17
uint32_tP0:1;
18
uint32_tSQ:3;
19
};
20
}GYRO1;
nicht auch funktioniert.
Beim gcc geht folgendes:
-funsigned-bitfields macht
Make any unqualified bitfield type unsigned. By default, they are
signed.
In dem obigen Fall müsste es aber gehen.
Und -fpack-struct bewirkt
Pack all structure members together without holes.
Kann nicht schaden.
Dem -fpack-struct kann man IMHO noch ein '=N', Potenzu von 2 mitgeben,
als packsize.
Ich würds aber trotzdem mal so wie oben probieren, ohne Options.
MoinMoin,
ich hatte auch mal eine DCF77-Uhr
(Beitrag "DCF77-TWI(I2C)-Slave") geschrieben. Da habe ich
auch einen solchen "Bit-Struct" verwendet, der aber etwas anders
aussieht:
1
volatile union dcf_t {
2
struct {
3
uint8_t b[8];
4
} bits;
5
struct {
6
unsigned start_mm : 1; // Bit 0
7
unsigned meteotime : 14;// Bit 1...14
8
unsigned ruf_bit : 1; // Bit 15
9
unsigned mez2mesz : 1; // Bit 16
10
unsigned mez : 1; // Bit 17
11
unsigned mesz : 1; // Bit 18
12
unsigned switch_ss : 1; // Bit 19
13
unsigned begin_time: 1; // Bit 20
14
unsigned mm : 7; // Bit 21...27
15
unsigned p_mm : 1; // Bit 28
16
unsigned hh : 6; // Bit 29...34
17
unsigned p_hh : 1; // Bit 35
18
unsigned dd : 6; // Bit 36...41
19
unsigned wd : 3; // Bit 42...44
20
unsigned mt : 5; // Bit 45...49
21
unsigned yy : 8; // Bit 50...57
22
unsigned p_date : 1; // Bit 58
23
unsigned click : 1; // Bit 59 (Merker, ob neue Sekunde)
24
unsigned valid : 2; // Bit 60...61 ("Zeitermittlungsgrad" 2=OK)
25
unsigned reserve : 2; // 2 Bit Reserve
26
} dat;
27
} dcf_temp;
Unterschied zur Ausgangsfrage ist das:
1
struct {
2
uint8_t b[8];
3
} bits;
Ich fand damals (und auch heute) keine schlechte Sache, denn damit ist
dann z.B. soetwas möglich, da es sich ja eigentlich in den
DCF77-Informationen um BCD-Codierung handelt (was die Uhrzeit betrifft):
1
dcf77.mm = bcd2dec(dcf_temp.dat.mm);
2
dcf77.hh = bcd2dec(dcf_temp.dat.hh);
3
dcf77.dd = bcd2dec(dcf_temp.dat.dd);
4
dcf77.mt = bcd2dec(dcf_temp.dat.mt);
5
dcf77.yy = bcd2dec(dcf_temp.dat.yy);
6
dcf77.wd = bcd2dec(dcf_temp.dat.wd);
7
dcf77.mez = dcf_temp.dat.mez;
8
dcf77.mesz = dcf_temp.dat.mesz;
Auch das Reinschieben der Daten ist relativ elegant lösbar:
1
dcf_temp.bits.b[(idx/8)] |= 1 << (idx % 8);
wobei idx ein fortlaufender Index ist...
Grüße Uwe
PS.:
Peter Dannegger schrieb:> Ansonsten sind Bit-Structs deutlich langsamer und erzeugen größeren Code> als alles andere.>
aber es sieht schöner und eleganter aus, finde ich :-)
Da ist kein Compilerschalter nötig, das lässt sich per Attribut machen.
Wenn ich das im Manual vom C30 richtig sehe, sollte das auch dort
klappen:
1
typedefunionGYRODATA
2
{
3
longData;
4
struct__attribute__((__packed__))
5
{
6
unsignedintP1:1;
7
unsignedintCHK:1;
8
unsignedintCST:1;
9
unsignedintPWR:1;
10
unsignedintPOR:1;
11
unsignedintNVM:1;
12
unsignedintQ:1;
13
unsignedintPLL:1;
14
unsignedintempty:2;
15
unsignedintDaten:16;
16
unsignedintST:2;
17
unsignedintP0:1;
18
unsignedintSQ:3;
19
};
20
}GYRO1;
Nur schneller ist der Zugriff nicht, er wird langsamer besonders da
"Daten" über 3 Bytes verstreut wird und bei jedem Zugriff diese 3 Bytes
maskiert werden müssen.
Uwe Berger schrieb:> Ich fand damals (und auch heute) keine schlechte Sache, denn damit ist> dann z.B. soetwas möglich, da es sich ja eigentlich in den> DCF77-Informationen um BCD-Codierung handelt (was die Uhrzeit betrifft):> dcf77.mm = bcd2dec(dcf_temp.dat.mm);> dcf77.hh = bcd2dec(dcf_temp.dat.hh);> dcf77.dd = bcd2dec(dcf_temp.dat.dd);> dcf77.mt = bcd2dec(dcf_temp.dat.mt);> dcf77.yy = bcd2dec(dcf_temp.dat.yy);> dcf77.wd = bcd2dec(dcf_temp.dat.wd);
Ja, die BCD-Kodierung hat mich auch gestört, ne CPU rechnet ja lieber
binär.
Deshalb lese ich direkt binär ein, d.h. jedes Bit addiert gleich seinen
richtigen Wert (1,2,4,8,10,20,40,80).
Eine nachträgliche Umkodierung ist nicht mehr nötig.
Ein Grund ist allerdings auch, daß der der AVR-GCC long long nur
grauslig schlecht implementiert, sodaß es nicht mehr in den ATtiny26
paßt.
Ist schon ein Unterschied, ob man etwas mit 5KB Code implementiert oder
nur mit knapp über 100 Byte.
Peter
Mein DCF77 läuft in der Zwischenzeit auch zuverlässig.
Wenn ihr allerdings gleich beim EMpfang die richtigen Werte jedes
empfangenen Bits addiert, wartet ihr dann beim EInschalten auf den
Minutemarker? Geht ja kaum anders oder?
Michael S. schrieb:> Wenn ihr allerdings gleich beim EMpfang die richtigen Werte jedes> empfangenen Bits addiert, wartet ihr dann beim EInschalten auf den> Minutemarker?
Das ergibt sich automatisch, da ich nur Pakete akzeptiere, die genau 59
Pulse lang sind. Störungen sind ja asynchron, d.h. entweder die Störung
überdeckt Pulse oder erzeugt zusätzliche Pulse.
Auch braucht der Empfänger erstmal mehrere Impulse, um die Verstärkung
einzuregeln.
Peter