C Bitfelder, Structs und Datentypen

  • Friedenstaube
    "Es gibt keinen Weg zum Frieden, denn Frieden ist der Weg." - Mahatma Gandhi

Hemi

Aktives Mitglied
Premium Benutzer
30 Nov 2008
1,101
18
38
Korntal-Münchingen, Germany
Sprachen
  1. ANSI C
  2. C++
  3. PHP
  4. Java
Hallo zusammen,

ich nutze bei meinem aktuellen Projekt für die Konfiguration das TunerStudio. Das ist ein Tool, mit dem die Steuergeräte konfiguriert und appliziert werden. Das ist richtig cool gemacht. Für die Konfiguration wird eine INI-Datei angelegt, in der unter anderen die eigentliche Konfiguration des Steuergerätes beschrieben wird, bei mir sieht sie zum Beispiel so aus:



CodeBox C
    isCANEnabled                = bits, U08, 0, [0:0], "false", "true"
    canSpeed                    = bits, U08, 0, [1:2], "125kbit", "250kbit", "500kbit", "1mbit"
    interfaceActivation         = bits, U08, 0, [3:3], "Input", "CAN"
    isCANDebugEnabled           = bits, U08, 0, [4:4], "false", "true"
    unused1                     = bits, U08, 0, [5:7], "1", "2", "3", "4", "5", "6", "7", "8"
   
    isChannel1Enabled           = bits, U08, 1, [0:0], "false", "true"
    isChannel2Enabled           = bits, U08, 1, [1:1], "false", "true"
    channel1OutputMode          = bits, U08, 1, [2:3], "Analog", "CAN", "Analog & CAN", INVALID
    channel2OutputMode          = bits, U08, 1, [4:5], "Analog", "CAN", "Analog & CAN", INVALID
    channel1AnalogOutputMode    = bits, U08, 1, [6:6], "Wideband", "Narrowband emulation"
    channel2AnalogOutputMode    = bits, U08, 1, [7:7], "Wideband", "Narrowband emulation"

    stoich_ratio                = scalar, U08, 2, ":1", 0.1, 0.0, 0.0, 25.5, 1

    channel1CANid               = bits, U16, 3, [0:10], $CAN_ADDRESS_HEX
    channel2CANid               = bits, U16, 5, [0:10], $CAN_ADDRESS_HEX
    debugMessageID              = bits, U16, 7, [0:10], $CAN_ADDRESS_HEX


Wie man sieht, besteht die Konfig aus drei U08 Bytes (entspricht uint8_t) und zwei U16 (was uint16_t entspricht) Bytes, also insgesamt 9 Byte lang.

Das ist zum Beispiel das Menü um den Byte 0 und 2 zu konfigurieren:

1652378418020.png

Und hier werden Byte 1 und der Rest konfiguriert:

1652378473805.png

Insgesamt umfasst die Konfig 9 Byte im EEPROM der MCU. So weit, so gut. Wenn man jedoch Byte 0 und 1 anschaut, sieht man eigentlich eine Mischung als Bitfelder ( mit der Größe) und ENUM (mit den möglichen Werten, INVALID bedeutet, dass dieser Wert nicht angezeigt wird).

In der MCU ist es wie folgt angelegt:

1. Initialie Konfig:


CodeBox C
uint8_t eeprom_config[] EEMEM = {0x03, 0x03, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

2. Wird beim Start gelesen und in den RAM gepackt:


CodeBox C
uint8_t controllerSettings[sizeof(eeprom_config)];
eeprom_read_block((void*)controllerSettings, (const void*) eeprom_config, sizeof(eeprom_config));

Das funktioniert alles sehr gut.

Nun wird das ganze in einen Struct gepackt:


CodeBox C
typedef struct {
    // first byte in the config:
    uint8_t isCanEnabled : 1;
    uint8_t canSpeed : 2;
    uint8_t interfaceActivation : 1;
    uint8_t isCANDebugEnabled : 1;
    uint8_t unused1 : 3;

    // second byte in the config:
    uint8_t isChannel1Enabled : 1;
    uint8_t isChannel2Enabled : 1;
    uint8_t channel1OutputMode : 2;
    uint8_t channel2OutputMode : 2;
    uint8_t channel1AnalogOutputMode : 1;
    uint8_t channel2AnalogOutputMode : 1;

    // third by in the config:
    uint8_t stoich_ratio;

    uint16_t channel1CANid;
    uint16_t channel2CANid;
    uint16_t debugMessageID;

} tConfig;

tConfig* configuration = (tConfig*)controllerSettings;


Nun kann ich über die Struct-Member auf die Daten zugreifen:


CodeBox C
if (configuration->isCanEnabled == 1)
    {
        uart2_sendS((uint8_t*) "CAN ist enabled\n\r", 17);
    }

Auch das geht.

Wenn man sich jetzt zum Beispiel die Zeile
canSpeed = bits, U08, 0, [1:2], "125kbit", "250kbit", "500kbit", "1mbit"
anschaut, sieht man, dass es eigentlich ein enum mit vier Member ist und im Bitfeld steht dann entsprechend 0x00, 0x01, 0x10 und 0x11 diese vier Werte eben. Wenn ich es jetzt in was "Brauchbares" übersetzen müsste, müsste ich einen enum mit den vier Werten anlegen und das Bitfeld drauf casten:


CodeBox C
typedef enum
{
    can_125
    , can_250
    , can_500
    , can_1000
} tCANSpeed;

.....

    switch ((tCANSpeed) configuration->canSpeed)
    {
        case can_125:
            // mach was
            break;
        case can_250:
            // mach was
            break;
        case can_500:
            // mach was
            break;
        case can_1000:
            // mach was
            break;
    }


Finde ich jetzt ehrlich gesagt nicht so prickelnd....

Gibt es eine elegantere Möglichkeit sowas zu lösen?

Vielen Dank Euch!
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)