Problem mit Variablendeklaration

Hi, folgendes Szenario: Ich habe 2 Arduino Megas, auf denen das gleiche Programm laufen soll. Da ich aber eine unterschiedliche Pin Belegung auf beiden habe, möchte ich über eine boolean Variable am Anfang des Sketches die Pinbelegung einstellen können, quasi:

boolean switch_arduino = true;
//true = arduino 1
//false= arduino 2

if(switch_arduino){
// Pin Belegung 1
} else {
// Pin Belegung 2
}

void setup() {
//...
}

void loop(){
//...
}

Leider funktioniert das nicht: Eine If/ Else Abfrage vor setup() geht nicht und wenn ich die Pin Belegung im Setup mache, kann er im loop nicht auf die Variablen zugreifen (was not declared in this scope)... Wie löst man das Problem? Grüße

Die Deklaration

boolean switch_arduino = true;

//true = arduino 1
//false= arduino 2

gehört für das was du willst vor setup(). Als globale Variablen. Dann kann auch loop darauf zugreifen.

und

if(switch_arduino){
// Pin Belegung 1
} else {
// Pin Belegung 2
}

gehört in setup.

Code außerhalb von Funktionen oder Methoden geht nicht. Wann sollte der auch ausgeführt werden ?

Ulli

Ich würde das eher über defines lösen. Sprich "sprechende Namen" für die verwendeten Pins vergeben und daann auf den verwendeten Arduino mappen.

Z.B.

#define ARDUINO1

#ifdef ARDUINO1

#define MOTORPIN 5
#define LEDPIN 3
#define INPUTPIN 7

#endif

#ifdef ARDUINO2

#define MOTORPIN 6
#define LEDPIN 2
#define INPUTPIN 9

#endif

...

void setup() {
 pinMode(MOTORPIN, OUTPUT);
 pinMode(LEDPIN, OUTPUT);
 pinMode(INPUTPIN,INPUT);
 ...
}

void loop() {
...
 digitalWrite(LEDPIN,HIGH);
...
}

Du sparst Dir damit Code und vor allem Speicher, weil die Werte nicht als Variable im Speicher stehen müssen, sondern vom Präprozessor beim compilieren schon ersetzt werden. Um zwischen den Arduinos zu wechseln musst Du dann nur noch das "#define ARDUINO1" auf "#define ARDUINO2"

ändern.

Mario.

beeblebrox: Die Deklaration

boolean switch_arduino = true;

//true = arduino 1 //false= arduino 2




gehört für das was du willst vor setup(). Als globale Variablen.
Dann kann auch loop darauf zugreifen.

und


if(switch_arduino){ // Pin Belegung 1 } else { // Pin Belegung 2 } ```

gehört in setup.

Code außerhalb von Funktionen oder Methoden geht nicht. Wann sollte der auch ausgeführt werden ?

Ulli

ok, habe das jetzt so gemacht aber der Fehler "was not declared in this scope" tritt weiterhin auf:

boolean switch_arduino = true;
//true = arduino 1
//false= arduino 2

void setup() {
  Serial.begin(9600);
  if (switch_arduino) {
    int i = 1;
  } else {
    int i = 2;
  }
}

void loop() {
  Serial.println(i);
}

Beide oben vorgestellten Varianten sind eine gute Lösung - erfordern aber jeweils ein manuelles Eingreifen in den Code um zu sagen, auf welchen Arduino man nun übertragen will.

Ein dritter "Trick" wäre eine Kombination von allem - in Verbindung mit einem freien Pin auf beiden Boards: Bei Arduino1 wird z.B. Pin 10 auf GND gelegt, auf Arduino2 wird Pin 10 via 10 kOhm auf 5V gelegt. Dieser Pin wird im Programm abgefragt - und steuert das Verhalten. Spart die Eingriffe in den Code und minimiert das Risiko, den "falschen" Code zu übertragen.

LG, Rudi

void setup() {
  Serial.begin(9600);
  if (switch_arduino) {
    int i = 1;
  } else {
    int i = 2;
  }
}

Bis auf Serial.begin ist das natürlich Unfug. Die beiden lokalen Variablen i sind weg, noch bevor setup zu Ende ist.

2 Arduino Megas, auf denen das gleiche Programm laufen soll

Wenn du es strikt meinst, ist natürlich eine Konstante (globale Variable)boolean switch_arduino = true;verkehrt, denn du musst die für jeden der beiden Arduinos unterschiedlich setzen und neu kompilieren/hochladen. Dann ist die vorgeschlagene #ifdef Lösung besser.

Wenn du es ernst meinst mit "identisches Programm", müsstest du in setup etwas abfragen, woran du die beiden unterscheiden kannst.

const byte DETECTPIN=20; // Bei Arduino1 auf HIGH, bei Arduino2 auf LOW
byte motorpin; // kann leider nicht const sein

void setup() {
bool switch_arduino = digitalRead(DETECTPIN);
  if (switch_arduino) {
     // Arduino 1
     motorpin=5; 
     ...
  } else {
     // Arduino 2
     motorpin=6; 
     ...
  }
  Serial.begin(9600);
  Serial.print(F("Start Arduino"));
  Serial.println(switch_arduino?"1":"2");
}

Du könntest die Pinbelegung in den EEPROM legen und hättest damit nur einen Kode ohne Trickserei.

Whandall: Du könntest die Pinbelegung in den EEPROM legen und hättest damit nur einen Kode ohne Trickserei.

Das ist gut, wenn das Projekt final ist und sich nicht mehr ändert. Ansonsten ist der Aufwand die Daten im EEPROM aktuell zu halten recht groß, wenn sich mal was ändert. Ist ja jedesmal ein eigener Sketch der die Konfig (abhängig davon welcher Arduino) in den EEPROM schreibt.

Die Idee mit dem freien PIN ist gut. Der wird mit INTERNAL_PULLUP als Eingang gesetzt. Bei einem Arduino ist er auf Masse (GND) gelegt und auf dem anderen nicht. Dann kann der Code selbst entscheiden auf welchem Arduino er läuft.

100-200-00:
Wie löst man das Problem?

Ich habe schon Ähnliches programmiert und es so gelöst, wie whandall es vorschlägt.

Benutze entweder einen freien Pin, um die beiden Arduinos per Jumper als Arduino Nr. 1 oder Nr. 2 zu identifizieren, oder lege jeweils einen entsprechenden „Hinweis“ im EEPROM ab.

Gruß

Gregor

mkl0815: Das ist gut, wenn das Projekt final ist und sich nicht mehr ändert.

Wenn vom Start weg klar ist, dass es zwei Arduinos braucht und man nur einen Wert ins EEPROM schreibt, der die Arduinos identifiziert, muss man das nur einmal machen. Der Aufwand hierfür (einen eigenen Sketch für das Schreiben ins EEPROM) ist überschaubar.

Ich habe das mal bei einer Handvoll Arduinos so gemacht. Dort war am Anfang des EEPROMs lediglich eine andere I²C-Adresse abgelegt.

Gruß

Gregor

Das Setzen der Information im EEPROM mache ich im selben Sketch, die Funktion wird halt erst durch ein Kommando ausgelöst.

Nicht gesetzt lässt sich einfach erkennen, defaults sind also einfach.

ok, habe das jetzt so gemacht aber der Fehler "was not declared in this scope" tritt weiterhin auf:

Ja! Ist auch berechtigt!

'i' was not declared in this scope

Tipp: Meldung nochmal aufmerksam lesen!

ok, ich muss mich entschuldigen. Ich musste feststellen, dass es Abweichungen im Code zwischen Arduino1 und Arduino2 gibt (Bei Arduino1 lese ich digital und bei Arduino2 analog), mein Code soll also ähnlich sein. Habe jetzt auch mein Fehler entdeckt: Die Deklaration meiner Variablen i erfolgte nur lokal in der Funktion setup. Daher würde ich das jetzt wie folgt lösen:

boolean switch_arduino = false;
//true = arduino 1
//false= arduino 2
int i; //const geht nicht
void setup() {
  Serial.begin(9600);
  if (switch_arduino) {
    i = 1;
  } else {
    i = 2;
  }
}

void loop() {
  Serial.println(i);
  //gleicher Code
  //...
  //unterschiedlicher Code
  if (switch_arduino) {
    //Code Arduino1
  } else {
    //Code Arduino2
  }
}

Edit: Die Idee mit der Abfrage eines Pins ist für die Entscheidung einer Variablendeklaration ist gut, aber ich werde das einfach mit meiner boolean switch_arduino lösen, die ich vor dem Compilieren händisch änder, bevor der Sketch hochgeladen wird.

aber ich werde das einfach mit meiner boolean switch_arduino lösen, die ich vor dem Compilieren händisch änder, bevor der Sketch hochgeladen wird.

#ifdef solltest du prinzipiell auch ins Auge fassen, selbst wenn es auf Speicherplatz und Ausführungsgeschwindigkeit nicht ankommt.

Generell noch meine besten Wünsche: Hoffentlich passiert nichts, wenn du aus Versehen mal den falschen Sketch lädst.

Verdammt, die Bibliothek AccelStepper.h lässt keine nachträgliche Änderung der Pins zu. Sobald der Befehl

AccelStepper stepper(1, pin_pulse, pin_direction);

ausgeführt wurde, wird eine Wertzuweisung von pin_pulse und pin_direction nicht mehr übernommen :(… (d.h. mein stepper ist als “stepper(1, NULL, NULL);” definiert

Fügst du eben eine Funktion hinzu:

Im einfachsten Fall direkt in die Library ( https://github.com/adafruit/AccelStepper )

in AccelStepper.h irgendwo hinter public:

  void setPins(byte pin1, byte pin2);

in AccelStepper.cpp

void AccelStepper::setPins(byte pin1, byte pin2){
   _pin1 = pin1;
   _pin2 = pin2;
   enableOutputs();
}

stepper.setPins() kannst du dann in setup aufrufen

Alternativ kannst du auch eine eigene Klasse von Accelstepper ableiten, die dann die Methode setPins hat...

ifdef solltest du prinzipiell auch ins Auge fassen

michael_x: Alternativ kannst du auch eine eigene Klasse von Accelstepper ableiten, die dann die Methode setPins hat...

Das wird vermutlich leider nicht klappen, denn die Pins sind als private nicht als protected deklariert. Damit kann eine Klasse die von Accelstepper ableitet nicht direkt auf die Attribute zugreifen.

Ein Accelstepper Objekt soll nacheinander zwei verschiedene Sätze von Pins bedienen?

Ich verstehe nicht warum du die Pins ändern willst.

Leg das Objekt doch erst an, wenn du weisst welche Pins du benutzt.

michael_x:

ifdef solltest du prinzipiell auch ins Auge fassen

Ich habe jetzt eine Kombination aus beiden gemacht:

//##CHOOSE THE RIGHT BOARD!!##
#define Arduino1 // choose between Arduino1 / Arduino2
boolean switch_arduino = false; // choose between true: Arduino1/ false: Arduino2
//############################

#ifdef ARDUINO1
#define PULSE 5
#define DIRECTION 3
#define ENABLE 7
#endif

#ifdef ARDUINO2
#define PULSE 6
#define DIRECTION 2
#define ENABLE 9
#endif

int speed;
int acceleration;

AccelStepper stepper(1, PULSE , DIRECTION);

void setup(){
if(switch_arduino) {
speed = 100;
acceleration= 50;
}else{
speed = 200;
acceleration= 100;
}
stepper.setMaxSpeed(speed);
stepper.setAcceleration(acceleration);
stepper.setEnablePin(ENABLE);
}
void loop(){
//...
}

über #define deklariere ich meine Konstanten (Pin Belegung), boolean switch_arduino deklariert meine Variablen (Geschwindigkeit, Beschleunigung). Bisher klappt es mit Arduino 2, Arduino 1 werde ich erst nächste Woche testen können (ist in einem Versuchsaufbau integriert)

Danke für die Tipps!

100-200-00: Danke für die Tipps!

Noch ein Tippchen: Verwende nicht #define sondern z. B. const byte.

Das Problem mit #define ist, dass der Präprozessor dabei eine einfache „suchen und ersetzen“-Funktion ausführt. Dabei wird die Typprüfung des Compilers umgangen.

Andererseits: Wenn's auf diese Weise funktioniert ...

Gruß

Gregor