Hallo,
ich würde gerne auch einem PIC24 Speicher ein einfaches BMP auf einem
Display ausgeben (MI0283QT-9).
Code und Quelle siehe unten!
Ich würde gerne das grundsätzliche Vorgehen verstehen.
fopen() öffnet die BMP-Datei zum lesen. Mit Hilfe des Zeigers fd vom Typ
File wird dabei ein Stream zum lesen eingerichtet.
Nach
1
FILE*fopen(constchar*filename,constchar*mode);
öffnet fopen die Datei die unter dem parameter filename angegeben ist,
also zum Beispiel "image.bmp". Der Mode gibt an wie auf den Stream
zugeriffen werden soll, also z.B. r für Read und "rb" gibt an, dass die
Datei als binary File gelesen werden soll. Wenn die Datei nicht geöffnet
werden kann oder nicht gefunden wird, dann liefert fopen() den NULL
Zeiger zurück und der String "File not found" wird ausgegeben.
Wo genau muss ich das image.bmp hinterlegen, wenn ich es nachher mit
OpenBMPFile("image.bmp", 20, 20); anzeigen möchte. Einfach im
Projektordner?
Danach wird überprüft ob der Header der zu lesenen Datei dem eines BMP
Headers entspricht (also 2Byte ASCII "BM", offset54). Wenn die Datei ein
BMP Datei ist wird fread() aufgerufen. Diese FUnktion ist wie folgt
definiert:
Diese Funktion liest Blöcke vom Eingangsstream (hier: fd) mit Count
Elementen (in unserem Fall 1) und speichert Sie in einem Block für den
bereits Speicher reserviert wurde (hier unser Feld char buf[40]).
Dann wird jeder Pixel zeilenweise aus dem Buffer ausgelesen und auf dem
Display ausgegeben.
Dies nur zum groben Verständnis der Funktion. Ich habe nur ein Image.Bmp
mit 80x80Pixel im Hauptverzeichnis des Projektes abgelegt und versuche
es auf dem Display über OpenBMPFile("image.bmp", 20, 20); ohne Erfolg
auszugeben. Stattdessen sieht es vielmehr so aus, als würde die main()
Funktion in einer Endlosschleife aufgerufen werden, d.h. das Display
cleart sich jedes Mal aufs Neue. Das Display ist richtig initialisert
und die Funktionen setarea() und draw Pixel() richtig implementiert.
Über Anregungen wäre ich dankbar.
Gruss TImm
1. Was ist der Code von dir bzw. in was schreibst du dein Programm? Der
angehängte sieht wie ein C++ Programm aus.
2. Habe ich dich richtig verstanden, dass du das Display korrekt
ansteuern kannst, Dinge ausgeben kannst und jetzt ein Bild, welches du
im PIC Flash hinterlegen willst, ans Display senden willst?
3. Kennst du die Microchip Library of Applications?
http://www.microchip.com/pagehandler/en-us/devtools/mla/
Ich würde dir raten die Grafik API deren zu verwenden.
Dazu musst du nur ein paar Dateien einbinden und einen einfacher Treiber
für dein Display schreiben, d.h. die Funktion DrawPixel in Putpixel
umbenennen und zwei weitere Funktionen implementieren: (siehe
..\Microchip\Graphics\Drivers\CustomDisplayDriver.c)
1
voidResetDevice(void)
2
{}
3
4
5
voidPutPixel(SHORTx,SHORTy)
6
{}
7
8
9
WORDGetPixel(SHORTx,SHORTy)
10
{
11
return(0);
12
}
Dafür bekommst du dann Zugriff auf zahlreiche Funktionen um beliebige
Texte auszugeben bzw. Bilder. In dem selben Ordner findest du viele
fertige weitere Treiber zu weiteren Displays, dort findest du auch
Beispiele für die Bildausgabefunktionen. Diese musst du dann eben auf
dein Display anpassen und in deinen Treiber implementieren.
Installiere einfach die MLA, schau dir ein paar Beispielprojekte an,
bedenke was du willst (also nicht gleich eine komplette GUI) und kopiere
dann das nötige, siehe:
http://www.microchip.com/forums/FindPost/718663
4. Du willst ein Bild aus dem Flash laden, d.h. du musst das Bild erst
einmal in den Flash bekommen. Da reicht es natürlich nicht einfach das
BMP File in den Ordner zu schieben, was soll der Compiler damit auch
anfangen. Der Code, den du gepostet hast, lädt ein Bild von einer
SD-Karte. Daher muss man die Bilddatei auch erst öffnen (fopen) ... Das
willst du aber nicht. Du hinterlegst die Bilddatei im Flash des uC,
somit musst du sie in dein Programm irgendwie als Konstantes Array
importieren. Wenn du die MLA installiert hast findest du unter
..\Microchip\Graphics\bin\grc den 'Graphics Resource Converter' mit dem
du Bilder, aber auch Schriften in C-Files umwandeln kannst. Danach musst
du dann noch die entsprechende Funktion zum Zeichnen auf das Display
aufrufen, der du das Array dann übergibst.
Hallo Frank, vielen Dank für die ausführliche Antwort.
Alle Punkte haben mir sehr geholfen. Werde morgen nochmal einiges
ausprobieren und dann nochmal eine Rückmeldung geben.
Gruss
Timm
Hallo,
die mla Libraray habe ich zwar installiert, aber ein ausführlicher Blick
auf die verschiedenen Treiber hat mit schon mal etwas weitergeholfen.
Ich kann das Display bereits initialisieren und habe eine Fülle an
Funktionen (Integer schreiben, Strings schreiben, diverse
Zeichenfunktionen etc.) bereits implementiert.
Es geht jetzt "nur" noch darum Bilder anzuzeigen (erst BMP aus Flash des
PICS, später dann von SD-Karte).
Also vielen Dank nochmal für die Erklärung.
Ich habe es gestern geschafft einmal ein einfaches 10x10 Pixel BMP mit
24 Bit darzustellen.
Dazu habe ich mir folgendes kleines Programm geschrieben:
// helfer = helfer + 3; // wenn 0x00 nicht angehängt
16
helfer=helfer+4;// -> wenn 0x00 angehängt bei 24Bit
17
}
18
helfer=0;
19
}
Das BMP File habe ich wie beschrieben mit dem Graphics Resource
Converter umgewandelt. Was mich hier bei den 24Bit Farbtiefe gewundert
hat ist, dass nach jedem Pixel (also 3Byte) ein 4.Byte mit 0x00
angehängt wird???
Das lässt sich im Code zwar leicht über helfer + 4 abfangen, aber bei
größeren Arrays wird das doch umständlich. Bei 16-Bit wird dieses Byte
nicht angehängt?
Weiterhin muss man sich das Array im Texteditor ja doch relativ
umständlich zu Recht basteln. Für ein 10x10 Pixel habe ich
beispielsweise mit folgenden Array gearbeitet (0x00 für jedes Pixel
angehängt):
1
unsignedcharbuffer2[10][40]=
2
{{x00,x01,...,x039},
3
{................},
4
{x90,x91,...,x939}};
Für so ein kleines Array geht das noch. Bei größeren Arrays jeweils die
"{" einzubauen und auf die jeweiligen Zeilen und Spalten umzubauen ist
schon relativ mühselig.
Bei sehr großen Arrays meckert der Compiler, dass die Maximal Größe für
ein Array erreicht ist etc. Weiss jemand wie ich das umgehen kann?
Nochmals Danke und Gruss
Timm
Also so recht verstanden habe ich jetzt nicht was du gemacht hast und
warum du die Ausgabe des grc im Texteditor veränderst. Dein buffer2 ist
nachher ein variables Array das 400 Byte Groß ist und zu Beginn mit
deinem Bild geladen wird. Natürlich sprengt das irgendwann den Rahmen.
Der grc gibt dir aber ein C File aus, oder zumindest assembler code,
welcher eigentlich fix und fertig verwendbar ist.
Schau dir einmal das Beispielprojekt in '\PIC24F Starter Kit 1' an.
In der Datei PicturesFont.c sind anfangs Schriften im Flash abgelegt, am
Ende des Dokuments zwei größere Bilder (Schwarz Weiß).
Aber du siehst den Aufbau, dort ist alles wesentliche mitgespeichert.
Also Bit-Tiefe, Höhe und Breite.
Wenn du dann das Projekt mal öffnest und dir die Primitive.c anschaust,
dann siehst du, dass dort ALLE Grafik-Funktionen schon enthalten sind.
Sofern du in deinem Treiber die PutPixel Funktion implementiert hast,
kannst du auf diese Routinen zurückgreifen und damit Bilder jeglicher
Art etc. ausgeben.
Wenn du die Bildausgabe beschleunigen willst und spezielle Funktionen
deines Displays benutzen willst, bspw. dass mehrere Pixel in einem
Aufwasch geschrieben werden können, so kannst du dann nach und nach
Funktionen von Primitive.c in deinen eigenen Treiber übernehmen und dort
optimieren. Da die Funktionen in Primitive.c das Attribut
'__attribute__((weak))' haben, werden die Funktionen in deinem Treiber
dann bevorzugt.
Also schau dir einfach mal das Projekt an, dort siehst du wie Bilder und
Schriften eingebunden werden und im von mir geposteten Beitrag auf
microchip.com siehst du wie du mit der PutImage Funktion aus der
Primitive.c Datei Bilder ausgeben kannst. (Die PutImage Funktion erkennt
dann welche Art von Bild du ausgeben willst und leitet die Informationen
an die zugehörige Funktion weiter)
Ich hatte Schwierigkeiten mit dem AssemblerCode und in dem generierten
File wurden noch LIBs etc. eingebunden, so dass ich mich entschlossen
habe einfach das Array rauszukopieren und selber weiterzuverarbeiten.
Das Programm geht also Zeile für Zeile jeden Pixel durch und greift
dabei auf die 24 Bit pro Pixel zu
(buffer2[h][helfer+2],buffer2[h][helfer+1],buffer2[h][helfer]). Das 4.
Byte (das Ox00) wird logischerweise nicht genutz. Über helfer = helfer +
4 wird dann auf den nächsten Pixel (also die nächsten 3Byte) gesprungen
und der Pixel gezeichnet.
Hoffe das war einigermaßen verständlich.
Werde mir heute Abend mal das von Dir angesprochene Beispiel angucken.
Da muss das Ganze ja eigentich ähnlich realisiert sein.
Hallo ich habe mir das BEispiel Projekt des Starterkits einmal
angeguckt. So ganz blicke ich noch nicht ganz durch.
Nehmen wir einmal die vermutlich einfachste Funktion für ein Bit
Farbtiefe:
void PutImage1BPP(SHORT left, SHORT top, FLASH_BYTE *image, BYTE
stretch, PUTIMAGE_PARAM *pPartialImageData);
Als Bild habe ich mir aus der PictureFont.c das einfache 8x8 pixels,
1-bits per pixel rauskopiert -> const IMAGE_FLASH ballSquare
Die Funktion beinhaltet wie angesprochen die Funktion PutPixel(), die
einfach nur einen Pixel setzt.
Ich habe eine fertige Funktion void drawPixel(unsigned int x0, unsigned
int y0, unsigned int color) die den jeweiligen Pixel noch in einer
ausgewählten Farbe setzt. Was macht jetzt genau die Funktion SetColor??
Die werde ich vermutlich gar nicht brauchen, weil ich die Farbe ja mit
meiner Funktion draw Pixel realisieren kann.
Die Funktion SetColor ist ja einfach wie folgt defined:
#define SetColor(color) _color = (color)
Das ist mir noch nicht ganz klar.
Die Funktion PutPixel müsste ich also einfach durch meine Funktion
drawPixel ersetzen können.
Aufrufen kann ich die Funktion dann später vermutlich in etwa wie folgt:
PutImage1BPP(20, 20, (void *) &ballSquare, 1)
Was ich für den Parameter PUTIMAGE_PARAM *pPartialImageData einsetzen
muss ist mir ebenfalls nicht ganz klar.
Gruss
Timm
Es wäre Vorteilhaft du würdest den Code posten, den du geschrieben hast.
Und dann:
Ändere absolut rein gar nichts in der Primitive.c Datei rum. Die musst
du so verwenden wie sie von Microchip gegeben ist. Was die dort gemacht
haben folgt einer Struktur und einem Sinn.
d.h. wirf deine DrawPixel Funktion weg, und verwende die PutPixel
Funktion, die du hoffentlich in deinem eigens geschriebenen Treiber
implementiert hast (neben der ResetDevice und GetPixel Funktion).
Die PutPixel Funktion zeichnet einen Pixel an der Stelle, die als
Parameter mit übergeben wird.
Die Farbe des Pixels wird global in der Variable _color gespeichert,
welche mit deinem zitiereten Befehl
1
#define SetColor(color) _color = (color)
modifiziert wird.
Genauso wird in der PutPixel Funktion noch überprüft ob der Pixel
außerhalb der Clipping Region ist.
Schau dir einfach mal die vorhandenen Treiber an.
Im einfachsten Fall sieht die PutPixel Funktion so aus:
Hast du erst einmal diese drei Funktionen implementiert, auf die alle
Funktionen in Primitive.c zurückgreifen wollen, so kannst du Bilder
jeglicher Art zeichnen.
Und hier verwendest du (zumindest vorerst) wieder nicht die spezielle
Funktion PutImage1BPP sondern die Allgemeine: PutImage, welche die Daten
an die jeweils passende Funktion, bspw. PutImage1BPP weiterleitet.
Was PUTIMAGE_PARAM *pPartialImageData bedeutet kann ich dir nicht sagen,
da die MLA die ich verwende (2012) dies noch nicht hatte. Im Quellcode,
im Header der Funktion steht es aber vermutlich was damit gemeint ist.
Auf jeden Fall nur ein 'Zusatzfeature', damit man vermutlich nur einen
Ausschnitt aus dem Bild zeichnen lassen kann. Vermutlich gut in Spielen
für Sprite sheets.
Hallo,
ich habe nicht das komplette Projekt des Starterkits genutzt, sondern
versuche mir nur die Dinge die ich benötige rauszusuchen.
Wie erwähnt möchte ich als erstes die 8x8 Pixel mit 1 Bit Farbtiefe
anzeigen
-> const IMAGE_FLASH ballSquare
DIeses habe ich mir aus der Pictures Font.c herauskopiert.
Ich brauche aus der Primitive.c vorerst nur die PutImage1BPP(SHORT left,
SHORT top, FLASH_BYTE *image, BYTE stretch, PUTIMAGE_PARAM
*pPartialImageData). Diese habe ich mir mit der WORD
PutImagePartial(SHORT left, SHORT top, void* image, BYTE stretch, SHORT
xoffset, SHORT yoffset, WORD width, WORD height)ebenso herauskopiert und
unberührt gelassen.
Die PutImage ist dann wie folgt definiert:
Für diese Funktionen benötige ich ausschließlich die PutPixel FUnktion:
Diese habe ich wie folgt implementiert:
1
GFX_COLOR_color;
2
3
voidPutPixel(SHORTx0,SHORTy0)
4
{
5
if((x0>=LCD_WIDTH)||(y0>=LCD_HEIGH))
6
{
7
return;
8
}
9
10
setArea(x0,y0,x0,y0);
11
12
drawStart();
13
draw(_color);
14
drawStop();
15
16
return;
17
}
Ich habe noch nicht genau verstanden wie ich die Putimage() nun aufrufen
muss.
Ich habe es in etwa so versucht:
1
PutImage(20,0,(void*)&ballSquare,1);
Der Compiler gibt jedoch immer die Fehlermeldung "main.c:210:9: error:
'ballSquare' undeclared (first use in this function)" aus, obwohl ich
das Array inkludiert habe!
Gruss
Timm schrieb:> Hallo,>> ich habe nicht das komplette Projekt des Starterkits genutzt, sondern> versuche mir nur die Dinge die ich benötige rauszusuchen.
Das ist auch richtig so. Das Projekt hat eine volle GUI, viel zu komplex
für den Anfang.
Dennoch empfehle ich dir die ganzen Dateien unberührt zu laden, also das
komplette Primitive.c und nicht einzelne Happen rauskopieren. Macht das
Aktualisieren auf neuere Versionen einfacher und du weißt ja auch nicht
sicher, ohne viel Zeit ins Suchen zu investieren, welche Funktionen alle
benötigt werden.
Ebenso willst du in Zukunft weitere Funktionen nutzen und ersparst dir
so eine Zusammenklauberei.
Wenn du dir doch nochmal den Beitrag aus:
http://www.microchip.com/forums/m196855-p2.aspx#718663
anschaust, dann siehst du doch welche Dateien du unbedingt brauchst.
Warum probierst du es nicht einfach? Es ist viel einfacher als sich nur
einzelne Happen da raus zu kopieren.
Du wirst wohl etwas falsch eingebunden haben, wenn dieser Fehler
auftaucht.
Dazu muss man aber den Quellcode deiner Dateien sehen und sehen welche
Dateien du in deinem Projekt eingebunden hast.
Wenn du das Microchip Projekt öffnest und mal nach 'snakeBody' in allen
Dateien suchst, so siehst du, dass du per 'extern' in deinem c-file auf
die globale Konstante snakeBody noch verweisen musst, was du vermutlich
nicht getan hast.
Siehe Beitrag "Re: Den Befehl extern"
Hallo,
ich kann jetzt erste Bilder mit 1Bit Farbtiefe anzeigen. Darauf lässt
sich alles andere aufbauen.
Möchte mich nochmals für die ausführliche und nicht selbstverständliche
Hilfe bedanken!
Gruss
Timm
Hallo,
ich habe noch eine Frage für die Implementierung der SD-Karte. Wertvolle
Informationen bietet ja schon das AN1045 von Microchip. Weiterhin ist in
der MLA 2013-06-15 ja die beispiel LIB "MDD FS-FILE System SD"
vorhanden.
Diese scheint bereits alles mitzubringen.
Ich will aber wiederum nicht mit der ganzen LIB arbeiten, sondern
vorerst nur die LIBs einbinden, die ich wirklich brauche. DIe
HardwareProfile.h müsste ich natürlich auch meine PINs angleichen,
weiterhin brauche ich sicher die FSIO.C und SD-SPI.c. EIn
Demonstrationsbeispiel für den PIC24F ist auch vorhanden. Dieses könnte
ich recht einfach auf einen PIC24E umschreiben.
Das wären die Dateien, die ich als erstes in mein Projekt einfügen
würde, um es dann sukzessive zu erweitern.
Ich rate dir ab die MDDFS lib zu verwenden, da sie sehr langsam ist.
Deutlich schneller und übersichtlicher ist FatFS:
http://elm-chan.org/fsw/ff/00index_e.html
am unteren Ende der Seite gibt es auch 'FatFS sample projects' zum
Download, unter anderem für den PIC24F.
Wieder einmal rate ich dir das unveränderte File einer lib einzubinden
und zu verwenden. Natürlich musst du nicht alle Files einbinden, da
viele nichts mit der lib zu tun haben, aber wenn du ein File einer lib
einbindest, dann das komplette, unverändert.
Das erlaubt dir später leicht weitere Funktionen zu nutzen und leicht
auf neuere Version zu aktualisieren. In der FatFS lib (genauso wie in
der MDD lib) kannst du auch in deren Konfiguration festlegen welche
Teile der lib compiliert und zur Verfügung gestellt werden sollen und
welche nicht (bspw. nur lesen, kein schreiben).
Die Dateisysteme libs bestehen aus zwei großen Teilen, einmal Funktionen
die die SD-Karte direkt per SPI ansprechen. Und dann der zweite Teil
enthält Funktionen die die vorher genannten Routinen verwenden und ein
Dateisystem verwalten.
Hallo,
Danke schon mal für die Antwort. Ich habe die MDDFS Library von
Microchip gewählt und bin damit gut gefahren. Die SD-Karte wird erkannt
und ich kann Txt. Dateien von der SD-Karte öffnen und auf dem Display
ausgeben, sowie in Dateien schreiben.
Jetzt bin ich am überlegen wie ich am besten Bilder (vorerst wieder BMP)
von der SD Karte auf dem Display ausgeben kann.
Der Weg das Bild in C-Code zu konvertieren und nur die Rohdaten (also
ohne Header) in einem Txt.File auf der SD Karte abzuspeichern, dann
diese Datei öffnen und Pixel für Pixel zu zeichnen wäre sicherlich
einfach zu realisieren. Natürlich wäre der riesen Nachteil, dass ich das
Array jedes Mal zurechtschneiden müßte.
Besser wäre wiederum ich könnte mit den Funktionen aus der Graphic Lib
weiterarbeiten (PutImage() etc., die dieKonvertierung des Arrays,
Farbtiefe etc.von alleine erledigen). Wie ich dann aber auf die Dateien
auf der SD-Karte im geeigneten Format zugreifen kann ist mir noch nicht
ganz klar.
Weiterhin bin ich soeben auf die ImageDecoder Lib von Microchip
gestossen. Diese unterstützt Eingangsdaten aus dem MDDFSS Filesystem und
die Ausgangsdaten können dann mti Hilfe des jeweiligen Displaytreibers
direkt auf dem Display angezeigt werden. Unterstützt werden JPEG, BMP
und GIF.
Denke da werde ich erstmal ansetzen.
Gruss
Timm