Pages: [1] 2   Go Down
Author Topic: Probleme mit Void und Funktionen.  (Read 1366 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.  smiley-confuse

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  smiley-grin ). 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
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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.
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 146
Posts: 3031
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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.
« Last Edit: December 01, 2012, 02:24:45 pm by jurs » Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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.
Logged

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3482
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
void Blink(boolean blinkerGesetzt) {
    digitalWrite(blinkPin, (millis()/500) & blinkerGesetzt);
}
« Last Edit: December 02, 2012, 04:53:59 am by Udo Klein » Logged

Check out my experiments http://blog.blinkenlight.net

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3482
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nachtrag: das "/ 500" habe ich glatt übersehen. Das ist auch teuer, also besser alle 512ms schalten, dann bekommt man:

Code:
void Blink(boolean blinkerGesetzt) {
    digitalWrite(blinkPin, (millis() >> 9) & blinkerGesetzt);
}
« Last Edit: December 02, 2012, 05:00:20 am by Udo Klein » Logged

Check out my experiments http://blog.blinkenlight.net

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Kürzer und eleganter geht es ja kaum noch.  smiley-eek
Nicht schlecht.
Zusammengefasst wäre dann
Code:
/**
Time Table für "time"
value         blink time
 1               2 ms
 2               4 ms
 3               8 ms
 4               16 ms
 5               32 ms
 6               64 ms
 7               128 ms
 8               256 ms
 9               512 ms
10              1024 ms
11              2048 ms
12              4096 ms
13              8192 ms
...
**/
void Blink(boolean blinkerGesetzt,byte time, byte blinkPin) {
    digitalWrite(blinkPin, (millis() >> time) & blinkerGesetzt);
}
Damit kann ein beliebiges Pin entsprechend der "Time Table" (sogar bedingt) umgeschaltet werden, ohne ein einziges IF statement.
Was mich mal wieder zu dem Schluss bringt, das C eine coole Sprache ist und das mit deutlich weniger Sonderzeichen als perl :-)
« Last Edit: December 02, 2012, 06:09:51 am by mkl0815 » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

vielen dank für eure mühen aber ich schaffe es nicht eins der von euch geposteten beispiele in meinen vorhandenen sketch einzubauen. Ich verstehe zwar was die beispiele machen dank eurer beschreibung und das sie den arduino nicht blockieren aber bekomme sie auch nach zwei tagen "fummeln" einfach nicht an den richtigen stellen implementiert.

Ich ersetze eure beispiele durch diese stelle,

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

passe hier und da noch etwas an aber bekomme nur errors. Ich denke da wohl viel zu sehr in böcken bzw. blockweise.  smiley-confuse
Logged

Germany
Offline Offline
Faraday Member
**
Karma: 58
Posts: 3044
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Ich denke da wohl viel zu sehr in böcken bzw. blockweise.
 

Weiss nicht.
In C sagt man halt Funktion statt Block, und eine Funktion, die keinen Wert zurückliefert und keine Parameter braucht, ist nichts anderes als ein Funktionsblock, der mehrfach verwendet werden kann.

Liegt ein Problem etwa daran, dass du in deinem performCommand() oder in loop() gar nichts machst, wenn kein neues Kommando kommt ?
Damit es blinkt, musst du schon in jedem loop() - Durchlauf irgendwo etwas wie Udo's  Blink(true); aufrufen.

Quote
passe hier und da noch etwas an aber bekomme nur errors
Dann hast du ja was zu tun. -- Wir sind nicht neugierig  smiley-wink
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Dann poste doch mal den Code wo Du Fehler bekommst. Dann muss Uwe seine Kristallkugel nicht polieren, falls die überhaupt schon von der Reparatur zurück ist  smiley-wink
Wenn wir sehen wo Du das Beispiel eingebunden hast, können wir Dir auch sagen wo es klemmt.
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 146
Posts: 3031
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nachtrag: das "/ 500" habe ich glatt übersehen. Das ist auch teuer, also besser alle 512ms schalten, dann bekommt man:

Code:
void Blink(boolean blinkerGesetzt) {
    digitalWrite(blinkPin, (millis() >> 9) & blinkerGesetzt);
}

Schön zusammengefaßt!
:-)

Nachtrag: das "/ 500" habe ich glatt übersehen. Das ist auch teuer, also besser alle 512ms schalten, dann bekommt man:

Okay, ich bin von beliebig einstellbarer Blinkzeit ausgegangen.

Wobei die Arduino-Software beim Kompilieren den Compiler mit Optimierungsoption verwendet. Wenn man also von Hand Zweierpotenz-Konstanten im Code verwendet, dann sollte
(millis() / 512)
und
(millis() >> 9)
zu keiner unterschiedlichen Laufzeit des Programms  führen, da der Compiler das selbst in entsprechend optimierten Maschinencode umsetzt, wenn Zweierpotenz-Konstanten bei einer Integerdivision verwendet werden.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Dann poste doch mal den Code wo Du Fehler bekommst. Dann muss Uwe seine Kristallkugel nicht polieren, falls die überhaupt schon von der Reparatur zurück ist  smiley-wink
Wenn wir sehen wo Du das Beispiel eingebunden hast, können wir Dir auch sagen wo es klemmt.

Hi,

so z.b:

Code:
#define blinkPin 13
boolean blinkState=true;

char val;

void setup() {
 
 
pinMode(blinkPin, OUTPUT);
 
Serial.begin(9600);
}

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

void performCommand() {
  if (Serial.available()) {
    val = Serial.read();
}
    if (val == 'f') {
      performBlinkState();
          }
        }

void loop() {
performCommand();
performBlinkState(blinkState);
}

 smiley-red
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 146
Posts: 3031
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

void performCommand() {
  if (Serial.available()) {
    val = Serial.read();
}
    if (val == 'f') {
      performBlinkState();  // ERROR!
          }
        }

performBlinkState ist eine Funktion, die einen Parameter erwartet, entweder "true" wenn geblinkt werden soll und "false" wenn nicht geblinkt werden soll. Du kannst diese Funktion nicht ohne Parameter aufrufen!

Außerdem gehört die Funktion hier nicht her, denn die Funktion wird aus der loop heraus aufgerufen.

An Stelle der von mir mit ERROR! gekennzeichneten Zeile gehört sowas hin, was nur den Blinkstatus umschaltet:
blinkState=!blinkState;
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mit Code meinte ich eigentlich auch das komplette Programm. Auszüge sind immer ungünstig, weil man sich keinen Überblick verschaffen kann was sonst noch so ausgeführt wird und welche globalen Variablen es gibt.
Ansonsten hat jurs recht, in der Funktion "performCommand()" sollten nur Flags gesetzt werden, um Funktionen Deines Modells zu aktivieren oder deaktivieren. Ausgeführt werden die Funktionen separat in der loop().
Mario.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


An Stelle der von mir mit ERROR! gekennzeichneten Zeile gehört sowas hin, was nur den Blinkstatus umschaltet:
blinkState=!blinkState;


mmh, wenn blinkState=!blinkState; umschaltet (on/off/off/on), dann müsste was ich wieder getrieben hab grundsätzlich falsch sein. Blinken wird zwar aktiviert bei "f" empfang über serial aber das wars dann auch schon.

Code:
#define blinkPin 8
boolean blinkState=false;
int f = true;

char val;

void setup() {
 
 
pinMode(blinkPin, OUTPUT);
 
Serial.begin(9600);
}

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

void performCommand() {
  if (Serial.available()) {
    val = Serial.read();
}
            }

void loop() {
performCommand();
performBlinkState(blinkState);
    if (val == 'f')  { blinkState=!blinkState; }
}

Btw, wie ist denn das mit dieser "Flag" geschichte gemeint ?  smiley-sleep
Logged

Pages: [1] 2   Go Up
Jump to: