Forum: Mikrocontroller und Digitale Elektronik Arduino: serial.read() Zahl als integer


von Nico J. (niiico)


Lesenswert?

Grüezi wohl zusammen.

Ich schätze mal, meine Frage bzw mein Anliegen ist bereits bekannt aber 
leider habe ich keine brauchbare Lösung gefunden.
Es geht um folgendes:
Ich habe einen Schrittmotor mit dem ich ein Schlitten auf die gewünschte 
Position fahre.

Ich habe bereits eine Funktion: "goTo(int position)" die mir den 
Schlitten an den gewünschten Ort fährt. Diese Funktion funktioniert 
problemlos.

Nun möchte ich aber über den PC (Serial Monitor) die Position eingeben, 
wohin der Schlitten soll.

Das ist jedoch schwieriger als ich gedacht habe.

Kann mir bitte jemand sagen, wie ich eine Funktion z.b "goToSerial()" 
schreiben kann, damit ich über die Konsole einen Zahlenwert eingeben 
kann und dieser dann der Funktion "goTo(int position)" übergeben wird?

Ich wäre über eure Hilfe sehr Dankbar!

Grüsse aus der Schweiz
 Niiico

von Karl H. (kbuchegg)


Lesenswert?

Von der Seriellen Schnittstelle kriegst du einen String.
Den wandelts du mittels atoi() oder dtostrl() in einen int um und 
steckst ihn in deine Positionier-Funktion rein.


(Komisch: Es gibt Fragen, die tauchen in abgewandelter Form an jedem 
einzelnen Tag mindestens 5 mal im Forum auf. Und auch komisch: es sind 
zu 90% Fragen, deren Lösung in jedem auch noch so grindigem 
Einsteiger-C-Buch zu finden ist. Wenn man nur eines hätte und es auch 
durchgearbeitet hätte.)

von Nico J. (niiico)


Lesenswert?

Vielen Dank Karl Heinz
Sowas habe ich mir bereits überlegt! Ich versuche noch entwas heraus zu 
finden. Denn den String muss ich ja elementweise auslesen und 
anschliessend zusammenführen?

von us73 (Gast)


Lesenswert?

Vielleicht schaust Du einfach mal nach, wie atoi() funktioniert ???

von Hansi C. (honsey)


Lesenswert?


von Nico J. (niiico)


Lesenswert?

Salut zusammmen.
Danke für die Inputs sowie Links! Ich habe es geschafft, die Funktion 
hinbekommen und die Übertragung klappt wunderbar.

Schönes Wochenende und Gruss

von Sticky (Gast)


Lesenswert?

Hallo,
ich habe das gleiche Problem.
Wie hast du es gelöst??

LG Sticky

von Christian B. (chbalnuweit)


Lesenswert?

Meinst du das elementweise Aauslesen des Strings oder das Konvertieren 
in einen Integer?

von Sticky (Gast)


Lesenswert?

Hallo,
eigentlich meine ich beides.

ich weis wie es ca. aussehen müsste:

while (Serial.available() > 0) {
  for (index = 0; index < 20; index++) {
  inChar[index] = Serial.read();
  index++; // Increment where to write next
  inChar[index] = '\0'; // 0 for String
  }
  incomingByte = atoi(inChar);

Das Problem ist, wenn ich den Wert incomingByte an den Steppermotor 
schicke, macht der Motor garnichts.

rotate(incomingByte, .5);

Wenn ich aber einen fixen Wert eingebe wie zB:

rotate(3000, .5);

dann dreht sich der Motor um 3000 steps mit der geschwindigkeit 0.5

Ich habe selber sehr wenig programmiererfahrung und das sind erst meine 
ersten Schritte.
Bin für jede Hilfe oder Hinweis Dankbar.

Lg Sicky

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Sticky schrieb:
> Ich habe selber sehr wenig programmiererfahrung und das sind erst meine
> ersten Schritte.
> Bin für jede Hilfe oder Hinweis Dankbar.

Wert irgendwo ausgeben um zu prüfen das auch das richtige/erwartete 
ankommt.

von Karl H. (kbuchegg)


Lesenswert?

Sticky schrieb:

> while (Serial.available() > 0) {

Nun ja.
Ich weiß zwar nicht ganz genau was Serial.available macht, kann es mir 
aber  so ungefährt vorstellen.
Und genau das ist der falsche Weg. Ein String ist nicht dadurch zu Ende, 
dass an der UART keine Zeichen mehr da sind. Denn: Dein µC frägt die 
Serialle viele Tausend mal in der Sekunde, ob ein Zeichen vorliegt. So 
schnell kannst du aber gar nicht tippen, bzw können Zeichen gar nicht 
übertragen werden!

D.h. der Sender (ein anderes Programm oder zb auch du vor einem 
Terminalprogramm) muss mit dem Empfänger ein Zeichen ausmachen, mit dem 
der Sender dem Empfänger mitteilt: 'Jetzt ist der String zu Ende. Jetzt 
kommt nichts mehr'. Nur weil der Sender eine gewissen Zeit lang nichts 
sendet, ist ein String noch lange nicht zu Ende. Dein Benutzer kann vor 
seinem Terminal sitzen und zb sich einen Kaffee holen, aber deswegen ist 
die Eingabe, die er gerade macht ja noch lange nicht beendet.

Oft wird zb ein Carriage Return ('\n') für diesen Zweck benutzt. Und das 
macht Sinn. Denn Benutzer, die noch nicht klicki-bunti-verseucht sind, 
sind daran gewöhnt, dass sie Text tippen können und erst ein Druck auf 
die große Return Taste, leitet dann alles weitere ein. Sie ist praktisch 
die 'Ich bin fertig - du bist drann' Taste.

>   for (index = 0; index < 20; index++) {

War nicht davon die Rede, dass man beliebig langen Text (in Grenzen) 
eingeben können soll. Wo kommen dann die 20 her? Warum 20?


Dein Code muss (in Grundzügen so aussehen)
1
   do {
2
     hole Zeichen von der Uart wenn eines da ist
3
 
4
     if( Zeichen != '\n' )
5
       hänge Zeichen an den bisherigen Text an
6
7
  } while( Zeichen != '\n' und das Array noch groß genug so dass
8
         noch ein Zeichen reinpasst )
9
10
  hänge ein \0 Zeichen an den Text hinten drann, damit
11
  aus dem Zeichenhaufen ein C-String wird
12
13
  atoi anwenden


und wie Läubi völlig richtig schon angemerkt hat: Lass dir die 
Zwischenergebnisse ausgeben.
Du willst wissen:
* kommt jedes Zeichen auch so an, wie ich mir das vorstelle.
* Ist der zusammengebaute String der, den ich erwarte
* Kommt bei der Umwandlung mittels atoi das richtige raus.

Wenn du nur hinten nach feststellst, dass dein Motor falsch dreht, dann 
machst du beim Debuggen einen grundsätzlichen Fehler: Du hast viele 
Stufen, in denen etwas schief gehen kann! Also sieh dir diese 
Zwischenstufen auch an. Kein Mensch sucht in einer 5-seitigen Berechnung 
Fehler, indem er sich nur das Endergebnis ansieht und dann hinterher 
verzweifelt nach Hilfe ruft, sondern er sieht sich jede Zeile der 
Berechnung an, ob er irgendwo einen Fehler gemacht hat. Und genau 
dasselbe macht man auch beim Programmieren. Wenn hinten nicht das 
gewünschte rauskommt, dann muss man sich eben überlegen, welche 
Zwischenergebnisse man sich ansehen muss, um rauszukriegen was da 
abgeht. Dein µC hilft dir dabei, indem er brav Zwischenergebnisse über 
die UART zb wieder auf das Terminal ausgeben kann. Nur reinprogrammieren 
musst DU derartige Ausgaben!

Beim Programm-Entwickeln immer schrittweise vorgehen! Deine Aufgabe 
lässt sich in mehrere Schritte zerlegen
* String empfangen
* String in Zahl umwandeln
* mit der Zahl den Motor ansteuern

Dann entwickle und vor allen Dingen teste das auch in Schritten!
Nur dann, wenn ein Schritt funktioniert, wird der nächste Schritt in 
Angriff genommen. Sonst stehst du am Ende mit einem Haufen ungetesteten 
Code da, der nicht funktioniert und du hast keine Ahnung, wo du mit der 
Fehlersuche anfangen sollst, weil in jedem Schritt Fehler sein können 
und auch sein werden.

Es ist ein grundsätzlicher, sehr beliebter Anfängerfehler, anzunehmen 
man könne ein Programm in einem Schritt fehlerfrei runterprogrammieren. 
Das kann man nicht. Niemand kann das. Auch die Profis können das nicht. 
Auch wir arbeiten in Schritten, nur sind unsere Schritte etwas größer. 
Nichts desto trotz sind sie aber da. Und genauso wie du das auch tun 
solltest, testen wir jeden Schritt ausgiebig, ehe es zum nächsten 
Schritt weitergeht.

von sticky (Gast)


Lesenswert?

Vielen Dank an Läubi .. Karl Heinz Buchegger. Vorallem die ausführliche 
Antwort.
Ja, mein Problem ist, ich will alles auf einmal. Schrittweise ist 
sicherlich der bessere Weg.

Die 20 in der for-Schleife war nur irgend ein Wert den ich zum Testen 
verwendet habe.

Danke nochmal für die neuen Denkansätze. Wahrscheinlich werde ich euch 
noch mit einigen noob-Fragen belästigen.

Frohes neues Jahr!
Sticky

von Karl H. (kbuchegg)


Lesenswert?

> Dein Code muss (in Grundzügen so aussehen)

Das muss man übrigens relativieren. Je nachdem was der Code sonst noch 
so alles können soll, kann das alles auch ganz anders aussehen.
Hängt halt davon ab, wie die Hauptschleife dann konkret aufgebaut ist 
und was sonst noch so alles zu tun ist. Der gezeigte Code geht davon 
aus, dass UART Empfang und PWM einstellen alles ist, was es zu tun gibt.

von Nico J. (niiico)


Lesenswert?

Salut Sticky...
Ich habe eine möglichst einfache Lösung gefunden. Sie ist noch 
provisorisch. Da ich auch noch ein grosser Amateur bin, werde ich mich 
schon noch darum kümmern.

Die Funktion "goToSerial()" liest den Wert über den Serial Monitor ein 
und übergibt den Wert an die Funktion "goTo(position)".
1
void goToSerial()
2
{
3
  int i;
4
  char X_buffer[4];       //Max. Zahl "9999"
5
  int incomingpos = 0;
6
7
  Serial.print("Fahre zur Position: ");
8
9
  while(incomingpos == 0)
10
  {
11
    if (Serial.available())
12
    {
13
      Serial.flush();
14
      delay(5); 
15
      i=0;      
16
      while(i<5)
17
      {
18
        X_buffer[i] = Serial.read();
19
        i++; 
20
      }
21
      Serial.flush();
22
      incomingpos = atoi(X_buffer);
23
      Serial.println(incomingpos);
24
      goTo(incomingpos);
25
      Serial.println("Position erreicht!");
26
    } 
27
  }
28
  incomingpos = 0;
29
}

Bitte denke daran, es ist nicht ganz sauber programmiert. Es war eine 
"Notlösung" die innerhalb von einem Tag funktionierten musste. Werde, 
wenn ich mal Zeit habe, einen sauberen Code schreiben.

Ich hoffe, du kannst damit etwas machen.

Verschneite Grüsse aus der Schweiz

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.