Hallo in die Runde,
ich beschäftige mich seit geraumer Zeit mit den Cypress PSoC Chips, aber
ich denke, meine Frage ist eher eine allgemeine C-Frage (wo ich noch
nicht allzulange zu Hause bin), für die ich einfach keine Lösung finde.
Zum konkreten Problem:
Der PSoC Creator erzeugt zur einfachen Ansteuerung von Pins bei der
Kompilierung eine entsprechende API.
Da gibt es dann diverse Befehle zum schreiben/lesen etc.
Die Syntax ist recht einfach. PinName_Funktion()
Pin1_Write(1) - setze Pin1 auf 1 na usw.
Jetzt hab muss ich das gleiche Bitmuster an verschiedene Pins ausgeben.
Dafür hab ich Funktionen.
1
voidBitmuster_an_Pin1(void){
2
Pin1_Write(1);// 1 auf Pin
3
//tu noch andere Sachen
4
Pin1_Write(0);// 0 auf Pin
5
}
Die gleiche Funktion hab ich dann noch für 3 andere Pins.
Was ich suche ist eine Möglichkeit, den API-Funktionsnahme dynamisch zu
erzeugen.
Etwa so:
1
//reiner Pseudocode
2
voidBitmuster_an_PinX(charPinNr){
3
API_Befehl="Pin"+PinNr+"_Write
4
API_Befehl(1);
5
6
//tu noch andere Sachen
7
8
API_Befehl(0);
9
}
Mit Makroexpansion bekomme ich es nicht hin:
#define Pin(i) Pin##i
expandiert ja nur wenn beim Aufruf i als Zahl benutzt wird.
uint8_t i = 1;
Pin(i)() -> Fehler
Pin(1)() -> expandiert zu Pin1()
Natürlich kann ich in eine Funktion mit switch oder case arbeiten, aber
das wird bei vielen Pins und API_Funktionen
schon sehr unübersichtich.
Ich hoffe, ich habe mich einigermaßen verständlich ausgedrückt.
Vlt. kann mich jemand in die richtige Richtung schupsen.
Reiner W. schrieb:> Der PSoC Creator erzeugt> Pin1_Write(1) - setze Pin1 auf 1 na usw.>Was ich suche ist eine Möglichkeit, den API-Funktionsnahme dynamisch zu>erzeugen.
Wenn dieser PSoC Creator keine funktion zum setzen des n-ten pins, oder
mehrerer pins hat, würde ich den gleich weglassen und selbst die
entsprechende funktion schreiben. In C kann man keine funktion über
einen zur runtime zusammengesetzten namen aufrufen, es sei denn man
speichert funktionsname und funktionspointer in einer liste. Mit
preprocessing ist es auch nicht möglich, weil das simple textersetzung
ist.
Man könnte im notfall Arrays verwenden: (code ungetestet)
Klaus Wachtler schrieb:> Evtl. helfen dir Funktionszeiger weiter:
Genauso hab ich es im Prinzip gemacht;-) Auch wenn dein Code
aufgeräumter aussieht. Aber da feile ich noch dran.
Komme aus alten seligen dBase Zeiten und da konnte man ja zur Laufzeit
ne Markosubstitution einfach mit
x="test()"
y = &x
machen. Aber man kann nicht alles haben.
Da die Funktionen als API ja alle schon konkret vorliegen, brauch ich ja
nur noch ein Array mit den Funktionspointern anlegen.
Ist halt blöd, wenn da mal ein Pin dazukommt, da muss man immer dran
denken, dass array zu erweitern.
Außerdem sind die API-Funktionen noch nicht die ganze Wahrheit, da gibt
es auch noch Konstanten (z.B. der Pin-Drive-Mode), die nach dem selben
Schema benannt sind. Das bedeutet schon eine zweite Dimension im Array,
wenn ich eine solche Konstante in meiner (allgemeinen) Funktion brauche.
Dennoch ist das besser und sicher auch platzsparender als 8 Funktionen,
die im Grunde gleich sind.
Daniel A. schrieb:> #define PinListItem(i) &PinMacro(i)
Die Zeile kann ich noch nicht ganz nachvollziehen. Was macht das & ?
Bin leider noch nicht so firm in der C-Programmierung.
Danke schon mal für eure Hilfe. Ist ja schon mal beruhigend zu wissen,
dass ich nicht von vorn anfangen muss, nur weil ich den Wald vor lauter
Bäumen nicht gesehen habe.
Reiner W. schrieb:> Ist halt blöd, wenn da mal ein Pin dazukommt, da muss man immer dran> denken, dass array zu erweitern.
In solchen Fällen kann man darüber nachdenken, Quelltext mit einem
Präprozessor zu generieren (m4, awk, sed, ...).
Wenn man eh über makefiles oder ähnliches kompiliert, ist das leicht
eingebaut.
Wenn sich etwas ändert, wird eine Konfigurationsdatei angepasst, und
nach einem make passt alles.
Klaus Wachtler schrieb:> In solchen Fällen kann man darüber nachdenken, Quelltext mit einem> Präprozessor zu generieren (m4, awk, sed, ...).
Gute Idee, im konkreten Fall lohnt sich aber ein Quellcodegenerator
sicher nicht. Und in so einem Fall muss man wieder höllisch aufpassen,
dass die PinNamen einer Regel folgen. Pin1, Pin2..Pinx. Aber das sollten
sie sowieso tun.
Reiner W. schrieb:> Daniel A. schrieb:>> #define PinListItem(i) &PinMacro(i)>> Die Zeile kann ich noch nicht ganz nachvollziehen. Was macht das & ?
Es gibt den funktions-pointer auf die Funktion zurück. Da eine funktion
immer auch ein funktionspoiner ist, ist es optional. Ich verwende es aus
kosmetischen und logik gründen. Wichtig ist, dass wenn man ein x=&func
verwendet, später (*func)() für den aufruf verwendet wird, und bei
x=func der aufruf immer mit x() erfolgt.
Funktion und Funktionspointer sind eben rein logisch betrachtet (nicht
praktisch) nicht das selbe.
1
voidx(){}// void(&){} funktion
2
void(*y)()=&x;// funktionspointer
3
void(**z)()=&y;// objekt-pointer auf funktionspointer
Sven B. schrieb:> Wo ist der Vorteil gegenüber dem die Pin-Nummer einfach als Argument zu> übergeben?
Ich weis jetzt nicht was du meinst. Das Problem hab ich ja schon bei her
TE geschildert. Die PinNummer als Argument geht nicht, weil ich über
dieses Argument nicht mehr auf den Funktion komme, es sei denn, ich
nehme die PinNummer als Array-Index und im Array stehen die
Funktionspointer. Das geht ganz gut, erfordert aber, dass im Vorfeld das
Array mit den Funktionspointern angelegt wurde, wie ja Klaus Wachtler
perfekt als Beispiel gezeigt hat.
Wenn ich es richtig sehen, läuft der Vorschlag von Daniel letztlich auch
darauf hinaus, setzt aber den Präprozessor intensiv ein.
Ich weis jetzt nicht, ob du da noch eine andere Möglichkeit siehst und
wie die aussehen könnte.