globales Array - Werte ändern klappt nicht

Hallo,

ich versuche, über eine serielle Verbindung ein Array zu ändern. Die serielle Übertragung via XBEE klappt hervorragend, leider werden die Werte nicht übernommen.
Hier zunächst mein Array:

int lightArray[16] [24] = { { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 3500, 2500,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 3500, 4095, 4095, 4095 }, 
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 3500, 2500,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 3500, 4095, 4095, 4095 },  
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 3500, 2500,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 3500, 4095, 4095, 4095 }, 
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 3500, 2500,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 3500, 4095, 4095, 4095 },  
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 3500, 2500,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 3500, 4095, 4095, 4095 },  
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 2500, 1500,  500,  500,  500,  500,  500,  500,  500,  500, 1500, 2500, 4095, 4095, 4095, 4095 },  
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 2500, 1500,  500,  500,  500,  500,  500,  500,  500,  500, 1500, 2500, 4095, 4095, 4095, 4095 }, 
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 2500, 1500,  500,  500,  500,  500,  500,  500,  500,  500, 1500, 2500, 4095, 4095, 4095, 4095 },  
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 2500, 1500,  500,  500,  500,  500,  500,  500,  500,  500, 1500, 2500, 4095, 4095, 4095, 4095 },  
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 2500, 1500,  500,  500,  500,  500,  500,  500,  500,  500, 1500, 2500, 4095, 4095, 4095, 4095 },  
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4070, 4095, 4095, 4095, 4095, 4095,    0,    0, 4095, 4095, 4095,    0,    0, 1000, 4095, 4095, 4095, 4095 }, 
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4070, 4095, 4095, 4095, 4095, 4095,    0,    0, 4095, 4095, 4095,    0,    0, 1000, 4095, 4095, 4095, 4095 },  
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 1500,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 2000, 4095, 4095, 4095, 4095 }, 
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 1500,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 2000, 4095, 4095, 4095, 4095 },
                            { 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 1500,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 2000, 4095, 4095, 4095, 4095 }, 
                            { 3700, 3600, 3600, 3700, 3800, 3900, 4000, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4000, 3900, 3800 } };

Die Werte werden über ein XBEE Library mittels API übertragen. Jede Übertragung schickt 12 Werte rüber, die im Array gespeichert werden sollen. Das klappt alles, habe ich über das Monitoring getestet, trotzdem der Code: :

if(text=="/2/write" && val==1) {
    if (ramcolor==0) {
      for (int i=1; i<13; i++) sendDataOut (8, (i+6), ram[i]);
    }
    if (ramcolor==1) {
      for (int i=1; i<13; i++) sendDataOut (9, (i+6), ram[i]);
    }
    if (ramcolor==2) {
      for (int i=1; i<13; i++) sendDataOut (10, (i+6), ram[i]);
    }
    if (ramcolor==3) {
      for (int i=1; i<13; i++) sendDataOut (11, (i+6), ram[i]);
    }
  }

void sendDataOut(int a, int b, int c) {
  payload[0] = a;
  payload[1] = b;
  payload[2] = c;  
  xbee.send(txLight);
}

Hier wird wieder im ZielArduino eingelesen:

void readXBEE() {
  xbee.readPacket();
  if (xbee.getResponse().isAvailable()) {
    if (xbee.getResponse().getApiId() == RX_16_RESPONSE) {
      xbee.getResponse().getRx16Response(rx16);
	  incomingByte[0]=rx.getData(0);
      incomingByte[1]=rx.getData(1);  
      incomingByte[2]=rx.getData(2);	

if (incomingByte[0]==8) {
        unsigned int mapvalue = map(incomingByte[2],0,255,4095,0);
        for (int i=0; i<5; i++) lightArray[i][incomingByte[1]] = mapvalue; 
      }
    
      if (incomingByte[0]==9) {
        unsigned int mapvalue = map(incomingByte[2],0,255,4095,0);
        for (int i=5; i<10; i++) lightArray[i][incomingByte[1]] = mapvalue; 
      }
    
      if (incomingByte[0]==10) {
        unsigned int mapvalue = map(incomingByte[2],0,255,4095,0);
        for (int i=10; i<12; i++) lightArray[i][incomingByte[1]] = mapvalue; 
      }
    
      if (incomingByte[0]==11) {
        unsigned int mapvalue = map(incomingByte[2],0,255,4095,0);
        for (int i=12; i<15; i++) lightArray[i][incomingByte[1]] = mapvalue; 
      }     
    }
  }
}

=> hier hakt es: Die Werte kommen zwar an aber wenn ich danach das array erneut abrufe, werden wieder die ursprünglichen Werte ausgelesen und nicht die neu abgelegten.

Sieht hier jemand den Fehler?
Bitte nicht über die letzte FOR Schleife wundern: Jeder Wert, der ankommt, wird an mehreren Positionen gespeichert.

Besten Dank

Überprüf mal ob der Arduino zwischenzeitlich neustartet ?
Dein Array belegt nun ca. 768 Byte SDRam. Es könnte ja sein das durch die anderen Libs der Ram Bereich von 2 KB überschritten wird und ein neustart der Software ausgelöst wird. Dadurch könnten dann die Änderungen keine Wirkung haben.

Tritt das gleiche Problem auch auf wenn du weniger Daten sendest ?

hi,

Tritt das gleiche Problem auch auf wenn du weniger Daten sendest ?

beziehungsweise ein wesentlich kleineres array zum testen anlegst...

gruß stefan

Hallo,

falls der Arduino nicht wegen Speichermangel die Waffen streckt, teste mal ob in incomingByte[1] was Sinnvolles drinsteht.

Gruß,
Ralf

Hi,

also die Werte, die ankommen habe ich alle übers Monitoring gecheckt, auch incomingByte[1] liefert ein sinnvolles Ergebnis.

Habe einen Atmega328, laut SPECS:
Flash Memory 16 KB (ATmega168) or 32 KB (ATmega328) of which 2 KB used by bootloader
SRAM 1 KB (ATmega168) or 2 KB (ATmega328))

Was genau wird denn alles im SRAM gespeichert? Der gesamte Sketch? Oder nur die Variablen und Libraries?
Kann ich mir das ausgeben lassen, wie voll der Speicher ist?

Werde es mal mit einem kleinerem Array testen´. Ich entnehme dem, dass der Code als solches keinen Fehler aufweist.

Gruß

Hallo,

Variablen und dgl. Dinge werden im RAM gespeichert, der Sketch im Flash. Den freien Speicher kannst Du Dir mit folgender Funktion ansehen:

extern int __bss_end;
extern void *__brkval;


int get_free_memory()
{
  int free_memory;

  if((int)__brkval == 0)
    free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else
    free_memory = ((int)&free_memory) - ((int)__brkval);

  return free_memory;
}

Wenn der Arduino aber die Grätsche macht, weil der Speicher voll ist, zeigt Dir diese Funktion leider auch nichts mehr an, weil sie nicht mehr läuft.

Mach am besten das Array erst mal ganz klein und vergrößere es sukzessive und behalte dabei den freien Speicher im Auge.

Gruß,
Ralf

hi,

Was genau wird denn alles im SRAM gespeichert? Der gesamte Sketch? Oder nur die Variablen und Libraries?

die variablen, natürlich auch die der libraries.

Hallo,
habe es noch nicht geschafft zu testen, aber mal eine Frage dazu:
Wenn das wirklich der Fall wäre und der Arduino Speicherbedingt immer neustarten würde, dann dürfte der Sketch doch gar nicht funktionieren oder?
Also die Lampe, die damit gesteuert wird, funktioniert soweit einwandfrei, auch die zeitliche STeuerung, die über das Array abgebildet wird.

Oder startet der ARduino in u-Sek so dass man es gar nicht merkt?

VG

Was genau passiert, wenn Speicherbereiche ineinander überlaufen ist unmöglich vorher zu sagen. Irgend etwas zufälliges. Normalerweise so fehlerhaft das der Controller irgendwann - und das heißt nach einigen bis einigen 10.000 Taktzyklen neu startet. Wenn z.B. der Stack kaputt geschrieben wird, können einige, einige 100 oder auch einige 1000 falsche Maschinenbefehle ausgeführt werden. Man weiß es einfach nicht. Um zu wissen, ob in einer solchen Situation noch ein Lämpchen blinkt, braucht es eine Kristallkugel. Zumindest ich habe keine solche.

Deshalb ist das Beste systematisch vorzugehen, das Array zu verkleinern und wenn es läuft, es Schritt für Schritt zu vergrößern, bis es nicht mehr läuft. Daraus kann man Rückschlüsse auf den Fehler ziehen.

Gruß,
Ralf

Eisebaer:
hi,

Was genau wird denn alles im SRAM gespeichert? Der gesamte Sketch? Oder nur die Variablen und Libraries?

die variablen, natürlich auch die der libraries.

Alle Variablen des Sketches und der Bibliotheken, auch die automatisch eingeschlossen werden aber auch Systemvariablen auf Maschienenebene und der STACK. Auf dem STACK wenden Rücksprungadressen, Registerinnhalte bei Interrupts und sonstige im machienencode vorgesehene Daten gespeichert bzw wieder abgerufen und darafhin gelöscht.

Das RAM wird langsam bei jedem print vollgeschrieben (von unten beginnend) bis es den STACK erreicht (dieser wird von oben nach unten geschrieben). Bei einem bestimmten Moment treffen sich die beiden und der STACK wird überschrieben. Wennd ie Daten aus dem Stack geholt werden (zb nach return bei einem Unterprogrammaufruf) ist die Rücksprungadressen falsch.

Grüße Uwe

alles klar - werde dann mal schritt für schritt testen.
Wo ich das so sehe, ich dürfte vermutlich auch schon sparen, wenn ich das array als byte aufsetze und mit Prozent arbeite, die ich hinterher auf 12Bit mappe?
Also statt 0 bis 4095 schreib ich 0-100.
Vielleicht gibt das ja schon einiges an Speicherfrei.

Bei Fragen meld ich mich dann mal wieder :wink:

gruß stefan

nimm lieber 0 bis 255, dann mußt Du nicht komplieziert mappen, sondern nur mit 16 multiplizieren. außerdem hast Du feinere stufungen...

gruß stefan

Hi,
habe die Wert gestern mal auf Byte angepasst. Danach einen simplen Testenlauf:

Serial.println(array[5][12]);
array[5][12]++;
delay(1000);

In meinen ursprungscode ist gar nix passiert, keine serielle Ausgabe.
Nachdem ich den angepasst habe (0-255) hats geklappt.
Über Xbee konnte ich es noch nicht testen, aber es liegt vermutlich in der Tat daran, dass der RAM voll war.
Weitere Tests werdens zeigen.

Die Idee mit 16 finde ich unglücklich, da 25516 nicht 4095 ergibt sondern 4080. Könnte man natürlich umgehen, indem ich ((array+1)*16)-1 setze, dann muss ich aber wieder ne IF Ausnahme für 0 schreiben.
VOn daher finde ich map deutlich besser, verstehe auch nciht was deagegen spricht??

VG

Die Idee mit 16 finde ich unglücklich, da 25516 nicht 4095 ergibt sondern 4080.

Dein "Unglück" ist : 256 * 16 = 4096

Willst du die 256 Werte ( 0 .. 255 ) als 16er Schritte
mit 0, 16, 32, ... ,4080
oder 15, 31, ..., 4095

sehen oder wie ???

0 ... 4095 geht nicht gut durch 256 zu teilen
du musst dich schon entscheiden

hi,

das mit dem *16 deshalb, weil Du, wie ich annehme, mit TLC5940 oder ähnlichem leds steuern willst. und zwar viele.
map macht:
x_neu = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
meins macht:
x_neu = x * 16

weniger aufwendig bei vielen berechnungen.

Du "verlierst" zwar die werte von 4081 bis 4095, aber ich garantiere Dir, daß Du zwischen 4080 und 4095 keinen unterschied sehen kannst.
vielleicht funkt auch ein word(x, 0), das könnte noch schneller gehen, aber ich weiß nicht, in welcher form der tlc die 12bit erwartet. kann man probieren.

gruß stefan

Hi,
in der Tat steuer ich damit 16 TLC Kanäle.
Den Unterschied (4080-4095) sieht man in sofern, das das SIgnal invertiert ist und bei 4095 die LEDs AUS sind. Heißt bei 4080 gibts noch ein minimales leuchten.

map macht:
x_neu = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
meins macht:
x_neu = x * 16

Ist einleuchtend, aber wenn dann möchte ich auch den ganzen Bereich nutzen.
Ich werds mal versuchen nach meiner Methode umzusetzen:

if ((array[][] > 0) x_neu=((array[][]+1)*16)-1;
else x_neu=0;

Frag mich trotzdem, ob ich dadurch wirklich relevant was gewinne?

hi,

nimm doch mal 0 bis 255 und berechne Deinen wert mit
x_neu = word(~x, 15)

hab jetzt keinen arduino da

gruß stefan

Sorry. Vergiß es. Kann nicht gehen

hi,

damit geht es: erg = word(~wert, 15) >> 4

wobei wert der arraywert von 0 bis 255 ist. erg ist dann von 4080 bis 0, und zwar gleich invertiert, wie Du es brauchst.

void setup() {
  Serial.begin(9600);
  for (byte n = 0; n < 256; n++) {
    if (n < 10) Serial.print("0");
    if (n < 100) Serial.print("0");
    Serial.print(n);
    Serial.print("  ");
    word e = word(~n, 15) >> 4;
    if (e < 10) Serial.print("0");
    if (e < 100) Serial.print("0");
    if (e < 1000) Serial.print("0");
    Serial.println(e);
  }
}  
  
void loop() {
}

gruß stefan