Serielle Datenübertragung..CmdMessenger?

Hallo sehr geschätzte Arduino Community,

folgendes Problem liegt vor:

Zwei Arduino Mega 2560 sollen miteinander kommunizieren. Der eine Arduino liest Daten einer Sonde aus. Der andere Arduino soll diesen Wert im LCD Display darstellen und nach einem bestimmten Delay immer aktualisieren. Ich bin übrigens ein blutiger Anfänger :frowning:

Hier der Code:

Sender:

void phControl(){
ph_sensor_value = analogRead(ph_probe_pin);  
ph = (ph_sensor_value * 5.0 / 1024 * 3.5 + ph_offset);

Serial1.print(char(ph));
}

Empfänger:

void receiveLoop(){
  if (Serial1.available()) {
  ph_1 = Serial1.read();
  } 
}

void graphLoop(){ 
myGLCD.printNumF(ph_1, 0, 52, 38);
}

Zu Testzwecken, habe ich beim Sender einen festen ph Wert von random(10) senden lassen. Dann funktioniert auch alles Bestens. Nur sobald ich keine ganzen Zahlen übertrage, sondern z.B. den festen Wert 5.54, wird im Display nur 5 angezeigt.

Das liegt meiner Meinung nach daran, dass nur der erste Char des Wertes übertragen wird.

Meine Frage ist nun, wie kann ich ohne Umrechnung in Char oder sonstiges einen Float Wert sicher übertragen. Es soll nur ein Wert mit 2 Nachkommastellen übertragen werden. Dieser schwankt jedoch die ganze Zeit, d.h der Empfänger muss erkennen: Aha hier ist der Wert zu Ende und der nächste Wert fängt an.

Habe schon an eine For Schleife gedacht, da der String ja immer die gleiche Länge hat; hier vielleicht den "." als Indikator für einen neuen Wert nutzen z.B. Wenn char = "." füge noch 2 Chars hinzu, danach beginne von vorne.

Wie würdet ihr sowas handhaben?

Vielen Dank im Vorraus und entschuldigt bitte meine Unwissenheit..

Schöne Grüße,
jdiephaus

Poste mal die interesanten Teile des Sketches, oder besser, den ganzen Sketch.

Im Empfangssketch wertest du ja nur ein byte aus.

Okay hier der ganze Sketch. Zur Info es handelt sich um einen Controller der den PH Wert eines Aquariums erfasst, und je nach Abweichung über Peristaltikpumpen Säure oder Base zufügt um den PH Wert konstant zu halten.

Sender:

#include <Wire.h>                     //One Wire library

int ph_probe_pin = A1;                   //Pin für pH Sonde

int acid_pump_left_pin = 9;              //Pin für Acid Pumpe Laufrichtung links
int acid_pump_right_pin = 8;             //Pin für Acid Pumpe Laufrichtung rechts
int acid_pump_speed_pin = 10;             //Pin für Acid Pumpe Geschwindigkeit

int base_pump_left_pin = 11;              //Pin für Base Pumpe Laufrichtung links
int base_pump_right_pin = 12;             //Pin für Base Pumpe Laufrichtung rechts
int base_pump_speed_pin = 13;            //Pin für Base Pumpe Geschwindigkeit

enum statemachine_phControl {            //Statemachine pH Control
  ph_check,
  ph_acid_pump,
  ph_base_pump,
};
statemachine_phControl ph_automat = ph_check;

float ph;                                //Variable für pH Wert
float ph_sensor_value = 0;               //Default Value = 0
unsigned long ph_previousMillis = 0;     //Default Value = 0
float time_pump_base_on = 0;             //Default Value = 0
float time_pump_acid_on = 0;             //Default Value = 0
                    
//****Werte die angepasst werden können****//

//***PH Control***//

float ph_setpoint_min = 5.8;            
float ph_setpoint_plus = 6.1;           
float ph_offset = 2.00;                 
                                      
const long time_pump_off = 180;         //Zeit in der beide Pumpen aus sind (In Minuten)

const int acid_pump_speed = 255;        //Acid Pumpe Geschwindigkeit (20 - 255)
const int base_pump_speed = 255;        //Base Pumpe Geschwindigkeit (20 - 255)

const int multiplicator = 5;           //Multiplikator auf Wassermenge anpassen für Base/Säuremenge

//*****************************************//

void setup()
{
  logicSetup();                      //Ersetzt void Setup
  Serial1.begin(9600);               //Serielle Ausgabe zum Senden von Werten
}

void loop()
{
  phControl();                       //Loop PH Control
}

void logicSetup()
{
  pinMode(acid_pump_left_pin, OUTPUT);
  pinMode(acid_pump_right_pin, OUTPUT);
  pinMode(acid_pump_speed_pin, OUTPUT);

  pinMode(base_pump_left_pin, OUTPUT);
  pinMode(base_pump_right_pin, OUTPUT);
  pinMode(base_pump_speed_pin, OUTPUT);  

  delay(300);
}
               
void phControl()
{
  unsigned long ph_currentMillis = millis();   //millis() seit Systemstart fungiert als Timer
 
 switch (ph_automat) 
 {
    case ph_check:    
   
  ph_sensor_value = analogRead(ph_probe_pin);  
  ph = (ph_sensor_value * 5.0 / 1024 * 3.5 + ph_offset);

  Serial1.print(char(ph));                     //Serielles Senden von ph Wert
  
  time_pump_base_on = (ph_setpoint_min - ph) * multiplicator;     
  time_pump_acid_on = (ph - ph_setpoint_plus) * multiplicator;   
  
        digitalWrite(acid_pump_left_pin, LOW);
        digitalWrite(acid_pump_right_pin, LOW);
        analogWrite(acid_pump_speed_pin, 0);

        digitalWrite(base_pump_left_pin, LOW);
        digitalWrite(base_pump_right_pin, LOW);
        analogWrite(base_pump_speed_pin, 0);
     
     if (ph_currentMillis - ph_previousMillis >= ((time_pump_off*1000)*60))  //Wenn Differenz größer ist als time_pump_off
     {
          ph_previousMillis = ph_currentMillis;                              //Timerwert gleichsetzen
          
        if (ph > ph_setpoint_plus)                                  
        {
              ph_automat = ph_acid_pump;                         
         }    

          if (ph < ph_setpoint_min)                                  
        {
              ph_automat = ph_base_pump;                         
         } 
      } 
    
      break;
    
    case ph_base_pump:
       
       digitalWrite(base_pump_left_pin, LOW);
       digitalWrite(base_pump_right_pin, HIGH);
       analogWrite(base_pump_speed_pin, base_pump_speed);                          
        
      if (ph_currentMillis - ph_previousMillis >= (time_pump_base_on*1000))  //Wenn Differenz größer ist als time_pump_base_on
      {
          ph_previousMillis = ph_currentMillis;                              //Timerwert gleichsetzen
       
          digitalWrite(base_pump_left_pin, LOW);
          digitalWrite(base_pump_right_pin, LOW);
          analogWrite(base_pump_speed_pin, 0);                        
            
          ph_automat = ph_check;                                  
      }
     
      break;
   
    case ph_acid_pump:
       
       digitalWrite(acid_pump_left_pin, LOW);
       digitalWrite(acid_pump_right_pin, HIGH);
       analogWrite(acid_pump_speed_pin, acid_pump_speed);                           
       
      if (ph_currentMillis - ph_previousMillis >= (time_pump_acid_on*1000))  //Wenn Differenz größer ist als time_pump_acid_on   
      {
          ph_previousMillis = ph_currentMillis;                              //Timerwert gleichsetzen
          
          digitalWrite(acid_pump_left_pin, LOW);
          digitalWrite(acid_pump_right_pin, LOW);
          analogWrite(acid_pump_speed_pin, 0);                                       

          ph_automat = ph_check;                                  
      }
      
      break; 
    
    default: 
    
    break;
  }
 }

Empfänger:

#include <UTFT.h>                     //16bit TFT screen library
#include <ITDB02_Touch.h>             //Touchscreen library
#include <Wire.h>                     //One Wire library
#include <DS1307new.h>                //RTC library
#include <SPI.h>                      //Adafruit SD Card library mit SPI
#include <SD.h>                       //Adafruit SD Card library mit SPI

UTFT myGLCD(ITDB32WC,38,39,40,41);    //Pins für TFT
ITDB02_Touch  myTouch(6,5,4,3,2);     //Pins für Touch

extern uint8_t BigFont[];                //Schriftarten
extern uint8_t SmallFont[];
extern uint8_t SevenSegNumFont[];
extern uint8_t SevenSegmentFull[];
extern uint8_t various_symbols[];

char ph_1;

long sd_previousMillis = 0;              //Variablen für SD Card
int sd_state = LOW;                      


//****Werte die angepasst werden können****//

long sd_time = 10;                   //Logging Interval auf SD Card (In Minuten)

float ph_setpoint_min = 5.7;         //Bereich für PH Anzeige Farbe
float ph_setpoint_max = 6.1;

//*****************************************//

void setup()
{
  graphSetup();                      //Initialsiert TFT
  sdSetup();                         //Initialisiert SD Card
  Serial1.begin(9600);               //Serielle Ausgabe ph_1
}

void loop()
{
  graphLoop();                       //Loop für TFT
  receiveLoop();                     //Loop Incoming Data
  sdLoop();                          //Loop SD Card
}

void graphSetup()                    //Initialisiert TFT
{        
  myGLCD.InitLCD(LANDSCAPE);         //LANDSCAPE oder PORTRAIT
  myGLCD.clrScr();
  myTouch.InitTouch(LANDSCAPE);      //LANDSCAPE oder PORTRAIT
  myTouch.setPrecision(PREC_HI);     //Touch Präzision
  mainscr();                         //Default screen ist mainscr
}
  
void sdSetup()
{
  pinMode(SS, OUTPUT);
  
  if (!SD.begin(10, 11, 12, 13))
  {
    return;
  }
}

void receiveLoop()
{
  if (Serial1.available()) {
  ph_1 = Serial1.read();
  } 
}  
               
void sdLoop()
{
  unsigned long sd_currentMillis = millis();
  if (sd_currentMillis - sd_previousMillis > ((sd_time*1000)*60))
  {
    sd_previousMillis = sd_currentMillis;
    
    if (sd_state == LOW)
    {
      sd_state = HIGH;              
      File data1 = SD.open("becken1.csv", FILE_WRITE);
      
      if (data1)
      {
        RTC.getTime();
        data1.print(RTC.day, DEC);
        data1.print('.');
        data1.print(RTC.month, DEC);
        data1.print('.');
        data1.print(RTC.year, DEC);
        data1.print(';');
        data1.print(RTC.hour, DEC);
        data1.print(':');
        data1.print(RTC.minute, DEC);
        data1.print(':');
        data1.print(RTC.second, DEC);
        data1.print(';');
        data1.print(ph_1, 2);
        data1.println();
        data1.close();
      }
    }
    else
    {
      sd_state = LOW;
    }
  }
}

void graphLoop()
{ 
  delay(500);                      //Dient als Refresh Time
  
  //Datum anzeigen
  RTC.getTime();
  myGLCD.setBackColor(VGA_BLACK);
  myGLCD.setFont(BigFont);
  myGLCD.setColor(VGA_WHITE); 
  myGLCD.printNumI(RTC.day, 132, 220);
  myGLCD.print(".", 162, 220);
  myGLCD.printNumI(RTC.month, 175, 220);
  myGLCD.printNumI(RTC.year, 240, 220);
  
  //Zeit anzeigen 
  myGLCD.printNumI(RTC.hour, 15, 220);
  myGLCD.print(":", 50, 220);
  myGLCD.printNumI(RTC.minute, 65, 220);
  
  //PH anzeigen
  myGLCD.setBackColor(VGA_BLACK);
  myGLCD.setFont(BigFont);
  
  if (ph_1 > ph_setpoint_max) 
    myGLCD.setColor(VGA_BLUE);
  else if (ph_1 < ph_setpoint_min)
    myGLCD.setColor(VGA_RED);
  else
    myGLCD.setColor(VGA_GREEN);
  myGLCD.printNumF(ph_1, 0, 52, 38);
}

void mainscr()
{ 
  myGLCD.fillScr(VGA_GREEN);                     
  
  //Rahmen Oben
  myGLCD.setColor(VGA_WHITE);                              
  myGLCD.fillRoundRect (2, 2, 317, 214);
  myGLCD.setColor(VGA_BLACK);                              
  myGLCD.fillRoundRect (3, 3, 316, 213);
  myGLCD.setColor(VGA_WHITE);
  
  //Rahmen Linien
  myGLCD.drawLine(2, 25, 317, 25);
  myGLCD.drawLine(30, 3, 30, 214);
  myGLCD.drawLine(122, 3, 122, 214);
  myGLCD.drawLine(222, 3, 222, 214);
  
  //Rahmen Unten
  myGLCD.setColor(VGA_WHITE);                              
  myGLCD.fillRoundRect (2, 238, 317, 217);
  myGLCD.setColor(VGA_BLACK);                              
  myGLCD.fillRoundRect (3, 237, 316, 218);
  
  //Viereck oben links
  myGLCD.setColor(VGA_WHITE);                              
  myGLCD.fillRoundRect (5, 5, 27, 22);
  myGLCD.setColor(VGA_GREEN);                              
  myGLCD.fillRoundRect (6, 6, 26, 21);
  
  //Titel Text
  myGLCD.setBackColor(VGA_BLACK);
  myGLCD.setFont(SmallFont);
  myGLCD.setColor(VGA_WHITE);
  myGLCD.print("Becken 1", 45, 8);
  myGLCD.print("pH", 9, 40);
}

Frage ist nun: Wie kann ich nun am besten den PH Float Wert vom Sender zum Empfänger übertragen und diesen in einem bestimmten Delay auf dem Display anzeigen lassen? Ist es der richtige Ansatz, den Wert als char übertragen zu wollen?

Wie würdet ihr sowas handhaben?

Ich?
Ich würde den CmdMessenger3 bzw. V4 verwenden.

Einfacher und schneller, kann man das Problem nicht erschlagen.
(glaube ich)

combie:
Ich?
Ich würde den CmdMessenger3 bzw. V4 verwenden.

Einfacher und schneller, kann man das Problem nicht erschlagen.
(glaube ich)

Vielen Dank erstmal für den Hinweis! Habe mich jetzt gerade etwas damit auseinandergesetzt, bekomme es jedoch nicht auf die Reihe (obwohl ich mir alle Examples angeschaut und bereits Google gefragt habe) :frowning:

Ich erstelle jetzt ein neues Thema explizit für CmdMessenger.

Funktioniert den deine serielle Übertragung zwischen den Arduinos schon ?

Auch wenn das mit dem CmdMessenger3 sicher eine komfortable Sache ist, geht das in deinem Fall doch bestimmt auch "einfacher".

In einem ähnlichen Fall habe ich es dadurch gelöst, dass ich den gemessenen Wert mit 100 (da 2 Nachkommastellen) multipliziert habe, als "int" dann seriell übertragen und am Empfänger wieder durch 100 geteilt habe. Das Ergebnis wird dann angezeigt.

Wow das ist auch ein guter Ansatz. Integer lassen sich nämlich ohne Probleme (EDIT: solange sie Einstellig sind) übertragen. Vielen Dank, ich probiere das mal aus!

Okay ich habe jetzt so gut wie alles probiert....langsam komm ich mir dumm vor...

Wie kann es so kompliziert sein, einen mehrstelligen Integer Wert seriell zu übertragen??

Integer Wert 5 übertragen, keine Probleme.

Integer Wert 55 übertragen, pain in the ass.

Ich habe jetzt auch schon mehrere Ansätze getestet in Bezug auf Integer Zerlegung in low und high byte um sie dann beim Empfänger wieder zusammenzusetzen. 4 Stunden Google, etliche Code Zeilen später geb ich das jetzt auch auf. Ich bekomme es wirklich nicht zum laufen.

Ich bräuchte nur ein Beispiel wo z.B die Integer 678 seriell übertragen und auf dem anderen Arduino auch als 678 ankommt. Bitte helft mir. :disappointed_relieved:

Schöne Grüße,
jdiephaus

jdiephaus:
Wie kann es so kompliziert sein, einen mehrstelligen Integer Wert seriell zu übertragen??

Integer Wert 5 übertragen, keine Probleme.

Integer Wert 55 übertragen, pain in the ass.

Weil dein Sketch immer nur ein Byte empfängt.

Sieh dir mal in der IDE das Beispiel "SerialEvent" an, damit kannst du mehrere Zeichen einlesen.

Das Beispiel ist zum Verständnis sicher gut geeignet, es verwendet aber String, was wiederum nicht so gut ist.
Schau Dir mal in einem Nachbarthread #70 die Funktion "einlesen()" an. Wenn Du das mit dem IDE-Beispiel kombinierst, kommt etwas vernünftiges raus.

Gruß Tommy