Forum: Mikrocontroller und Digitale Elektronik Unterstützung C Code + union


von Zo R. (hsch1978)


Lesenswert?

Hallo und guten Morgen,

für meine Mikrocontroller Anwendung habe ich folgendes Problem 
vorliegen:

Ich habe als Eingangsparameter ein union. Dieses union besteht aus 8 Bit 
(uint8_t). Jedes Bit steht für ein bestimmtest Symbol.
Nun soll dieser union Wert verwendet werden, um die entsprechenden 
Symbole auf dem Display darzustellen.
1
typedef union
2
{
3
  uint8_t rawByte;
4
  struct
5
  {
6
    uint8_t date : 1;
7
    uint8_t warning : 1;
8
    uint8_t lowBattery : 1;
9
    uint8_t temp : 1;
10
    uint8_t pressure : 1;
11
  }st_displaySymbols;
12
}un_displaySymbols;

Für die Darstellung eines Symbols wird eine Funktion verwendet:
1
typedef enum
2
{
3
  DISPLAY_SYMBOL_DATE,
4
  DISPLAY_SYMBOL_WARNING,
5
  DISPLAY_SYMBOL_LOW_BATTERY,
6
  DISPLAY_SYMBOL_TEMP,
7
  DISPLAY_SYMBOL_PRESSURE,
8
} en_displaySymbols;
1
void Display_SetSymbol(en_displaySymbols symbol, bool on)

von Adam P. (adamap)


Lesenswert?

Und was ist jetzt deine Frage?

von Wilhelm M. (wimalopaan)


Lesenswert?

Und wo ist das Problem?

von Bruno V. (bruno_v)


Lesenswert?

Ein Switch-Case über alle Elemente:
1
   switch(symbol)
2
   {
3
   case DISPLAY_SYMBOL_DATE: if(symbol.date) {...} else {...} break;
4
   case DIS...
5
   }

: Bearbeitet durch User
von Sebastian R. (sebastian_r569)


Lesenswert?

Joa. Kann man so machen.

von Bruno V. (bruno_v)


Lesenswert?

symbol.date --> union_symbol.st_displaySymbols.date

von Zo R. (hsch1978)


Lesenswert?

Ist schwer das zu formulieren. Ich versuche es mal.
Ich erhalte einen 8 Bit Wert. In diesen 8 Bits entspricht dann jedem Bit 
ein bestimmtes Symbol. Nun soll in der Weiterverarbeitung die Symbole 
auf das Display angezeigt werden. Ein einzelnes Symbol zu aktivieren auf 
dem Display ist kein Problem. Wenn ich aber einen 8 Bit Wert habe, wo 
jedes Bit einem Symbol entspricht, das bereitet mir Probleme wie ich das 
in Software umsetzen könnte.

Beispiel:
uin8_t = 0xA0 ==> bit: 1010 0000

Hier soll das entsprechende Symbol von der Bitstelle 7 und auch von der 
Bitstelle 5 auf dem Display dargestellt werden. Alle anderen Symbol 
sollen nicht angezeigt werden.

von Peter D. (peda)


Lesenswert?

Das Problem bei Bit-structs ist, die Order ist nicht eindeutig 
definiert.
Daher bevorzugt man oft Bitmasken (0x01, 0x02, .. 0x80).
Und wenn man nicht wirklich mit RAM knausern muß, nimmt man für jedes 
Bit einfach ein Byte.
1
uint8_t batt_status[5];

von Oliver S. (oliverso)


Lesenswert?

He S. schrieb:
> Wenn ich aber einen 8 Bit Wert habe, wo
> jedes Bit einem Symbol entspricht, das bereitet mir Probleme wie ich das
> in Software umsetzen könnte.

https://www.mikrocontroller.net/articles/Bitmanipulation#Standard-C_4

Oliver

von Zo R. (hsch1978)


Lesenswert?

Danke.

Ich würde es trotzdem gerne irgendwie mit switch case lösen.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

He S. schrieb:
> Ich würde es trotzdem gerne irgendwie mit switch case lösen.

Dann such dir halt eine passende Programmiersprache, in der du das 
kannst.

Oliver

von Adam P. (adamap)


Lesenswert?

He S. schrieb:
> Ich würde es trotzdem gerne irgendwie mit switch case lösen.

Wird so nicht möglich sein.
Ausser du machst eine switch case mit 256 cases. Aber das macht man so 
nicht und auf die Idee würde auch keiner kommen.

Prüfe das jeweilige Bit und gut ist.

von Peter D. (peda)


Lesenswert?

He S. schrieb:
> Ich würde es trotzdem gerne irgendwie mit switch case lösen.

Das geht nicht.
Switch/Case kann immer nur eine Auswahl treffen, d.h. es darf immer nur 
ein Bit gleichzeitig gesetzt sein.

von Wilhelm M. (wimalopaan)


Lesenswert?

He S. schrieb:
> Hallo und guten Morgen,
>
> für meine Mikrocontroller Anwendung habe ich folgendes Problem
> vorliegen:
>
> Ich habe als Eingangsparameter ein union. Dieses union besteht aus 8 Bit
> (uint8_t). Jedes Bit steht für ein bestimmtest Symbol.
> Nun soll dieser union Wert verwendet werden, um die entsprechenden
> Symbole auf dem Display darzustellen.

Evtl. so:
1
     un_displaySymbols v = ...;
2
     Display_SetSymbol(DISPLAY_SYMBOL_DATE, v.st_displaySymbols.date == 1); 
3
     Display_SetSymbol(DISPLAY_SYMBOL_WARNING, v.st_displaySymbols.warning);
4
     // ...

Ich nehme an, dass Du immer einen vollständige Zustandsupdate benötigst.


Ich hoffe, dir ist bewusst, dass das Dekodieren einer Leitungscodierung 
mit Hilfe einer union ein wenig gute Idee ist.

Du kannst den Namen der struct in der union auch weglassen, dann geht es 
eleganter:
1
     un_displaySymbols v = ...;
2
     Display_SetSymbol(DISPLAY_SYMBOL_DATE, v.date == 1); 
3
     Display_SetSymbol(DISPLAY_SYMBOL_WARNING, v.warning);
4
     // ...

: Bearbeitet durch User
von Zo R. (hsch1978)


Lesenswert?

Hallo Wilhelm was meinsrt du mit ohne struct?

von Wilhelm M. (wimalopaan)


Lesenswert?

He S. schrieb:
> Hallo Wilhelm was meinsrt du mit ohne struct?

Den Namen(!) des struct weglassen, wie geschrieben. Also so:
1
typedef union
2
{
3
  uint8_t rawByte;
4
  struct
5
  {
6
    uint8_t date : 1;
7
    uint8_t warning : 1;
8
    uint8_t lowBattery : 1;
9
    uint8_t temp : 1;
10
    uint8_t pressure : 1;
11
  };
12
}un_displaySymbols;

P.S.: Der Präfix "un_" ist unnötig im Typ-Namen.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

He S. schrieb:
> Ich würde es trotzdem gerne irgendwie mit switch case lösen.

Kein Problem. Prüfe immer das letzte gesetzte Bit ( (n&~(n-1)) , 
"position of rightmost bit"), mache eine Schleife über die Switch-Case 
und lösch am Ende des Schleifendurchlaufs die schon behandelten Bits.

von Peter D. (peda)


Lesenswert?

Walter T. schrieb:
> mache eine Schleife über die Switch-Case

Quasi nen Knopf an die Backe nähen.

von Oliver S. (oliverso)


Lesenswert?

Peter D. schrieb:
> Walter T. schrieb:
>> mache eine Schleife über die Switch-Case
>
> Quasi nen Knopf an die Backe nähen.

.. und sich dabei dann von hinten durch die Brust ins Auge und dann ins 
Knie schießen.

Oliver

von Walter T. (nicolas)


Lesenswert?

Peter D. schrieb:
> Quasi nen Knopf an die Backe nähen.

Jupp. Wobei ich das weniger sinnlos auch schon für einen primitiven 
priorisierten Scheduler genau so gemacht habe.

Aber der TO wollte doch unbedingt Switch/Case!

 Es würde mich noch nicht einmal wundern, wenn der Optimizer daraus 
durch loop unrollig wieder eine Reihe von if( byte & (1<<bit) ){} machen 
würde.

von Monk (Gast)


Lesenswert?

He S. schrieb:
> Ich würde es trotzdem gerne irgendwie mit switch case lösen.

Switch/case benutzt man für entweder/oder Szenarien. Bei dir können aber 
mehrere Flags gleichzeitig an sein.

von Zo R. (hsch1978)


Lesenswert?

Ich habe es ohne switch/case realisiert. Ich übergebe der Funktion den 
Wert von der union.
1
typedef union
2
{
3
  uint8_t rawByte;
4
  struct
5
  {
6
    uint8_t date : 1;
7
    uint8_t warning : 1;
8
    uint8_t lowBattery : 1;
9
    uint8_t temp : 1;
10
    uint8_t pressure : 1;
11
  };
12
}un_displaySymbols;
13
14
un_displaySymbols displaySymbols;
15
16
displaySymbols = incomming_data;
17
18
Display_SetSymbol(DISPLAY_SYMBOL_DATE, displaySymbols.date);
19
Display_SetSymbol(DISPLAY_SYMBOL_WARNING, displaySymbols.warning);
20
...
21
...

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

He S. schrieb:
> Ich habe es ohne switch/case realisiert.

Das ist die Lösung, die ich oben beschrieben habe.

> Ich übergebe der Funktion den
> Wert von der union.

Nicht ganz: Du benutzt eine impl. Typkonversion.

Es ist besser, wenn die Elemente des struct, die ja eigentlich Bool'sch 
sind, auch als solche deklariert werden.

Und wie gesagt: die Namen Deine DT sind Mist.

He S. schrieb:
> un_displaySymbols displaySymbols;
> displaySymbols = incomming_data;

Das schreibt man so:
1
const un_displaySymbols displaySymbols = incomming_data;

Ich denke, Dir ist dann auch klar, warum.

von Harry L. (mysth)


Lesenswert?

Ich würde das so machen:
1
#define USED_BITS  5
2
3
// Bit 0
4
void date(uint8_t val)
5
{
6
7
}
8
9
// Bit 1
10
void warning(uint8_t val)
11
{
12
13
}
14
15
// Bit 2
16
void lowBattery(uint8_t val)
17
{
18
19
}
20
21
// Bit 3
22
void temp(uint8_t val)
23
{
24
25
}
26
27
// Bit 4
28
void pressure(uint8_t val)
29
{
30
31
}
32
33
const void (*func[USED_BITS])(uint8_t val) =
34
{
35
  date,
36
  warning,
37
  lowBattery,
38
  temp,
39
  pressure
40
};
41
42
process_RawByte(uint8_t byte)
43
{
44
  for (int i = 0; i < USED_BITS; i++)
45
  {
46
    func[i](byte & 1);
47
    byte = byte >> 1;
48
  }
49
}

: Bearbeitet durch User
von Zo R. (hsch1978)


Lesenswert?

Hallo Wilhelm M.,

wie kann ich die union mit boolsche Werte verändern?

von Wilhelm M. (wimalopaan)


Lesenswert?

He S. schrieb:
> Hallo Wilhelm M.,
>
> wie kann ich die union mit boolsche Werte verändern?

Du änderst den DT der Elemente von uint8_t zu bool.

von Zo R. (hsch1978)


Lesenswert?

1
typedef union
2
{
3
  uint8_t rawByte;
4
  struct
5
  {
6
    bool date;
7
    bool warning;
8
    bool lowBattery;
9
    bool temp;
10
    bool pressure;
11
  };
12
}un_displaySymbols;

Das mit bool lässt der Compiler zu. Nur das mit der uint8_t Variable 
funktioniert nicht mehr. Diese ist aber schon für mich notwendig.

: Bearbeitet durch User
von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

He S. schrieb:
> Nur das mit der uint8_t Variable
> funktioniert nicht mehr.

Achtung, C kennt keine echten Bit-Typen. Ein "bool" wird intern als 
"int" verarbeitet. Je nach System hast du jetzt also "5 x 16Bit" oder "5 
x 32Bit".

von Wilhelm M. (wimalopaan)


Lesenswert?

He S. schrieb:
> Das mit bool lässt der Compiler zu. Nur das mit der uint8_t Variable
> funktioniert nicht mehr. Diese ist aber schon für mich notwendig.

Geht mit >= C11. Du solltest ggf. den C-Standard angeben mit -std=c11 
oder c17 oder c23.

Nennt sich unnamed Union member.

von Zo R. (hsch1978)


Lesenswert?

Ok diesen Standard nutzen wir nicht.

Wir nutzen ISO C99.

von Peter D. (peda)


Lesenswert?

Der AVR-GCC reserviert für bool Variablen 1 Byte.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Irgend W. schrieb:
> Achtung, C kennt keine echten Bit-Typen.

Eben. Das noch kombiniert mit Bitfeldern, welche in C weder 
plattformkapatibel noch sonstwas sind, setzt dem Ganzen noch die Krone 
auf. Man handelt sich ein Problem nach dem nächsten ein.

Meines Erachtens sind Bitfelder in C überflüssig. Man kann das auch 
klassisch aufziehen:
1
uint8_t symbol_mask;
2
3
#define DISPLAY_SYMBOL_DATE_MASK            0x01
4
#define DISPLAY_SYMBOL_WARNING_MASK         0x02
5
#define DISPLAY_SYMBOL_LOW_BATTERY_MASK     0x04
6
#define DISPLAY_SYMBOL_TEMP_MASK            0x08
7
#define DISPLAY_SYMBOL_PRESSURE_MASK        0x10

Rest siehe auch Artikel Bitmanipulation.

: Bearbeitet durch Moderator
von Wilhelm M. (wimalopaan)


Lesenswert?

He S. schrieb:
> Ok diesen Standard nutzen wir nicht.
>
> Wir nutzen ISO C99.

Wir???? Das alles hört sich sehr nach Hobbygekruschtel an...

Na dann, Gib dem struct wieder einen Namen...

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:
> Das noch kombiniert mit Bitfeldern, welche in C weder plattformkapatibel
> noch sonstwas sind, setzt dem Ganzen noch die Krone auf. Man handelt
> sich ein Problem nach dem nächsten ein.

Das habe ich ihm schon gaaaanz oben gesagt. Er hat es ignoriert.

von Harry L. (mysth)


Lesenswert?

He S. schrieb:
> Nur das mit der uint8_t Variable
> funktioniert nicht mehr. Diese ist aber schon für mich notwendig.

Dann mach es doch so, wie ich das gestern bereits vorgeschlagen hab:
Beitrag "Re: Unterstützung C Code + union"

Viel eleganter wirst du das in klassischem C kaum hinbekommen.

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.