Richtig Deklarationen und Code spliten

combie:
Stell dir nur mal vor, du würdest dich mal in das einarbeiten, was du da tust, und plötzlich verstehst du die verrücktesten Programme. Kannst dich mit ALLEN Programmieren weltweit austauschen.
Wäre das nicht wunderbar?
Mich würde erfreuen, wenn du da mal hin kommst!

Mich auch, jedoch ist das Thema extrem Komplex finde ich, leider fehlt mir auch oft die zeit, da ich sonst nihcts Programmire, und nur die kleinen für euch wahrscheinlich echt super kleinen Projekte habe.

Mein Weg ist der C++ Weg.
Der C++ Welt weit akzeptierte Standard Weg.
(zumindest dicht dran)

Denn habe ich mir angeschaut, ich bin auch sehr begeistert davon, verstehe aber extrem wenig davon, habe heute auch einiges nachgeschlagen und nachgelesen, und bin extrem verwirrt dadurch, ich kann dir noch nicht mal sagen warum eigendlich, es dreht sich alles udn ich verstehe davon fast nichts. sobald ich eine Kleinigkeit ändere kommen Fehlermeldungen die ich wider nachschlagen muss ;-).

Ich würde gerne so viel davon verstehen, und richtig Können, nur wir wissen ja wie das ist wenn man das gelernte nicht anwendet dann verblast es auch wider, ich wende es immer dann an wenn ich hier im Forum schreibe ansonsten habe ich damit 0,0 Zutun.

Tommy56:
Include bindet ein, da ist nix mit "an bestimmter Stelle per Include aufrufen".

Gruß Tommy

Verstehe ich nicht ;-(
ich hatte den Befehl Include bisher so verstanden das ich genau an der Stelle an der der Befehl steht denn Text schreibe der in der Datei steht der durch Include aufgerufen wird.

Sprich das was ich da im Kopf habe geht nicht?

Gruß Mücke

Was du im Kopf hast sehen wir nicht.
:smiling_imp: Ich weiß auch nicht ob ich das überhaupt sehen will. :smiling_imp:

Tipp:
Solange du begründest, warum das nichts werden kann, solange wird das auch nichts.

Denn:
Wer will, findet Wege.
Wer nicht will, findet Gründe.

, ich kann dir noch nicht mal sagen warum eigendlich,

Darüber solltest du dir klar werden.

Denn dann könntest du mich fragen.
So kleine konkrete Fragen....
Denn es hat ja Gründe, warum ich das so, genau so, und nicht anders, getan habe.

combie:
Was du im Kopf hast sehen wir nicht.
:smiling_imp: Ich weiß auch nicht ob ich das überhaupt sehen will. :smiling_imp:

:o ist vielleicht besser so, ist manchmal ziemlich Karotisch in meiner Birne :wink:

combie:
Tipp:
Solange du begründest, warum das nichts werden kann, solange wird das auch nichts.

Denn:
Wer will, findet Wege.
Wer nicht will, findet Gründe.

Das ist mir auch klar.

combie:
Darüber solltest du dir klar werden.

Denn dann könntest du mich fragen.
So kleine konkrete Fragen....
Denn es hat ja Gründe, warum ich das so, genau so, und nicht anders, getan habe.

genau das wäre echt schön wenn ich das wüste, ich wollte auch kein Blöden Fragen stellen, bei denen ich mit einfachen Google drauf komme, denn dann wird mir auch irgend wann nicht mehr geholfen das will ich nicht.

Etwas selbst zu erarbeiten ist auch mal ganz gut :wink:
Vielleicht kommt das wenn ich die ein oder andere Nacht drüber geschlafen habe, das ich das ein oder andere doch verstehe, und dann Konkrete fragen stellen kann.

@combie: Ich möchte es mal wagen: und kleine Fragen Stellen zu deinem Programm Aufbau.
Auch wenn ich Gefahr laufe das ich gleich mit Google bestraft werde.

Ich gehe das Haupt Programm von Oben nach unten durch.

  1. die Datei config.h wird eingebunden. OK
    es gibt jedoch keine Config.cpp somit stehen dort nur Deklarationen drin !

Hier hast du die Installation der Serielenschnitstelle und den Zeilenumbruch (Job Bestätigung) bei der Serielenschnitstelle.

ich habe das auseinander genommen was du da geschrieben hast: sieht dann so aus bei mir.

#pragma once

 static const unsigned long Baudrate = 9600;   // Geschwindigkeit, Serielle Schnittstelle
 static const char ZEILENTRENNZEICHEN = 10;    // Zeilenumbruch in der Serielle Komunikation


/*  static
 *   Variable bleibt bestehen wird nach einem Fungzionsaufruf nicht zerstört. 
 *  const
 *   Keine Variable sondern eine Konstante, kann werend des Programm 
 *   ablaufes nihct geändert werden. 
 *  unsigned long 
 *   keine negativen Zahlen, Bereich von 0 bis 4.294.967.295
 *  char
 *   ist ein art String wenn ein * dahinter steht dann wird nicht nur der
 *   Wert sondern die Zeichenkette im Speicher verändert ! extrem verwirend
 *   für mich.
 */

Meine Frage, warum hast du das #define hier raus genommen?
mit #define habe ich doch die Möglichkeit das der Wert der dahinter steht im gesamten Code eingetragen wird, warum hast du das bei dir so Kompliziert geschrieben?

Wenn ich die Config Datei richtig verstanden habe, kann ich in in die alles rein schreiben das sonst vor dem void setup() steht? auch genau so wie es vor dem Loop sonst steht, ich muss da auf nichts achten?

Ich arbeite mich langsam durch das Programm Stück für Stück, und versuche auch so viel als Möglich nach zu googeln.

Gruß Mücke

Damit man alles noch mal in der Übersicht hat:

MueckeAuslagern.ino

  #include "config.h"
  #include "Funktionen.h"                       // Deklarationen der Funkionen
  #include "Job.h"                              // Deklarationen der Funkionen
   
void setup()
{
  Serial.begin(Baudrate);                       // Seriellen Monitor Installiren
}

void loop()
{
  delay(10);                                    // warten für 10 millisekunde 
  Serielle_abfrage();                           // abfrage der Seiellen schnittstelle und Job aufrufen 
}

Funktionen.cpp

#include <Arduino.h>
#include "config.h"
#include "Job.h"
#include "Funktionen.h"

/* ***********************************************************************************************
 *                            FunktionSerielle Schnittstelle auslesen
 * ***********************************************************************************************/
  char* receiveBuffer() 
  {
    static char lineBuffer[35];
    static byte counter = 0;
    char c;
      if (Serial.available() == 0) return NULL;
      if (counter == 0) memset(lineBuffer, 0, sizeof(lineBuffer));
    c = Serial.read();
      if (c == ZEILENTRENNZEICHEN)
      {
        counter=0;
        return lineBuffer; 
      }
      else if (c>=40) 
      {
        lineBuffer[counter] = c;
        if (counter < sizeof(lineBuffer) - 2) counter++; 
      }
    return NULL; 
  }

/* ***********************************************************************************************
 *                            Funktion Serielle Schnittstelle Abfragen
 * ***********************************************************************************************/
void Serielle_abfrage()
{
  
   char* text=receiveBuffer();
     if(text != NULL)
     {
             if (strcmp_P(text, PSTR("Test"))==0)          { Job_Test(); }           // Ausgabe TEST
        else if (strncmp_P(text, PSTR("Print"), 5)==0)     { Job_Print(text + 6); }  // Ausgabe alles was Hinter Print: kommt
        else  { Serial.println(F("NOK, Unbekannter Job"));}
     } // if text 
     
} // Serielle_abfrage

Funktionen.h

#pragma once

char* receiveBuffer();
void Serielle_abfrage();

Job.cpp

#include <Arduino.h>
#include "Job.h"

/* ***********************************************************************************************
 *                            Job: Test
 * ***********************************************************************************************/
void Job_Test()
{ 
   Serial.println(F("OK, TEST")); 
}

/* ***********************************************************************************************
 *                            Job: Print
 * ***********************************************************************************************/
void Job_Print(char* str)
{ 
   Serial.print(F("Übergeben wurde: ")); 
   Serial.println(str); 
}

Job.h

#pragma once

void Job_Test();
void Job_Print(char* str);

Job.h

#pragma once

 static const unsigned long Baudrate = 9600;   // Geschwindigkeit, Serielle Schnittstelle
 static const char ZEILENTRENNZEICHEN = 10;    // Zeilenumbruch in der Serielle Komunikation
  1. die Datei config.h wird eingebunden. OK
    es gibt jedoch keine Config.cpp somit stehen dort nur Deklarationen drin !

Nein, das ist nicht wahr!

Dort werden 2 Konstanten deklariert und im gleiche Zug auch definiert.

Sie sind static, damit sie nur für jeweils eine Übersetzungseinheit gültig sind.
Sie sind nicht global für alle Übersetzungseinheiten.

Man könnte die Konstanten auch extern deklarieren und dann in einer *.cpp definieren.
Dann würde jede Übersetzungseinheit mit den selben Konstanten arbeiten.
Hat aber den Nachteil, dass diese Konstanten dann Ram brauchen, da sie dann für mehrere verlinkte Übersetzungseinheiten gelten. Denn der Linker kann das nicht optimieren.

Klarer:
Es werden für alle Übersetzungseinheiten die gleichen Konstanten verwendet. Aber es sind nicht die selben.

Größeren Variablen/Konstanten, z.B. Strings oder Arrays wird man in der config.cpp definieren und in der *.h als extern deklarieren. Eine Mehrfach Definition würde sonst Ram verplempern.

Im Grunde besteht das Programm aus 3 Übersetungseinheiten.
Die beiden Cpp und die Ino.
Jede arbeitet hier mit ihrem eigenen Konstantensatz. (welcher hier zufälliger Weise für alle gleich ist)

Meine Frage, warum hast du das #define hier raus genommen?
mit #define habe ich doch die Möglichkeit das der Wert der dahinter steht im gesamten Code eingetragen wird, warum hast du das bei dir so Kompliziert geschrieben?

Ich mag kein define!

Wo ich darauf verzichten kann, da tue ich es.

Hier lege ich Wert auf eine Typeprüfung.
Und im Falle das Falles auf aussagekräftige Fehlermeldungen/Warnungen.

Natürlich kannst du alternativ auch deine Defines nutzen.
Das kann und will ich dir nicht nehmen.

Es ist in weiten Kreisen, auch noch üblich das so zu tun.
Aber mit den neueren C++ Versionen, ist es kein Muss mehr.
Diese bieten meist bessere Wege.

Wenn ich die Config Datei richtig verstanden habe, kann ich in in die alles rein schreiben das sonst vor dem void setup() steht? auch genau so wie es vor dem Loop sonst steht, ich muss da auf nichts achten?

Das hättest du wohl gerne....

Das wird dir der Linker schon erklären, dass das so einfach nicht ist.

  • char
  • ist ein art String wenn ein * dahinter steht dann wird nicht nur der
  • Wert sondern die Zeichenkette im Speicher verändert ! extrem verwirend
  • für mich.

char ist ein grundlegender Datentype.
Die Abkürzung von Charakter, zu deutsch: Buchstabe.
Mir ist nicht logisch, wie so man nach so vielen Jahren davon noch verwirrt sein kann.
Offensichtlich hast du dich noch nie wirklich mit Datentypen beschäftigt.

Das solltest du mal tun. Das sind grundlegenste Grundlagen, ohne die du auf ewig und immer wieder der Verwirrungen erliegen wirst.

Und was du mit dem * hast, ist ja fast noch schlimmer....
Je nach Kontext, macht der Stern eine Multiplikation, oder er drückt aus, dass man sich mit einem Zeiger beschäftigt.
Offensichtlich verwendest du Zeiger, verstehst sie aber nicht.

char, int und auch die Zeigerwirtschaft mit dem * sind fast 50 Jahre alte Fakten.
Jeder, welcher erfolgreich programmieren möchte, MUSS das lernen.
Bedenke:
Du hast jetzt 4 Jahre Verwirrung, stochern im Nebel, und was auch immer, hinter dir.
Ein einziges Buch lesen.
1 Woche Konzentration.
Und das Thema wäre durch.


Eine Vergleich: (auch wenn er hinkt)
Der Straßenverkehr!
Ein Muecke im Straßenverkehr.
Er läuft da durch. Von einem Ende der Stadt, zum anderen Ende.
Immer wieder. Seit Jahren.
Hat aber nie die Verkehrsregeln gelernt.
Ampeln und Zebrastreifen sind ihm völlig egal.
Sie werden ausgeblendet, weil sie sonst nur verwirren.
Und sowieso, ist das alles bunt hier.
Verwirrend bunt.
Manchmal gelbe blinkende Lichter, manchmal rote Lichter.
Auch weiße Lichter. Manche haben sogar vorn und hinten weiße Lichter.
Manchmal bleiben die Autos stehen..
Mal einzelne, mal ganze Gruppen, wie auf ein heimliches Kommando.
Ohne jedes erkennbare System (denn die Ampeln werden ja ausgeblendet, weil zu verwirrend)
Und überhaupt, was sind Autos, wo kommen sie her?
Gibts da irgendwo Nester?
Wieso haben die alle 4 so schwarze Dinger, welche meist bis zum Boden reichen?

Wenn den Mücke nicht ab und zu mal eine ältere hilfsbereite Dame an die Hand nehmen würde, dann hätte er so manche Straßenüberquerung nicht überlebt.


Aus meiner Sicht bist du mehr und öfter und länger mit deiner Verwirrung beschäftigt, auf Irrwegen, als das Lesen eines Buches dauern würde.

Daraus erstelle ich eine Arbeitshypothese:
Du bist gerne verwirrt.
Du liebst deine Verwirrungen.
Und du bist um keinen Preis der Welt bereit auf diese herrlichen Verwirrungen zu verzichten.

Offensichtlich haben diese Verwirrungen dein bisheriges Überleben gesichert. Also kann der Weg so ganz falsch nicht sein. Auf eine Zukunft ohne diese Verwirrungen bist du darum nicht vorbereitet. Sobald eine Klarheit/Buch hinter einer Ecke hervorlugt, ziehst du dich schockiert/panisch in deine Verwirrung zurück.
Die Verwirrung hat eine Schutzfunktion!
Sie schützt dich vor Erkenntnis.
Vor der bösen Realität.
Und natürlich vor (leicht erreichten) Erfolgen.

Huch, das gleitet ja in die tiefe Psychologie ab. :o

um mal der einfacheren Methode wieder das Wort zu reden, die einfach besser für ungelernte Softwaredummies wie mich geeignet ist:

Muecke:
@guntherb du hast alles in ino Dateien gepackt, muss ich dann die Dinge nicht Deklarieren macht das die IDE dann wider?

ja, das macht alles die IDE.

Stell dir einfach vor, die IDE packe alle deine Reiter (also die *.ino Files im Sketchverzeichnis) von links nach rechts hintereinander.

Daher empfiehlt es sich auch, im ersten Reiter alle Deklarationen zu vereinbaren.
Ich habe bei mir meist eine Struktur wie diese:
Zwischenablage01.jpg
erster Reiter: Projektbeschreibung, Globale Variable, Inkludes, enums, Structs, Funktionsdeklarationen etc. Hier steht noch keine Zeile Programmcode

Zweiter Reiter: setup(), loop() und was dazugehört. Wobei die loop recht kurz ist und meist nur ein paar Zeitscheiben und Funktionsaufrufe enthält.

Dritter bis n-ter Reiter: das eigentliche Programm, aufgeteilt in mehr oder weniger sinnvoller Bereiche

Du kannst in den Reitern (Tabs) vollig frei programmieren. Die IDE behandelt das wie ein einziges grosses File, auch Fehlermeldungen des Compilers werden den entsprechenden Reitern zugeordnet.

Die Bezeichnung der Dateien mit x1_name, x2_name, ... sind so gewählt, weil die IDE die Reiter in alphabetischer Reihenfolge anordnet.

Huch, das gleitet ja in die tiefe Psychologie ab.

Habe ich übertrieben?
Ich denke schon!
Maßlos überzogen.

(Muecke, bist du mir jetzt böse?)

Hallo,

das mit den Fehlermeldungen der IDE Tabs kann auch ins Leere laufen. Der Fehlerhinweis zeigt dann plötzlich auf die falsche Stelle. Eine geschweifte Klammer im zusätzlichen Tab vergessen und die IDE will dir was von einem Fehler im Haupt-Tab erzählen. Da ist Vorsicht geboten. Immer erst dort schauen wo man zuletzt am Code geschrieben hat. Eine weitere Falle mit den Tabs kann noch lauern mit der Namensbenennung der Tabs. Irgendwas mit der alphabetischen Reihenfolge.

Ich sage mal so. Das mit den Tabs ist sehr einfach. Ist erstmal nichts dagegen zu sagen. Man sollte jedoch irgendwann versuchen sich mit der Beziehung Headerdateien und c/c++ Files auseinander zusetzen. Dann kann man auch später eigene Libs erstellen. Danach muss man nicht mehr jedes Tab .ino File rum und num kopieren sondern bindet einfache seine Lib oder seinen mühsam erstellten Funktionscode ein oder oder oder ...

Das macht man natürlich nicht von heute auf morgen ... so an Anregung.

Edit:
Wenn man sich das extra für dich/euch von combie vorbereitete "einbinden" anschaut, dann erkennt man eine gewisse Logik was wohin kommt, wie die Namen vergeben werden was wo eingebunden werden muss. Was neu hinzukommt ist eigentlich nur, dass man die Funktionsprototypen deklarieren muss in der Headerdatei. Das ist das was einem die IDE abnimmt.

Nunja...
Es ist ja nicht die erste Runde, in der Sache....
https://forum.arduino.cc/index.php?topic=502907.0

Da hatte ich schon empfohlen sich mal um den Unterschied von Deklaration und Definition zu kümmern.

Und dann kommt in hier in #3 dann dieses:

in der Datei Job.h habe ich hinein geschrieben

void Job_Test()
{ }

Welches keine Deklaration, sondern eine Definition ist.

Völlig hilflos, ich da bin....

Muecke:
in der Datei Job.h habe ich hinein geschrieben

void Job_Test()

{ }

Das ist eine DEFINITION, erkennbar an den geschweiften Klammern. Und zwar die Definition einer Funktion, die nichts tut.

Richtig wäre in Job.h die DEKLARATION

void Job_Test();

Hallo,

weil das gerade zum Thema passt. Auf eine Frage habe ich noch nirgends eine Antwort gefunden. Vielleicht wisst ihr das.
Warum ändert sich im Header plötzlich die Schreibweise der Headerdatei wenn diese abhängig definiert werden soll?
Die Headerdatei heißt meinetwegen test.h und man muss schreiben

// test.h
#ifndef test_h
#define test_h
...
#endif

Warum wird aus dem Punkt ein Unterstrich?

// test.h
#ifndef test_h
#define test_h
...
#endif

Das ist der "include guard"

Du kannst da jede beliebige Schreibweise verwenden.
Nur eben der Punkt, der ist da verpönt/unverwendbar.

// test.h
#ifndef qwertzuio
#define qwertzuio
...
#endif

Hat exakt die gleiche Wirkung.
Wichtig ist natürlich, dass nirgendwo anders im Code qwertzuio vorkommt.

Und:
Heutzutage tut man das nicht mehr!
Also den ganzen Salat weg lassen!

Und stattdessen:

#pragma once

Das ist der moderne Include Guard.
Einen anderen brauchen wir nicht mehr.

Weil test.h kein gültiger Token ( Name ) wäre.

dass du test_h definierst, ist übrigens dir freigestellt. Es sollte halt irgend ein Name sein, den es vorher nicht gab, und wenn doch, dann nur, weil vorher schon #include "test.h" durch irgendwelche Schachtelung von include-Dateien vorkam.

Mit dem Header-Namen selbst hat das nicht zwingend etwas zu tun. Der Name da könnte beliebig sein. Es wird lediglich eine Konstante definiert wenn der Header zum ersten mal eingebunden wird. Danach wird das nicht mehr ausgeführt. Das verhindert Mehrfach-Inkludierungen. Nennt sich "Include Guard"

Geht übrigens heutzutage einfacher mit #pragma once

Hallo,

hatte vorher über pragma gelesen das man damit vorsichtig umgehen soll, gezielt eingesetzt wiederum sehr nützlich, wie man sieht. Danke für die Erklärungen & Infos. :slight_smile:

Huch, jetzt war das doch länger als gedacht, das ich mal wider dazu komme etwas zu machen.
Kann man mit dem Arduinosich nicht auch etwas mehr Zeit Programmiren. :wink:

Ich wollte mit meiner Abwesenheit nichts andeuten oder bewirken! ich konnte mich leider nur nicht mit dem Thema Arduino C++ auseinander setzen da andere Dinge dazwischen gekommen sind. Sorry.

combie:
Habe ich übertrieben?
Ich denke schon!
Maßlos überzogen.

(Muecke, bist du mir jetzt böse?)

das vertrage ich schon noch, wenn es zu viel wird sage ich was, versprochen.
da musst du dir keine sorgen machen bei mir.

guntherb:
... Stell dir einfach vor, die IDE packe alle deine Reiter (also die *.ino Files im Sketchverzeichnis) von links nach rechts hintereinander. ...

Das habe ich heute morgen getestet, und das klappt bisher reibungslos, ich packe meinen Code in verschiedene Tabs die wiederum alle als INO gespeichert sind und in den TABs habe ich dann Funktionen erstellt in denen mein Ausführlicher Code steht.

So habe ich z.B. alle pinMode in die Funktion Setup_PIN() gepackt, die kann ich dann im Hauptprogramm im void setup() aufrufen, und mein Code ist etwas besser zu lesen :slight_smile: genau das wollte ich erreichen, denn sonst muss man immer so viel Scrollen.

Das Deklarieren übernimmt die IDE wider für mich, wobei ich dank @DrDiettrich

DrDiettrich:
Das ist eine DEFINITION, erkennbar an den geschweiften Klammern. Und zwar die Definition einer Funktion, die nichts tut.

Richtig wäre in Job.h die DEKLARATION

void Job_Test();

wies ich auch wie eine Richtige Deklaration funktioniert, ich habe versucht über das www heraus zu finden wie das funktionieren soll, leider nicht mit Erfolg.

ich tue mich mit den Beschreibung im C++ sehr schwer, leider.

Jetzt schaue ich das ich meinen Code etwas Strukturire, und immer schön langsam vor gehen, immer wider wenn ich was verändert habe Koppeliren lassen um zu sehen ob noch alle geht :wink:

Ich danke euch allen für die Hilfe. DANKE.

Wenn ich meinen Strukturierten Code fertig habe werde ich den mal hier veröffentlichen, das Ihr eure Hände über den Kopf zusammen schlagen könnt. ;-).

gruß Mücke