Funktions Aufrufe gibt Fehlermeldung

Hallo,
wie so fiele hier, versuche ich gerade meine Code aufzuräumen. Ich habe mich dazu mit dem erzeugen von Libs befast. Ich geb zu, das meine Kenntnisse in Sachen C++ nicht so doll sind. Aber mit genug Beispielen sollte das doch zu schaffen sein. Also habe ich hir

LibraryTutorial

nachgelesen wie das geht. Google´s übersetzung ist seid einiger Zeit erheblich besser geworden. Sodas ich das ganze eigentlich verstanden habe.

Beim Compilieren allerdings kommt eine Fehlermeldung die ich nicht nachvollziehen kann.

C:\Users\Turgut\Documents\Arduino\BlueTooth_Core_Version_4\BlueTooth_Core_Version_4.ino: In function 'void loop()':

BlueTooth_Core_Version_4:136: error: request for member 'timerControll' in 'btc', which is of non-class type 'BTC()'

   btc.timerControll() ;

       ^

exit status 1
request for member 'timerControll' in 'btc', which is of non-class type 'BTC()'

Ich benutze die IDE 1.8.5, die Dateien BTC.h und BTC.cpp sind im Editor geöffnet.
Was mache ich Falsch … oder habe ich etwas essemzielles übersehen?

MainCode wo die Funktion aufgerufen wird.

// Leider musste ich den Code wider raus nehmen da die Längenbeschränkung von 9000 zeichen
// zugeschlagen hat.

#define PIN_RECEIVE         11   // dieser Pin muss Interupt fähig sein
#define PIN_SEND            12

#define SerOnOff            0    // On/Off eingang für die Serielle ausgabe PC und Handy

#define SPEED_BLUETOOTH     57600    // diese geschwindigkeit muss im BlueThoot Modul eingestellt sein
#define SPEED_SERIAL        57600

#define StatusLED           13

byte    SerDelay      = 8   ;     // Warte Zeit nach Serial.println() in SPln()
byte    SerOn         = 1   ;     // Wenn sich die Com Schnitstelle gemeldet hat, Also ein Term angeschlossen ist

String s ;

unsigned long BlinkTimer ;
byte          BlinkState ;

unsigned long OldMill      ;
unsigned long Mill ;

#include <SoftwareSerial.h>
#include "BTC.h"

SoftwareSerial blueSerial(PIN_RECEIVE, PIN_SEND);

// Hir wird der Konstruktor für die BlueToothCore lib aufgerufen.
// Der name for der Klammer kann belibig sein. Er representiert die erzeugt
// Instance. Es könnte auch BTC Init(); sein. dann werden die Funktionen
// mit Init.Funktionsname(); aufgerufen. Dadurch lassen sich unterschiedliche
// Instancen mit den gleichen Codes erzeugen.

BTC btc();

void setup() {
  // put your setup code here, to run once:

  pinMode(StatusLED, OUTPUT) ;
  digitalWrite(StatusLED, HIGH) ;

  Serial.begin(SPEED_SERIAL);
  blueSerial.begin(SPEED_BLUETOOTH);

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println(F("Reset"));
  blueSerial.println(F("Reset"));

}

void loop() {
  // -----------------------------------------------
  // Hardware seitige aus und einschalten der Seriellen Ausgabe.

  if (analogRead(SerOnOff) > 900) { // Schalter für die Serielle Ausgabe  (A1)
    if (BlinkTimer < Mill)
    {
      BlinkTimer = Mill + 200 ;
      SerOn = 1;
      if (BlinkState == 0)
      {
        BlinkState = 1 ;
      }
      else
      {
        BlinkState = 0 ;
      }
      digitalWrite(StatusLED, BlinkState) ;
    }
  }
  else {
    if (BlinkTimer < Mill)
    {
      BlinkTimer = Mill + 1000 ;
      SerOn = 0;
      if (BlinkState == 0)
      {
        BlinkState = 1 ;
      }
      else
      {
        BlinkState = 0 ;
      }
      digitalWrite(StatusLED, BlinkState) ;
    }
  }

  Mill = millis() ;
  if (OldMill > Mill)
  {
    s = F("OverLoad millis()") ;
    SPln() ;
  }
  OldMill = Mill ;

  btc.timerControll() ;

}

//----------------------------------------------------------------------
void SPln()
{
  if ( SerOn == 1 ) {

    Serial.println(s) ;
    blueSerial.println(s);
    delay(SerDelay);

  }
}
//-----------------------------------------------------------

Die BTC.h

/* 
  BlueToothCore.h - Bibliothek für zurgriff auf HC-06 BlueTooth Modul. 
  Erstellt von Turgut Temucin aka TFT, 6. November 2017. 
  Publik Domain 
*/ 
#ifndef BTC_h 
#define BTC_h 

#include "Arduino.h" 

class BTC 
{ 
  public :
    // hir werden die Variablen und Funktionen Deklariert die von ausserhalb der lib
    // zugänglich sind.
    
    BTC() ; // Der Konstrucktor
    void timerControll() ; // Prüft den überlauf der millis() Funktion und Actualisiert diesen in _Mill
    
  private :
    // hir werden die Variablen und Funktionen Deklariert die nicht von ausserhalb der lib
    // zugänglich sind.
     
    unsigned long _OldMill ;

} ; 

#endif

Die BTC.cpp

/* 
  BlueToothCore.cpp - Bibliothek für zurgriff auf HC-06 BlueTooth Modul. 
  Erstellt von Turgut Temucin aka TFT, 6. November 2017. 
  Publik Domain 
*/ 

#include "Arduino.h"
#include "BTC.h"

//----------------------------------------------------------------------
// Der Konstrucktor, zum erstellen einer Instance, kann auch Installations Code enthalten
BTC::BTC()
{
  pinMode(13, OUTPUT) ;
}

//----------------------------------------------------------------------
// Hir kommen dann die Funktionen hin

void BTC::timerControll()
{
  delay(1000) ;
}

Ändere es mal in

BTC btc;

vor der Zeile

void setup() {

Hallo,

OK ... das hat geholfen. Aber warum?

Hmm,

BTC btc();

// Deklaration einer Funktion, die ein BTC-Objekt zurückliefert.

Das heißt ........ ich brauch die Klammer nur wenn ich auch wirklich Parameter übergebe?

ja.

Ausserdem - auch mit Parameter gibt es einen Unterschied, den der Compiler erkennen kann:

MyClass x(int p); // Eine Funktionsdeklaration

MyClass x(10);

// Die Definition eines Objekts, wenn der Konstruktor einen Parameter braucht.

OK ... das ist einleuchtend, darf ich dich noch weiter mit Fragen Plagen?
Ich verzweifle schier an der Umstellung von 30 Jahre Procedual Programmiert. Und jetzt C++.

Kopf hoch, das gibt sich.
Das ging mir bei der Umstellung von ANSI-C zu JAVA auch ne Weile so.

Gruß Tommy

Ich stelle mich gerade von PHP auf C++ um.
Jetzt ca 3 Jahre dabei, und noch nicht fertig damit.

Habe Geduld mir dir.

OK ... das ist einleuchtend

Das klingt doch schonmal vielversprechend :wink:

Dass dein Code

BTC::BTC()
{
  pinMode(13, OUTPUT) ;
}

nur ein Spaß-Beispiel ist, brauchen wir nicht zu diskutieren, richtig ?

brauchen wir nicht zu diskutieren, richtig ?

Doch, das müssen/sollten wir!

Denn: Das darin eingelagerte Problem dürfte längst noch nicht jedem bekannt sein.

Eigentlich sind es sogar 2 Probleme.

Mindestens.

Du meinst vermutlich so Fragen wie

  • wann nach Reset pinMode aufgerufen werden darf, bzw. wann der c'tor eines globalen Objekts läuft?
  • ob es gut ist, dass Pin 13 so tief vergraben hart kodiert ist?
  • ob solch eine Klasse sich überhaupt Pins fest reservieren sollte?

Tja Temucin, so kommt's hier schonmal bei interessanten Fragen.

Du meinst vermutlich so Fragen wie

Jawoll!
Und auch genau in dieser Reihenfolge!

Diese drei Dinge machen die Klasse zu einer Wegwerfklasse, bestenfalls für dieses eine Projekt geeignet.
Und das ist ja nicht unbedingt im Sinne der OOP, welche eher auf gute Wiederverwendbarkeit setzt.

Also den Pin würde ich nicht fest in der Klasse verdrahten, sondern eher als private Variable speichern und die im Konstruktor setzen. Evtl. könnte man ja LED_BUILTIN als Defaultwert angeben - gibt es den überall - wenn nein, dann eher nicht?

Den PinMode würde ich in eine begin()-Methode packen.

Das wären meine Gedanken dazu, ich bin da von der Erfahrung her aber eher etwas JAVA-lastig. Korrigiert mich, wenn ich für MC daneben liege.

Gruß Tommy

Den PinMode würde ich in eine begin()-Methode packen.

Genau!
Und dann in setup() aufrufen.

Auch wenn es bei den Pins des AVR egal ist.
Bei anderen µC/Dingen ist es das nicht.

Im Konstruktor kann man sich nur sicher sein, dass das Objekt selber gerade erzeugt wurde. Alle Abhängigkeiten können noch im Nirvana stecken.

Hallo,
in Anregung einiger Komments hier. Habe ich das Projekt komplett umstrukturiert. C++ ist gar-nicht nötig. Wenn man sich die Besonderheiten der Aktuellen IDE zu nutze macht. Das Main Programm, nachdem auch der Ordner benannt ist. Enthält nun alle Variablen Deklarationen. Der SetUp und MainLoop Teil befinden sich nun in einer weiteren Datei mit der Endung .ino (1_MainLoop.ino) , gefolgt von 1_Algemeine Funktionen.ino , 2_SystemCode.ino. Die Nummerierung entscheidet darüber in welcher Reihenfolge die Sketch geladen werden. Normaler weise sind diese dem Alphabet nach geordnet. Das kann aber zu Problemen führen wenn Funktionen aufgerufen werden die noch nicht deklariert wurden.

Danke für die anregende Diskusion.

Gruss TFT