zwei arrays an der gleichen speicher-adresse möglich?

hi,

eine aufgabe für die besser in C bewanderten:

in der fastled-library wird ein array definiert
CRGB leds[n];
in das der sollwert von n RGB-leds geschrieben wird. in der form:
leds[0].r=
leds[0].g=
leds[0].b=
leds[1].r=
.
.
leds[n-1].b=

ich nehme mal stark an, daß die werte im speicher in der reihenfolge leds[0].r, leds[0].g, leds[0].b, leds[1].r ... leds[n-1].b als bytes liegen.

in der gleichen form bekomme ich RGB-werte von der seriellen schnittstelle.

bei Serial.readBytes muß ich anzahl der zu lesenden bytes angeben und den buffer (z.b. char buf[690]), wo die bytes hingeschrieben werden.
es wäre doch umständlich, zuerst die werte in den buffer zu lesen und dann ins array rüberzuschreiben. könnte man nicht direkt bei readBytes leds[] als buffer angeben? da gibt es doch sicher eine gefinkelte pointer-methode...

oder einen buffer anlegen, der die gleiche startadresse wie leds hat. das würde zeit sparen (und die ist hier eng), und außerdem viel speicher.

gruß und dank, stefan

EDIT: das CRGB kommt aus der fastled-library. und ich hab' den thread-titel geändert.

Wieso nicht sowas ähnliches?

leds[i].r = Serial.read();
leds[i].g= Serial.read();
leds[i].b = Serial.read();

Und dass dann so oft machen wie du Werte bekommst

Eisebaer:
hi,
eine aufgebe für die besser in C bewanderten:

Da mußt Du andere meinen :wink: :wink: :wink:
Hast Du die Neopixel Bibliothek probiert.
Grüße Uwe

hi,

wieso die neopixel? hat die sowas?

mir ist jetzt endlich union eingefallen, aber das geht nicht, anscheinend weil bei einem CRGB ein konstruktor dranhängt.
es müßte etwas sein, wie man ein byte buf[690] an die speicheradresse von leds[0].r (oder leds[0]) bekommt.

gruß stefan

Hallo Stefan,

das leds Array ist nichts anderes als ein struct aus 3 Byte Werten je Pixel.
Was haste genau vor? Ich geh mal von deinem Ambilight aus.

Eine Möglichkeit wäre immer bis 2 (3) zu zählen. 0 - 3 = rg. Dnach wird die Le+ ge,amcjt.

hi,

klar kann man immer alles byte für byte reinschreiben, aber:

1, ich habe ein array CRGB leds der größe 690, in das die werte, die mit serial reinkommen, reingehören.
2, ich brauche einen buffer der größe 690, in den die serial-werte mit readBytes(buffer, 690) reingelesen werden sollen.
3, ich kann nicht mit readBytes(leds, 690) die werte direkt reinschreiben. auch nicht mit leds[0] oder leds[0].r. typkonflikt

ist es nicht möglich, ein CRGB leds anzulegen, und dann ein byte buffer[690], dessen startadresse die gleiche ist wie die von leds?

gruß stefan

Sich da auf readBytes() festzulegen ist halt nicht die einzige Lösung. Das macht intern auch nicht viel anderes als jedes Byte einzeln einlesen.

Ansonsten sollte man eigentlich einfach das Array aus struct auf byte* (d.h. Array aus Bytes) casten können. Auf einem 8-Bit System gibt es keine Padding Bytes, also kann man im Prinzip alles durch Casts auch als Byte Array ansprechen.

hi,

vergeßt doch bitte mal, was der hintergrund ist. die frage bleibt, wie ich zwei verschiedene variablen an die gleiche speicheradresse setzen kann.

wenn's da keine einfache möglichkeit gibt, ist es nicht denkbar:

ein CRGB leds[230] anzulegen, die adresse von leds und die spitze des heaps zu speichern, dann ein char buf[690] zu erstellen, buf auf die adresse von leds zu setzen und die spitze des heaps auf den zuvor gespeicherten wert zu setzen?

gott klingt das kompliziert. geht das nicht einfacher?

CRGB leds[230]
char buf[690] und jetzt kommts: auf der adresse von leds

keine anweisung dafür?

gruß stefan

Ich hab es doch gesagt. Cast auf byte*:

Serial.readBytes((byte*)leds, sizeof(leds));

Oder ausführlich:

byte* ptr = (byte*)leds;
Serial.readBytes(ptr, sizeof(leds));

hi,

hab' ich erst nicht verstanden, der beispielcode hilft. danke. mußte nur noch von byte* auf char* ändern. kompilieren geht, und so wie der code aussieht, schreibt er's dort auch rein.

danke Dir vielmals und liebe grüße,
stefan

PS.: das war's, was ich brauchte, aber gibt es in C(++) mit all seinen zeigern denn wirklich keine möglichkeit, die startadresse eines arrays gleich beim erstellen des arrays festzulegen?

Hallo,

Eisebaer:
aber gibt es in C(++) mit all seinen zeigern denn wirklich keine möglichkeit, die startadresse eines arrays gleich beim erstellen des arrays festzulegen?

du kannst die beiden Arrays z.B. in einen union legen.

Das Beispiel hier ist auf einen Due getestet, eventuell gibt es das sprintf so nicht auf den 8-Bittern.

struct RGB
{
  unsigned char r;
  unsigned char g;
  unsigned char b;
};

union Zusammen
{
  RGB leds[230];
  char buf[690];
};

Zusammen Test;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  
  memset(Test.buf, 0, 690);
  
  Test.leds[0].r = 1;
  Test.leds[0].g = 2;
  Test.leds[0].b = 3;
  
  Test.buf[3] = 4;
  Test.buf[4] = 5;
  Test.buf[5] = 6;
}

void loop() {
  // put your main code here, to run repeatedly:
  char result[100];
  sprintf(result, "Buf 0-1 = %d %d %d, Leds 1 = %d %d %d\r\n",
          Test.buf[0], Test.buf[1], Test.buf[2],
          Test.leds[1].r, Test.leds[1].g, Test.leds[1].b);
          
  Serial.write(result);
  
  delay(1000);
}

hi,

ja, das mit der union hab' ich zuerst probiert, aber das struct CRGB aus der fastled hat einen konstruktor, und sowas kann man anscheinend nicht in eine union legen.

Blink:16: error: member 'CRGB Zusammen::leds [230]' with constructor not allowed in union
Blink:16: error: member 'CRGB Zusammen::leds [230]' with copy assignment operator not allowed in union

gruß stefan

In C+11 geht das neuerdings:

C+11 geht auch auf dem Arduino ab 1.5.7. wenn man die platform.txt anpasst.

Ja, wenn man die C++ Trickkiste auspackt, fallen einem noch mehr Sachen ein.

Das hier ist jetzt Linux auf dem Beaglebone, der Due ist gerade nicht da:

#include <cstdio>

struct RGB
{
    unsigned char r;
    unsigned char g;
    unsigned char b;

    RGB() : r(1), g(2), b(3)
    {} 
};

template<typename T, int N>
class Wrapper
{
private:
    T m_Data[N];
    T m_Dummy;

public:

    T& get(size_t index)
    {
        if (index >= N)
        {
            return m_Dummy;
        }
        else
        {
            return m_Data[index];
        }
    }

    char& get_raw(size_t index)
    {
        char* ptr = reinterpret_cast<char*>(m_Data);

        return *(ptr + index);
    }
};

int main(int argc, char** argv)
{
    Wrapper<RGB, 230> Test;

    Test.get_raw(3) = 4;
    Test.get_raw(4) = 5;
    Test.get_raw(5) = 6;

    Test.get(0).r = 7;
    Test.get(0).g = 8;
    Test.get(0).b = 9;

    RGB eins = Test.get(0);
    RGB zwei = Test.get(1);

    printf("%d,%d,%d   %d,%d,%d\n",
           eins.r, eins.g, eins.b,
           zwei.r, zwei.g, zwei.b);

    return 0;
}

Man könnte die Klasse auch so bauen, dass sie das Array nicht selber enthält, sondern nur einen Pointer darauf. Auch könnte man den Array-Operator überladen, worauf ich jetzt mal aus Faulheit verzichtet habe. :smiley:

Da man auf dem Mikrocontroller wohl keine Exception schmeißen kann, habe ich bei der einen Funktion mal eine Ersatzlösung angedeutet.

Serenifly:
C+11 geht auch auf dem Arduino ab 1.5.7. wenn man die platform.txt anpasst.

Ja, das habe ich auch eingeschaltet. Wenn man jetzt noch Sachen wie std::string oder std::vector benutzen könnte, wie bei ARMs online Compiler auf mbed.org, würde das den Gebrauchswert meines Due stark erhöhen. 8)

Ja, der brachiale reinterpret cast :slight_smile: Daran hatte ich auch schon gedacht. Damit kann man praktisch alles auf alles umbiegen.

Es gibt eine STL Implementierung:

Ist schon etwas älter, aber funktioniert vielleicht auch mit 1.5.x. Weiß nicht wie es mit dem Due aussieht. Das ist eventuell nicht ganz ARM kompatibel. Auf dem AVR habe ich davon bisher nur Vector und den I/O Stream verwendet.

Ah, interessant. Sollte ich mir mal ansehen.

Das witzige ist ja, wenn man C++11 eingeschaltet hat, funktionieren ( in der 1.5.8 ) Sachen wie

#include <vector>

// ...
std::vector<int> v{ 0, 1, 2, 3 };

Aber ein push_back an einen vector geht, nicht, weil da im Code Exceptions benutzt werden. Und der g++ der bei Due verwendet wird, wird mit -nostdlib und -fno-exceptions aufgerufen.

Eventuell tut sich da ja mal was, wenn der Zero rauskommt. Manche Sachen in der 1.5.x IDE sind etwas seltsam, da wird z.B. jede Menge Quelltext der ARM CMSIS DSP Library mitgeliefert, in einer uralten Version 1.0.1 von 2011. Benutzt wird die scheinbar nirgendwo, sollte wohl mal eine Arduino Version von dem hier werden (die sind mittlerweile bei 1.4.1):

hi,

also 2 arrays an der gleichen stelle geht anscheinend nicht, aber die hilfe von serenifly war's. geht jetzt in einer zeile und in einem rutsch:

  Serial.readBytes((char*)leds, NUM_LEDS*3);
  FastLED.show();

danke Dir und auch den anderen,

gruß stefan

Wie gesagt, mit C++11 sollte es theoretisch gehen. Das hat "unrestricted unions", d.h. eine Union kann auch Typen mit nicht-triviale Konstruktoren enthalten. Ausprobiert habe ich es aber nicht.

Aber wirklich zwei Arrays zu definieren ist hier etwas übertrieben. Ein Cast ist einfacher.

hi,

ja, sicher, vom schreiben her einfach, ich hab' nur ein wenig angst, daß es ein zeitproblem heraufbeschwört.
wenn ich auf 500000 baud raufgehe, um anständige fps (bei 230*3 leds) zu bekommen, kann es bei 32 takten pro serial read, rüberschreiben, zählen, zähler überprüfen UND eben casten schon eng werden. aber ich hab' keine ahnung, wie eng.

die frage ist, was macht der cast eigentlich. wandelt er da wirklich was um (aber was sollte er da umwandeln, leds ja wohl nicht ?), oder schaltet er nur die typüberprüfung beim kompilieren aus.

gruß stefan

Eisebaer:
oder schaltet er nur die typüberprüfung beim kompilieren aus.

Genau. Die meisten Casts sind nur Anweisungen an den Compiler wie er die Datentypen zu behandeln hat. Ein Zeiger ist ein Zeiger. Der hat vorher und nachher zwei Bytes. Da muss nichts umgewandelt werden.

Ausnahmen sind dynamic_cast in C++ oder das Überladen das Cast Operators. Da muss zur Laufzeit was gemacht werden. Bei manchen Casts kann es auch sein dass etwas Initialisierungscode erzeugt wird (z.B. int/float), aber das lässt sich schwer pauschal sagen.