Mit der genannten Library (vielen Dank an den Autor an dieser Stelle)
habe ich guten Erfolg gehabt mit einem DOGM132 Display, funktionierte
schnell sehr gut.
Nun benötige ich aber noch die üblichen Grafikfunktionen, im Moment vor
allem gefüllte und ungefüllte Rechtecke. Da die Library keine Funktion
setpixel oder so ähnlich enthält, die meisten Rechteckfunktionen aber so
eine benötigen, muss die als Erstes her. Wie realisiert man die bei
diesem Display?
An die entsprechende Stelle zu kommen ist nicht das Problem, das es aber
keinen Ramspeicher oder so gibt, und das auch so bleiben soll, gibt es
ein Problem, da immer ein ganzes Byte geschrieben werden muss und die
anderen Bits, die schon gesetzt sind, wieder überschrieben werden...
Gibts dafür eine Lösung?
Grüsse
Martin
Hi
>Byte lesen, das bewusste Bit setzen, Byte zurückschreiben
Das Display kann man aber nicht auslesen!
Also entweder ein Abbild im RAM anlegen oder geschickt planen.
MfG Spess
Martin Geissmann schrieb:> Nun benötige ich aber noch die üblichen Grafikfunktionen, im Moment vor> allem gefüllte und ungefüllte Rechtecke. Da die Library keine Funktion> setpixel oder so ähnlich enthält, die meisten Rechteckfunktionen aber so> eine benötigen, muss die als Erstes her. Wie realisiert man die bei> diesem Display?
Byte lesen, Bit setzen, Byte schreiben
Da du vom LCD nicht lesen kannst, musst du dir im Programm ein
entsprechendes Duplikat des Display-RAM anlegen (falls das deine Lib
nicht sowieso schon macht)
> keinen Ramspeicher oder so gibt, und das auch so bleiben soll,
das geht nicht. Entweder du hast irgendwo Speicher aus dem du die
aktuelle Bitsituation auslesen kannst, dann kannst du allgemeine
Grafikfunktionen aufsetzen. Oder du hast ihn nicht. Dann gehts nicht -
zumindest nicht in voller Allgemeinheit.
> Gibts dafür eine Lösung?
In dem Fall: im Allgemeinen - nein.
Ok wenns nicht anders geht habe ich mich drangemacht, die Bibliothek so
abzuändern, dass in einen Zwischenspeicher geschrieben wird. Teilweise
konnte ich anderen Code zu Hilfe ziehen. Eine Rechteckfunktion habe ich
jetzt und die scheint auch zu funktionieren, aber dafür habe ich
Probleme mit der Schriftausgabe. Aber von vorne, ich habe fongendes
getan:
Zuerst ein Array, das so lang ist wie das Display Punkte hat (132x32):
Soweit scheints zu funktionieren, zum Test habe ich ein kleines
Schachbrettmuster geschrieben. Nun schaffe ich es aber nicht, die
Funktion korrekt abzuändern, die einen ganzen Character schreibt.
Original sieht die so aus:
verwendet werden, aber ich schaffs wie gesagt nicht, dass da was
gescheites angezeigt wird, was wohl vor allem an der Position liegt.
Zudem muss ich auch zugeben, dass ich nicht ganz durchblicke, wie diese
Fonts organisiert sind.
Kann bitte jemand helfen? Der Originale Quelltext ist in folgendem
Thread zu finden:
Beitrag "Library für EA-DOGM Grafikdisplays inkl. Font-Generator" (Version 092)
Grüsse
Martin
Martin Geissmann schrieb:> Zuerst ein Array, das so lang ist wie das Display Punkte hat (132x32):
Gut
> Schachbrettmuster geschrieben. Nun schaffe ich es aber nicht, die> Funktion korrekt abzuändern, die einen ganzen Character schreibt.
Schreib sie neu.
So kompliziert ist das nicht und danach verstehst du sie.
Hier ist dein Ausgangspunkt
1
structfont_info{
2
uint16_tsize;//size of data array
3
uint8_twidth;//(maximum) width of character
4
uint8_theight;//height of character
5
uint8_tfirstchar;//the number of the first included character (often 0x20)
6
uint8_tlastchar;//the last included character (often 0xFF)
7
PGM_Pwidthtable;//Pointer to the table holding character widths (NULL for monospaced fonts)
8
PGM_Pdata;//Pointer to data arrray
9
};
Die Beschreibung eines Fonts
Als Beispeil nimmst du dir den einfachst möglichen Font her. Fixed 8
Pixel
So sieht seine Struktur aus
1
conststructfont_infofont_fixed_8pxPROGMEM=
2
{256*6,// komplette Grösse der Data Sektion in Bytes
3
6,// pro Zeichen werden 6 Bytes benötigt
4
8,// wobei ein Zeichen aus 8 übereinanderliegenden Pixel besteht
5
0x00,0xFF,// erstes Zeichen in der Tabelle = 0x00, letzten = 0xFF, also kompletter ASCII Code inkl Sonderzeichen
6
0,// keine Kerning Daten
7
font_fixed_8px_data// und dort finden sich die Daten
8
};
soweit so gut.
Die einzelnen Felder dürften alle eindeutig sein. Oder gibt es dazu
Fragen?
Angenommen du sollst ein 'A' ausgeben. Was gibt es zu tun.
Zunächst mal muss man die dazu nötigen Bytes (mit den Pixel) in der Data
Tabelle finden.
Dazu benötigst du:
Aus wievielen Bytes besteht denn 1 Zeichen (=width)?
Denn klarerweise fängt die Beschreibung dieses Zeichens
an der Zeichen*width Position an.
Das ist aber noch nicht alles. Die Fontbeschreibung erlaubt auch noch,
dass am Anfang der Tabelle Zeichen für die keine Pixel vorhanden sind
aus der Tabelle ausgelassen werden.
Das erste Byte für die Pixel von 'A' findet sich daher bei
data [ ( 'A' - firstchar ) * width ];
'A' hat den ASCII Code 0x41 (= dez 65), firstchar ist in diesem Fall 0.
width ist laut Struktur 6. D.h. das erste Byte mit codierenden Pixel für
ein 'A' findet sich in data bei
( 65 - 0 ) * 6 -> 390 oder hex 0x186
also in data[390]
Sehen wir mit diesem Index in der Data Tabelle nach, so erhalten wir von
diesem Index ausgehend die nächsten 6 Bytes (6, weil in der Struktur
steht, dass wir 6 Bytes pro Buchstabe haben)
0x00, 0x7E, 0x11, 0x11, 0x11, 0x7E
Das sind die 6 Bytes, die die Pixel kodieren. Wie tun sie das? Jedes Bit
in je 1 Byte steht für ein Pixel und jedes Byte steht für eine komplette
Spalte. Das weiss ich deswegen, weil in der Strukturbeschreibung steht,
dass eine Zeichenhöhe von 8 vorliegt und in einem Byte gibt es nun mal 8
Bits.
Schlüsseln wir die 8 Bytes mal nach Bits auf (in Spaltenform) dann
erhalten wir:
00 7E 11 11 11 7E
+---+---+---+---+---+---+
7 | 0 | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+
6 | 0 | 1 | 0 | 0 | 0 | 1 |
+---+---+---+---+---+---+
5 | 0 | 1 | 0 | 0 | 0 | 1 |
+---+---+---+---+---+---+
4 | 0 | 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+---+
3 | 0 | 1 | 0 | 0 | 0 | 1 |
+---+---+---+---+---+---+
2 | 0 | 1 | 0 | 0 | 0 | 1 |
+---+---+---+---+---+---+
1 | 0 | 1 | 0 | 0 | 0 | 1 |
+---+---+---+---+---+---+
0 | 0 | 0 | 1 | 1 | 1 | 0 |
+---+---+---+---+---+---+
lass ich mal die Tabellenlinien weg und schreibe die 0 mit einem
Leerzeichen (für nicht gesetztes Pixel) und die 1 mit einem # (für
gesetztes Pixel), dann kommt da raus
# #
# #
#####
# #
# #
# #
###
Ich weiß nicht wie's dir geht. Aber für mich sieht das ganz stark nach
einem auf dem Kopf stehenden 'A' aus.
D.h. die Pixel werden so ausgegeben: das 0-te BIt kommt oben hin, das
7te Bit kommt unten hin.
D.h. die Grundstruktur wird (zunächst mal) so aussehen:
berechen Anfangsadresse im data Array
for( i = 0; i < width des Zeichens; ++i ) {
byte = data[ anfangsadresse + i ];
gib alle 8 Bit (genauer height bits) dieses Bytes aus
beginnend beim Bit 0 {
Bit i extrahieren
if Bit ist 1
set_pixel( x + i, y + Bitnummer des Pixels );
else
clear_pixel( x + 1, y + Bitnummer des Pixels );
}
}
x und y sind die Koordinaten, an der der Text ausgegeben werden soll. Wo
du im Text dann deinen 0 Punkt haben willst, musst du noch festlegen.
Übernimmst du x und y einfach so, dann ist der logischerweise links oben
im Eck (weil ja x von dort mit jeder Spalte um 1 wächst, bzw. die Pixel
mit steigender Pixelnummer um 1 nach unten gehen.
Ehe dich um all die möglichen Sonderfälle kümmerst, solltest du erst mal
mit dem einfachst möglichen Font anfangen: 8 Pixel pro Spalte,
Zeichenbreite fix. Daher: keine Sonderfälle, das Kochrezept kann man
mehr oder weniger 1:1 von da oben übernehmen. Einzig die 6 kommen aus
der Strukturbeschreibung (und natürlich der Pointer auf den Anfang des
data Feldes)
Wenn du den erst mal auf dem Schirm hast, schaust du dir die anderen
Fonts genauer an und versuchst erst mal auf dem Papier nachzuvollziehen,
wie man zu den 0/1 für die Pixel kommt. Das wird sehr ähnlich sein wie
beim einfachst möglichen Fall, nur muss man einige Sonderfälle mehr
berücksichtigen.
Den Anfang der Funktion habe ich stehen lassen weil es das alles früher
oder später wohl wieder brauchen wird. Jetzt muss ich als nächsten
Schritt die Funktion lcd_put_string_xy dazu schreiben, was ich ganz
ähnlich der normalen Stringfunktion so versucht habe:
Das klappt irgendwie nicht. Mit col += 6 erhöhe ich den Wert doch um die
korrekte Characterbreite von 6 für diesen Font? Auch wenn das klappen
würde, irgendwie müsste ich die Characterbreite ja bestimmen können um
die Funktion universell zu benutzen. Wie könnte das geschehen?
> Also entweder ein Abbild im RAM anlegen oder geschickt planen.
Da bereut man es bestimmt wenn man keinen fetten Microcontroller mit
20kB internem Ram hat oder? :-)
Ich hatte in der Elektor mal einen Artikel ueber ein Grafikdisplay am
R8C13. Dort habe ich einen mitlaufenden Puffer verwendet. Man hat also
nur die zuletzt geschriebenen 10, 20, 50 usw (beliebig einstellbar)
Pixel im internen Ram. So konnte man den Rambedarf passend auf seine
Anwendung zuschneiden. Normalerweise bedeutet das das man mit 25 bis 50%
des Rams auskommt den ein Display sonst braucht. Gerade bei so mickrigen
Controllern mit nur 1kByte Ram ist das eine grosse Hilfe.
Olaf
>> Das klappt irgendwie nicht.
Kannst du das konkretisieren? Was klappt nicht?
> Mit col += 6 erhöhe ich den Wert doch um die> korrekte Characterbreite von 6 für diesen Font? Auch wenn das klappen> würde, irgendwie müsste ich die Characterbreite ja bestimmen können um> die Funktion universell zu benutzen. Wie könnte das geschehen?
Die Characterbreite steht ja in der Font Struktur drinnen, auf die du
freundlicherweise einen Pointer mitbekommen hast
col += font->width;
Bzw. ich sehe gerade, dass es ja eine Funktion gibt, die für ein Zeichen
die Breite bestimmt
col += font_get_char_width( font, t );
NOch geschickter ist es allerdings, wenn du dir einmal ansiehst, was
denn die Funktion lcd_put_char_xy eigentlich als Returnwert
zurückliefert :-)
Genau den Wert, den du brauchst :-)
while((t = *str++)) {
col += lcd_put_char_xy(font, style, t, page, col);
}
Vielen Dank, in der Zwischenzeit hatte ich auch noch ein wenig
Gelegenheit, damit rumzuprobieren, und es hat auch so geklappt, aber auf
genau die Weise wie du schreibst: