Forum: Mikrocontroller und Digitale Elektronik eigenen port aus einzelnen "Portpins" zusammensetzen


von Markus P. (markus64)


Lesenswert?

Hallo mal wieder.

Habe folgendes Problem:

Bin gerade etwas am rumbasteln mit 7 segment Anzeigen im 
Multiplexverfahren.
Es scheint ja gängig zu sein, für das ansteuern der jeweiligen Anzeige 
die Zahlen/Symbole durch ein entsprechendes array zu codieren also in 
z.B:

const char 7SEG[] = {hexwert für 0, hexwert für 1, hexwert für 2, usw.};

um dies dann über einen 8 bit breiten PORT ausgeben zu können:

PORTX = 7SEG[1];

nächstes digit();

PORTX = 7SEG[2];

soweit so primitiv.
Was mache ich jetzt aber, wenn ich z.B aus Platzgründen die Pins von 
mehreren PORTs
zusammenfassen muss sagen wir z.B PD0-PD5 für Segmente a-e und PC0-PC2 
für Segmente f und DP, um auf meine 8 bits zu kommen. Wie könnte ich mir 
in C einen "virtuellen" PORT erstellen, welcher meinen 8 bit wert wie 
ich es mir wünsche auf die Portpins verteilt?

von Kevin M. (arduinolover)


Lesenswert?

Du kannst dir ein Struct bauen, indem du die Pointer auf den jeweiligen 
Port speicherst, aber wirklich viel bringen tut das nicht, sobald du 
mehr als einen Port benutzt musst du auch entsprechend viele 
Schreibzugriffe auf die einzelnen Portes machen.

Verschiedene Ports haben immer den Nachteil das man das Digit nicht in 
einem schreiben kann und je nachdem wieviele benutzt werden dauert es 
natürlich länger.

eine Alternative wäre ein externer IO Expander bzw. ein 7-Segment 
Treiber.

von HildeK (Gast)


Lesenswert?

Meines Wissens geht das nicht direkt.
Aber du kannst dir natürlich eine Funktion schreiben, die das aufdröselt 
und das übergebene Byte an PD0-PD5 und PC0-PC2 schreibt.

von Noch ein Kommentar (Gast)


Lesenswert?

Ja, einfach eine Funktion, die nur genau für diese Kombination die Bits 
aufdröselt. Jede elegante und wiederverwendbare Lösung bringt mehr 
Verwirrung als Nutzen.

von MagIO (Gast)


Lesenswert?

Da gibt es viele Möglichkeiten, jeweils mit Vor- und Nachteilen 
behaftet.

Z.B.: man kann das Array so lassen, wie es ist und mit ein oder zwei 
Schleifen jeden Port-Pin einzeln setzen/löschen
- mit einer Schleife und in der Schleife ein if-Statement zum 
entscheiden, ob der eine oder der andere Port gerade bearbeitet wird
- mit zwei Schleifen, eine für den einen Port, die andere für den 
anderen Port, das spart das if

oder man bleibt bei dem Array, so wie es ist, und manipuliert die 
Ports/Array-Daten durch Maskieren und entsprechendes verschieben der 
Bits.
PORTX = PORTX & 0b11000000 | 7SEG[1] & 0b00111111   // im Beispiel aus 
der Frage wäre das für PD
PORTX = PORTX & 0b11111100 | 7SEG[1] >> 6   // im Beispiel aus der Frage 
wäre das für PC
der erste &-Teil löscht erst die Pins, die verändert werden sollen und 
behält die 2 MSB bei, der zweite &-Teil sorgt dafür, dass die Daten in 
7SEG nicht die 2 MSB "überschreiben"

oder man hat eine sehr zeitkritische Anwendung aber noch etwas Speicher 
frei, dann kann man die Daten natürlich auch schon entsprechend 
vorbereitet in 2 Arrays bereitstellen und spart sich das 2te & bzw. das 
verschieben der MSB.

von Holger Z. (boomboommagic)


Lesenswert?

oder man nimmt einen TM1637 -> 2 Pins , 6 Segmente
oder einen max7219 -> 3 Pins , 8 Segmente

von Markus P. (markus64)


Lesenswert?

Na ich glaube das mit dem Maskieren ist in meinem Fall wohl das 
Angenehmste.
Habe mir auch sowas in der Art überlegt nur habe ich was das Thema 
Bitmanipulation angeht noch viel zu lernen ;)

Großes Danke an euch!

von foobar (Gast)


Lesenswert?

Mach einfach ein SEG-Array für jeden Port.  Kein gumgeshifte und 
kompakt.
Z.B.:
1
  #define SEG_PA_BITS 0xc3  // PA0/1/6/7
2
  #define SEG_PC_BITS 0x87  // PC0/1/2/7
3
  const uint8_t SEG_PA[] = { ... };
4
  const uint8_t SEG_PC[] = { ... };
5
  ...
6
  PORTA = (PORTA & ~SEG_PA_BITS) | SEG_PA[x];
7
  PORTC = (PORTC & ~SEG_PC_BITS) | SEG_PC[x];

von mIstA (Gast)


Lesenswert?

Holger Z. schrieb:
> oder man nimmt einen TM1637 -> 2 Pins , 6 Segmente

Wie kommst Du jetzt da drauf, der kann genauso 8 Segmente für jede der 6 
Stellen.

von Wolfgang (Gast)


Lesenswert?

Kevin M. schrieb:
> Verschiedene Ports haben immer den Nachteil das man das Digit nicht in
> einem schreiben kann und je nachdem wieviele benutzt werden dauert es
> natürlich länger.

Bei einer Multiplexperiode von z.B. 10ms ist es natürlich gaaanz 
schlimm, wenn  Segmengruppen mit einem Zeitversatz von vielleicht 1µs 
angesteuert werden ;-)

von Martin (Gast)


Lesenswert?

- Segmente seriel ausgeben (Schiberegister)
- I2C 7-Segment Treiber verwenden
- BCD zu 7-Segment Dekoder verwenden

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Ohh wenn ich das hier so Lese, weiss ich gerade wieder Warum ich die
MSP430 MPUX V2 und Assembler so liebe,

1 Befehl, beschreibt oder List mir grad alle oder die Gewünschte anzahl 
Ports :-D
Leider in "C" von IAR noch nicht Implementiert
Der Compiler macht da immer noch eine Spagetti-Rutiene :-(

: Bearbeitet durch User
von Markus M. (Gast)


Lesenswert?

Markus P. schrieb:
> const char 7SEG[] = {hexwert für 0, hexwert für 1, hexwert für 2, usw.};

Ist das C++ oder Arduino oder was?

vgl. K&R "The C Programming Language":

2.1 Variable Names
Although we didn't say so in Chapter 1, there are some restrictions on 
the names of variables and symbolic constants. Names are made up of 
letters and digits; the first character must be a letter. The 
underscore `` _ '' counts as a letter; it is sometimes useful for 
improving the readability of long variable names.

von Falk B. (falk)


Lesenswert?

Markus M. schrieb:
>> const char 7SEG[] = {hexwert für 0, hexwert für 1, hexwert für 2, usw.};
>
> Ist das C++ oder Arduino oder was?

Das ist Pseudocode, kein vollständiger, korrekter C Code.

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Frage dazu, (rein Interessenshalber) habe ja mit Arduino nix am Hut.
Aber der Prozessor unterstützt doch auch Befehle die mehrere Adressen 
mit einem Rutsch von a nach B schiebt?

Dann kann man doch das Display als Shadowbereich im Ram ablegen und mit 
1 Befehl das ganze in die Ports schieben, so das garantiert kein 
"Gezappel" im Display ist?

Für Direkt CRT an µC verwende ich das Prinzip auch, das beim Bildaufbau 
kein Geflicker auf dem CRT/LCD zu sehen ist, und spart nebenbei noch 
erheblich Code.

Wen ich Segmentdisplays habe nehme ich e die µC mit integriertem LCD 
Kontroller, das macht es erheblich einfacher..

alles etwas OT,(Sorry) aber selbst der Z80 kannte schon den LDIR 
befehl?

von c-hater (Gast)


Lesenswert?

Patrick L. schrieb:

> Frage dazu, (rein Interessenshalber) habe ja mit Arduino nix am Hut.

Das merkt man, nichtmal eine grobe Übersicht ist vorhanden...

> Aber der Prozessor unterstützt doch auch Befehle die mehrere Adressen
> mit einem Rutsch von a nach B schiebt?

Nun, ich bin auch nicht gerade Arduino-Fan, aber so viel weiß ich dann 
doch:
Das hängt vom Prozessor ab. "Arduino" gibt's schon seit undenklichen 
Zeiten für (ziemlich verschiedene) Prozessoren, in jüngerer Zeit ist 
deren Zahl sogar förmlich explodiert.

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

c-hater schrieb:
> nichtmal eine grobe Übersicht ist vorhanden...

Richtig erkannt :-)

Trotzdem Danke für die Antwort, auch wenn die Frage dabei noch offen 
bleibt.
Etwas Spezifisziert:

@TO hat der den Du verwendest, nicht ein µC Drauf der die Befehle 
unterstützt?

von c-hater (Gast)


Lesenswert?

Patrick L. schrieb:

> @TO hat der den Du verwendest, nicht ein µC Drauf der die Befehle
> unterstützt?

Das alleine würde ja noch nicht reichen. Es müssten zusätzlich auch die 
PORT-Register an linear aufsteigenden Adressen liegen oder sich 
zumindest irgendwie so hinmappen lassen. Und das ist (zumindest bei den 
"Arduino-Prozessoren", die ich kenne) bei keinem der Fall.

Und selbst wenn es irgendeinen Exoten gibt, bei dem das möglich wäre, 
wäre es ziemlicher Unsinn, dieses exotische Feature zu verwenden. Eben 
weil es dann bei allen anderen nicht funktioniert.

Sollte logisch sein, oder?

von Forist (Gast)


Lesenswert?

Patrick L. schrieb:
> Der Compiler macht da immer noch eine Spagetti-Rutiene :-(

Schreib lieber "Befehlsfolge". Vielleicht stehen da die Chancen besser, 
dass du das unfallfrei hinbekommst. ;-)

von Markus M. (Gast)


Lesenswert?

Markus P. schrieb:
>
> Bin gerade etwas am rumbasteln mit 7 segment Anzeigen im
> Multiplexverfahren.
>
> Was mache ich jetzt aber, wenn ich z.B aus Platzgründen die Pins von
> mehreren PORTs zusammenfassen muss sagen wir z.B PD0-PD5 für Segmente a-e
> und PC0-PC2 für Segmente f und DP, um auf meine 8 bits zu kommen.

Keinen Zweifel, das geht sicher - irgendwie. Z.B. könnte man im 
7Segment-Code für a-e (resp. PD0-PD5) die unteren 6 bits reservieren und 
bei der Ausgabe PD6-PD7 trickreich rein- und rausmaskieren. Oder du 
könntest dir aus Langeweile ein Loch ins Knie bohren und Backpulver 
einfüllen ...

Ich würde mir aber diesen Stress nicht machen, sondern die Ports 
sinnvoll zuordnen. Aber mach mal wie Du denkst, ist schließlich dein 
Projekt...

von foobar (Gast)


Lesenswert?

Patrick schrieb:
> Ohh wenn ich das hier so Lese, weiss ich gerade wieder Warum ich die
> MSP430 MPUX V2 und Assembler so liebe,
>
> 1 Befehl, beschreibt oder List mir grad alle oder die Gewünschte anzahl
> Ports :-D

Erzähl mal mehr - kann nichts darüber finden (nur über die MPU, und die 
kann sowas nicht).

von Markus P. (markus64)


Lesenswert?

> Das ist Pseudocode, kein vollständiger, korrekter C Code.


DIES!

von W.S. (Gast)


Lesenswert?

Markus M. schrieb:
> Oder du
> könntest dir aus Langeweile ein Loch ins Knie bohren und Backpulver
> einfüllen ...

Ein wirklich weiterführender Ratschlag. Gelle?

Also, daß man sich die Ports nicht so heraussuchen kann, wie es einem 
grad genehm ist, das ist recht üblich. Oftmals sind die Ports nur bei 
der größten Gehäuseform (BGA) komplett herausgeführt oder irgendwelche 
Pins mittendrin sind bereits anderweitig belegt.

So konzentriert sich das Problem darauf, eine bestimmte Datenmenge auf 
verschiedene Ports und Pins zu verteilen. Das muß nicht ein Byte sein, 
es kann auch mal irgend eine andere Datenbreite haben.

Schlußendlich wird man in den meisten Fällen darauf kommen, daß eine 
stupide Einzelverteilung (hi oder lo) nach dem Übersetzen zum 
effektivsten Maschinencode führt. Ohne Schleifenkonstrukte und ohne 
Arrays. Sowas führt hier nur zu zusätzlichem Verwaltungsaufwand.

W.S.

von Εrnst B. (ernst)


Lesenswert?

W.S. schrieb:
> Schlußendlich wird man in den meisten Fällen darauf kommen, daß eine
> stupide Einzelverteilung (hi oder lo) nach dem Übersetzen zum
> effektivsten Maschinencode führt. Ohne Schleifenkonstrukte und ohne
> Arrays. Sowas führt hier nur zu zusätzlichem Verwaltungsaufwand.

Wenn die Pin-Verteilung zur Compile-Zeit bekannt ist, kann dieses 
GCC-Builtin hilfreich sein:

-->  __builtin_avr_insert_bits

https://gcc.gnu.org/onlinedocs/gcc/AVR-Built-in-Functions.html

https://godbolt.org/z/sh4bM64Ke

: Bearbeitet durch User
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.