Können einzelne Pins verschiedener Ports eines Mikrocontrollers einem Register zugeordnet und ihre Werte geändert werden, wenn der Registerwert geändert wird?

F: Können einzelne Pins verschiedener Ports eines Mikrocontrollers einem Register zugeordnet und ihre Werte geändert werden, wenn der Registerwert geändert wird?

Szenario: Ich habe einige Pins von jedem Port (8-Bit) des Mikrocontrollers verbraucht. Jetzt möchte ich ein Gerät anschließen, das einen 8-Bit-Bus benötigt (angenommen, D0 bis D7 IN SEQUENCE), dh ich benötige 8 Pins vom Controller, damit ich sie eins zu eins verbinden kann

portx0  -> D0 // x is the name of port followed by bit location on that port
portx1  -> D1
...
portx7  -> D7

aber ich habe keinen ganzen Port mit 8 Pins, den ich mit diesem Gerät verbinden kann, sondern ich habe einige Pins von portx, einige von porty und einige Pins von portz. Das neue Verbindungsszenario ist wie folgt (Verbindung vom Mikrocontroller zum Gerät)

portx0  -> D0
portx1  -> D1
portx2  -> D2
porty4  -> D3
porty5  -> D4
porty6  -> D5
porty7  -> D6
portz1  -> D7

In diesem Zustand, wenn ich einen Wert senden möchte, sagen Sie

unsigned char dataReg = 0xFA;

Zu meinem Gerät vom Controller muss ich bitweise Operationen an dem zu sendenden Wert durchführen und jeden Pin entsprechend dem Wert im Register einzeln einstellen. Zum Beispiel

portx0 = ((dataReg & 0x01) >> 0 );  // Masking and shifting as bit position
portx1 = ((dataReg & 0x02) >> 1 );
portx2 = ((dataReg & 0x04) >> 2 );
porty4 = ((dataReg & 0x08) >> 3 );
porty5 = ((dataReg & 0x10) >> 4 );
porty6 = ((dataReg & 0x20) >> 5 );
porty7 = ((dataReg & 0x40) >> 6 );
portz1 = ((dataReg & 0x80) >> 7 );

Kommen wir nun zur Hauptfrage, um diese individuellen Berechnungen für jedes Bit an verschiedenen Ports zu vermeiden, können einzelne Pins verschiedener Ports eines Mikrocontrollers einem Register zugeordnet und ihre Werte geändert werden, wenn der Registerwert geändert wird?

Ich hatte vor einiger Zeit die gleiche Idee. Mit PICs ist dies nicht möglich: microchip.com/forums/tm.aspx?high=&m=696277 - Ich glaube nicht, dass es mit jedem Mikro möglich ist, aber die Auflistung Ihres Geräts wäre hilfreich.

Antworten (4)

Es scheint, dass Ihre Frage darauf hinausläuft, einen 8-Bit-Wert in der Firmware zu haben und diesen von und zu einer beliebigen Sammlung von Port-Pins lesen und schreiben zu wollen.

Es gibt keine direkte Hardwaremöglichkeit, dies zu tun. Sie müssen zwei Routinen schreiben, eine zum Lesen des 8-Bit-Werts und eine zum Schreiben. Andere haben die Verwendung von Gewerkschaften erwähnt, aber das ist eine schlechte Idee. Bei Gewerkschaften müssen Sie jedes Bit einzeln behandeln, und der Code wird von der Bitreihenfolge des Mikros abhängig. Dies könnte sowieso der richtige Weg sein, wenn alle 8 Bits völlig unabhängig voneinander gestreut werden. Wenn dies der Fall ist, können Sie wenig tun, außer für jedes Bit einen speziellen Code zu erstellen.

Der bessere Weg, dies zu tun, insbesondere wenn Sie die Bits in einigen zusammenhängenden Blöcken an den physischen Ports gruppieren können, ist die Verwendung von Maskierung, Verschiebung und ODER-Verknüpfung. Wenn sich zum Beispiel die unteren drei Bits des internen Bytes auf den Bits <6-4> eines Ports befinden, verschieben Sie diesen Portwert um 4 nach rechts und verknüpfen Sie ihn mit 7, um diese Bits an ihre endgültige Position zu bringen. Verschiebe und maskiere (oder maskiere und verschiebe) Bits von anderen Ports an ihren Platz und setze das letzte 8-Bit-Byte zusammen, indem du die Ergebnisse darin ODER-verknüpfst.

Diese Art von Low-Level-Bit-Twiddling ist in Assembler einfacher als in C. Ich würde wahrscheinlich die Byte-Lese- und -Schreibroutinen in ein einziges Assembler-Modul stecken und die Schnittstelle von C aus aufrufbar machen.

Meine Antwort wäre fast identisch mit Ihrer, außer dass ich überhaupt keine Assemblierung verwenden würde; Die Bit-Manipulationen sind in C trivial. Ich denke, es wäre eher ein Kopfzerbrechen, die spezifische C-Aufrufkonvention für den Compiler (wieder) zu lernen und wie der Linker ausgeführt wird. Hängt wirklich vom Compiler ab und wie schwierig es die Dinge macht. :-)
@Andrew: Ernsthaft? Die Aufrufkonventionen sind in jedem Compiler-Handbuch, das ich gesehen habe, klar dargelegt, wo möglicherweise eine Schnittstelle mit Assembler-Code erforderlich ist. Die Bit-Manipulation mag in C "trivial" zu schreiben sein, aber dies ist ein Bereich, in dem Compiler schrecklichen Code produzieren können. Wenn Geschwindigkeit oder Coderaum keine Rolle spielen, verwenden Sie das, was Ihnen angenehmer ist. Ich fühle mich mit Assembler für Bit-Twiddling auf niedriger Ebene wohler, also würde ich das verwenden. Wenn dies eine geschwindigkeitskritische Routine auf niedriger Ebene ist, sollten Sie dies in Assembler tun. Es sollte wirklich einfach sein.
Was ich damit sagen will, ist, dass ich mich mit so etwas Trivialem wie Bit-Manipulation nicht herumschlagen würde, es sei denn, es gäbe einen sehr guten Grund dafür. Wir kennen die Einzelheiten seines parallelen Busses nicht, aber die meisten Busse haben Strobe-Signale, die die Notwendigkeit von "nahezu atomaren" Aktualisierungen aller Bus-Pins beseitigen, so dass es wahrscheinlich eine unnötige Optimierung und unnötige Komplexität ist, auf die Assemblierung zu verzichten (selbst wenn es so ist geradlinig).
@Andrew: Es ist nur herumalbern oder komplex, wenn Sie nicht wissen, was Sie tun. Ich denke, das eigentliche Problem ist, dass manche Leute Angst vor Assembler haben und es nicht gut kennen. Das ist ein Fehler. Es muss ein fertiges Werkzeug in Ihrer Werkzeugkiste sein. Wenn Sie es nicht gut kennen oder sich damit unwohl fühlen, werden Sie immer rechtfertigen, wie die Dinge auf andere Weise erledigt werden sollten. Einige Dinge sind in Assembler einfacher , wenn Sie es und das HLL gleich gut kennen. Die meisten Leute tun das nicht, aber das ist ein Problem bei ihnen, nicht bei der Verwendung von Assembler.
Ich bin mit der Assemblersprache auf einer Reihe von Mikrocontrollern/Mikroprozessoren vertraut. Ich bin nicht der Meinung, dass es ein fertiges Werkzeug sein sollte; Es sollte sparsam und nur bei Bedarf verwendet werden, normalerweise für die Initialisierung auf sehr niedriger Ebene, für zeit- oder größenkritischen Code oder im häufigeren Fall für die Optimierung eines Bereichs, den Sie bereits als Engpass erkannt haben. Ich finde, dass Projekte, bei denen Autoren, die zur Assemblierung springen, weil es dort ist, oft weniger klaren Code schreiben oder nicht erkennen, wenn ein Algorithmus falsch angewendet wird. Ich sage nicht ausdrücklich, dass Sie das sind, sondern im allgemeineren Fall.

Generell ist dies nicht möglich. Mit PICs geht das meines Wissens nicht.

Mir ist nur ein Mikrocontroller bekannt, der dies kann, der Cypress PSoC . Es ist ein hochgradig konfigurierbares System-on-Chip. Unter den vielen Dingen, die Sie tun können, ist, buchstäblich Ihr eigenes Register (1-8 Bit) zu definieren und es mit beliebigen Pins oder sogar mit internen Schaltkreisen zu verbinden.

PSoC-Verkabelung

Hier habe ich zum Beispiel ein 6-Bit-Steuerregister erstellt. 5 der Bits gehen direkt zu Pins, während das 6. Bit ich mit XOR mit dem Eingang von einem 7. Pin verwende.

PSoC-Pins

Auf dem Chip kann ich diese Pins einem der verfügbaren GPIO-Pins zuweisen. (Es sind die grauen auf dem Bild)

LPC800 sollte das auch können, da man Pins frei Funktionen zuordnen kann.

Sie können Folgendes versuchen. Schreiben Sie eine eigene Struktur, die den jeweiligen Pins der 2 Ports (die verwendet werden sollen) zugeordnet ist. Wenn Sie nun den Wert in diesem Register aktualisieren, werden die Pins dieser 2 Ports gesetzt / zurückgesetzt. Probieren Sie es einfach aus und lassen Sie uns wissen, ob es funktioniert hat !!

Ich bin zuversichtlich, dass dies funktionieren sollte.

In C können Sie eine Struktur einem Speicherort zuordnen, und Sie können Bits Ihrer Struktur (Bitfelder) Bit-Offsets zuordnen, aber es gibt keine Möglichkeit, den Compiler daran zu hindern, mit den 'Zwischen'-Bits herumzuspielen, und das gibt es jetzt Möglichkeit, die "Gesamt"-Struktur anzuzeigen, ein einzelner ganzzahliger Wert. Das wird nicht funktionieren.

Wenn ich die Frage richtig verstanden habe, geht das ganz einfach in C:

Generische Typdeklaration, kann für jedes Register wiederverwendet werden:

typedef union    // Generic 8-bit register Type
{
  uint8 reg; // Whole register
  struct
  {
    unsigned  bit7     : 1;  // Bit 7 
    unsigned  bit6     : 1;  // Bit 6 
    unsigned  bit5     : 1;  // Bit 5 
    unsigned  bit4     : 1;  // Bit 4 
    unsigned  bit3     : 1;  // Bit 3 
    unsigned  bit2     : 1;  // Bit 2 
    unsigned  bit1     : 1;  // Bit 1 
    unsigned  bit0     : 1;  // Bit 0 
  } bit;
} typ_GENERIC_REG8;

Um also einen Port zu definieren, wollen wir Folgendes adressieren:

#define MCU_GPO_PORTx   (*(volatile typ_GENERIC_REG8 *)(0x12345678)) // Number is address

Und um direkt einen Pin an diesem Port zu drehen:

#define MCU_PORTx_PINn  (MCU_GPO_PORTx.bit.bit0)

In Code:

MCU_PORTx_PINn = 1; // Set pin high

Gesamtes Register:

MCU_GPO_PORTx.reg = 0xF; // All pins high

Es lohnt sich, sich über Structs, Unions, Typedefs und Enums zu informieren - all dies macht das Leben in Embedded & im Allgemeinen so viel schöner!

OP möchte mehrere Bits von verschiedenen Ports zu "einem Byte" kombinieren. Ich verstehe nicht, wie das gehen soll? Olin Lathrop erklärt, warum das nicht möglich ist.
Dies behebt das Problem nicht wirklich und je nachdem, wie "smrt" Ihr Compiler ist, könnte es zu einer ganzen Reihe neuer Probleme beim Debuggen kommen.