Ich denk mir, ich bau mal ein Tetris mit WS2815

Gedacht hatte ich
6 Stück WS2815 8 x 32 Pixel zu verarbeiten.


Das macht dann 1536 Pixel. Ups :slight_smile:
Bei dieser Größe wollte ich die Spielsteine in eine 6x6 Matrix aufbauen.
Beim ersten Testen auf eine 8 x 8 Matrix (WS2812) sieht das soweit schon schick aus.
Aber die ersten Fragen ergeben sich ja wenn man anfängt.
Mein kleines Testprog

Tetris Steine
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define PIN        6 // On Trinket or Gemma, suggest changing this to 1
#define NUMPIXELS 64 // Popular NeoPixel ring size
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
enum Steinfarbe {SCHWARZ, ROT, GELB, GRUEN, BLAU, PINK};
struct Stein
{  
  const byte S1;
  const byte S2;
  const byte S3;
  const byte S4;
  const byte S5;
  const byte S6;
  const byte S7;
  const byte S8;  
  Steinfarbe Farbe;
};
const byte Dreh = 4; // Anzeigerichtungen

// Beispiel Stein1 8 mal 8 Matrix
//     7 6 5 4 3 2 1 0
//                     0
//                     1
//           * *       2
//           * *       3
//       * * * * * *   4
//       * * * * * *   5
//                     6
//                     7
Stein stein1[Dreh]  // ******  T    *****
{                                          
  {0,0,126,126,24,24,0,0, 0},  //   0 Grad   
  {0,12,12,60,60,12,12,0, 0},  //  90 Grad    
  {0,0,24,24,126,126,0,0, 0},  // 180 Grad    
  {0,48,48,60,60,48,48,0, 0}   // 270 Grad    
};
Stein stein2[Dreh] // ******  J    *****
{
  {0,0,126,126,96,96,0,0, 0},
  {0,60,60,12,12,12,12,0, 0},
  {0,0 ,6 ,6,126,126,0,0, 0},
  {0,48,48,48,48,60,60,0, 0}
};
Stein stein3[Dreh] // ******  U    *****
{
  {0,0,102,102,126,126,0,0, 0},
  {0,60,60,12,12,60,60,0, 0},
  {0,0,126,126,102,102,0,0, 0},
  {0,60,60,48,48,60,60,0, 0}
};
Stein stein4[Dreh] // ******  I    *****
{
  {0,0,0,255,255,0,0,0, 0},
  {24,24,24,24,24,24,24,24, 0},
  {0,0,0,255,255,0,0,0, 0},
  {24,24,24,24,24,24,24,24, 0}
};
Stein stein5[Dreh] // ******  Z S   *****
{
  {0,0,30,30,120,120,0,0, 0},   // Z
  {0,48,48,60,60,12,12,0, 0},   // Z
  {0,0,120,120,30,30,0,0, 0},   // S
  {0,12,12,60,60,48,48,0, 0}    // S
};
Stein stein6[Dreh] // ******  O    *****
{
  {0,0,60,60,60,60,0,0, 0},
  {0,0,60,60,60,60,0,0, 0},
  {0,0,60,60,60,60,0,0, 0},
  {0,0,60,60,60,60,0,0, 0}
};
Stein stein7[Dreh] // ******  L    *****
{
  {0,0,126,126,6,6,0,0, 0},
  {0,12,12,12,12,60,60,0, 0},
  {0,0,96,96,126,126,0,0, 0},
  {0,60,60,48,48,48,48,0, 0}
};
byte Richtung;

// Farben  //
const uint32_t schwarz = 0x000000;  
const uint32_t rot     = 0x800000;
const uint32_t gelb    = 0x808000;
const uint32_t gruen   = 0x008000;
const uint32_t blau    = 0x000080;                  
const uint32_t pink    = 0x800080;

void setup() {
  Serial.begin(115200);
  #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
    clock_prescale_set(clock_div_1);
  #endif
  pixels.begin();
  delay(2000); 
  pixels.setBrightness(10);
  pixels.clear(); 
  stein7[0].Farbe=1;stein7[1].Farbe=3;stein7[2].Farbe=5;stein7[3].Farbe=2;
}

void loop() {  
    
  for(int i = 0; i < NUMPIXELS; i++) {
    switch (i) {
    case 0 ... 7:   if(bitRead(stein7[Richtung].S1, i))    SETPIX(i,stein7[Richtung].Farbe);  break;   // Reihe 1
    case 8 ... 15:  if(bitRead(stein7[Richtung].S2, i-8))  SETPIX(i,stein7[Richtung].Farbe);  break;   // Reihe 2
    case 16 ... 23: if(bitRead(stein7[Richtung].S3, i-16)) SETPIX(i,stein7[Richtung].Farbe);  break;   // Reihe 3
    case 24 ... 31: if(bitRead(stein7[Richtung].S4, i-24)) SETPIX(i,stein7[Richtung].Farbe);  break;   // Reihe 4
    case 32 ... 39: if(bitRead(stein7[Richtung].S5, i-32)) SETPIX(i,stein7[Richtung].Farbe);  break;   // Reihe 5
    case 40 ... 47: if(bitRead(stein7[Richtung].S6, i-40)) SETPIX(i,stein7[Richtung].Farbe);  break;   // Reihe 6    
    case 48 ... 55: if(bitRead(stein7[Richtung].S7, i-48)) SETPIX(i,stein7[Richtung].Farbe);  break;   // Reihe 7
    case 56 ... 63: if(bitRead(stein7[Richtung].S8, i-56)) SETPIX(i,stein7[Richtung].Farbe);  break;   // Reihe 8
    }        
  }

  pixels.show();
  delay(5000);
  pixels.clear();  
  delay(500);
  Richtung++;if(Richtung==4) Richtung=0;
}

void SETPIX(byte i,byte Color)
{
  switch(Color){  // {SCHWARZ, ROT, GELB, GRUEN, BLAU, PINK};
    case 0: pixels.setPixelColor(i, schwarz); break;
    case 1: pixels.setPixelColor(i, rot);     break;
    case 2: pixels.setPixelColor(i, gelb);    break;
    case 3: pixels.setPixelColor(i, gruen);   break;
    case 4: pixels.setPixelColor(i, blau);    break;
    case 5: pixels.setPixelColor(i, pink);    break;
  }  
}

Zum Testen habe ich erstmal 8 mal 8 angenomen, wo ich dann die Pixel für die Spielsteine bestimme. Meine Frage. Wie bekomme ich die einzelnen Steine als Variabel eingebunden.
Zum Ansteuern wird vielleicht ein Mega 2560 reichen. Das ist alles noch Planung und da bin ich auf eure Ratschläge angewiesen.

"durchnummerierte" Variablen scheinen mir der falsche Ansatz zu sein.

schau dir an was andere machen "Arduino Tetris Neopixel"
das ist nur ein Suchergebnis das zumindest zu funktionieren scheint:

1 Like

Wenn Du "Ups" sagen möchtest, dann beim maximalen Strom:

1536 Pixel * 60 mA/Pixel = 92 A (WS2812)
1536 Pixel * 15 mA/Pixel = 23 A (WS2815)

Die Diskussion "es sind nicht alle an" und "es sind nicht alle weiß" hatten wir hier schon mehrfach, aber ein "Ups Ups" ist dennoch angebracht. Lösungsansatz sind Pixel mit höherer Spannungsversorgung.

Das Timing der WS2812 läßt nur eine begrenzte Anzahl Pixel zu. Abhilfe bietet eine Aufteilung auf mehrere Pins oder ein anderer Pixeltyp wie APA102 mit Takt und Daten getrennt wie beim Schieberegister. APA102 sind darüberhinaus mit passend schnellem µC bis zu zehnmal schneller in der Animation.

EDIT: Strom von WS2812 auf WS2815 geändert.

Wird wahrscheinlich schon reichen.
Der Mega hat 8K RAM; Der "Bildspeicher" für die LED braucht alleine 4608 Byte.
Aber Du brauchst sicher ein starkes Netzteil; Jedes Pixel braucht sobald eine Farbe ein ist 18mA und ddas sind dann wenn alle LED leuchten dann ca 28A oder ca 350W

Grüße Uwe

Wie kommst Du auf 60 mA? WS2812 ? Deswegen hatte ich dann WS2815 gewählt.

WS2815.PDF (612,3 KB)

Davon abgesehen 23A ist ja auch schon eine Hausnummer

Aber dass dann Multipliziert mit Brightness max. 50% . Da werden sich wohl Wege finden.

Ja kann man Aufteilen auf 3 Pin.

Da wollte ich einen anderen Weg gehen.
Und gedacht war ja eine 6x6 Matrix über die Pixel laufen zu lassen. Und wenn dann in den unteren Reihen schon Steine liegen so müssen diese ja nicht permanent neu gesetzt werden. Die Pixel sind ja in Farbe gesetzt.
So gehe ich jetzt noch davon aus, das dann pro Loop maximal 6x(6 +1) für ein Stein angesprochen werden. Das +1 ist dann für das Löschen der Pixel wenn der Stein sich im Feld bewegt. (In Anlehnung an C64 Sprites)
Das Spielfeld soll dann in einem Array uint32_t Reihen[48]; festgehalten werden. (193 Byte) Beim Zusammentreffen auf den schon gesetzten Bit in der Reihe würde dann das Absacken des Spielsteines gestoppt und entsprechend die Bit des Spielsteines auf das Array übertragen.
Ist eine Reihe komplett hatte ich vor die obenliegende Reihe dann auszulesen.
(32 Bit * 3 Byte für die Farbe)
Dann die Reihe mit einem Lichteffekt löschen. Danach dann die gelöschte Reihe wieder mit der Ausgelesenen wiederherstellen.
So in etwa mein Jungfreulicher Gedanke :slight_smile:

Vorschläge ? Denn da bin ich am grübeln wie ich es anstelle.

Ja, Du hast mich verwirrt, oben schreibst Du "WS2815", testest dann aber mit "WS2812". Sorry, habe meinen Text geändert :blush:

Wenn ich Dich dafür sensibilisieren konnte, dann habe ich erreicht, was ich wollte :slightly_smiling_face:

Wenn doch mal alle Pixel 100% weiß sind, hilft ein kurzschlußfestes Netzteil.

Das wird nicht gehen. Die Pixel werden alle immer geschrieben.

1 Like

Nur wenn ich clear anwende. Du kannst auch Pin6 trennen und die gesetzten LED bleiben.

Bitte lese einmal das Datenblatt. Und dann erkläre mir bitte, wie du LED 3 und 5 alleine setzen kannst.

NEIN, Es werden immer die Daten für alle WS2815 übertragen, auch wenn Du nur eines änderst.
Grüße UWe

1 Like

Hast recht aber was hat das dann mit dem Progaufbau zu tun? Das geht ja von der Lib aus

Die Lib braucht den Speicher. Und ein UNO/Nano hat davon z.B. nicht genug. Und du musst mind 1536 Pixel = Bit (192 Byte) einfarbig noch mal zusätzlich vorhalten.

pixels.setPixelColor(3, farbe);
pixels.setPixelColor(5, farbe);

Das ist richtig, man kann aber mittels uint32_t getPixelColor(uint16_t n) const; die Farbe eines Pixels aus dem Feld der Datenbank lesen und verarbeiten. Das ist vermutlich, was @martin-lo meint. Nach show() bleibt der Inhalt erhalten.

Mehr Speicher ist für die ersten, nicht optimalen Versuche sicherlich nicht verkehrt. Die Tendenz geht ja dahin.

@martin-lo: Da ich weiß, daß Du die Möglichkeiten eines ESP32 kennst, weise ich Dich nicht ausdrücklich auf diese Möglichkeit hin. Damit könntest Du "verschwenderisch" programmieren.

ja man kann dir Vorschläge machen.

Das:

geht auch in einer Zeile als

const byte s[8];

Bitte lies mal das Datenblatt Seite 4 mitte:
"Data Transmission Method" durch.

oder ein neueres Datenblatt (der interessante Teil ist aber auf Chinesisch):

oder ein ganz altes:

Grüße Uwe

Als " Bildspeicher" verstehe ich den RAM-Bereich, in dem die Bibliothek zb mittels

pixels.setPixelColor(3, farbe);

die Farbdaten der WS28xx abspeichert. Aus diesem Speicherbereich nimmt die Bibliothek die Daten die bei show an die WS28xx geschickt werden.
Grüße Uwe

Was meinst Du damit?

Grüße Uwe

Das kann ich Dir wahrscheinlich erklären
Diese brauche ich zusätzlich zu den von Dir veranschlagten 4608 Byte.
Diese 4608 Byte werden in der von mir unterschlagenden Lib ja mindestens gebraucht.
Das ist mir nach euren Kommentaren dann aufgefallen.

Nein, wieso?