Unerklärlicher Fehler: Serial + Arrays + FOR schl.

Hallo liebe Arduinogemeinde, bis jetzt hab ich noch alle Probleme mit genügend Geduld lösen können, doch dieser Art von Fehler is mir unerklärlich und deswegen suche ich eure Hilfe. Zuerst mal was mein Projekt ist (falls es nicht interessiert, ab den *** kommts direkt zum Problem):

Ich Plane mein Arduino Duemilanove mit einer IR-Diode und einem Foto-Transistor zu einer Universal-Fernbedienung zu machen. Welche über den Computer mit einem selbstgeschriebenen C# Programm bedient wird.

Wenn ich jetzt ein Signal von einer Fernbedienung nachmachen will brauche ich folgende 5 Angaben (wovon nur 3 wirklich unbedingt notwendig sind):

  1. Modulationsfrequenz (zb. 46KHz)
  2. Bitlänge in µS (zb. 866µS)
  3. Das Kommando ansich in 1 und 0 (zb. 101011010101001011010101010)
  4. Kommandowiederholung (zb. 03)
  5. Kommandowiederholungsrate in µS (zb. 85562 µS)

Diese Angaben schickt dann mein Programm per Comport an den Arduino. Natürlich kann ich es nicht in einer Wurscht schicken also hab ich mir folgendes ausgedacht:

= 35 (ascii) = beginn der übertragung = geht in leseschleife für datensätze

! = 33 = beginn datensatz = macht neues array für datensatz und füllt es bis ende
; = 59 = ende datensatz = ende füllung des arrays

  • = 42 = ende übertragung = verlässt leseschelife für datensätze

eine ganze Übertragung vom Programm würde dann so aussehen:
#!47000;!866;!101011010101001011010101010;!03;!85562;*


//Variablen für Einkommende Daten
char incomingBytes[255] = {};
int incomingBytesLength = 0;

//Variablen für Erkannte Datenübertragung
char transmission[255] = {};
int transmissionLength = 0;

//Variablen für Datensatz Frequenz
char dataSetFrequenz[255] = {};
int dataSetFrequenzLength = 0;

//Variablen für Datensatz Bitlänge
char dataSetBitlength[255] = {};
int dataSetBitlengthLength = 0;

//Variablen für Datensatz Binarycommando
char dataSetBinarycommando[255] = {};
int dataSetBinarycommandoLength = 0;
           
//Variablen für Datensatz Wiederholung wie oft
char dataSetRepeating[255] = {};
int dataSetRepeatingLength = 0;

//Variablen für Datensatz Wiederholungsrate
char dataSetRepeatrate[255] = {};
int dataSetRepeatrateLength = 0;

int DataSetNumber = 1;

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

void loop()
{
  if (Serial.available() > 0)
  {
    Serial.println("*Starte GetIncomingBytes");
    GetIncomingBytes();
    Serial.println("*Starte ShowIncomingBytes");
    ShowIncomingBytes();
    Serial.println("*Starte ExtractTransmission");
    ExtractTransmission();
    Serial.println("*Starte ShowTransmission");
    ShowTransmission();
    Serial.println("*Starte ExtractDataSets");
    ExtractDataSets();
    Serial.println("*Starte ShowDataSetFrequenz");
    ShowDataSetFrequenz();
    Serial.println("*Starte ShowDataSetBitlength");
    ShowDataSetBitlength();
    Serial.println("*Starte ShowDataSetBinarycommando");
    ShowDataSetBinarycommando();
  }
}

void GetIncomingBytes() //Speichert 255 übertragene Bytes in incomingBytes[] ab. & Leert Serialspeicher
{
  int i = 0;
  while (Serial.available() > 0)
  {
    incomingBytes[i] = Serial.read();
    i++;
    delay(3);
  }
  incomingBytesLength = i;
  Serial.flush();
}

void ShowIncomingBytes() //Sendet alle angekommen Bytes zurück zb."Eingegangen Bytes: 101001"
{
  Serial.println("Eingegangene Bytes: ");
  
  for (int i = 0; i <= incomingBytesLength; i++)
    {
     Serial.print(incomingBytes[i]);
    }
}

void ExtractTransmission() //Ließt incomingBytes[] aus, von # bis *  wird alles in transmission[] geschrieben
{
  for (int i = 0; i <= incomingBytesLength; i++)
  {
    if(incomingBytes[i] == 35)
    {
     int t = 0; //Zähler für transmission
     for (int y = i + 1; incomingBytes[y] != 42; y++) //speicherung beginnt mit 1. byte nach # bis byte * kommt
      { 
        transmission[t] = incomingBytes[y];
        t++;
      }
     transmissionLength = t; 
    }
  } 
  
  
}

void ShowTransmission() //Sendet Extrahierte Transmission zurück
{
  if (transmissionLength == 0)
   {
    Serial.println("Keine Transmission erkannt!");
   }
  
  else
  {
   Serial.println("Extrahierte Transmission: ");
   for (int i = 0; i <= transmissionLength; i++)
    {
      Serial.print(transmission[i]);
    }
   Serial.println("");
  }  
}

void ExtractDataSets() //liest Transmission aus und Speichert Datensätze ab, Datensatz beginn = ! DatenSatz ende = ;
{
 DataSetNumber = 1; 
  for(int i = 0; i <= transmissionLength; i++) //lese transmission
  {
    if (transmission[i] == 33) //wenn ! kommt dann
     {
       if (DataSetNumber == 1) //check wievielter datensatz
       {
        dataSetFrequenzLength = 0;
        DataSetNumber++;
        for (int y = i + 1; transmission[y] != 59; y++) //weiterlesen und speichern von datensatz bis ; kommt
        {
         dataSetFrequenz[dataSetFrequenzLength] = transmission[y];
         dataSetFrequenzLength++;
        }
       dataSetFrequenzLength--;
       i++;
       Serial.println("Dataset 1 fertig extrahiert");
       }      
     }
    
    if (transmission[i] == 33) //wenn ! kommt dann
     {
       if (DataSetNumber == 2) //check wievielter datensatz
       {
        DataSetNumber++;
        dataSetBitlengthLength = 0;
       
        for (int y = i + 1; transmission[y] != 59; y++) //weiterlesen und speichern von datensatz bis ; kommt
        {
         dataSetBitlength[dataSetBitlengthLength] = transmission[y];
         dataSetBitlengthLength++;
       }
       dataSetBitlengthLength--;
       i++;
       Serial.println("Dataset 2 fertig extrahiert");
       }
     }
     
     if (transmission[i] == 33) //wenn ! kommt dann
     {
       if (DataSetNumber == 3) //check wievielter datensatz
       {
        DataSetNumber++;
        dataSetBinarycommandoLength = 0;
       
        for (int y = i + 1; transmission[y] != 59; y++) //weiterlesen und speichern von datensatz bis ; kommt
        {
         dataSetBinarycommando[dataSetBinarycommandoLength] = transmission[y];
         dataSetBinarycommandoLength++;
        }
       dataSetBinarycommandoLength--;
       i++;
       Serial.println("Dataset 3 fertig extrahiert");
       }
     }
     
     if (transmission[i] == 33) //wenn ! kommt dann 
      {
        if (DataSetNumber == 4) //check wievielter datensatz
        {
          DataSetNumber++;
          dataSetRepeatingLength = 0;
          Serial.println("Datensatz 4 sollte hier mit einer For schleife extrahiert werden");
                   
          //for schleife sollte hier sein,
          //egal was für eine art von schleife ich hier reingebe...
          //mein arduino spuckt nur datenmüll aus, wenn er überhaupt noch reagiert
          //beispielschleife (gleich schleife wie die anderen drei nur angepasst auf datensatz4)
          
        // for (int y = i + 1; transmission[y] != 59; y++)
        //   {
        //    dataSetRepeating[dataSetRepeatingLength] = transmission[y];
        //    dataSetRepeatingLength++;
        //   }
            
          //böse schleife... mein arduino produziert nur datenmüll wenn überhaupt
          //lässt man diese for schleife weg dann gehts ohne probleme... 
          dataSetRepeatingLength--;
          i++;
          
        }
      }
     
  }
}

void ShowDataSetFrequenz()
{
  if (dataSetFrequenzLength == 0)
  {
    Serial.println ("Es konnte kein Frequenz Datensatz extrahiert werden!");
  }
  
  else
  {
   for (int i = 0; i <= dataSetFrequenzLength; i++)
    {
      Serial.print(dataSetFrequenz[i]);
    }
   Serial.println("");
  }
}

void ShowDataSetBitlength()
{
  if (dataSetBitlengthLength == 0)
  {
    Serial.println ("Es konnte kein Bitlength Datensatz extrahiert werden!");
  }
  
  else
  {
   for (int i = 0; i <= dataSetBitlengthLength; i++)
    {
      Serial.print(dataSetBitlength[i]);
    }
   Serial.println("");
  }
}

void ShowDataSetBinarycommando()
{
    if (dataSetBinarycommandoLength != 0)
     {
      for (int i = 0; i <= dataSetBinarycommandoLength; i++)
       {
        Serial.print(dataSetBinarycommando[i]);
       }
     }
    
    else
     {
       Serial.println("Es konnte kein Binarycommando Datensatz extrahiert werden!");
     }
}

Alles klappte ganz gut bis zu dem Zeitpunkt wo ich beginnen wollte den 3. Datensatz auszulesen… da machte er schon probleme… aber nach langer zeit, immer wieder probieren gings aufeinmal…

So dachte ich… super jetzt kann ich mit Datensatz 4 beginnen…
Also kopierte ich einfach wie schon zuvor die schleife, passte die variablen an und erwartete das es genau so gut funktioniert wie bei den 3 datensätzen davor… denkste… (Quellcode zeile 190)

Ddurch das so vielfältig verschiedene fehler entstehen, is es auch schwer für mich einen grund dafür zu finden.

Einmal öffnete ich nach dem upload, den comport und überhaupt noch bevor ich daten schickte bekam ich nur datenmüll vom arduino geschickt…
gleicher quelltext, nur neu geuploaded… keine reaktion auf datensendungen über comport…

gleicher quelltext, nur neu geuploaded… es wird nur einmal “*Starte GetIncomingBytes” (Quellcode zeile 40) gesendet und keine reaktion mehr!
Falls ihr noch fragen habt pls.

Ahja probiert einfach mal den Code aufm Arduino aus und schickt dann über den SerialMonitor folgende zeile:

!47000;!866;!101011010101001011010101010;!03;!85562;*

dann aktiviert mal die schleife bei zeile 190 und schaut euch an was passiert... ich kanns mir nicht erklären...

Das klingt sehr danach, daß du mehr speicher verwendest als du hast. Wenn das passiert, schreibt jemand willkürlich über andere Variablen drüber, die dann Dinge bewirken, die keiner will.

char incomingBytes[255] = {};
char transmission[255] = {};
char dataSetFrequenz[255] = {};
char dataSetBitlength[255] = {};
char dataSetBinarycommando[255] = {};
char dataSetRepeating[255] = {};
char dataSetRepeatrate[255] = {};

In deinem Code sind die zitierten Buffer 1.75 kB von 2 verfügbaren (am Atmega328). Dann kommen noch 128 Byte von Serial dazu, plus alle deine Strings die du als Debug rausschickst, plus der Stack und andere Variablen. Nix gut mein Freund, du bist nicht auf einem PC mit GB Speicher.

Was dagegen hilft: Mehr auf den Speicher aufpassen, Daten nicht sinnlos kopieren sondern an Ort und Stelle verarbeiten etc. Also all die Dinge, die Microsoft, Intel und sie Speicherhersteller in den letzten Jahrzehnten versucht haben, den Programmieren abzugewöhnen.

Korman

Oh mann gut an sowas hab ich mal echt nicht gedacht ;) aber so wies aussieht hast du da schon genug erfahrung :)

Hab jetzt gleich mal die Arrays schrumpfen lassen und werde noch mal ordentlich das ganze durchdenken müssen wie ich das am besten mache... vorallem weil das eig. nur die kommunikationsbasis sein sollte und nich das hauptprogramm...

Hast du viell. noch eine Seite mit tipps in die richtung?

Danke für die flotte hilfe... war echt schon am durchdrehen :)

Hast du viell. noch eine Seite mit tipps in die richtung?

Die ganze Nachricht beim Empfang gleich zerlegen, die Zahlen gleich zeichenweise in long oder int konvertieren und das Bitmuster in den Bitmusterbuffer kopieren. Du merkst dir für jedes Muster den Anfang im Buffer und beendest das Muster mit ASCII 0 (\0). Damit hast du den Speicherbedarf auf Bitmuster + 3 Long (Felder 1, 2 und 5) + 1 Int (Felde 4) reduziert. Wenn du viele Bitmuster hast, kannst du die '0' und '1'-Zeichen als Bits in Bytes gepack abspeichern. Das braucht 1/8 soviel Platz, nur mußt du abspeichern wie viele Bits es sind.

Und das war es schon dann. Damit solltest in 255 Zeichen locker 16 Befehle unterbringen ohne mit der Bitklauberei anfangen zu müssen.

Ach ja, als Trennung innerhald deiner Nachricht würde ich nur ein Zeichen (entweder ! oder ; ) verwenden, nicht beides. Und das Ende würde ich einfach annehmen, wenn alle gewünschten Felder da sind. Etwa so: #47000;866;101011010101001011010101010;03;85562;

Korman

So ich habe deinen Rat beherzigt, hab es inzwischen mit etwas überlegen auch hinbekommen das gleich ich in int bzw. gleich in long speichere… danach sind mir noch die Arrays:
incomingBytes und transmission übrig geblieben was ja auch unnötig ist, also hab ich mir gedacht ich lasse incomingBytes weg und check gleich beim empfangen der Bytes wo die Nachricht beginnt und speicher nur die Nachricht (transmission) ab.

Als dies dann nicht wie gewünscht funktioniert hat, hab ich mir mal alle Bytes anzeigen lassen die er aufnimmt und siehe da… er speichert nur jedes 2 byte ab?! ich hab schon versucht mit verschiedenen delay zeiten zu arbeiten aber es klappt nicht…

viell. könntest du ja mal einen blick drauf werfen :slight_smile:

void GetIncomingBytes() //Speichert übertragene Bytes von # bis * in transmission ab. & Leert Serialspeicher
{
int i = 0;
while (Serial.available() > 0)
{
delay(4);
if (Serial.read() == 35) //wenn eine # kommt
{ delay(4);
for (;Serial.read() != 42; i++) //wenn # so lange speichern bis *
{ delay(4);
transmission_ = Serial.read();_

  • }*
  • }*
  • }*
  • transmissionLength = i;*
    _ Serial.flush();_
  • for (int a = 0; a < i; a++) //komplette wiedergabe der empfangenen daten*
  • {*
    _ Serial.print(transmission[a]);_
  • }*
    _ Serial.println("");_
    _ Serial.println(i); //wie viel bytes empfangen wurden_
    }
    [/quote]
    Wenn ich hier testweise #1234567890* sende speichert er 24680 ab in transmission[]!
    ahja nur so ne verständnisfrage sicherheitshalber…
    ich sende 4 bytes an arduino (dieser speichert sie im serial puffer ab, welcher 128bytes fasst)
    wenn ich dann Serial.available() abfrage sollte ich doch 4 bekommen…
    und die daten bleiben ja so lange im puffer bis ich sie mit Serial.flush lösche…
    also könnte ich die daten empfangen und auch noch minuten später erst abfragen oder?
    und wo fängt dann serial.read() an ab zufragen? merkt es sich wo es im puffer das letzte mal abgefragt hat? (so wie ne for schleife mit zähler quasi?)
    ps: ich hab zwar gegoogelt, aber über bitmuster nichts gefunden, hast du einen link für mich?

Hier liegt Dein Problem:

         for (;Serial.read() != 42; i++) //wenn # so lange speichern bis *
         { delay(4);
           transmission[i] = Serial.read();

Pro Schleifendurchgang liest Du zwei Bytes (2x Serial.read()) aus der seriellen Schnittstelle, speicherst aber nur eines ab.

So sollte es funktionieren:

        char buf;
        for (;buf = Serial.read() != 42; i++) //wenn # so lange speichern bis *
        {
            delay(4);
            transmission[i] = buf;

Und das Serial.flush() brauchst Du nicht.

Hey danke, jetzt hab ichs verstanden, deine lösung hat bei mir leider keinen erfolg gebracht, aber dank dir hab ich gesehen wo der fehler ist (weil du es ja klar und deutlich geschrieben hast ^^...) hier is jetzt meine lösung die auch funktioniert :) danke noch mal

void GetIncomingBytes() //Speichert übertragene Bytes von # bis * in transmission[] ab. & Leert Serialspeicher { int i = 0; while (Serial.available() > 0) { delay(4); if (Serial.read() == 35) //wenn eine # kommt { delay(4); for (byte test; ; i++) //wenn # so lange speichern bis * { delay(4); test = Serial.read(); if (test == 42) { break; } transmission* = test;* * }* * transmissioncomplete = true;* * }* * }* * transmissionLength = i;* _ Serial.flush();_ } [/quote] Ahja warum brauch ich serial.flush nicht? Wir automatisch nachm auslesen der buffer geleert?

Serial.read() entnimmt ja das Byte aus dem Puffer (darum kannst Du es ja nicht zweimal auslesen). Serial.flush() brauchst Du nur, wenn Du den Puffer leeren willst ohne die darin enthaltenen Bytes auszulesen.