PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : bitmap auf nokia-display (tutorial)



robocat
14.03.2007, 20:11
hi ihr,

vielleicht interessierts jemanden, wie man mit einem mega8 ein bitmap auf einem alten nokia-3310-display anzeigt. diese schwarzweiss-displays haben 84*48 pixel und werden mit max. 3,3V betrieben.

die beschaltung habe ich von http://www.microsyl.com/nokialcd/nokialcd.html beinahe 1:1 übernommen, nur der data/command-pin hängt bei mir auf PB7. ausserdem muss man spannungsteiler vorsehen, wenn man (wie ich) den mega8 mit 5V betreibt:
http://katze.dead-men.de/3310circuit.png

mit dem code von der microsyl-seite lässt sich das display sehr einfach ansteuern, man muss nur im header ein define ändern

#define LCD_DC_PIN 0x80 // PB7
und noch eine main-funktion in der c-datei hinzufügen

int main(void)
{
unsigned char buffer[]="ein text";
LcdInit ();
//LcdContrast (64); //hier koennte man den kontrast regeln
LcdGotoXY (1,1);
LcdStr(1,buffer);
LcdUpdate ();
for(;;);
return 0;
}

man kann auch schön pixel setzen oder linien malen:

LcdLine(0,0,83,47,1);
LcdPixel(5,5,1);
LcdUpdate();

das display muss mit LcdInit() initialisiert werden, bevor es verwendet werden kann. alle zeichendaten werden (mit LcdPixel, LcdLine, LcdStr) zuerst in einen puffer im atmega geschrieben und erst durch LcdUpdate() auf das display übertragen.

ich wollte eigentlich mit sprintf etwas in einen puffer schreiben, aber sobald ich stdio.h include, hängt sich mein AVRstudio (bzw. winAVR?) komplett auf. wenn jemand weiß, woran das liegen könnte, bitte hilfe.

wenn man allerdings bitmaps abbilden will, empfiehlt es sich, nicht alle pixel einzeln zu setzen, sondern den RAM des displays direkt vollzuschreiben. dazu sind 2 dinge zu beachten:
1. der display-ram-zeiger muss gesetzt werden, bevor man reinschreiben kann
2. während in windows-bitmaps die bilddaten zeile für zeile gespeichert sind (bei schwarzweiss also ein byte 8 horizontale pixel sind) sind es im display-ram 8 vertikale pixel.
http://katze.dead-men.de/3310ram.png
3. ein schwarz-weiss-windows-bitmap enthält headerdaten vor den bilddaten, ausserdem ist die länge einer zeile (in byte) immer durch 4 teilbar. das führt dazu, dass statt 84 pixel (10,5byte) 96 pixel (12 byte) gespeichert werden. angezeigt werden die übrigen 12 pixel im zeichenprogramm nicht.

folgender code konvertiert ein schwarzweiss-bitmap (muss 84*48pixel gross sein) in das nokia format. erzeugt wird eine textdatei, die direkt in den AVR-code gecopypastet werden kann.

/*----------------------------------------------------------------
84*48 schwarz-weiss bitmap in nokia 3310 daten wandeln
compiler: bcc32
OS: XP
robocat, 14.03.07
----------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>

int main()
{

FILE *pDatei;
unsigned int size,i,x,y;
unsigned char buf[64],*file1,*file2;
long pos1,pos2;

pDatei = fopen("J:\\test.bmp", "rb");

if(pDatei == NULL)
{
printf("Fehler beim Oeffnen der Quell-Datei!\n");
printf("Programm beendet.\n");
exit(1);
}

fseek(pDatei,0,SEEK_END);
pos2=ftell(pDatei);
fseek(pDatei,10,SEEK_SET);
fread(&pos1,4,1,pDatei);
fseek(pDatei,pos1,SEEK_SET);

size=pos2-pos1;
file1=malloc(size);
fread(file1,1,size,pDatei);
fclose(pDatei);

file2=malloc(504);
memset(file2,0,504);

for(x=0;x<84;x++)
{
for(y=0;y<48;y++)
{
if(!(*(file1+y*12+x/8)>>(7-(x%8)))&1==1)
{
*(file2+(5-y/8)*84+x)|=1<<(7-(y%8));
}
}
}

pDatei = fopen("J:\\test.txt", "w");
if(pDatei == NULL)
{
printf("Fehler beim Oeffnen der Ziel-Datei!\n");
printf("Programm beendet.\n");
free(file1);
free(file2);
exit(1);
}
sprintf(buf,"unsigned char picture[]={");
fwrite (buf,strlen(buf),1,pDatei);
for(i=0;i<504;i++)
{
if(i%8==0)fwrite("\n",1,1,pDatei);
sprintf(buf,"%u,",*(file2+i));
fwrite(buf,strlen(buf),1,pDatei);
}
fseek(pDatei,-1,SEEK_END);
fwrite ("};\n",3,1,pDatei);
fclose(pDatei);
free(file1);
free(file2);
return 0;
}
bei bedarf kann ich auch das executable zur verfügung stellen.

nun die bitmapdaten noch aufs lcd bringen:

unsigned char picture[]={
0,0,64,192,64,64,64,128,........ }; // beispiel, das ist der bytecode

int main(void)
{
word i; // typedef unsigned int word;
LcdInit();
LcdSend( 0x80, LCD_CMD );
LcdSend( 0x40, LCD_CMD );
for ( i = 0; i < 504; i++ )
{
LcdSend(picture[i], LCD_DATA );
}
for(;;);
return 0;
}

damit hat man das bitmap auf dem display:
http://katze.dead-men.de/3310bmp.png

bei fragen helfe ich gern.

gruesse von der katze

edit:
hier noch eine weitere einfache möglichkeit, eine katze darzustellen, sogar mit hintergrundbeleuchtung..
http://katze.dead-men.de/display.jpg

robocat
16.03.2007, 15:35
da ich ums verrecken keine ausgabe eines integers mit den oben genannten routinen hinbekommen habe (ich konnte stdio.h nicht verwenden, deshalb kein sprintf - was aber sowieso sehr speicherfressend sein soll), habe ich eine kleine routine dafür geschrieben:

/*----------------------------------------------------------------
ausgabe eines signed long (bzw. int)
robocat, 16.03.07
----------------------------------------------------------------*/
void LcdLong(long l)
{
unsigned long i,z;
char b=0;
if(l==0){LcdChr(1,'0');return;}
else if(l<0){LcdChr(1,'-');l*=-1;}
for(i=1000000000;;i/=10)
{
if((z=l/i)>0)b=1;
if(b)LcdChr(1,'0'+z);
l-=z*i;
if(i==1)break;
}
}
geht vielleicht auch eleganter, aber genügt mir vorerst.
wenn jemand weiss, wie man mit AVR studio die stdio einbinden kann, verratets mir bitte.

gruesse