Forum: Mikrocontroller und Digitale Elektronik PORTs in Array


von Hannes (Gast)


Lesenswert?

Moin,
ich bin momentan dabei einen älteren Code zu kürzen.
in einem Array stehen momentan Zahlenwerte für die Portbezeichnungen und 
die Pins also für PA2 würde drin stehen:

uint8_t pinPorts[100][2] = {{(0),(1<<PA2)}, ...}

Das Ganze dann für alle Pins des atmega2560.

Ausgewertet wird das dann über nen Switch case der für jeden Port einen 
case hat und je nach Port den zugehörigen Pin ein oder ausschaltet.


So nun die Frage, kann ich die Ports irgendwie in einem Array definieren 
um die Switch case loszuwerden?

Ich hätte gerne einen Array Ports[] = {PORTA, PORTB}
Und einen Array Pins[] = {(1<<PA2), (1<<PA1)}

Damit ich dann
int i = 2;

Ports[i] |= Pins[i];

Nutzen kann anstatt 11 cases zu haben.


Viele Grüße Hannes

von Hannes (Gast)


Lesenswert?

Unten ist es natürlich ein i < 2

von Clemens L. (c_l)


Lesenswert?

Die Definition von PORTA ist ungefähr:
1
#define PORTA (*(volatile uint8_t *)(0x22))

Es ist möglich, Zeiger auf diese Ports zu definieren, aber du musst sie 
dann explizit dereferenzieren:
1
volatile uint8_t *ports[] = { &PORTA, &PORTB };
2
3
*ports[i] = pins[i];

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Wozu möchte man sowas umständliches tun?
Bei mir haben haben alle IO-Pins eine zur Laufzeit konstante Funktion, 
d.h. man kann sie schnell und codesparend bereits zur Compilezeit 
definieren, z.B.:

Beitrag "Re: Codingstyle vs Makros"

von Einer K. (Gast)


Lesenswert?

Hannes schrieb:
> So nun die Frage, kann ich die Ports irgendwie in einem Array definieren
> um die Switch case loszuwerden?

Dummer weise hast du vergessen, zu sagen, um welche Sprache es sich 
handelt.

Eine C++ Lösung kann ich dir evtl anbieten....

von Hannes (Gast)


Lesenswert?

Moin,
Sprache ist C

Es geht ja nicht um eine Anfangsdefinition die geschieht durch feste 
Makros. Im späteren Verlauf hängt das ein oder ausschalten aber in einem 
interrupt der möglichst kurz sein sollte. Daher würde ich mir gerne die 
beiden Switch case sparen und eine einfache Alternative haben.

Viele Grüße
Hannes

von Einer K. (Gast)


Lesenswert?

Ich sehe keine switch case in deinem Code.
Kann mir auch nicht vorstellen, wofür die gut sind....

von Hannes (Gast)


Angehängte Dateien:

Lesenswert?

Wenn du den Eingangstext gelesen hättest wüsstest du das welche 
existieren.

Aber auch gerne nochmal als „Beweis“
Die Teile hinter |= wurden jetzt bereits mit einem anderen Vektor 
abgelöst. Ich wäre aber gerne die 11. cases los, dafür müsste ich die 
Ports in nen Vector bekommen.

von Michael B. (laberkopp)


Lesenswert?

Hannes schrieb:
> Ich hätte gerne einen Array Ports[] = {PORTA, PORTB}
> Und einen Array Pins[] = {(1<<PA2), (1<<PA1)}
>
> Damit ich dann
> int i = 2;
>
> Ports[i] |= Pins[i];
>
> Nutzen kann anstatt 11 cases zu haben.

Hast du doch, also mach doch, musst halt deie Array für alle 100 i 
auffüllen.

Ports[] = {PORTA, PORTA, PORTA, .. PORTA, PORTB ..}
Pins[] = {(1<<PA0), (1<<PA1), (1<<PA2)... , (1<<PA7), (1<<PB0)...}

Allerdings kannst du mit dem code gerade mal einen Ausgang setzen 
(high).

Für das Rücksetzen (low) und für das Einlesen (input) brauchst du 
anderen code, der aber auf denselben Arrays aufsetzen kann.

Schau dir mal den source code an, wie der Arduino digitalWrite und 
digitalRead macht.

Allerdings hat der genau so wie dein Code das Problem, das setzen von 
mehreren Pins (8 Datenleitungen zum LCD..) zu immensem Laufzeitaufwand 
aufzublähen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Hannes schrieb:
> Daher würde ich mir gerne die beiden Switch case sparen und eine
> einfache Alternative haben.

Case-Switches können sehr kurz sein, nämlich lediglich aus einer 
Sprungtabelle bestehen. Das kannst Du kaum noch toppen. Schau Dir mal 
den erzeugten Assembler-Output an.

Im Zweifelsfall setzt Du in der ISR nur ein Flag und machst Deinen 
Switch in der Hauptschleife.

von Peter D. (peda)


Lesenswert?

Hannes schrieb:
> Im späteren Verlauf hängt das ein oder ausschalten aber in einem
> interrupt der möglichst kurz sein sollte.

Du willst also einem Interrupt Pins übergeben, die zur Compilezeit noch 
nicht bekannt sind.
Dann nimm einfach das Arduino Framework, da ist sowas schon dabei.
Allerdings ist das eben deutlich langsamer als ein direkter Pinzugriff, 
wenn man ihn schon zur Compilezeit festlegen kann.

Man darf switch/case aber auch nicht unterschätzen. Wenn es nur wenige 
Pins sind, z.B. 20, dann wird ein switch/case durchaus schneller sein, 
als erstmal ewig mit Pointern zu jonglieren. Ein Interrupt muß 
zusätzlich den Mehrverbrauch an Registern für die Pointerrechnungen 
sichern und restoren.

von Einer K. (Gast)


Lesenswert?

Hannes schrieb:
> Wenn du den Eingangstext gelesen hättest wüsstest du das welche
> existieren.
Is klar....

Hannes schrieb:
> Aber auch gerne nochmal als „Beweis“
Ich brauche keine Beweise/Bilder, du ...
Sondern testbaren Code!

Aber ich sehe schon, mit uns beiden wird das so nichts.

von Hannes (Gast)


Lesenswert?

Mein interrupt prüft bei jedem Aufruf ob ein Pin verändert werden soll 
oder nicht. Somit sollte das Programm nicht ewig jonglieren sondern 
genau 2 arrays an einer Stelle bearbeiten.

Die Pins sind beim Compilen definiert aber an den Ausgängen hängen 
schrittmotoren/ Servos/ LEDs/ Sensoren etc. die durch i2c Kommunikation 
geändert werden.

Damit ich keinen allzu großen Delay erhalte, möchte ich die interrupt 
Zeit möglichst klein halten, da stört der Switch case immens. (Ca 7us 
mehr als direkte Anweisung)

von Peter D. (peda)


Lesenswert?

Hannes schrieb:
> Aber auch gerne nochmal als „Beweis“

Es war auch nicht die Frage, daß Dein Code so aussieht, sondern warum er 
unbedingt so aussehen muß.
Warum darf erst im Interrupt entschieden werden, welcher von den 86 Pins 
gesetzt werden soll?

von Peter D. (peda)


Lesenswert?

Hannes schrieb:
> Die Pins sind beim Compilen definiert aber an den Ausgängen hängen
> schrittmotoren/ Servos/ LEDs/ Sensoren etc. die durch i2c Kommunikation
> geändert werden.

Also quasi ein I2C-Portexpander.
Für Schrittmotoren würde ich entsprechend viele Instanzen von 
Schrittmotortreibern in einem Timerinterrupt aufsetzen.
Für Servos entsprechend viele Instanzen von PWMs, ebenfalls in einem 
Timerinterrupt.
Und jede Instanz greift direkt auf die benötigten Pins zu, indem man die 
Instanzen als Inline-Funktion definiert mit den Pins als Argument. Das 
dürfte bei 256kB Flash ja kein Problem sein.

Hannes schrieb:
> da stört der Switch case immens. (Ca 7us
> mehr als direkte Anweisung)

Das wären ja 112 Zyklen bei 16MHz, kommt mir reichlich viel vor.
Switch/case arbeitet mit binärer Suche, d.h. bei 86 aufeinanderfolgenden 
Cases ist es nach 7 Vergleichen am Ziel.

von Einer K. (Gast)


Lesenswert?

Peter D. schrieb:
> Switch/case arbeitet mit binärer Suche, d.h.
Nicht unbedingt.
Der gcc entscheidet selber, und in Abhängigkeit von Compileroptionen, 
wie er es tut. Da kann man schon die ein oder andere Überraschung 
erleiden.

von Bernd K. (prof7bit)


Lesenswert?

Scroll nach oben. Deine Frage wird im dritten Post vollständig 
beantwortet.

: 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.