Go Down

Topic: Probleme mit Void und Funktionen. (Read 1 time) previous topic - next topic

ThinkCentre

Erstmal ein herzliches hallo an alle!
Eine super community ist das hier -habe schon sehr viel gelesen -nur leider nicht alles kapiert.  :smiley-red:

Zum Projekt.

Ich habe vor einiger Zeit ein Ferngesteuertes Auto umgebaut (aus einem Tutorial das ich im Netz fand) welches nun mit einem Arduino Uno bzw. meinem Smartphone (Android) gesteuert wird. Der Arduino dient als Empfänger und mein Smartphone als Sender über Bluetooth. Soweit funktioniert das auch alles (Die Kiste fährt und tut was sie soll) da alles ganz simpel über Low/High gesteuert wird. Ich sende ein "F" an den Arduino und der Schaltet mir einen Pin auf High. Ich sende ein "Z" und dieser schaltet den Pin wieder auf Low. (u.s.w)

(Hier der Link zum BasisTutorial: http://www.mobot.es/MobotBTCar.html ) -die App habe ich mit AppInventor nachgebaut weil ich die App aus dem Tutorial hässlich fande und ich das Smartphone lieber im Landscape Modus halte.

Jetzt zum Punkt der ganzen geschichte.

Ich würde gerne bei meinem neuen Auto welches ich gerade baue auch gerne Blinker und solche Funktionen einbauen. Und genau da hängt es in meinem Gehirn wenn ich den Code aus dem Tutorial als Basis nehme.

Hier ein Bsp:

Quote
int light = 12;    // Pin 12 - Light


char val;  // Variable to receive data from the serial port

void setup() {
 
  // initialize the digital pins as output
  pinMode(light, OUTPUT);
 
    Serial.begin(9600);    // Start serial communication at 9600bps
}

// Block Light on

void light_on() {
  digitalWrite(light, HIGH);   // turn the LED on (HIGH is the voltage level)
 
}

// Block Light Off
void light_off() {
  digitalWrite(light, LOW);
}
// Read serial port and perform command
void performCommand() {
  if (Serial.available()) {
    val = Serial.read();
  }
    if (val == 'f') { // Command Light On
      light_on();
    } else if (val == 'z') { // Command Light Off
      light_off();
      }
}

void loop() {
  performCommand();
  }


Die Led/Pin wird per Smartphone High/Low geschaltet. Funktioniert. Aber sobald ich möchte, dass in diesem Block

Quote
void light_on() {
  digitalWrite(light, HIGH);   // turn the LED on (HIGH is the voltage level)
 
}


geblinkt wird fangen die Probleme an. Die "Blink" beispiele der Arduino-Referenz einfach in den "Block" zu Kopieren klang einfach, stellten sich aber schnell als "Scheisse, geht doch nicht" raus -ob nun mit Delay oder ohne. Das Problem ist einfach diese Void Geschichte. Jede Art von "Blink" setzt irgendwie ein Void Loop() vorraus. Void Loop() habe ich allerdings schon am ende des Sketches zum Lauschen auf Serial.  :~

Ich habe langsam das gefühl, dass der komplette aufbau des codes einfach nicht mit meinem vorhaben zu machen ist. Ich möchte einfach, dass mein arduino diverse funktionen "loopt" wie zb. blinken aber nebenbei noch in der lage ist variablen zu empfangen bzw. zu verarbeiten um andere pins weiterhin high/low zu schalten z.b um das blinken abzuschalten oder rückwärts und forwärts zu fahren. 

Ich habe zwar u.a auch das Buch von Erik Bartmann zum Arduino allerdings bringt mich das auch nicht wirklich weiter da ich einfach zu blöd bin meine wünsche im sketch umzusetzen. Ich verstehe zwar das grundproblem in "meinem" code, habe aber absolut keine skills es so zu frickeln, dass es funktioniert. Bin da mittlerweile wirklich sehr frustriert da ich schon viele nächte hinter diesem problem hänge (immer mit dicken augen zur arbeit  :D ). Ich kann jetzt auch nicht unbedingt die programmiersprache von A-Z lernen da ich dafür einfach keine zeit habe durch meinen beruf.

(Ich würde auch gerne diverse €€€ springen lassen damit die scheisse endlich funktioniert. Damit hätte ich kein problem.)

Vll. kann mir ja jemand helfen.  :smiley-red:

mkl0815

Zunächstmal denke ich das hier das Anbieten von Geld Deine Chancen auf Hilfe nicht steigert. Ich kann mich irren, aber das ist bisher mein Eindruck.
Du wirst vermutlich nicht darum herum kommen, Dich mit einigen Dingen auseinander zu setzen, da hier recht einheitlich "Hilfe zur Selbsthilfe" - gelebt wird.

Zu Deinem Problem. Eine loop() Funktion reicht eigentlich völlig. Was Du zusätzlich brauchst, sind erstmal Variablen, die bei bestimmten Kommandos die von Deinem Smartphone kommen, gesetzt werden. Z.B.
" boolean  blinker_left, blinker_right = false;"
Das Blinken sollte nicht das Smart-Phone übernehmen, sondern der Arduino. Das Smartphone sendet nur ein Blinker ein oder aus.
Diese Variablen kannst Du global definieren, dann können alle Funktionen darauf zugreifen. Das "performCommand()" setzt nun nur die die Variablen auf "true" oder "false". In Deiner loop()-Funktion baust Du nun mehrere Schritte ein, bei denen Du prüfst ob eine dieser Variablen gesetzt ist. Wenn ja springst Du in eine der Funktionen
z.B.
Code: [Select]

void blink_left(int pin) {
  static long lastmillis = 0;
  //wenn eine sekunde um ist, dann pin umschalten
  if((lastmillis + 1000) < millis()) {

     //lesen und negieren des "Blink"-Pins und dann zurück schreiben
     digitalWrite(pin,(!digitalRead(pin)));

     //aktuelle Zeit merken
     lastmillis = millis();
  }
}

Die Funktion blockiert nicht und lehnt sich an das "Blink without delay" an. Ich habe die einzelnen Schritte halbwegs dokumentiert. Versuch mal zu verstehen wie die Funktion arbeitet und baue die dann in Deinen Sketch ein.
Mario.

jurs

#2
Dec 01, 2012, 08:20 pm Last Edit: Dec 01, 2012, 08:24 pm by jurs Reason: 1

Ich möchte einfach, dass mein arduino diverse funktionen "loopt" wie zb. blinken aber nebenbei noch in der lage ist variablen zu empfangen bzw. zu verarbeiten um andere pins weiterhin high/low zu schalten z.b um das blinken abzuschalten oder rückwärts und forwärts zu fahren.  


Im Prinzip brauchst Du ein nicht-blockierendes Blinken, das ohne delay funktioniert.

Und zur Arduino-Entwicklungsumgebung gehört sogar ein Beispiel dazu namens "BlinkWithoutDelay".
Das ist ein bisschen zu kompliziert gemacht. Ich zeige Dir mal was anderes.

Das Grundprinzip funktioniert so:
Du nimmst einen bestimmten Timer, der in einem Takt eine Zahl fortlaufend weiterzählt.
Und dann schaust Du einfach nach
- Wenn Blinker nicht gesetzt ist ==> Blinkerlampe aus
- Wenn Blinker gesetzt ist
+ Falls Timertakt eine gerade Zahl ist, Lampe aus
+ Falls Timertakt eine ungerade Zahl ist, Lampe an

Als Takt kannst Du den millis() Timer verwenden. Der Tickt im Millisekundentakt, und 1000 mal Blinken pro Sekunde ist vielleicht etwas zu viel. Zweimal pro Sekunde blinken wäre OK? Dann nimm als Takt "millis()/500"!

Und die loop erweiterst Du um eine weitere Prüfung, nämlich nicht nur, ob ein Kommando verarbeitet werden muss, sondern auch, um es Zeit ist, den Blinker umzuschalten.

Code: [Select]

#define blinkPin 13
boolean blinkState=true;

void performBlinkState(boolean blinkerGesetzt) {
 if (blinkerGesetzt) {
   if (((millis()/500)%2)==0) digitalWrite(blinkPin,LOW);
   else digitalWrite(blinkPin,HIGH);
 }
 else
   digitalWrite(blinkPin,LOW);
}

void loop() {
 // put your main code here, to run repeatedly:
performCommand();
performBlinkState(blinkState);
}


Die globale Variable "blinkState" setzt Du dann immer mit Deinen Funkkommandos true oder false. Und je nachdem blinkt es am blinkPin immer an/aus oder nicht. Wenn Du eine andere Blinkfrequenz möchtest, ersetzt Du die Umschaltzeit von 500 Millisekunden durch einen anderen Wert, für eine Lampenumschaltung alle 333 Millisekunden setzt Du z.B. einfach 333 statt 500 in der Funktion ein.

Hilft das vielleicht weiter?
Hinweis: Die Erweiterung auf zwei Blinker (links/rechts) ist relativ einfach.

mkl0815

Hallo jurs,

eine sehr elegante Lösung, um ein Pin zwischen den zwei Zuständen umzuschalten. Zumal zusätzlich noch RAM gespart wird, weil man sich den alten Wert nicht merken muss.
Die Funktion läßt sich sogar noch ein wenig eindampfen, wenn man den zu setzenden Wert direkt aus aus der Berechnung verwendet:
Code: [Select]

void performBlinkState(boolean blinkerGesetzt) {
  if (blinkerGesetzt) {
    digitalWrite(blinkPin,(millis()/500)%2);
  }
  else
    digitalWrite(blinkPin,LOW);
}

Da die Funktion ansich ja "stateless" ist, kann man sie sogar für mehr als eine "Blinkaufgabe" einsetzen, wenn man blinkPin und die Zeit zusätzlich als Parameter übergibt.

Vielen Dank für diese clevere Lösung.

Mario.

Udo Klein

#4
Dec 02, 2012, 10:49 am Last Edit: Dec 02, 2012, 10:53 am by Udo Klein Reason: 1
Autsch, "%2" ist nicht elegant. Die Modulo Funktion ist teuer. Besser wäre es "&1" zu schreiben weil "&" direkt in Maschinensprache übersetzt werden kann. Weiterhin kann man auch das "if" noch wegoptimieren, d.h. die bessere Lösung wäre:

Code: [Select]

void Blink(boolean blinkerGesetzt) {
   digitalWrite(blinkPin, (millis()/500) & blinkerGesetzt);
}
Check out my experiments http://blog.blinkenlight.net

Go Up