Ich arbeite an einem flexiblen LED-Bildschirm, der aus 20 Metern digitalem RGB-LED-Streifen mit WS2811- IC für jede LED besteht.
Ich möchte dies mit Arduino steuern, was mit FastSPI kein Problem ist. Mein Problem ist, dass ich verschiedene LED-Programme erstellen möchte (z. B. mit LedEdit 2013), die dann in *.led-Dateien exportiert werden können.
Dies ist an sich kein Problem, da ich diese Dateien bereits generiert habe. Das Problem ist, wie man die *.led-Datei liest und dekodiert? Nach dem, was ich im Internet lesen konnte (jetzt ein paar Stunden lang gesucht), bestehen die Dateien aus einer Art Header, gefolgt von Base64-codierten Informationen über die x- und y-Position der LEDs, die eingeschaltet werden sollten, und welche Farbe sie haben sollten sein (RGB-Wert 0-255, nehme ich an). Ich bin mir nicht ganz sicher, wie genau ich dieses Signal entschlüsseln und etwas wirklich Nützliches daraus machen soll?
Wenn ich nur ein paar nützliche Informationen herausholen kann, kann ich sicher meinen Ausweg programmieren, wenn ich es mit der FastSPI-Bibliothek für Arduino implementiere.
BEARBEITEN:
Ich habe zwei einfache Beispieldateien erstellt, die für euch vielleicht einfacher zu betrachten sind.
Beide bestehen aus einem einfachen 10 x 10 LED-Setup, beide nur eine Szene; eine ganz schwarz und eine ganz weiß.
Schwarz: http://www.codesmith.dk/black.led und Weiß: http://www.codesmith.dk/white.led
Ich hatte auch Probleme, die Struktur der .LED-Datei zu interpretieren, aber eine andere Methode wäre, eigene Bitmaps zu erstellen. Ich habe ein LED-Bild mit Microsoft Paint erstellt, unter File | Properties
habe ich die Breite und Höhe auf 10 Pixel eingestellt, gefolgt von a File | Save As
und Auswahl 24-bit Bitmap
als Typ. Wenn Sie maximal hineinzoomen, ist es einfach, Pixel einzeln auszuwählen, und Linux und Mac OSX haben viele Anwendungen, die Windows-Bitmaps schreiben können, wenn Sie ein anderes Betriebssystem verwenden.
Dann habe ich die folgende Visual C++-Befehlszeilenanwendung erstellt, um die Bitmap zu lesen und eine konstante Array-Definition zu erstellen. Es schreibt den Code in stdout, sodass Sie ihn beispielsweise mit aufrufen können bitmapconvert test.bmp > test.h
. Beachten Sie, dass es verschiedene Annahmen bezüglich der Bitmap-Größe und Bit-Tiefe trifft, also in keiner Weise „Produktionscode“ ist, so dass Sie sich irgendwann näher mit dem Bitmap-Dateiformat befassen möchten.
#include "stdafx.h"
#include <stdio.h>
#include <stdint.h>
#define BITMAP_WIDTH 10
#define BITMAP_HEIGHT 10
#pragma pack (1)
struct PIXEL_DEF {
uint8_t B, G, R;
} pixels[BITMAP_HEIGHT][BITMAP_WIDTH];
void read_bitmap_data(FILE *bmp)
{
uint32_t data_offset, curx = 0, cury = 0;
fseek(bmp, 10, SEEK_SET); // Skip to offset to bitmap bits
fread(&data_offset, sizeof(data_offset), 1, bmp);
fseek(bmp, data_offset, SEEK_SET); // Move to start of bits
while (fread(&pixels[cury][curx], sizeof(PIXEL_DEF), 1, bmp))
{
curx++;
if (curx >= BITMAP_WIDTH)
{
// Rows padded to 4 bytes, so we may need to skip some data
fseek(bmp, 32 - curx * sizeof(PIXEL_DEF) % 32, SEEK_CUR);
curx = 0;
cury++;
}
}
fclose(bmp);
}
// Following assumes top-left to bottom-right order, you may need to change
void dump_bitmap()
{
int x, y;
printf("const uint8_t bitmap_data[] = {\n");
for (y=0; y < BITMAP_HEIGHT; y++)
{
for (x=0; x < BITMAP_WIDTH; x++)
{
if (x == 0)
printf("\t");
else
printf(",");
printf("0x%02X,0x%02X,0x%02X", pixels[y][x].R, pixels[y][x].G, pixels[y][x].B);
}
if (y < BITMAP_HEIGHT)
printf(",");
printf("\n");
}
printf("};\n");
}
int _tmain(int argc, TCHAR* argv[])
{
FILE *bmp;
if (argc != 2)
printf("Usage: BitMapConvert infile.bmp");
else {
if (bmp = _wfopen(argv[1], _T("rb")))
{
read_bitmap_data(bmp);
dump_bitmap();
}
}
return 0;
}
Die 10 x 10 24-Bitmap, die ich zum Testen verwendet habe, hat das folgende Muster.
Die vom obigen Programm generierte Ausgabe wurde am Anfang des folgenden Pseudocodes eingefügt, der meiner Interpretation aus dem Datenblatt entspricht, wie Daten an das Gerät gesendet werden sollten. Die folgenden Verzögerungen gelten für den Low-Speed-Modus, verwenden Sie die Hälfte der Werte für High-Speed (obwohl das Zurücksetzen gleich bleiben kann). Pin 7 ist für niedrige Geschwindigkeit mit VDD verbunden und für hohe Geschwindigkeit getrennt, sodass Sie überprüfen müssen, wie Ihre Hardware konfiguriert ist. Wenn möglich, ist eine niedrige Geschwindigkeit einfacher.
const uint8_t bitmap_data[] = {
0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,
0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0xFF,
0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,
0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,
0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,
};
void send_zero()
{
set_DI_high();
delay_us(0.5);
set_DI_low();
delay_us(2);
}
void send_one()
{
set_DI_high();
delay_us(1.2);
set_DI_low();
delay_us(1.3);
}
void send_reset()
{
set_DI_low();
delay_us(50);
set_DI_high();
}
void send_image()
{
uint8_t i;
send_reset();
for (i=0; i < sizeof(bitmap_data); i++)
{
if (bitmap_data[i] & 0x80) send_one() else send_zero();
if (bitmap_data[i] & 0x40) send_one() else send_zero();
if (bitmap_data[i] & 0x20) send_one() else send_zero();
if (bitmap_data[i] & 0x10) send_one() else send_zero();
if (bitmap_data[i] & 0x08) send_one() else send_zero();
if (bitmap_data[i] & 0x04) send_one() else send_zero();
if (bitmap_data[i] & 0x02) send_one() else send_zero();
if (bitmap_data[i] & 0x01) send_one() else send_zero();
}
}
Wie Sie sehen können, ist das Protokoll kein SPI, und eine Herausforderung besteht darin, das richtige Timing innerhalb der im Datenblatt angegebenen +/- 150 ns zu finden, was etwa 1 Zyklus bei 8 MHz entspricht. Anstatt irgendeine Form von zu verwenden, delay_us
müssen Sie wahrscheinlich nop
Anweisungen verwenden und Zeitverzögerungen berücksichtigen, die durch das Setzen der Ports und Funktionsaufrufe usw. verursacht werden. Manchmal kann es in dieser Hinsicht nützlich sein, die Assembler-Ausgabe des Compilers zu untersuchen, und ein Bereich ist immer nützlich um es zu verifizieren. Das Datenblatt scheint den gleichen 150-nS-Wert für den Niedrig- und den Hochgeschwindigkeitsmodus zu zeigen. Es kann sein, dass es im Low-Speed-Modus in der Praxis etwas weniger kritisch ist.
Allerdings habe ich mir gerade die von Ihnen erwähnte FastSPI-Bibliothek angesehen und sie erwähnt die Unterstützung für dieses Gerät. Es scheint den SPI-Kanal auf eine nicht standardmäßige Weise zu verwenden (nicht, dass es damit ein Problem gibt), um die Zeitbeschränkungen zu verringern. Ein guter Ausgangspunkt wäre also, dies in Kombination mit der obigen Bitmap-Tabelle zu verwenden.
PeterJ
Simon
Anindo Ghosh
PeterJ
Simon
Simon
Simon
PeterJ