Datenstruktur für ein Displaybuffer in C

OP #3012495
Lesenswert?

Hi,
in einem Projekt möchte ích mit einem AT89S8051 Prozessor eine 
LED-Matrix ansprechen die durch Multiplexing insgesamt 20 Spalten und 14 
Spalten besitzt (eine Matrix besteht aus 7 Zeilen und 5 Spalten)

Als Programmiersprache dient C. Den Inhalt des Displays soll der 
Prozessor im Ram halten und per Interrupt (Timer ca. alle 20ms) auf das 
Display Spaltenweise schreiben.

Mein Problem besteht darin die Datenmenge im Ram zu halten. Ich dachte 
an ein Array der Dimension 20x14. Leider unterstützt C jedoch kein 
Bit-Array.

Könnt ihr mir sagen wie man solch einen "Display-Buffer" effizient 
programmieren kann?

Viele Grüße,
Moderator Persönliche Seite #3012511
Lesenswert?

Sven W. schrieb:
> Mein Problem besteht darin die Datenmenge im Ram zu halten. Ich dachte
> an ein Array der Dimension 20x14. Leider unterstützt C jedoch kein
> Bit-Array.

Nicht direkt, aber es geht trotzdem in C, siehe Bitmanipulation.
1
#define N_LINES    20
2
#define N_COLUMNS  14
3

4
uint16 display[NUM_LINES];

Da passen dann 20 x 16 Bit rein, wovon Du aber nur 20 x 14 brauchst. Der 
Speicherverbrauch liegt also bei 40 Bytes.

Den Rest zur Speicherung/Abfrage entnimmst Du dem oben genannten 
Artikel.
#3012533
Lesenswert?

Es ist natürlich toll, wenn man den Displayinhalt in möglichst wenig 
Speicher quetschen kann.
Aber wenn du nicht grad mit einem Tiny unterwegs bist (wovon ich mangels 
genug I/O Pins ausgehe) hast du den Speicher.

Beispiel: Ich könnte bei einem LED-Cube (8*8*8) mit 64 Byte speicher 
auskommen.
Aber ich definiere mir mein Array als uint8_t cube[8][8][8];
Mein ATmega1284P hat 16k RAM, da drück ich die 512 Byte doch locker ab.

Vorteile:   1) höchstwahrscheinlich schnellerer Code da Bitgeschiebe und 
-verknüpfungen entfallen
      2) Die Schnittstellen ändern sich nicht (kaum) wenn ich mal auf 
RGB LEDs umsteigen wollte. Dann hab ich z.B. 1 Byte für 
Farbinformationen.

Wenn du das Display nicht gerade kommerziell vertreibst dann zahl den 
Euro mehr den der ATmega1284P gegenüber einem alten 16er kostet.
#3012542
Lesenswert?

Sven W. schrieb:

> Mein Problem besteht darin die Datenmenge im Ram zu halten. Ich dachte
> an ein Array der Dimension 20x14. Leider unterstützt C jedoch kein
> Bit-Array.

Kann man ja auch selber machen.

Wenn du (nur so als Beispiel) 40 Bits nebeneinander brauchst, dann 
kannst du die in 5 Bytes unterbringen.
Warum?
Weil 5*8 die 40 ergeben

Also:
uint8_t Line[5];

In welchem Byte befindet sich daher das Bit mit der Nummer 12?
Na, wenn in jedem Byte jeweils 8 Bit sind, dann ist das Bit mit der 
Nummer 12 in Line[1].
Warum?
Weil  12/8 gleich 1 ergibt.

In diesem Byte, an welcher Bitposition ist denn da das 12-te Bit?

(mal kurz eine Skizze machen

   0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 absolute Bitnummer
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--
 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--

   7  6  5  4  3  2  1  0  7  6  5  4  3  2  1  0  Bit im Byte
 |                       |                       |
 +--- Line[0] -----------+------ Line[1] --------+

so, nachdem das soweit klar ist, zurück zur Frage: das wievielte Bit ist 
denn das Bit Nummer 12, gesehen aus der Sicht von Line[1]. Aus der 
Zeichnug sehen wir: das ist Bit 3)

Warum ist das so?
Weil 12 % 8 gleich 4 ergibt, und 7 - 4 die 3 macht.

Wenn das Display die Bits genau anders rum haben will, so dass Bit 0 
links ist, anstatt rechts, dann ist es noch einfacher. Dann ist 12 % 8, 
also 4 die Bitnummer.


D.h. wird ein Pixel gesetzt, dann setzt man in

  Line[ xPos / 8 ]

das Pixel mit der Nummer

  ( 1 << ( 7 - xPos%8 );

oder, wenn das Bit 0 links ist (wie meistens), dann eben das Bit

  ( 1 << (xPos%8) );

Alles zusammengenommen:

void setPixel( uint8_t xPos )
{
  Line[xPos/8] |= ( 1 << xPos%8 );
}


Und das ganze hat dann auch noch den Vorteil, dass du wahrscheinlich 
diese ganzen 8 Bits in dem Byte als ganzes zum LCD schicken kannst, ohne 
dass du erst mal die Einzel-Bits aus 8 Einzelvariablen zusammensetzen 
musst. D.h. deine ISR hat die auszugebenden Bytes schon fix fertig 
vorliegen und muss sie nur ans LCD weitergeben. Und das ist gut so. Denn 
deine ISR ackerte früher x mal in der Sekunde, um die Einzelbits zum im 
wesentlichen immer gleichen Byte zusammenzusetzen, weil sich der Display 
Inhalt viel seltener ändert, als ihn die ISR benötigt. D.h. du 
verschiebst zwar ein wenig Aufwand in den Funktionsblock Pixel-Setzen. 
Dafür entlastest du aber im Gegenzug die ISR massiv. Und im Summe bringt 
dir das mehr, weil die ISR ja dauernd läuft, während du im Vergleich 
dazu eher selten ein Pixel setzt oder löscht.


Sind die Pixel am LCD nicht zeilenweise in Bytes zusammengefasst, 
sondern spaltenweise (also immmer 8 Pixel übereinander in einem Byte), 
dann ist das genau so einfach. Einfach mal aufmalen und überlegen, wie 
man aus der x/y Position des zu setzenden Pixels, auf das Byte und auf 
die Bitnummer in diesem Byte kommt.

Jaaa, man kann sich Formeln auch selber herleiten. Das wird auf dieser 
Ebene selten komplizierter als eine Multiplikation und/oder Division 
und/oder Division mit Rest und vielleicht, möglicherweise noch eine 
Addition dazu. Aber schwieriger wirds nicht. Eine kleine Skizze, in der 
man sich die Dinge einträgt, hilft da oft Wunder, die Zusammenhänge zu 
sehen.
#3012559
Lesenswert?

le x. schrieb:
> Vorteile:   1) höchstwahrscheinlich schnellerer Code da Bitgeschiebe und
> -verknüpfungen entfallen

Nö, im Gegenteil.
Du mußt immer umständlich schieben, um die 8 einzelnen Bits wieder zu 
einem Byte zusammen zu friemeln.
Neben mehr RAM brauchst Du deutlich mehr Code.

Wenn aber schon 8 Bits in einem Byte sind, dann kannst Du sie einfach 
parallel an ein Latch (74HC573) für 8 LEDs ausgeben oder seriell per SPI 
an einen 74HC595.
In jedem Timerinterrupt werden dann einfach 5 Bytes auf 5 Latches 
gegeben und die nächste Zeile eingeschaltet.


Peter
Gast #3012661
Lesenswert?

Da hast du natürlich recht Peter!

Mir gings aber eher um "aufwendige" Animationen.
Die Ausgabe sollte normalerweise nicht so das Problem sein, aber das 
nächste Bild sollte nach Möglichkeit fertig berechnet sein...
#3012781
Lesenswert?

lex schrieb:
> Da hast du natürlich recht Peter!
>
> Mir gings aber eher um "aufwendige" Animationen.
> Die Ausgabe sollte normalerweise nicht so das Problem sein, aber das
> nächste Bild sollte nach Möglichkeit fertig berechnet sein...

Reißt sich aber trotzdem um nix.
Denn die ISR muss das Bitgepfriemel zwingend ein paar Hundert mal in der 
Sekunde machen, die Animationsroutine nur dann, wenn sich ein Pixel auch 
tatsächlich ändert.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren