Go Down

Topic: erweiterte Funktionsparameter Übergabe (Read 862 times) previous topic - next topic

arduino-wasser

Hallo, ich habe mir einige Funktionen in meinem Code ausgelagert. Ich weiß das ich einer Funktion Variablen übergeben kann
Code: [Select]

void foo(uint_8 uebergabebyte, char woerter[10])

aber wie kann ich einen "Befehl" ähnlich der Topologie von z.B. der pinMode Funktion nutzen indem ich direkt einen "Befehl" oder eine "Anweisung" übergebe
Code: [Select]

pinMode(A0, INPUT)

ich suche nach der "Variante" wie ich in meiner selbst geschrieben Funktion zwischen mehreren Methoden wählen kann, also ähnlich dem Auswahlmenü was mir die pinMode Funktion mit INPUT, OUTPUT, INPUT_PULLUP bietet.

Ich hoffe ich konnte mich verständlich machen. Dankeschön schon mal im voraus

combie

#1
Sep 19, 2018, 05:02 pm Last Edit: Sep 19, 2018, 05:03 pm by combie
Im einfachsten Fall so:

Code: [Select]

enum Variante {Bli,Bla=42,Blub=4711};



void tuwas(Variante variante)
{
  if(variante == Blub) Serial.println("Blub");
  switch(variante)
  {
    case Bli: Serial.println("Bli"); break;
    case Bla: Serial.println("Bla"); break;
  }
}


void setup()
{
  Serial.begin(9600);     
  Serial.println("Start");
  tuwas(Blub);
}

void loop()
{

}
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Rintin

INPUT ist nur ein Platzhalter für eine Zahl (s.h. Arduino.h) und pinMode() erwartet dementsprechend auch eine (s.h. wiring_digital.c)

combie

#3
Sep 19, 2018, 06:23 pm Last Edit: Sep 19, 2018, 06:26 pm by combie
INPUT ist nur ein Platzhalter für eine Zahl (s.h. Arduino.h) und pinMode() erwartet dementsprechend auch eine (s.h. wiring_digital.c)
Dass das im Arduino Core so gelöst ist, ist nicht unbedingt ein Qualitätsmerkmal.
Allerdings typisch für die etwas ältere C Welt.
Zumindest hat es den Vorteil, dass man pinMode() auch in C Programmen nutzen kann.


Arduino *.ino Dateien sind allerdings C++, da kann man auf die alten Zöpfe ganz entspannt verzichten.

Und sogar einen Schritt weiter gehen, und die Sache vollständig Typesicher und weniger Seicherintensiv gestalten:
Code: [Select]
enum class Variante:byte {Bli=0,Bla=3,Blub=42};



void tuwas(Variante variante)
{
  if(variante == Variante::Blub) Serial.println("Blub");
  switch(variante)
  {
    case  Variante::Bli: Serial.println("Bli"); break;
    case  Variante::Bla: Serial.println("Bla"); break;
  }
}


void setup()
{
  Serial.begin(9600);     
  Serial.println("Start");
  tuwas(Variante::Blub);
}

void loop()
{

}



Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Serenifly

Die direkte Konvertierung von klassischen enums und Integer hat hier aber auch Vorteile. Vor allem bei digitalWrite(). Da kann man dann sowas machen:
Code: [Select]

digitalWrite(led, var1 > var2);

Wenn man da nur die typisierte enums übergeben könnte, ginge das nicht mehr

combie

#5
Sep 19, 2018, 06:43 pm Last Edit: Sep 20, 2018, 08:53 am by combie
Ihm sprach von "Auswahl".
Wenn an der Stelle allerdings auch Ausdrücke gewünscht sind, dann hast du Wahr.
Das kann ich mir bei pinMode() allerdings kaum vorstellen

Quote
und Integer
Gerade bei digitalWrite() , wäre bool vermutlich der passendere Datentype.
Und nicht eine enum Konstante, oder gar ein int

Aber auch hier wieder:
Damit es in C funktioniert, ist das Original schon ok


----

Wie auch immer...
Bis jetzt habe ich das eigentliche Problem von arduino-wasser noch nicht verstanden!

Also können meine Vorschläge, nur Vorschläge sein, keine festen Empfehlungen.
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

arduino-wasser

Ich baue gerade aus 8Stück 4-fach 7Segment Anzeigen (also 32 7Segmente) eine Matrix mit meinen noch übrigen 74HC595. Die Segmente sind in 2 Zeilen a 16 Digits angeordnet. (was ich aber später auch noch flexibel in die große Funktion einbinden will, sodass Länge x Breite beliebig werden)

Dazu brauch ich nun eine "dicke" Funktion die mir eine simple Print-Befehl Ausgabe ermöglicht. Ich will so Sachen lösen wie ALIGN_LEFT, ALIGN_RIGHT als auch die eventuelle Zahlenbasis (DEC, HEX, OCT).
Die einzelnen Funktionsbrocken habe ich schon fertig. Weitere grundliegende Textformatierungen kommen noch. Zur Zeit funktioniert schon die ersten beiden Formatierungsanweisungen, jedoch man muss halt zur Zeit immer noch separat geschachtelte Funktionen aufrufen.

Den zweiten Lösungsvorschlag von combie finde ich sehr interessant. Bis dato hatte ich noch keinerlei Kontakt mit "echtem" C++ und somit auch weder mit enum noch mit Klassen (deutscht man das eigentlich ein?)

Gibt es da eventuell zu einen Verständlichen Artikel um sich dem Thema langsam zu widmen und danach auch zu kapieren was man denkt zu tun? Vielleicht sogar auf Deutsch?

Tommy56

Da sollte es ein richtiges C++ Buch tun.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

combie

Quote
Dazu brauch ich nun eine "dicke" Funktion die mir eine simple Print-Befehl Ausgabe ermöglicht. Ich will so Sachen lösen wie ALIGN_LEFT, ALIGN_RIGHT als auch die eventuelle Zahlenbasis (DEC, HEX, OCT).
Zum Teil ist das schon fertig.
Du könntest von Print erben, so wie es auch Serial und die LCD Klassen tun.
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Serenifly

#9
Sep 20, 2018, 03:54 pm Last Edit: Sep 20, 2018, 03:56 pm by Serenifly
Enums gibt es auch in C. Die C enums haben aber ein paar Probleme:
1.) sie sind nur schwach typisiert und direkt in Integer konvertierbar. Das kann zwar auch Vorteile haben (siehe oben), aber erlaubt auch allerlei Unsinn.
2.) in Standard C/C++ nicht möglich den darunter liegenden Typ anzugeben (z.B. byte oder int). Einige Compiler wie GCC erlauben das aber
3.) die einzelnen Konstanten landen im gleichen Scope. Das heißt z.B. wenn zwei enums eine Konstante namens "None" haben gibt es einen Fehler.
4.) es war nicht möglich ein enum mit dem vollen Namen (d.h. Enumeration::Konstante) anzugeben (in C++11 geht das)

Letztlich sind C enums daher nicht viel anders als einzelne #define Konstanten (und die Arduino Software verwenden für solche Sachen auch #define Makros)


Deshalb gibt es seit C++11 strongly typed enums. Das gibt man mit "enum class" an, aber mit Klassen hat das eigentlich nichts zu tun. Hier hat jetzt jede Konstante nur den Scope ihrer eigentlichen Enumeration (das ist auch der Grund weshalb man "class" als Schlüsselwort genommen hat. Die Konstanten sind so gekapselt). Man kann Konstanten so mehrfach verwenden. Und sie haben ihren eigenen Typ der nicht in Integer konvertierbar ist

arduino-wasser

#10
Sep 21, 2018, 09:58 am Last Edit: Sep 21, 2018, 10:09 am by arduino-wasser
Ok, also das ganze denke ich ist genau das was ich gesucht habe. Nur eines habe ich noch nicht wirklich verstanden, in deinem Beispiel definierst du

Code: [Select]
enum class Variante:byte {Bli=0,Bla=3,Blub=42};

und rufst dann die Funktion (nennt man das dann noch Funktion, oder Beschreibt man das nun anders?) via Variante::Blub, Variante::Bla etc. auf, das hab ich soweit verstanden.

Aber wird dann den "Namen" in dieser Funktion beim Deklarieren ein byte Wert zugewiesen? Ist die Zuweisung der Werte in der geschweiften Klammer in etwa das was ich auch mit #define mache, nur in diesem Fall lokal auf meine jeweilige Funktion begrenzt (also nur in diesem Scope). Könnte ich somit auch die Funktion so aufrufen Variante::42?

Wie rufe ich dann "tuwas" richtig auf
tuwas(42) oder tuwas(Blub)   .....ich denke ich versuche mich gerade selbst zu verwirren. Ich will so eine Art von Übergabe einer Funktion haben ala
tudass(zahlzumdarstellen, ALIGN_LEFT, ROWx, COLUMNx, HEX) und da wäre halt gut wenn man den byte Wert bereits mit dem "Namen" der Variante substituieren könnte.

Und noch eine Frage, wie gebe ich einen Standartwert für eine solche Funktion vor wenn kein Wert übergeben wird?

//Es wird übrigens ein 32-Digit 7-Segment Anzeige Modul mit modularer Länge x Breite. Darum kann ich die .print Funktionen eigentlich nicht wirklich beerben, da ich alles via 74HC595 ausshifte und meine eigene Bitmap habe zum Darstellen aller Möglichen Symbole der Matrix. Und genau dafür brauch ich die einfache Auswahl der Methode der Anzeige beim direkten übergeben.

combie

#11
Sep 21, 2018, 10:50 am Last Edit: Sep 21, 2018, 10:51 am by combie
Du kannst auch
> enum class Variante:byte {Bli,Bla,Blub};
schreiben.
Dann überlässt du dem Kompmiler, welche Werte er vergibt.
Er wird mit Null beginnend aufwärts zählen


Quote
Standartwertf
So wie immer....
Code: [Select]
void tuwas(Variante variante = Variante::Bli)
{}



Quote
tudass(zahlzumdarstellen, ALIGN_LEFT, ROWx, COLUMNx, HEX) und da wäre halt gut wenn man den byte Wert bereits mit dem "Namen" der Variante substituieren könnte.
Darum habe ich dir das Beispiel in Posting #1 gezeigt.


Quote
Wie rufe ich dann "tuwas" richtig auf
Nicht ohne Grund, habe ich dir voll funktionsfähige, testbare, Beispiele gezeigt.
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Serenifly

Das sind keine Funktionen! Enum steht für Enumeration. Oder auf deutsch "Aufzählung". Da wird einfach jeder Konstante sequentiell ein Wert zugewiesen. Aber gerade bei den strongly typed enums interessiert dich der Wert dahinter nicht wirklich. Deshalb ist es besser man lässt die direkte Zuweisung weg und lässt das den Compiler erledigen

arduino-wasser

#13
Sep 22, 2018, 11:01 am Last Edit: Sep 22, 2018, 11:02 am by arduino-wasser
Ok nach einigem herumprobieren habe ich nun herausgefunden das man es nur über den folgenden aufruf klappt
tuwas(Variante::Blub);
nun würd mich aber interessieren wie denn die "eigentlichen" Arduino Funktionen bzw. dessen Librarys das  ganze ohne den Zusatz von 
Variante::
 vor dem Konfigurationsparameter schaffen?
als Beispiel nur mal diese PID Library https://playground.arduino.cc/Code/PIDLibraryConstructor dieser werden zur Konfiguration die Parameter
"Direction" und "POn"
 übergeben. Wie wird das gemacht? Ich hab mir die Library selbst schon angeschaut, stehe aber scheinbar ein wenig auf dem Schlauch.

noiasca

#14
Sep 22, 2018, 11:35 am Last Edit: Sep 22, 2018, 11:55 am by noiasca
OK, noch mal in einfachen Worten:
Die meisten core libraries verwenden defines
gehe dazu in Arduino/hardware/avr/cores/arduino und schau dir z.b. die print.h an
#define DEC 10
#define HEX 16
#define OCT 8

also kannst du das gleiche tun, bzw. wenn du etwas findest, dass du brauchen kannst auch reusen. D.h. deine Optionen für DEC, HEX, OCT sind schon da. Du brauchst in deinen Funktionen nur entsprechend darauf reagieren. Eigentlich musst du nicht einmal wissen welcher numerische wert hinter dem define steckt, denn du kannst ja auch beispielsweise auf case HEX abfragen und dann dein 0x... so wie du es haben möchtest selber ergänzen.

oder du verwendest enumerationen.

Auf Basis dessen was dir schon geschrieben wurde zwei Beispiele:

Code: [Select]

// mittels precompiler defines - so wie in vielen core libraries:
#define NO_BLINKING 0
#define BLINKING 1

// enumerationen können die die manuelle Durchnummerierung abnehmen:
// enumeration/Aufzählung in der einfachsten Art:   
enum {ALIGN_LEFT,               // die Aufzählung zählt die Elemente einfach durch: 0
      ALIGN_RIGHT,              // = 1
      ALIGN_MIDDLE,             // = 2
      ALIGN_MAGIC = 48          // du kannst aber auch einen Wert vergeben
     };         
// eigentlich soll dich der numerische Werte gar nicht interessieren,
// du verwendest ab jetzt deine Aufzählung ähnlich wie Konstanten.


void blinken(byte variante)
{
  switch (variante)
  {
    case  NO_BLINKING: Serial.println(F("no blinking")); break;
    case  BLINKING: Serial.println(F("blinking"));
  }
}

void tuwas(byte variante)
{
  switch (variante)
  {
    case  ALIGN_LEFT: Serial.println(F("Linksbündig")); break;
    case  ALIGN_RIGHT: Serial.println(F("Rechtsbündig")); break;
    case  ALIGN_MIDDLE: Serial.println(F("Zentriert")); break;
    case  ALIGN_MAGIC: Serial.println(F("blabla Irgendwas"));
  }
}


void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start"));
  tuwas(ALIGN_LEFT);
  blinken(BLINKING);
}

void loop()
{

}



so, wenn nun der Groschen gefallen ist, und du dir die erste Funktion zur Ausgabe erstellt hast, beherzige den Rat von Combie und schau dir mal die Print.h/Print.c an. Die sollst du wirklich beerben, denn die nimmt dir schon einiges ab: einen string in einzelne zeichen zerlegen, dec/hex/bin etc.
how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

Go Up