Können einzelne Pins verschiedener Ports eines Mikrocontrollers einem Register zugeordnet und deren Werte beim Ändern des Registerwerts geändert werden?


12

F: Können einzelne Pins verschiedener Ports eines Mikrocontrollers einem Register zugeordnet und ihre Werte beim Ändern des Registerwerts geändert werden?

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

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

aber ich habe nicht einen 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 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

unsigned char dataReg = 0xFA;

An meinem Gerät vom Controller muss ich bitweise Operationen an dem zu sendenden Wert durchführen und jeden Pin gemäß dem Wert im Register einzeln einstellen. Beispielsweise

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 auf ein Register abgebildet und ihre Werte beim Ändern des Registerwerts geändert werden?


1
Ich hatte vor einiger Zeit die gleiche Idee. Bei PICs ist dies nicht möglich: microchip.com/forums/tm.aspx?high=&m=696277 - Ich denke, mit keinem Mikro ist dies möglich, aber das Auflisten Ihres Geräts wäre hilfreich.

Antworten:


6

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 Hardware-Mö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 muss jedes Bit separat behandelt werden, und der Code hängt von der Bitreihenfolge des Mikros ab. Dies könnte sowieso der Weg sein, wenn alle 8 Bits völlig unabhängig voneinander verstreut sind. In diesem Fall können Sie nur für jedes Bit einen speziellen Code erstellen.

Die bessere Möglichkeit, dies zu tun, besteht insbesondere dann, wenn Sie die Bits in ein paar zusammenhängenden Blöcken auf den physischen Ports gruppieren können, darin, Maskierung, Verschiebung und ODER-Verknüpfung zu verwenden. Wenn sich die unteren drei Bits des internen Bytes beispielsweise auf den Bits <6-4> eines Ports befinden, verschieben Sie diesen Portwert nach rechts um 4 und UND mit 7, um diese Bits an ihre endgültige Position zu bringen. Verschieben und maskieren (oder maskieren und verschieben) Sie Bits von anderen Ports an die richtige Stelle und setzen Sie das letzte 8-Bit-Byte durch ODER-Verknüpfung der Ergebnisse zusammen.

Diese Art von Bit-Twiddling auf niedriger Ebene ist in Assembler einfacher als in C. Ich würde wahrscheinlich die Lese- und Schreibroutinen für Bytes in ein einziges Assembler-Modul schreiben und die Schnittstelle von C aus aufrufbar machen.


6
Meine Antwort wäre fast identisch mit Ihrer, außer dass ich Assembler überhaupt nicht verwenden würde. Die Bit-Manipulationen sind in C trivial. Ich denke, es würde mehr Kopfzerbrechen bereiten, die spezifische C-Aufrufkonvention für den Compiler (neu) zu lernen und den Linker auszuführen. Kommt wirklich auf den Compiler an und wie schwierig es die Dinge macht. :-)
Akohlsmith

@ Andrew: Im Ernst? 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 "trivial" sein, um in C zu schreiben, aber dies ist ein Bereich, in dem Compiler horrenden Code erzeugen können. Wenn Geschwindigkeit oder Code-Platz keine Rolle spielen, verwenden Sie, was Ihnen besser gefällt. Ich bin mit Assembler für Low-Level-Bit-Twiddling 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.
Olin Lathrop

1
Was ich damit sagen will, ist, dass es nichts ist, was ich tun würde, wenn ich nicht aus einem sehr guten Grund damit herumspielen müsste. Wir kennen die Besonderheiten seines parallelen Busses nicht, aber die meisten Busse haben Strobe-Signale, die die Notwendigkeit von "nahezu atomaren" Aktualisierungen aller Bus-Pins eliminieren. Daher ist das Fallenlassen auf eine Baugruppe wahrscheinlich eine unnötige Optimierung und eine unnötige Komplexität (auch wenn dies der Fall ist) geradlinig).
Akohlsmith

@ Andrew: Es ist nur umständlich oder komplex, wenn Sie nicht wissen, was Sie tun. Ich denke, das eigentliche Problem ist, dass einige Leute Angst vor dem Assembler haben und es nicht genau wissen. Das ist ein Fehler. Es muss ein fertiges Werkzeug in Ihrer Toolbox sein. Wenn Sie es nicht gut kennen oder sich nicht wohl fühlen, werden Sie immer rechtfertigen, wie die Dinge auf eine andere Weise zu tun sind. Einige Dinge sind in Assembler einfacher , wenn Sie es und die HLL gleich gut kennen. Die meisten Leute tun das nicht, aber das ist ein Problem bei ihnen, nicht bei der Verwendung von Assembler.
Olin Lathrop

2
Ich bin mit Assemblersprachen auf einer Reihe von Mikrocontrollern / Mikroprozessoren vertraut. Ich bin nicht einverstanden, dass es ein fertiges Werkzeug sein sollte; es sollte sparsam und nur bei Bedarf verwendet werden, normalerweise für Initialisierung auf sehr niedriger Ebene, zeit- oder größenkritischen Code oder im allgemeineren Fall für die Optimierung eines Bereichs, den Sie bereits als Engpass eingestuft haben. Ich finde, dass in Projekten Autoren, die zu Assembler wechseln, weil dort oft weniger klarer Code geschrieben wird oder die nicht erkennen, wann ein Algorithmus falsch angewendet wird. Ich sage nicht ausdrücklich, dass Sie das sind, sondern eher im allgemeinen Fall.
Akohlsmith

4

Im Allgemeinen ist dies nicht möglich. Soweit ich weiß, ist das mit PICs nicht möglich.

Es gibt nur einen mir bekannten Mikrocontroller, den Cypress PSoC . Es ist ein hoch konfigurierbares System auf dem Chip. Unter den vielen Möglichkeiten können Sie buchstäblich Ihr eigenes Register (1-8 Bit) definieren und es mit beliebigen Pins oder sogar mit internen Schaltkreisen verbinden.

PSoC-Verkabelung

Zum Beispiel habe ich hier ein 6-Bit-Steuerregister angelegt. 5 der Bits gehen direkt zu den Pins, während das 6. Bit, das ich verwende, mit der Eingabe von einem 7. Pin zu XOR.

PSoC-Stifte

Auf dem Chip kann ich diese Pins jedem der verfügbaren GPIO-Pins zuweisen. (Es sind die Grauen das Bild)


1
LPC800 sollte dies auch können, da die Funktionen den Pins frei zugewiesen werden können.
Starblue

-1

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. Versuchen Sie einfach und lassen Sie uns wissen, ob es funktioniert hat !!

Ich bin zuversichtlich, dass dies funktionieren sollte.


2
In C können Sie eine Struktur einem Speicherort zuordnen und Sie können Bits Ihrer Struktur (Bitfelder) Bitoffsets zuordnen, aber es gibt keine Möglichkeit, den Compiler daran zu hindern, mit den 'Zwischen'-Bits zu experimentieren, und das ist jetzt der Fall Möglichkeit, die "Gesamt" -Struktur eines einzelnen Integer-Wertes anzuzeigen. Das wird nicht funktionieren.
Wouter van Ooijen

-1

Wenn ich die Frage richtig verstanden habe, ist es in C einfach genug:

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 einen Port zu definieren, den wir ansprechen möchten:

#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 Strukturen, Gewerkschaften, Typedefs und Aufzählungen zu informieren - all dies macht das Leben im Embedded- und im Allgemeinen so viel schöner!


OP möchte mehrere Bits von verschiedenen Ports zu 'einem Byte' zusammenfassen. Ich verstehe nicht, wie das das machen würde? Olin Lathrop erklärt, warum es nicht möglich ist.

Hiermit wird das Problem nicht wirklich behoben, und je nachdem, wie "smrt" Ihr Compiler ist, kann es zu einer ganzen Reihe neuer Probleme beim Debuggen kommen.
Akohlsmith
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.