UNO und NANO über serielle pins TxD X RxD verbinden

wer kann mir einen kurzen funktionfähigen code vorschlagen, der die daten eines NANO empfängt und
in ein brauchbares datenformat für die anzeige umwandelt.

gesendet wird vom NANO eine float-variable.

diese sollte dann am UNO entweder genau so ankommen, oder zumindest als string mit gleichlautendem inhalt.

ich gebe es langsam auf, sowas in schlauen büchern über C zu finden. da steht überall was anderes und nix was man auf arduino zum laufen kriegt.....

Hallo,

ich weiß nicht so genau ob ich Dich richtig verstanden habe (was für ne Anzeige?), aber ich glaube was dir fehlt ist ein vernünftiges Protokoll.

Du kannst das Protokoll von Nick Gammon RS485 nutzen und nur die RX/TX ohne die RS485 Chips dazwischen verbinden dies Funktioniert auch Point to Point incl etwas sicherheit.
Gruß
DerDani

Ich verweis jetzt eifnach mal auf meinen Post:
http://forum.arduino.cc/index.php?topic=401845.0
Ich wollte auch eine Verbindung zwischen 2 Mikrocontrollern, In dem Fall Mega und micro Boards....
Dort ist auch Code enthalten der funktiniert.

hallo
und vielen dank erstmal für eure ratschläge.

wie das so ist, hatte ich dann gestern nacht noch den zündenden wurf... irgendeine seite im netz...eine ganz simple art das zu lösen. jedenfalls für meinen verwendungszweck.

es muss nur noch ein wenig "schön" gemacht werden.

C....ist eine sehr spröde art zu programmieren. aber was ist schon perfekt.
wenn ich nun noch rauskrieg, wie man einen string möglichst aufwandfrei aufdröselt, ist es perfekt.

ich will dann die daten als CSV senden und beim empfänger entsprechend für eine sinnvolle anzeige zerlegen.

senden vom NANO ganz einfach mit Serial.println(daten)

empfangen am UNO

void loop(void) {
buf="";
if (Serial.available()>0) {
int len=Serial.available();

for (int i=0;i<len;i++){
buf += (char)Serial.read();
}

}
}

editiert, bevor ich gesteinigt werde :smiley:

dann kommt ein datensatz in ganzer länge der gesendeten daten. man muss nur noch das passende für die anzeige separieren. es empfiehlt sich für den gesendeten datensatz separierungszeichen zu verwenden.

wenn es fertig ist, werde ich den gesamten code hier reinsetzen.
der NANO dient als datenleser der UNO überwiegend nur als "monitor" eine verarbeitung der daten kann jeweils da erfolgen, wo es sinnvoll ist und platz ist.

if (Serial.available()<>"\n") <<
Was soll dass denn werden ? Du vergleichst hier die Länge des Inputbuffers mit einem
Zeichen.

Das kann glaube ich nicht funktionieren, es sei denn deine gesendeten Strings sind immer 13 Byte lang :slight_smile:

Ulli

beeblebrox:
Was soll dass denn werden ? Du vergleichst hier die Länge des Inputbuffers mit einem
Zeichen.

Nö, er vergleicht die Länge des Inputbuffers mit der Adresse eines const char[2] mit dem Inhalt 13 und 0.

Das ist natürlich genauso falsch.

Indeed Mr. Steed.

Ulli

Dein Beispiel benutzt Serial als Eingabe, das hinterfrage ich jetzt mal nicht weiter.

Die Verarbeitung von CSV Zeilen könnte etwa so aussehen (beispielhaft für longs):

void setup() {
  Serial.begin(115200);
  Serial.println(F("CSV Zeilen (longs, ',') von Serial"));
}
void loop() {
  serialHandler();
}

void processCmd(char *buff) {
  Serial.print(F("Zeile: '"));
  Serial.print(buff);
  Serial.println(F("'"));
  byte num = 1;
  for (char* dahinter = buff; *dahinter; ) {
    long val = strtol(dahinter, &dahinter, 0);
    Serial.print(F("Wert "));
    Serial.print(num++);
    Serial.print(F(" ist "));
    Serial.println(val);
    while (isWhitespace(*dahinter)) {
      dahinter++;
    }
    if (*dahinter == ',') {
      dahinter++;
    } else {
      break;
    }
  }
}

void serialHandler()
{
  const byte aCr = 13;
  const byte aLf = 10;
  const byte sCBMax = 41;
  static char sCBuffer[sCBMax];
  static byte buffIndex = 0;

  for (bool doCheck = false; Serial.available(); ) {
    byte inChar = Serial.read();
    if (inChar == aCr) {
      doCheck = true;
    } else if (inChar != aLf) {
      if ((buffIndex == 0) && isWhitespace(inChar)) {
        continue;
      }
      sCBuffer[buffIndex++] = inChar;
      doCheck = (buffIndex == (sCBMax - 1));
    }
    if (doCheck) {
      sCBuffer[buffIndex] = 0;
      doCheck = false;
      if (buffIndex != 0) {
        processCmd(sCBuffer);
        buffIndex = 0;
      }
    }
  }
}
CSV Zeilen (longs, ',') von Serial
Zeile: '1,2,3'
Wert 1 ist 1
Wert 2 ist 2
Wert 3 ist 3
Zeile: '1    ,   2    ,      3'
Wert 1 ist 1
Wert 2 ist 2
Wert 3 ist 3

halt halt halt.....

unsinn sicher. auch sowas.... wenn man es nicht merkt, als anfänger ... beim compilieren speichert
dieses programmierdings einfach jeden quatsch in das original....

also bitte keine kommentare erstmal.
ich weiss was funktioniert...und dass es funktioniert.
dies war eine panikattacke um den datenfluss, der zwar richtig ist, aber noch nicht zu bändigen , in den griff zu bekommen.

irgendwie geht es ja, einen string sinnvoll aufzuteilen. aber---(wenn man es einmal weiss ist alles einfach)---
das muss man erstmal finden.

vll kann sich dazu jemand äussern: ein string: "|1232|56782.99|578.56|4563.89|" und nun schön die
einzelnen variablen separieren. eigentlich super einfach...aber nicht in C. es sei denn man weiss es.

und öh...nein, eigentlich war das gar kein unsinn....ich weiss ja nur nicht, wie das da in echt funktioniert.

dachte, es könnte vll daten lesen, solange kein CR kommt... und die länge ..ja, keine ahnung worauf sich diese länge bezieht. dachte dann auf die datenmenge, solang eben ungleich CR...
das könnte doch so sein, oder?

nirgendwo steht, wie das im kern funktioniert. ich hab mind 7 bücher über c und c++ das ist eine kraut und rüben sprache, wenn mich jemand fragt. null standard von wegen ANSI C....

aber irgendwie lässt es sich schon in einen sinn pressen. jetzt weiss ich wenigstens, warum die meisten anwendungen so ihre haken und ösen haben..... von windowas angefangen...

so. das musste mal raus

@Whandall

das muss doch aber einfacher gehen, oder?

CSV ist für Char-Separated-Value wobei Value ein numerischer- oder string-wert sein kann

ich erhalte also einen wert "xvdzsr" dem füge ich ein zeichen z.b. "|" hinzu dann kommt der nächste wert "34567" und wieder der separator "|" usw....

und das soll dann nach der datenübernahme wieder getrennt werden....

hab da gestern schon was entdeckt... aber leider muss man ja alles, was man entdeckt erstmal ausprobieren...

meist funktioniert es nicht... häufig auch einfach, weil es so mal eben hinkopiert wurde...wie ich das da aben eben gemacht hab.

stern:
"|1232|56782.99|578.56|4563.89|" und nun schön die
einzelnen variablen separieren.

Das ist kein CSV Format.

Und zu deiner fehlenden Groß- und Kleinschreibung sage ich nur: helft den armen vögeln!

CSV ist "Comma Separated Values" wobei deutsches Excel gerne lieber ein Semikolon statt Komma hätte.

Wenn String dir mühsam erscheint, vergiss es. Die sind nur pro Forma da, damit arduino ein bisschen wie Java aussieht.
Erfasse entweder die numerischen Werte gleich beim Einlesen, oder nimm lieber c-strings und strtok().

Um eine unbekannte Anzahl an Floats einzulesen:

const int SERIAL_BUFFER_SIZE = 40;
char serialBuffer[SERIAL_BUFFER_SIZE];

const int MAX_FLOATS = 3;
float floatValues[MAX_FLOATS];

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (readSerial(Serial))
  {
    Serial.print(F("Read: ")); Serial.println(serialBuffer);
    parseSerial();
  }
}

void parseSerial()
{
  char* ptr = strtok(serialBuffer, ",;");

  int index = 0;
  while (ptr != NULL && index < MAX_FLOATS)
  {
    floatValues[index++] = atof(ptr);
    ptr = strtok(NULL, ",;");
  }

  for (int i = 0; i < index; i++)
    Serial.println(floatValues[i]);
  Serial.println("---");
}

bool readSerial(Stream& stream)
{
  static byte index;

  while (stream.available())
  {
    char c = stream.read();

    if (c > 32 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c;
    }
    else if ((c == '\n' || c == '\r') && index > 0)
    {
      serialBuffer[index] = '\0';
      index = 0;
      return true;
    }
  }
  return false;
}

Wenn die Anzahl bekannt und immer konstant ist kann man auch einfach das machen:

void parseSerial()
{
  floatValues[0] = atof(strtok(serialBuffer, ",;"));
  floatValues[1] = atof(strtok(NULL, ",;"));
  floatValues[2] = atof(strtok(NULL, ",;"));

  for (int i = 0; i < MAX_FLOATS; i++)
    Serial.println(floatValues[i]);
  Serial.println("---");
}

Der String ist jeweils mit einem LF oder CR abgeschlossen

Für int statt float nimmt man einfach atoi() (ascii to integer) statt atof()

dank @Serenifly,

das sieht gut aus....werd ich heute nacht mal ausprobieren.

@Whandall, ja auf sowas warte ich immer. top!

@michael_x - Today

, ja, wenn Char ein "," dann kann man das durchaus als comma bezeichnen. aber in excel z.b.
kann man den separator wählen.... und die allegmeine definition ist dann durchaus Char-separated. mit dem comma bekommst du nämlich auch ganz schnell probleme bei manchen daten.

so geht das erstmal:

// UNO
// IMPORTANT: Adafruit_TFTLCD LIBRARY MUST BE SPECIFICALLY
// CONFIGURED FOR EITHER THE TFT SHIELD OR THE BREAKOUT BOARD.
// SEE RELEVANT COMMENTS IN Adafruit_TFTLCD.h FOR SETUP.
//Technical support:goodtft@163.com
//  freie pins:  A3 A5    D10 11 12 13
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library

// The control pins for the LCD can be assigned to any digital or
// analog pins...but we'll use the analog pins as this allows us to
// double up the pins with the touch screen (see the TFT paint example).
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0

#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin




// Assign human-readable names to some common 16-bit color values:
#define	BLACK   0x0000
#define	BLUE    0x001F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
// If using the shield, all control and data lines are fixed, and
// a simpler declaration can optionally be used:
// Adafruit_TFTLCD tft;

//char d1,d2,d3,d4;
char dat[10];
String buf;
int lang;

void setup(void) {
  Serial.begin(9600);
  
  Serial.println(F("TFT LCD test"));

#ifdef USE_ADAFRUIT_SHIELD_PINOUT
  Serial.println(F("Using Adafruit 2.4\" TFT Arduino Shield Pinout"));
#else
  Serial.println(F("Using Adafruit 2.4\" TFT Breakout Board Pinout"));
#endif

  Serial.print("TFT size is "); Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());

  tft.reset();

  uint16_t identifier = tft.readID();
   if(identifier == 0x9325) {
    Serial.println(F("Found ILI9325 LCD driver"));
  } else if(identifier == 0x9328) {
    Serial.println(F("Found ILI9328 LCD driver"));
  } else if(identifier == 0x4535) {
    Serial.println(F("Found LGDP4535 LCD driver"));
  }else if(identifier == 0x7575) {
    Serial.println(F("Found HX8347G LCD driver"));
  } else if(identifier == 0x9341) {
    Serial.println(F("Found ILI9341 LCD driver"));
  } else if(identifier == 0x8357) {
    Serial.println(F("Found HX8357D LCD driver"));
  } else if(identifier==0x0101)
  {     
      identifier=0x9341;
       Serial.println(F("Found 0x9341 LCD driver"));
  }else {
    Serial.print(F("Unknown LCD driver chip: "));
    Serial.println(identifier, HEX);
    Serial.println(F("If using the Adafruit 2.8\" TFT Arduino shield, the line:"));
    Serial.println(F("  #define USE_ADAFRUIT_SHIELD_PINOUT"));
    Serial.println(F("should appear in the library header (Adafruit_TFT.h)."));
    Serial.println(F("If using the breakout board, it should NOT be #defined!"));
    Serial.println(F("Also if using the breakout, double-check that all wiring"));
    Serial.println(F("matches the tutorial."));
    identifier=0x9341;
   
  }

  tft.begin(identifier);

 
}

void loop(void) {
   buf=""; 
  if (Serial.available()) {
    int len=Serial.available(); 
    
       
    for (int i=0;i<len;i++){
    buf += (char)Serial.read();
    }  
      
    }
 
//zeitformatierung 
  int time=millis()/1000;
int stime=time;  
int mtime=time/60;
int htime=time/3600;
int dtime=time/3600*24;
stime=stime-mtime*60;
mtime=mtime-htime*60;
htime=htime-dtime*24;


String sti = String(stime);
String mti = String(mtime);
String hti = String(htime);   
  
   tft.fillScreen(BLACK);
  unsigned long start = micros();
  
  uint16_t identifier = tft.readID();
  tft.setCursor(50,30);
  tft.setTextColor(BLUE); tft.setTextSize(1);
  tft.println("490323  20160516");
  tft.println("shield identfizierung:"),
  tft.println(identifier,HEX);
  tft.setTextColor(GREEN); tft.setTextSize(2);
   tft.println("anfang");
  tft.println(0);
  tft.print("zeit     "+ hti+":"+ mti+ ":"+sti);
  tft.println();
  tft.println();
  
  tft.setTextColor(BLUE);    tft.setTextSize(2);
   tft.println("uno  2.8inch  ");
  tft.println("daten seriell in");
  tft.setCursor(1,180);
  tft.println("volt    ");
  //controlle am seriellen monitor
   Serial.println(buf);
   lang=buf.length();
   Serial.println(lang);
  // vorläufige version den  messwert aus data zu separieren
  // bis mir was besseres einfällt oder ich einen vorschlag erhalte.   nach art basic: mid$
  //separatorposition bestimmen
    
   int pos=buf.indexOf('|');
  //für seriellen monitor 
   Serial.println(pos);
  buf.toCharArray(dat,pos+1);
  Serial.println(dat);

  //anzeige auf TFT
  tft.setCursor(55,180);
  tft.print(dat);
  tft.println();
  
  tft.setTextColor(WHITE);    tft.setTextSize(2);
   tft.println("test  grundprogramm");
   tft.setTextColor(YELLOW);    tft.setTextSize(5);
   tft.println("");
   tft.setTextColor(RED);    tft.setTextSize(1);
   tft.println("ende");
  
  tft.println();
  
  delay(1000);delay(1000);delay(1000);delay(1000);delay(1000);
}
//  und der sendeteil vom NANO

/*
  NANO 
  lademanager  solar-akku-wandler    lsaw   c20160505- wb49
                panel-spannung messen   analog  A2
                akku-spannung messen    analog  A3
                ssr (akku-hauptschalter) schalten D2 
                serielle schnittstelle öffnen
                werte verarbeiten
                bedingung für digitale ausgabe (if ..else)
                digitale ausgabe  als leuchtende LED
                 
                
                ausgabe des anlog eingelesenen wertes durch den seriellen monitor
 */


// setup  des programmes

void setup() {
  #define adf 0.004882
  // initialize digital pin 13 and  3  as an output.
  pinMode(13, OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(2,OUTPUT);   //  ssr ansteuern
  // öffnen der seriellen schnittstelle
  Serial.begin(9600);
  //ad-wandlung  faktor
  
  
  
  
}
  
// programm schleife

void loop() {
//float adf= 5.0/1024.0*10;

//up panelspannung
//ua akkuspannung 
float up = analogRead(A2);
float ua = analogRead(A3);
 
float U1 = up*adf;
float U2 = ua*adf*10;
//Serial.println(U1 ); 

Serial.print(U2 );
Serial.print("|");

 

   
 //  bedingungen für das schalten des ssr
 //  z.b.  u1>u2    ssr einschalten   
 // da nach einschalten des ssr u1=u2   
 //  ausschalten des ssr wenn u1=u2< 36V
  
  if (U2 < 25.5 )  
  {
  digitalWrite(13, LOW);
  
  }
  else   if (U2 >41.2)
  {
  digitalWrite(13, HIGH);
  

  
  }
  
  
  
  
  delay(500);

 
 
                // wait for a second
}

gern verbesserungsvorschläge in ähnlich einfacher art.

Damit die du dann genauso ignorierst wie die anderen Vorschläge?

Danke nein, dass ist mir zu... sinnlos.

An deiner Verwendung von Strings wirst du noch viel 'Spaß' haben.
Einmal loop alle 5 Sekunden wäre mir ca. 150000-fach zu langsam.

void loop(void) {
   buf="";
  if (Serial.available()) {
    int len=Serial.available();
       for (int i=0;i<len;i++){
    buf += (char)Serial.read();
    } 
     
    }
 
// ...
 
  delay(1000);delay(1000);delay(1000);delay(1000);delay(1000);
}

dann wird es dich erstaunen, dass das eigentlich für meinen zweck viel zu schnell ist. es geht doch recht simpel aus deden codes hervor, was das werden soll. das sind vorgänge, die stunden brauchen. und das display soll nicht flimmern, sondern lesbar einen überblick über den vorgang vermitteln.
erstmal musste ich ja, ganz ohne ahnung von arduino und programmiersprache, ein gerüst haben, um die grundfunktionen zum erfolg zu bringen. mir geht es auch nicht um programmierakrobatik, sondern um die verwendung anschliessend.
das muss jetzt erstmal in einen vernünftigen rahmen gebracht werden und dabei auch programmtechnisch optimiert werden. das ist mir auch klar. aber im vordergrund steht der zweck. und dafür ist es jetzt schon brauchbar.
und soviel ist klar: das eröffnet eine erhebliche vielzahl von möglichkeiten. und mit dem kleinen aber sehr guten display ist es eine runde lösung.

erstaunlich, wie wenig konstruktiv solch ein forum ist. da wird der kleinste fehler gleich erstmal zum kapitalverbrechen und die rechtschreibung des posters verhöhnt..super...das braucht man.

ich kann leider noch keine programmtechnischen hilfen gewähren. aber der code, den ich da reinkopiert hab, ist auch von einem anfänger erstmal so nutzbar, sofern er ähnliches vor hat. da kann ich dann sogar schon weiterhelfen.

falls es dich interessiert: ich bin kein neuling im programmieren. aber um c /c++ hab ich bisher einen grossen bogen gemacht. und eine "hello world"-allergie entwickelt. :wink:

stern:
dann wird es dich erstaunen, dass das eigentlich für meinen zweck viel zu schnell ist. es geht doch recht simpel aus deden codes hervor, was das werden soll. das sind vorgänge, die stunden brauchen. und das display soll nicht flimmern, sondern lesbar einen überblick über den vorgang vermitteln.

Es wird dich vielleicht erstaunen, dass delay() keine vernünftige Methode ist um ein Display am Flimmern zu hindern.
Mit delay() machen das nur blutige Anfänger (bevor sie festgestellt haben wie sinnlos das ist).

Gleiches gilt für das Einlesen von Daten mit deiner Methode, die mehrfach falsch ist.

  • Sammeln der Daten in ein String durch Anhängen einzelner Zeichen
  • Hoffen dass alle nötigen Daten in einem Stück lesbar wären
  • Keine Begrenzung der Menge an eingelesenen Daten

P.S. das gleiche Problem in zwei verschieden Threads zu diskutieren ist kontraproduktiv.

Wenn man die Daten direkt anzeigen willl, kann man den Code aus #13 auch vereinfachen. Da werden die Zahlen bei atof() in floats konvertiert. Statt dessen kann man die Teil-Strings die man per strtok() bekommt auch direkt auf dem Display ausgeben.

Flimmern verhindert man dadurch dass man nicht vor dem Schreiben erst mal das Display löscht, sondern direkt drüberschreibt und nur die Differenz zum alten Text mit Leerzeichen überschreibt.