2012-04-06 10 views
2

Ich verwende C# (.NET Micro Framework läuft auf dem Netduino Plus), um einen LCD-Bildschirm von 84 x 48 Pixel zu steuern.Mapping (x, y) Koordinaten zu Bits in einem Byte-Array - so schnell und effizient wie möglich

Jedes Pixel im LCD-Bildschirm hat zwei Zustände: 1 (ON) oder 0 (OFF). Um die Pixel auf dem Bildschirm zu steuern, muss ich ein Array von 504 bytes senden, wobei jede byte eine Spalte von 8 Pixel darstellt (dh der Bildschirm wird in 6 Zeilen von 84 x 8 Pixel aufgeteilt).

Dies wird am besten mit einem Beispiel veranschaulicht:

  • Das Byte 00000001 (2^0) stellt eine Spalte von acht Pixeln, wobei das erste Pixel an der Spitze der Säule eingeschaltet ist (1).

  • Das Byte 00001001 (2^0 + 2^3) stellt eine weitere Spalte von acht Pixeln dar, wobei das erste und vierte Pixel vom oberen Rand der Spalte EIN sind.

Hieraus kann man sehen, dass ON oder OFF sind eine bitweise AND Betrieb zeigen, welche in einer bestimmten Spalte Pixel. Zum Beispiel, um zu sehen, ob der 4. Bildpunkt in einer gegebenen Spalte von 8 Pixeln ist ON:

00001001 AND 
00001000 
----------------- 
00001000 > 0 
∴ The 4th pixel is ON 

Das Problem ist, dass ich brauche (x,y) Koordinaten zu verwenden, um in die Lage, jedes Pixel auf dem Schirm zuzugreifen. Zum Beispiel würde der Punkt (3,10) das Pixel 4 rechts von und 11 unter dem Pixel in der oberen linken Ecke des Bildschirms darstellen. In ähnlicher Weise würde der Punkt (83,47) das untere rechte Pixel des Bildschirms darstellen.

Ich habe den folgenden C# -Code geschrieben, dies zu erreichen:

byte[] display = new byte[504]; 

// storing these means they don't need to be calculated every time: 
byte[] base2 = { 1, 2, 4, 8, 16, 32, 64, 128 }; 

// Determine if the pixel is ON (true) or OFF (false) 
public bool PixelState(Pixel px) 
{ 
    return (display[GetColumn(px)] & base2[GetPxNum(px)]) > 0; 
} 

// Find the number of the pixel in its column of 8 
private int GetPxNum(Pixel px) 
{ 
    return px.y % 8; 
} 

// Find the index of the byte containing the bit representing the state of a pixel 
private int GetColumn(Pixel px) 
{ 
    return (px.y/8 * 84) + px.x; 
} 

// Set a pixel's state 
public void SetPixel(Pixel px, bool state) 
{ 
    int col = GetColumn(px); 
    int num = GetPxNum(px); 

    if (state && !PixelState(px)) 
     display[col] += base2[num]; 
    else if (!state && PixelState(px)) 
     display[col] -= base2[num]; 
} 

// Represents one (x,y) point 
public struct Pixel 
{ 
    public int x, y; 

    public Pixel(int x, int y) 
    { 
     this.x = x; 
     this.y = y; 
    } 
} 

Da diese auf einem Mikrocontroller läuft, muss ich den Code so schnell und effizient wie möglich sein. Dies ist auch notwendig, da diese Methoden oft in schneller Folge aufgerufen werden können, um Pixel auf dem LCD-Bildschirm zu aktualisieren.

Daher ist meine Frage Wie kann ich diesen Code schneller und effizienter machen? Gibt es dafür einen besseren Weg?

EDIT: Nach einigen umfangreichen Tests habe ich gemerkt, dass ich soll Math.Floor (oder nur eine Integer-Operation) wurde unter Verwendung von in GetColumn. Ich habe meinen Code aktualisiert.

+0

Wie verwenden Sie C# in einem Mikrocontroller? Oder ist es nur ein Proof of Concept? Auch: welcher Mikrocontroller? Diese Frage hängt A LOT von dem verfügbaren Befehlssatz ab. – kaoD

+0

Natürlich sollte ich diese Information in die Frage aufgenommen haben. Es ist das Netduino Plus: http://www.netduino.com/netduinoplus/specs.htm, das den Atmel AT91SAM7X512 Mikrocontroller verwendet. – Xenon

+1

Dann sind Sie ziemlich durch Ihre Framework-Optimierung eingeschränkt. Diese Art von Frameworks neigen dazu zu saugen, so dass es schneller und effizienter ist ... Drop .NET und bleiben Sie bei reinen ASM oder mindestens eine niedrigere Sprache, wie C (Atmel C ist ziemlich cool, sollten Sie verwenden es!) BTW, musst du es wirklich effizienter machen? Es scheint nicht so, als wäre dies ein Engpass, so dass Sie Opfer einer vorzeitigen Optimierung werden könnten. – kaoD

Antwort

1

Dieser kleine Ausschnitt in SetPixel:

if (state && !PixelState(px)) 
    display[col] += base2[num]; 
else if (!state && PixelState(px)) 
    display[col] -= base2[num]; 

könnte ersetzt werden durch:

if (state) 
    display[col] |= base2[num]; 
else 
    display[col] &= (byte)~base2[num]; // You could precompute this inverse array too 

Wenn Sie precomputing verfügbar viel Speicher haben könnte in Ordnung sein, aber, im Ernst, haben UCS SO MUCH Verarbeitungsleistung in diesen Tagen. Werden Sie wirklich eine kleine Verschiebung oder Verneinung bemerken?


Auch könnten Sie interessieren könnten nicht mit (double) und Math.ceiling() seit Ihrem Mikrocontroller wahrscheinlich keine Floating-Point-Unterstützung hat, also muss es emuliert werden (mit einem daraus folgenden Rückgang der Leistung. (float) Verwendung wäre es besser machen (Einzel Präzision Emulation ist schneller), aber noch besser wäre dies:

return ((px.y/8 + ((px.y%8)?1:0)) * 84) + px.x; 

EDIT: bei näherem Hinsehen Netduino es Macht eine FPU haben (obwohl ich es nicht sehen kann das Datenblatt, so tut es wahrscheinlich auch nicht ...) Die ganze Zahl math Alternativen wahrscheinlich schneller ist noch :)


Wether es schneller ist nur durch Testen, aber sicher sein, wie ich in den Kommentaren gesagt, das ist wird wohl ein Flaschenhals sein und Sie sehen genauso aus wie ein anderes Opfer einer vorzeitigen Optimierung.

Der größte Engpass ist hier Ihr Framework.

+0

Toller Punkt über die FPU; Daran habe ich nie gedacht! – Xenon

+0

Sorry, meinst du '(px.y% 8> 0)? 1: 0) '? Ihr Code gibt einen Typkonvertierungsfehler. – Xenon

+0

Mach dir keine Sorgen - ich habe gerade gemerkt, dass ich in GetColumn statt der Decke das Wort ergreifen sollte. Ich habe die Frage aktualisiert und eine Bearbeitung für Ihre Antwort gesendet. :) – Xenon