Ich versuche, mehrere Werte in ein 32-Bit-Register zu setzen, und jeder Wert hat 2 Bits. Versuchen Sie, dies auf elegante Weise zu tun.
Schreiben Sie jetzt, ich habe so etwas:
struct MuxRegister {
Uint16 PIN1:2;
Uint16 PIN2:2;
...
}
#define LED PIN1 (in a different file of course)
#define PWM PIN2
#define Mux_GPIO 1 (value from 0-3 selects different options)
#define Mux_PWM 3
MuxRegister.LED = Mux_GPIO;
MuxRegister.PWM = Mux_PWM;
...
Und ich möchte etwas tun, bei dem ich nicht jedes MuxRegister.X und MuxRegister.Y für jeden der 16 Pins in der Struktur durchlaufen muss.
Meine Idee war, so etwas zu machen:
#define BIT1 0x00000001
#define BIT2 0x00000002
#define BIT1 0x00000004
#define BIT2 0x00000008
#define LED (BIT1&&BIT2)
#define PWM (BIT3&&BIT4)
MuxRegister |= ((Mux_GPIO && LED) || (Mux_PWM && PWM) || ... ;
Es gibt jedoch keinen Mechanismus, um den Abstand für das Mux-Code-Register (Werte zwischen 0 und 3) über die allererste Position hinaus beizubehalten. Wie in diesem Beispiel ist der Wert für Mux_PWM 0x00000003, aber der Wert für PWM ist 0x0000000C, und sie interagieren überhaupt nicht, da sie sich nicht "überlappen".
Gibt es einen Mechanismus, mit dem die Werte der Mux-Codes verteilt werden können, damit sie mit den richtigen Pin-Werten interagieren? Sorry, wenn ich die Frage nicht gut erkläre. Ich habe nicht viel von der richtigen Terminologie.
Ich würde versuchen, nur ein uint32_t anstelle von Bitfeldern zu verwenden. Folgendes würde ich wahrscheinlich tun:
typedef enum
{
LED,
PWM,
...
} MUX_E;
uint32_t MuxRegister;
void SetMuxOption (uint8_t const option, MUX_E const bits)
{
MuxRegister &= ~(uint32_t) (3 << 2*bits);
MuxRegister |= (uint32_t) (option << 2*bits);
}
Es gibt keine superpräzise, elegante Methode, dies zu tun, die ich kenne. Wenn Sie mehrere Bits setzen möchten, benötigen Sie für jedes Feld mindestens die folgenden Informationen:
Es sieht so aus, als ob Sie den Pins und den Mux-Werten auch funktionale Namen geben möchten. Das sind eine Menge Informationen.
Ehrlich gesagt denke ich, dass Ihr erstes Code-Snippet ein guter Anfang ist. Die Bitfeldstruktur kann die Verschiebungen, Masken und Pinnamen im Strukturtyp codieren, was den Code einigermaßen prägnant macht. Man könnte sich einen Arbeitsschritt sparen, indem man statt PIN1, PIN2 etc. die Bitfelder LED, PWM etc. nennt.
Alternativ können Sie die Codegröße verkleinern, indem Sie ein konstantes Array von Mux-Werten erstellen und diese dann über eine for-Schleife laden:
// P1: LED P2: PWM P3: ADC P4: SW
const Uint32 muxValues[] = {MUX_GPIO, MUX_PWM, MUX_ADC, MUX_GPIO, ... //12 more
MuxRegister = 0x00000000;
for (pin = 0; pin < sizeof(muxValues); pin++)
{
MuxRegister |= muxValues[pin] << 2*pin;
}
Oder du könntest so etwas tun:
MuxRegister = (MUX_LED << 0) | (MUX_PWM << 2) | (MUX_ADC << 4) | (MUX_GPIO << 6) | ...
Sie können Makros verwenden, um die Lesbarkeit zu verbessern:
#define PIN(p) (2 * (p - 1))
MuxRegister = (MUX_LED << PIN(1)) | (MUX_PWM << PIN(2)) | (MUX_ADC << PIN(3)) | (MUX_GPIO << PIN(4)) | ...
Aber ich glaube nicht, dass Sie etwas massiv Kürzeres finden werden. Sie haben sechzehn eindeutige Mux-Auswahlen, und auf die eine oder andere Weise müssen sie alle in Ihren Code passen. Wenn Sie eindeutige Pin-Namen wünschen, sind das weitere sechzehn Werte.
Gewerkschaften können dein Freund sein:
typedef union {
struct {
Uint32 PIN1:2;
Uint32 PIN2:2;
...
} bits ;
Uint32 reg;
} MuxRegister;
Jetzt können Sie wie folgt darauf zugreifen:
MuxRegister muxReg;
...
muxReg.reg = 1234; //As an integer
muxReg.bits.PIN1 = 1; //As bits.
Sie werden feststellen, dass ich die Bitfeldeinträge Uint32 gemacht habe, weil Sie 32-Bit-Register verwenden (nicht sicher, warum Sie sie Uint16 gemacht haben?). Sie sollten auch erwägen, Standardtypen von <stdint.h>
z. B. uint32_t
für eine bessere Portabilität zu verwenden.
Abhängig von Ihrem Compiler und ob er anonyme Strukturen zulässt, können Sie Folgendes tun:
typedef union {
struct {
Uint32 PIN1:2;
Uint32 PIN2:2;
...
};
Uint32 reg;
} MuxRegister;
Auf die zugegriffen werden würde als:
MuxRegister muxReg;
...
muxReg.reg = 1234; //As an integer
muxReg.PIN1 = 1; //As bits.
Gewerkschaften können manchmal ein Problem sein, aber meistens funktionieren sie gut. Meistens liegt das Problem an der Ausrichtung der Wörter, aber das ist ziemlich einfach zu überprüfen. Dieses wirklich nützliche Stück Code ermöglicht es, während der Kompilierung zu überprüfen, ob eine Vereinigung die erwartete Größe hat - normalerweise ändert sich die Größe, wenn die Ausrichtung aus dem Gleichgewicht gerät.
#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
#define ct_assert(a,e) enum { ASSERT_CONCAT(assert_sizeof_, a) = 1/(!!(sizeof(a) == e)) }
Dann können Sie Folgendes tun:
ct_assert(MuxRegister,sizeof(Uint32));
Dadurch wird ein Fehler angezeigt, wenn die Vereinigung kein 32-Bit-Wort ist.
Seien Sie als Nebenbemerkung auch vorsichtig mit Ihren Operatoren.
MuxRegister |= ((Mux_GPIO && LED) || (Mux_PWM && PWM) || ... ;
Das würde das bitweise oder von MuxRegister
mit boolean true oder false tun. Warum? weil Sie logische Operatoren verwenden. (Mux_GPIO && LED)
ergibt entweder wahr, wenn beide Werte ungleich Null sind, oder andernfalls falsch.
Ich denke, was Sie mit dieser Zeile gemeint haben, ist:
MuxRegister |= ((Mux_GPIO & LED) | (Mux_PWM & PWM) | ... ;
Dies verwendet bitweise Operatoren.
Robherc KV5ROB
Lundin
&&
Betreiber ist nicht der&
Betreiber. Ich denke, Sie müssen die Grundlagen sowohl der bitweisen als auch der logischen Operatoren studieren, bevor Sie irgendetwas anderes tun.