Pages: [1]   Go Down
Author Topic: Serielle Kommunikation zwischen zwei Arduinos  (Read 610 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 1
Posts: 60
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich experimentiere jetzt schon eine Weile damit herum , komme aber nicht wirklich weiter.
Ich habe einen Atmega328 auf Steckbrett auf dem eine Sketch läuft in dem Daten an der seriellen Schnittstelle ausgegeben werden (RX an D0, TX an D1).
In etwa so:
Code:
'H',1403,1401,
U/min :1402
mw_Drehzahl: 1401
micros pro Umdrehung: 42808
time - Drehzahlberechnung, ca: 61ms
Number of devices on 1-Wire: 2
Requesting temperatures... | T1 = 21.94, T2 = 22.75
Zeit, 'aktSensoren()' Ende, ca: 1025ms
Jetzt lese ich mit einem ARduino MEga 2560 und folgendem Sketch die Daten ein.
Code:
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

void setup() 
{
  // Open serial communications and wait for port to open:
  Serial.begin(57600);
 

  Serial.println("Goodnight moon!");

  // set the data rate for the SoftwareSerial port
  mySerial.begin(4800);
 
}

void loop() // run over and over
{
  if (mySerial.available())
    Serial.write(mySerial.read());
  if (Serial.available())
    mySerial.write(Serial.read());
}

So bekomme ich auch alle Daten am HardwareMonitor angezeigt, nur vertehe ich noch nicht wie ich die Daten im Mega2560 herrausfiltere und Variablen zuweise so dass ich sie weiterverarbeiten kann. Also z.B in der Zeile "'H',1403,1401,", die beiden Werte int Variablen zuweisen.
Kann mir wer weiterhelfen?

Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4755
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich verstehe nicht, wieso Du auf einem Mega2560 SoftwareSerial einsetzt. Der Mega hat 4 serielle Schnittstellen in Hardware, da würde ich dem Prozessor nie eine Software-Emulation zumuten, das gibt nur potentielle Probleme.

Zu Deinem eigentlichen Problem: Deine Ausgaben vom ATmega328 sind nicht gerade das, was man ein maschinenlesbares Protokoll nennen würde. Ich würde also mal dort anfangen und jede Meldung, die Du auf dem Mega auswerten willst, mit einem Start- und Stopzeichen versehen (damit Du weisst, wo ein Wert anfängt und wo er aufhört). Nach dem Startzeichen würde ich ein bis zwei Zeichen vorsehen, die den Inhalt des Wertes bezeichnen, also worum es sich handelt. Den Wert selbst kannst Du in ASCII übertragen (so wie Du es jetzt machst), wenn Du das Protokoll weiterhin menschenlesbar halten willst. Ansonsten würde ich aus Performanz-Gründen auf eine binäre Übertragung wechseln (mit 2 Zeichen hast Du dann einen Integer übertragen).
Logged

Germany S-H
Offline Offline
Edison Member
*
Karma: 117
Posts: 2455
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In etwa so:
Code:
'H',1403,1401,
U/min :1402
mw_Drehzahl: 1401
micros pro Umdrehung: 42808
time - Drehzahlberechnung, ca: 61ms
Number of devices on 1-Wire: 2
Requesting temperatures... | T1 = 21.94, T2 = 22.75
Zeit, 'aktSensoren()' Ende, ca: 1025ms

Ich würde mir ebenfalls als erstes mal ein besser maschinenauswertbares Übertragungsprotokoll ausdenken, das über die serielle Schnittstelle geht. Wie wäre es mit Pärchen aus Bezeichner und Wert, je Zeile ein Wertepaar, etwa:

Code:
<H1>1403
<H2>1401
<U/min>1402
<Drehzah>1401
<micros>42808
<time>61
<Number>2
<T1>21.94
<T2>22.75
<Zeit>1025

Sowas ließe sich viel einfacher einlesen, als wenn mal ein Datenwert in einer Zeile steht, mal mehrere, mal der Wert zwischen zwei Kommas steht, mal ein Datenwert nach einem Doppelpunkt, mal ein Wert zwischen Gleichheitszeichen und Komma, mal aber auch ein Wert zwischen Komma und Zeilenende. Was Du oben stehen hast, ist ein Tohuwabohu!
Logged

Offline Offline
Jr. Member
**
Karma: 1
Posts: 60
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

danke erstmal für eure Antworten.

was am Software.Serial empfangen wird kann ich ja noch einstellen.
Wenn ich jetzt bspw. A als Startparameter festlege und E als Endparamter und die Zeile:
Code:
A, 100, 10, E
ausgebe, müsste ich doch das in Software.Serial irgendwie abfangen können und die Zahlen int Variablen zuweisen. Doch hab ich leider keine Vorstellung wie ich das in Code umsetze.
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 96
Posts: 4755
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Was heisst hier abfangen? Du liest ja Zeichen für Zeichen ein und gibst es wieder aus, da musst Du nichts abfangen.

Verwendest Du deshalb SoftwareSerial, weil Du denkst, dass damit etwas einfacher "abzufangen" sei?
Logged

Germany S-H
Offline Offline
Edison Member
*
Karma: 117
Posts: 2455
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

was am Software.Serial empfangen wird kann ich ja noch einstellen.
Wenn ich jetzt bspw. A als Startparameter festlege und E als Endparamter und die Zeile:
Code:
A, 100, 10, E
ausgebe, müsste ich doch das in Software.Serial irgendwie abfangen können und die Zahlen int Variablen zuweisen. Doch hab ich leider keine Vorstellung wie ich das in Code umsetze.

Das "E" kannst Du eigentlich immer einsparen, wenn Du jede Zeile mit "println" sendest, dann ist ja als Endezeichen für die Zeile schon das Zeilenende-Zeichen vorhanden, das man erkennen kann.

Du bräuchtest dann nur am Anfang der Zeilen ein A, B, C, etc. Startzeichen, wenn Du Zeilen verschiedenen Inhalts bzw. mit verschiedenen nachfolgenden Werten sendest. Wenn alle Datenzeilen gleiche Inhalte in gleicher Reihenfolge aufweisen, ist es überflüssig.

Wie es gemacht wird, ist immer gleich:
1. die Zeichen von der Serial in einen Zeilenpuffer vom Typ C-String/Char-Array einlesen
2. die Zahlen rausziehen am besten mit meiner Funktion getIntFromString , die ich zuletzt hier gepostet habe:
http://arduino.cc/forum/index.php/topic,147168.0.html

Wenn der Wertebereich für int bei meiner Funktion nicht ausreicht und Du benötigst long, brauchst Du nur den Rückgabewert der Funktionsdeklaration auf long ändern.
Logged

Offline Offline
Jr. Member
**
Karma: 1
Posts: 60
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Was heisst hier abfangen? Du liest ja Zeichen für Zeichen ein und gibst es wieder aus, da musst Du nichts abfangen.
Verwendest Du deshalb SoftwareSerial, weil Du denkst, dass damit etwas einfacher "abzufangen" sei?

Abfangen soll in dem Fall heißen, dass ich auf eine bestimmtes Zeichen/Zeichenkette die seriell eingelesen wird reagieren will, sozusagen als Startparameter. Das nachfolgende Zahlen die kommen, weiterverarbeitet werden können. SoftwareSerial habe ich gleich mit eingebunden, da das ganze später auch auf einem attiny laufen soll.

Danke jurs für deinen Link, aber ich verstehe nur Bahnhof, da brauch ich ne Weile für...
Logged

Germany S-H
Offline Offline
Edison Member
*
Karma: 117
Posts: 2455
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Danke jurs für deinen Link, aber ich verstehe nur Bahnhof, da brauch ich ne Weile für...

Du brauchst die getIntFromString nicht im Detail zu verstehen, um sie verwenden zu können.

Einen einfachen Test-Sketch zum Empfangen von "Zeilen mit Zahlen" über die serielle Schnittstelle hänge ich mal dran.

Code:
void setup() {
  // put your setup code here, to run once:
 Serial.begin(9600);
}


long getIntFromString (char *stringWithInt, byte num)
// input: pointer to a char array
// returns an integer number from the string (positive numbers only!)
// num=1, returns 1st number from the string
// num=2, returns 2nd number from the string, and so on
{
  char *tail;
  while (num>0)
  {
    num--;
    // skip non-digits
    while ((!isdigit (*stringWithInt))&&(*stringWithInt!=0)) stringWithInt++;
    tail=stringWithInt;
    // find digits
    while ((isdigit(*tail))&&(*tail!=0)) tail++;
    if (num>0) stringWithInt=tail; // new search string is the string after that number
  }  
  return(strtol(stringWithInt, &tail, 0));
}  


void loop(void)
{
  char commandbuffer[40];
  char c;
  int i=0;
  if (Serial.available())
  {
    delay(75); // warten, bis die Zeile eingetroffen ist
    // Puffer mit Nullbytes fuellen und dadurch loeschen
    memset(commandbuffer,0,sizeof(commandbuffer)); // Speicher loeschen
    while (Serial.available())
    {
      c=Serial.read(); // Zeichen einlesen
      // Zeichen nur verarbeiten, wenn kein Steuerzeichen und Platz im Puffer
      if (c>=32 && i<sizeof(commandbuffer)-1)
      {
        commandbuffer[i] = c;
        i++;
      }  
      if (c<32) break; // Abbrechen bei Zeilenende-Zeichen
    }
    if (strcmp(commandbuffer,"\0")>0) // keine Leerzeile
    {
      Serial.print("Zeile empfangen: ");
      Serial.println(commandbuffer);
      Serial.print("Enthaltene Zahlen:  ");
      for (i=1;i<6;i++) // Versuche 5 Zahlen aus der Zeile auszulesen
      {
        Serial.print(getIntFromString(commandbuffer, i));
        Serial.print("   ");
      }    
      Serial.println();
    }  
  }
}

Wenn Du eine höhere Schnittstellengeschwindigkeit als 9600 verwendest, kannst Du das delay entsprechend auf Werte unter delay(75) verkleinern.

Pro Zeile sollten nicht mehr als maximal 60 Zeichen gesendet werden (Größe des Commandbuffers anpassen!), sonst reicht ggf. der serielle Empfangspuffer nicht. Mit commandbuffer[40] reicht es für den Empfang von Zeilen mit maximal 38 Zeichen.
« Last Edit: February 11, 2013, 02:58:06 pm by jurs » Logged

Pages: [1]   Go Up
Jump to: