Daten von Arduino seriell empfangen ??

Hallo Forum,
ich bräuchte bitte Hilfe, bzw. einen Denkanstoss:
Ich möchte eine Kommunikation zwischen zwei Unos aufbauen
via seriell. Ich habe mit der Empfängerseite begonnen und sende
über den Seriell Monitor einen Zahlenwert ( Ganzzahl ).
Nun stolpere ich über ASCII da immer nur der Wert der ersten Stelle
relevant ist.
Was muss ich tun um einen Wert 0 - 4000 zu codieren, wandeln o.ä.
zur korekten Anzeige auf dem angeschlossenem LCD?

Vielen Dank

Gruss olmuk

Bin weiter mit funktionierendem Code :

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

float celsius = 25.6;            // Temperatur von Sensor
int counter; 
char* input = "0";           
LiquidCrystal_I2C lcd2(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  lcd2.begin(20,4);
}

void loop()
{
if (Serial.available())
{
  input[0] = Serial.read();
}  
  int counter = atoi(input); 
  lcd2.setCursor(2,0);
  lcd2.print("LCD2 :");
  lcd2.print(counter);

}

Es wird aber nur 1 Stelle angezeigt - wie kann ich Empfänger - / Senderseite anpassen ?

Serial.read() holt genau ein Zeichen. Wenn Du mehr Zeichen übertragen willst, brauchst Du eine Schleife. Da loop() eine Schleife ist, kannst Du diese nutzen. Wird ein Steuerzeichen übertragen, setzt Du den Cursor auf die Startposition. Ungetestet als Gedankenanstoß:

void loop() {
  if (Serial.available()) {
    eingabe = Serial.read();
    if (eingabe == 0x0A) {
      lcd2.setCursor(2, 0);
      lcd2.print("LCD2 :");
    } else {
      lcd2.print(eingabe);
    }
  }
}

Du liest ja auch niemals mehr als eine Ziffer ein. Außerdem musst du auch mal Speicher anlegen. Du kannst nicht einfach einen Zeiger deklarieren und dann Daten einlesen. Das ist ein katastrophaler Fehler.

So geht es korrekt:
http://forum.arduino.cc/index.php?topic=329469.msg2273780#msg2273780

Den seriellen Monitor dabei so einstellen, dass ein CR oder LF am Ende gesendet wird. Dann machst du in parse_serial() einmal atoi() (das mit strtok() ist wenn man mehre Zahlen auf einmal eingibt). Wobei das genaugenommen unnötig ist wenn du die Zahl nur auf dem LCD anzeigen willst. Wenn man damit rechnen will, braucht man es natürlich

olmuk:
Was muss ich tun um einen Wert 0 - 4000 zu codieren, wandeln o.ä.
zur korekten Anzeige auf dem angeschlossenem LCD?

Du brauchst zunächst ein "Übertragungsprotokoll".

Das Übertragungsprotokoll kann zum Beispiel sein "ASCII mit Trennzeichen". Dann würdest Du Deine Zahlenwerte zum Beispiel getrennt von einem Trennzeichen übertragen. Also etwa:

1;2;3;4;512;513;514;

Also der Sender sendet immer "Zahl und Trennzeichen".

Und der Empfänger muss die Daten mit einer bestimmten Empfangslogik dann wieder in Zahlenwerte einlesen. Und jedesmal wenn ein Semikolon empfangen wird, ist eine Zahl komplett.

Pseudologik: Wenn Serial.available(), dann lies ein Zeichen ein. Ist das Zeichen eine Ziffer von 0 bis 9, dann multipliziere die temporäre Zahl mit 10 und addiere die gelesene Ziffer dazu. Ist das gelesene Zeichen ein Semikolom, verarbeite die temporäre Zahl als endgültige Zahl und setze die temporäre Zahl auf 0.

jurs:
Pseudologik: Wenn Serial.available(), dann lies ein Zeichen ein. Ist das Zeichen eine Ziffer von 0 bis 9, dann multipliziere die temporäre Zahl mit 10 und addiere die gelesene Ziffer dazu. Ist das gelesene Zeichen ein Semikolom, verarbeite die temporäre Zahl als endgültige Zahl und setze die temporäre Zahl auf 0.

Habe ich auch schon gemacht, aber generell finde ich flexibler einen String einzulesen und dann zu konvertieren. Das braucht natürlich erst mal mehr Speicher, aber soviel sollte eigentlich frei sein.

Man hat dann den Vorteil, dass man das Protokoll sehr leicht ändern kann. Bei manchen Anwendungen ist z.B. sowas in der sinnvoll:
"a:123"
"b:456"

Also irgendeinen Buchstaben voranstellen damit man weiß welcher Wert was ist. Wenn immer nur die gleichen Werte zusammen übertragen werden sollen ist das überflüssig. Aber schön wenn sich die Zusammensetzung oder Reihenfolge der Werte ändern kann.

Danke vor allem an Serenifly und jurs die immer mit Hilfe zur Seite stehen!!!
Allen anderen natürlich auch !!!

Ich habe nun folgendes hinbekommen und bitte Euch mir nochmal zu helfen
um es nachhaltig zu verstehen. Nach dem Motto : Codeschnipsel zusammenfügen
und es geht ( oder nicht ).
Warum funktioniert dies nun ohne Felddefinition ?

Anmerkung : ich komme aus der SPS-Ecke
und C ist mir noch nicht so geläufig. Zahlensystem usw sind klar.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
String readString, serinput;
LiquidCrystal_I2C lcd2(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup() 
{
  Serial.begin(9600);
  Wire.begin();
  lcd2.begin(20,4);
}

void loop() 
{

  while (Serial.available())
  {
    delay(3);
    if (Serial.available() >0)
    {
      char c = Serial.read();
      readString += c; 
    }
  }

  if (readString.length() >0) 
  {
   Serial.println(readString); //Test
     
   serinput = readString.substring(0, 4); //get the first four characters
   int counter = serinput.toInt();   
   
   lcd2.setCursor(2,0);
   lcd2.print("Besucher: ");
     if (counter < 10 ) lcd2.print("   ");
     else if(counter < 100) lcd2.print("  ");
     else if(counter < 1000) lcd2.print(" ");
   lcd2.print(counter,1);
         
   readString="";
  }
}

Weil du die String Klasse verwendest. Die verschwendet allerdings nur Speicher und Zeit. Vor allem da die praktisch niemand korrekt verwendet, weil kaum jemand kapiert was reserve() genau macht. Die String Klasse ist außerdem sehr beschränkt was Konvertierungsfunktionen betrifft. Mit C Strings hat man viel mehr Optionen. Und das bei weniger Flash und RAM Verbrauch.

Ansonsten ist das Murks, weil du nicht beachtest wie langsam Serial ist. Oder dein Code ist von der Baudrate abhängig und funktioniert vielleicht mal geradeso mit 3 Zeichen.
Bei 9600 Baud dauert ein Zeichen ca. 1ms! In der Zeit läuft loop() zig mal durch. Das ist der Grund weshalb man das Ende des Strings mit einem Zeichen wie CR oder LF kennzeichnet. Dann kann man einlesen was da ist und zwischendurch was anderes machen bis der String später mal komplett da ist. Und es ist vollkommen egal wie lange der String ist oder wie hoch die Baudrate ist.

C Strings sind Null-terminierte char Arrays. Du musst ein Array aus char anlegen und dann den Index inkrementieren. Dann muss man abfragen ob der Index noch gültig ist und am Ende den Terminator setzen. Das war es. Siehe den Link in Reply #3

ok, ich mache Murks aber schlauer bin ich nun auch nicht....
Leider kann ich mit der Erklärung nicht viel anfangen.

Der Ursprung war ja eine gedoppelte Anzeige eines I2C Displays
bei einer Leitungslänge von ca 7m mit Wertänderungen im
Sekundenbereich.

Ich spendiere so einen Uno für die serielle Übertragung, sonst
hat der nix zu tun. Und der Sender hat einen Serial.print Befehl mehr.

Wäre schön mir mal einen ( für mich ) verständlicheren Tipp zu geben

Auf diesen Link weise ich dich jetzt zum dritten mal hin:
http://forum.arduino.cc/index.php?topic=329469.msg2273780#msg2273780

Das ist fast der vollständige Code den du brauchst. Das Array da hat Platz for 15 Zeichen (+ Terminator). Das kannst du kleiner machen. Ansonsten kannst du read_serial() so verwenden wie es ist.

Und dann in parse_serial() die Konvertierung + Anzeige machen. Wobei da atoi() gar nicht wirklich braucht. Du kannst auch direkt lcd.print(serial_buffer) machen. Also den empfangenen String direkt ausgeben.

Beim Senden wie gesagt ein CR und/oder LF anhängen. Da reicht es wenn du einfach println() verwendest. Wenn du den Serial Monitor als Test zum Senden verwendest ist da unten rechts eine Dropbox wo man die Endekennung einstellen kann.

Hat so nicht funktioniert - werde es mit den Tipps probieren, vielen Dank

Wenn der Code bei dir nicht funktioniert machst du irgendwas falsch. Eventuell auch beim Senden. Das geht selbst mit 500.000 Baud.

olmuk:
Ich spendiere so einen Uno für die serielle Übertragung, sonst
hat der nix zu tun. Und der Sender hat einen Serial.print Befehl mehr.

Wäre schön mir mal einen ( für mich ) verständlicheren Tipp zu geben

Die einzige serielle Schnittstelle auf einem UNO ist mit dem USB-Anschluss verbunden und dient zur seriellen Kommunikation mit dem PC, z.B. Ausgabe von Zeichen auf dem seriellen Monitor über USB-Kabel.

Für eine zusätzliche serielle Kommunikation zwischen zwei Arduinos brauchst Du also eine zweite serielle Schnittstelle, und da diese beim UNO als Hardware nicht vorhanden ist, bleibt dafür nur eine Softwareemulation. Entweder SoftwareSerial oder AltSoftSerial.

Ich würde Dir empfehlen, AltSoftSerial zu verwenden.

Beim UNO wäre der Sendepin Pin-9 und der Empfangspin Pin-8 für die emulierte serielle Schnittstelle, und außerdem kann Pin-10 dann nicht für PWM verwendet werden.

Sind diese Voraussetzungen auf Deinen beiden UNOs erfüllt:

  • Pin-8 und Pin-9 sind bisher noch frei
  • Pin-10 wird nicht für PWM verwendet
    Wie sieht es aus?

Ja jetzt bin ich total baff!
Die Unos sind mit Gnd und Tx und Rx verbunden - zum Übertragen
Von neuen Programm muss ich die Tx, Rx halt trennen.
Ist nicht elegant aber ?
Das ist ja dann noch mal ne Baustelle....

Nimmt man alternativ einen Leonardo, hat amn diese Probleme nicht. Der setzt nämlich auf einen Mikrocontroller vom Typ Atmega32U4 und der hat hardwareseitig USB drin, die serielle Schnittstelle an Pino 0 und 1 wird also nicht zur Programmierung mitgenutzt.

olmuk:
Das ist ja dann noch mal ne Baustelle....

Das normale SoftSerial ist Schrott, aber AltSoftSerial sollte es bei so geringen Baudraten tun.

Das sind auch im Code nur minimalste Änderungen. Von der Syntax her ist es das gleiche wie Hardware Serial.