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
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"
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....
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
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.
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.
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.
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.
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.
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)
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?
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.
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.