Es gibt einen Unterschied zwischen normalen Funktionszeigern und Zeigern auf Klassenmethoden. Der Grund ist ganz einfach. Klassenmethoden haben zusätzlich noch den versteckten this-Zeiger als Parameter. Man kann also einem Zeiger der eine einfache Funktion erwartet keinen Zeiger auf eine Methode innerhalb einer Klasse zuweisen, da die Parameter nicht passen.
Die Lösung ist eine statische Wrapper Funktion (die dann durch das static keinen this-Zeiger hat), welche wiederum die eigentliche Klassen-Methode aufruft. Diese statische Funktion kannst du dann einem Funktionszeiger zuweisen. Zwei Funktionen deshalb weil man in einer statischen Funktion keinen Zugriff auf nicht-statische Variablen hat. Die statische Funktion kann dann public sein und die nicht-statische private.
Ansonsten poste mal mehr Code. Dir sind die Zusammenhänge klar, aber wenn man die verwenden Klassen nicht kennt (was ist NewPing?) ist das etwas verwirrend.
#include "SONARsensor.h"
NewPing dypme007[SONAR_NUM] = {NewPing (SONIC_N_PING, SONIC_N_ECHO, MAX_DISTANCE),
NewPing (SONIC_E_PING, SONIC_E_ECHO, MAX_DISTANCE),
NewPing (SONIC_S_PING, SONIC_S_ECHO, MAX_DISTANCE),
NewPing (SONIC_W_PING, SONIC_W_ECHO, MAX_DISTANCE)
};
uint8_t currentSonar = 0;
uint8_t cm[SONAR_NUM]; // Where the ping distances are stored.
//--------------------------- end of declarations and initilisations ------------------------------
bool SONARsensorClass::init(dypme007data_t* _ref) {
dypme007data = _ref;
printf("Initializing DYPME007 devices...\n\r");
pingTimer[0] = millis() + 75; // First ping starts at 75ms, gives time for the Arduino to chill before starting.
for (uint8_t i = 1; i < SONAR_NUM; i++) { // Set the starting time for each sensor.
pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}
printf("DYPME007 connection successful for %i sensors\n\r",SONAR_NUM);
return true;
}
//--------------------------- end of init ---------------------------------------------------------
void SONARsensorClass::updateSonar() {
for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
if (millis() >= pingTimer[i]) { // Is it this sensor's time to ping?
pingTimer[i] += PING_INTERVAL * SONAR_NUM; // Set next time this sensor will be pinged.
if (i == 0 && currentSonar == SONAR_NUM - 1) {
oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
}
dypme007[currentSonar].timer_stop(); // Make sure previous timer is canceled before starting a new ping (insurance).
currentSonar = i; // Sensor being accessed.
cm[currentSonar] = 0; // Make distance zero in case there's no ping echo for this sensor.
dypme007[currentSonar].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
}
}
}
//--------------------------- end of readDYPME007 -------------------------------------------------
void SONARsensorClass::echoCheck() {
if (dypme007[currentSonar].check_timer()) {
cm[currentSonar] = dypme007[currentSonar].ping_result / US_ROUNDTRIP_CM;
}
}
//--------------------------- end of echoCheck ----------------------------------------------------
void SONARsensorClass::oneSensorCycle() {
static uint32_t lastMillis = millis();
if(millis()-lastMillis>=1000){
for (uint8_t i = 0; i < SONAR_NUM; i++) {
Serial.print(i);
Serial.print(" = ");
Serial.print(cm[i]);
Serial.print("cm ");
}
Serial.println();
lastMillis = millis();
}
}
//--------------------------- end of oneSensorCycle -----------------------------------------------
void SONARsensorClass::calcAverageDistanceToGround() {
uint16_t _temp = 0;
// averageDistanceToGround = _temp / SONAR_NUM;
}
//--------------------------- end of calcAverageDistanceToGround ----------------------------------
SONARsensorClass sonarSensor;
/*----------------------------------------------- end of DYPME007Class --------------------------*/
.h
// SONARsensor.h
#ifndef _SONARSENSOR_h
#define _SONARSENSOR_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "NewPing.h"
#include "Config.h"
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
#define SONAR_NUM 4
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).
/*----------------------------------------------- end of declarations and initialisations -------*/
typedef struct {
uint8_t distanceToGround[SONAR_NUM];
}dypme007data_t;
void echoCheck(); // If ping received, set the sensor distance to array.
/*--------------------------- end of echoCheck --------------------------------------------------*/
class SONARsensorClass
{
protected:
dypme007data_t* dypme007data;
void oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
// void echoCheck();
void calcAverageDistanceToGround();
int32_t lastMicros;
uint32_t pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
public:
uint8_t currentSonar; // Keeps track of which sensor is active.
void echoCheck();
bool init(dypme007data_t*);
void updateSonar();
};
extern SONARsensorClass sonarSensor;
#endif
/*----------------------------------------------- end of SONARsensorClass -----------------------*/
Aus dem Hauptprogramm wird "upateSonar" aufgerufen.
um es vorneweg zu sagen. Dieses Verständnis für C++ Programmierung werde ich wohl nicht mehr erreichen. Da bekomme ich Hirnfrost ;). Ich bin da Realist, d.h. ambitionierter Anfänger der froh ist wenn sein Quadrocopter mal aufsteigt. Wenn derartige Probleme wieder auftauchen, werde ich auch weiterhin auf eure Hilfe angewiesen sein.
Ich habe mir die NewPing Klasse mal angeschaut, und die Unterschiede zu Deiner Version gekennzeichnet.
.h
class PingClass {
public:
....
void ping_timer(void (*userFunc)(void)); <-------------------------- Orginal, sieht aus wie Dein void set(void (*f)(void));
private:
...
void (*funcPtr)(); <--------------------------- Das fehlt im Orginal funcPtr > userFunc umbenennen ?
};
.cpp
void PingClass::set(void (*f)(void)) <--------------------------- das fehlt auch im Orginal funcPtr > userFunc umbenennen
{
funcPtr = f;
}
In meiner Sensorklasse würde ich dann alle Members und Methoden mit static versehen. Wäre das so richtig? Ich habe die Orginaldateeien mal angehangen.
kucky:
In meiner Sensorklasse würde ich dann alle Members und Methoden mit static versehen. Wäre das so richtig? Ich habe die Orginaldateeien mal angehangen.
Bei statischen Variablen musst du diese allerdings auch ein der .cpp Datei implementieren, sonst bekommst du einen Fehler vom Linker.
Dafür war das in der Test-Klasse da:
int SensorClass::testvalue;
const int SensorClass::MAX_SENSORS = 3;
Ping SensorClass::sensors[MAX_SENSORS];
Bei nicht-statischen Variablen ist das nicht nötig
EDIT:
Du musst nichts an der Ping Klasse ändern!! Ich habe mir da nur eine primitive Klasse geschrieben um das zu testen und zu sehen ob es kompiliert. Lass es so wie es ist.
In der Klasse sind die Funktionszeiger hier:
void (*intFunc)();
void (*intFunc2)();
Und den Zeiger den du übergibst wird dann an timer_us() durchgereicht