T6963C anteuern
Freitag, 18. Mai 2012
 
 

PIC Mikrocontroller Forum  |  PIC Mikrocontroller  |  CCS Compiler  |  LCD (CCS)  |  T6963C anteuern « vorheriges nächstes »
Seiten: [1] 2 3 Nach unten Drucken
Autor Thema: T6963C anteuern  (Gelesen 12130 mal)
 
maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« am: August 08, 2005, 11:14:28 »

Hallo,

hat mir jemand einen Code zum ansteuern eines LCDs mit T6963C(das 128x64 von Pollin).
Habe zwar im CCS Forum einen Code gefunden, dieser nutzt aber irgendwie die Chip Enable Leitung nicht. Ziehe ich diesen PIN manuell auf 0, so sehe ich zwar das sich etwas tut. Was aber normalerweise ein einzeiliger Text sein sollte sind nun über das gesamte Diplay verteilte pünktchen.

Benutze immer noch ein 18F452
Hier der Test Code:
Code:
http://www.ccsinfo.com/forum/viewtopic.php?t=19957&highlight=t6963c


Gruß
Malte
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #1 am: August 08, 2005, 20:19:41 »

Hallo Malte,

es ist richtig, daß CE auf Masse gelegt werden muß. Hast Du auch FS (Font Select) auf Masse gelegt?

Was mir an dem Code nicht gefällt:
Für die Steuersignale werden Bits des PORTC-Registers verwendet und nicht des LATC Registers. Du solltest mal versuchen, ob es damit funktioniert.

Code:
#byte LCD = ...    // LATC Adresse

Für den Lesezugriff auf die 8-Bit Daten des LCDs mußt Du dann "LCD.data" durch
Code:
#byte LCD_read_data = ... // PORTD Adresse

ersetzen, da "LCD.data" auf LATD verweist, und somit nur noch ein Schreiben des Registers sinnvoll ist.


Viele Grüße

Bernd
Gespeichert

maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« Antworten #2 am: August 09, 2005, 20:23:08 »

Hallo,

weil ich immer noch Probleme habe will ich die Libary neu schreiben. Habe dazu die T6963C Libary von Holger Klabunde als Vorlage. Die ist in C18 gehalten. Weiter unter der Code.

Folgende Probleme habe ich. Ist PortD richtig konfiguriert?
Im MPLAB sehe ich, das PORTC beschrieben wird.

Wie setze ich das hier von C18 nach CCS um?


Code:
#define READ_DATA()    PORTB   // read from data port
#define WRITE_DATA(a)  PORTB=(a);  // write to data port

Hatte an folgendes gedacht
Code:

#byte PORTD =   0xF83
#define READ_DATA PORTD
#define WRITE_DATA PORTD
und dann
wert=READ_DATA;
geht das? Da D sich im MPLAB nicht verändert glaube ich nicht an die Richtigkeit.
Und letzens: Was ist ein const rom char???(in der LCDText Funktion.

Hier die .h
Code:
//*********************************************************
//T6963C.h
//
//CCS Compiler
//*********************************************************
#include <18F452.h>
#use delay(clock=20000000)
#fuses NOWDT,HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

//Werte für 18F452

#byte PORTD =   0xF83
#byte PORTC =   0xF8B //LATC
#bit T_WR = PORTC.4
#bit T_RD = PORTC.5
#bit T_CD = PORTC.6


//diese Werte entsprechend ändern
#define LCD_WIDTH 128
#define LCD_HEIGHT 128

//gewünschter Wert auskommentieren
#define PIXPERBYTE 6
//#define PIXPERBYTE 8

//wieviele Bytes pro Zeile(0x0010)
#define BYTES_PER_ROW LCD_WIDTH/PIXPERBYTE
#define DISPLAYBYTES (unsigned int)(BYTES_PER_ROW * LCD_HEIGHT)

//Def. LCD Display Screen 0
#define T_BASE 0x0000
#define T_END (unsigned int)(BYTES_PER_ROW * LCD_HEIGHT/8))
#define G_BASE (unsigned int)0x0200
#define G_END G_BASE+DISPLAYBYTES-1
//Def. Screen 1
#define G_BASE1 G_BASE+DISPLAYBYTES
#define G_END1 G_BASE+DISPLAYBYTES-1

#define DATA_DIR_IN() set_tris_d(0xFF)
#define DATA_DIR_OUT() set_tris_d(0x00)
#define READ_DATA PORTD
#define WRITE_DATA PORTD

//8F=100011111
#define INIT_CONTROL_PINS() {set_tris_c(0x8F); set_tris_d(0xFF);}

//jeweils mit kleiner Pause
#define WR_ON() {T_WR=1; delay_ms(1);}
#define WR_OFF() {T_WR=0; delay_ms(1);}

#define RD_ON() {T_RD=1; delay_ms(1);}
#define RD_OFF() {T_RD=0; delay_ms(1);}

#define CTRL() {T_CD=1; delay_ms(1);}
#define DATA() {T_CD=0; delay_ms(1);}

Code:

#include <T6963C.h>

unsigned char xcursor,ycursor;
void CheckBusy(void);
void WriteCTRL(unsigned char dat);
void WriteData1(unsigned char dat, unsigned char command);
void WriteData2(unsigned int dat, unsigned char command);
void WriteData(unsigned char dat);
void WriteCommand(unsigned char command);
void SetPixel(unsigned char xpos, unsigned char ypos, unsigned char mode);
void DisplayOn(void);
unsigned char ConvertText(unsigned char ch);
void LCDText(const rom char *txt, unsigned char xpos, unsigned char ypos);
void ClearTextScreen(void);
void ClearGScreen(unsigned int begin, unsigned int end);
void ClearScreen();
void SetGBaseLine(unsigned char line);
void ShowHex(unsigned char dat);
void SetGCursor(unsigned char x, unsigned char y);
//*********************************************************
void CheckBusy(void)
{
int status=0;
int temp=0;
DATA_DIR_IN();
CTRL();
do
{
RD_OFF();
temp=READ_DATA;
RD_ON();
status = temp & 0x03;
}while(status != 3);
DATA();
}
//*********************************************************
void WriteCTRL(unsigned char dat)
{
DATA_DIR_OUT();
CTRL();
WRITE_DATA=dat;
WR_OFF();
WR_ON();
DATA();
}
//*********************************************************
void WriteData1(unsigned char dat, unsigned char command)
{
WriteData(dat);
WriteCommand(command);
}
//*********************************************************
void WriteData2(unsigned int dat, unsigned char command)

{
WriteData((unsigned char)(dat&0xFF));
WriteData((unsigned char)(dat>>8));
WriteCommand(command);
}
//*********************************************************
void WriteData(unsigned char dat)
{
CheckBusy();
DATA_DIR_OUT();
DATA();
WRITE_DATA=dat;
WR_OFF();
WR_ON();
}
//*********************************************************
void WriteCommand(unsigned char command)
{
CheckBusy();
WriteCTRL(command);
}
//*********************************************************
void SetPixel(unsigned char xpos, unsigned char ypos, unsigned char mode)
{
unsigned int adress;
unsigned char tmp, pixel;
if(xpos>=LCD_WIDTH) return;
if(ypos>=LCD_HEIGHT) return;
adress=(unsigned int)G_BASE;
adress+=(unsigned int)BYTES_PER_ROW * (unsigned int)ypos;
adress+=(unsigned int)xpos/(unsigned int)PIXPERBYTE;
WriteData((unsigned char)(adress&0xFF));
WriteData((unsigned char)(adress>>8));
if(mode==0) pixel = 0xF0;
else pixel = 0xF8;
tmp=(PIXPERBYTE-1)-(xpos%PIXPERBYTE);
pixel|=tmp;
WriteCommand(pixel);
}
//*********************************************************
void DisplayOn(void)
{
INIT_CONTROL_PINS();
WR_ON();
RD_ON();
DATA();
DATA_DIR_OUT();
WriteData2(T_BASE, 0x40);
WriteData2(G_BASE, 0x41);
WriteData2(BYTES_PER_ROW, 0x42);
WriteData2(BYTES_PER_ROW, 0x43);
//WriteCommand(0x80);
//WriteCommand(0x9C);
WriteData2(0x0000, 0x24);
WriteData2(0x0000, 0x24);
ClearScreen();
}

//*********************************************************
void LCDText(const rom char *txt, unsigned char xpos, unsigned char ypos)
{
  char ps;
WriteData2(xpos+(BYTES_PER_ROW)*ypos,0x24);

  while(ps = txt) //Solange Zeichen größer 0x00
  {
    txt++;
    if (ps== 0) break;
    ps=ConvertText(ps); //Übersetzungstabelle aufrufen
    WriteData1(ps,0xC0); //Write ps, Auto Inkrement
  }
}
//*********************************************************
void ClearTextScreen(void)
{
int i;
WriteData2(T_BASE, 0x24);
for(i=0; i<(BYTES_PER_ROW * LCD_HEIGHT/8); i++)
{
WriteData1(0x00, 0xC0);
}
output_low(PIN_B7);
delay_ms(1000);
}
//*********************************************************
void ClearGScreen(unsigned int begin, unsigned int end)
{
  unsigned int i;
WriteData2(begin,0x24); //Setze Startadresse des zu löschenden Bereiches
for(i=begin; i<=end; i++) WriteData1(0x00,0xC0);
}
//*********************************************************
void ClearScreen()
{
ClearGScreen(G_BASE,G_END1);
ClearTextScreen();
SetGCursor(0,0);
}

//*********************************************************
void SetGBaseLine(unsigned char line)
{
  unsigned int adr;
  adr=G_BASE;
  adr+=BYTES_PER_ROW * line;
  WriteData2(adr,0x42);
}
//*********************************************************
void ShowHex(unsigned char dat)
{
  unsigned char tmp;
  tmp=dat>>4;
  if(tmp<0x0A) WriteData1(tmp+'0'-0x20,0xC0); //Write ps, Auto Inkrement
  else  WriteData1(tmp+0x37-0x20,0xC0);
  tmp=dat&0x0F;
  if(tmp<0x0A) WriteData1(tmp+'0'-0x20,0xC0); //Write ps, Auto Inkrement
  else  WriteData1(tmp+0x37-0x20,0xC0);
}
//*********************************************************
void SetGCursor(unsigned char x, unsigned char y)
{
 xcursor=x;
 ycursor=y;
}
//*********************************************************
//Hauptprogramm
//*********************************************************
void main()
{
delay_ms(100);
output_high(PIN_B7);
DisplayOn();
ClearScreen();
delay_ms(1000);
output_low(PIN_B7);
//LCDText("Interner 8x8 Font",0,0);
SetPixel(10,10,1);
SetPixel(11,10,1);
SetPixel(12,10,1);
SetPixel(13,10,1);
}
Gespeichert
maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« Antworten #3 am: August 10, 2005, 17:34:19 »

Hallo,

erster Fehler: int bei CCS unterscheidet sich doch erheblich von int beim C18(Clearscreen). Wie sollte i hier 256 erreichen. Naja. Anzeigen tuts zwar immer noch nichts.
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #4 am: August 10, 2005, 18:41:28 »

Zitat
Wie setze ich das hier von C18 nach CCS um?
Code:
#define READ_DATA()    PORTB      // read from data port
#define WRITE_DATA(a)  PORTB=(a);  // write to data port

Ich würde es für den Anfang so versuchen, da ich nicht weiß, wie der CCS Makros (#define) mit seinen #byte Definitionen behandelt:
Code:
#byte  LCD_PORT = 0xF83

LCD_PORT = 0x35;         // WRITE_DATA
wert = LCD_PORT;         // READ_DATA


Zitat
Und letzens: Was ist ein const rom char???

Der C18 besitzt zusätzlich zum Qualifier "const" den Qualifier "rom". Der besagt, daß sich die Variable im ROM (also im Flashspeicher) befindet. Ohne das "rom" würde sich die Variable beim C18 im RAM befinden. "const" bedeutet beim C18 nur, daß dieser Wert nicht modifizert werden kann und darf.

Die Funktion LCDText ist mit dem CCS-Compiler etwas problematisch und so wie Du sie hier gezeigt hast, auch nicht korrekt:
Code:
void LCDText(const rom char *txt, unsigned char xpos, unsigned char ypos)
       char ps;                                          // ps ist uninitialisiert
       WriteData2(xpos+(BYTES_PER_ROW)*ypos,0x24);

       while(ps = txt) //Solange Zeichen größer 0x00     // txt ist ein Zeiger auf eine Konstante, hier überprüfst Du die Adresse
                                                         // des Zeigers, nicht deren Inhalt (das währe "*txt")    
       {
               txt++;
               if (ps== 0) break;
               ps=ConvertText(ps); //Übersetzungstabelle aufrufen
               WriteData1(ps,0xC0); //Write ps, Auto Inkrement
       }
   }

Nun zur eigentlichen schlechten Nachricht: Der CCS Compiler unterstützt keine Zeiger auf const (const befinden sich beim CCS automatisch im ROM, "const" bewirkt also das selbe wie "const rom" beim C18).

Prinzipiell hast Du zwei Möglichkeiten. Entweder, du kopierst den auszugebenden Text ins RAM und übergibst einen Zeiger auf den String im RAM
Code:
void LCDText(char *txt, unsigned char xpos, unsigned char ypos)

oder Du verwendest die Besonderheit des CCS, daß Funktionen, denen nur ein char übergeben wird, auch mit einem String im ROM aufgerufen werden können.
Code:
void foo (char);
foo ("Textausgabe");

Der Code der Funktion foo wird dann für jedes im String enthaltene Zeichen erneut ausgeführt. Die Abbruchbedingung für den wiederholten Aufruf der Funktion ist auch hier die Endekennung des Strings, geschieht aber intern durch den CCS-Compiler. Das funktioniert aber nur mit einem char als einzigem Argument, d.h. auf die Positionsangabe müßtest Du verzichten (bzw. diese in einer zustäzlichen Funktion vorher realisieren).

Ehrlich gesagt würde ich die erste Möglichkeit bevorzugen.


Viele Grüße

Bernd
Gespeichert

maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« Antworten #5 am: August 13, 2005, 13:22:41 »

Hallo,

der Code funktioniert nun
Code:

#include <16F877a.h>
#include <math.h>
//#device *=16
//#device adc=10
#use delay(clock=20 000 000)
#fuses NOWDT,HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
//#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#define set_tris_lcd(x) set_tris_d(x)
const int16 TextHome = 0x0000;
const int8  TextArea = 0x0010; // how many bytes before a new line
const int16 GraphicsHome = 0x0101;
const int8  GraphicsArea = 0x0010; // how many bytes before a new line
const int8 AutoModeWrite = 0xB0;
const int8 AutoModeRead  = 0xB1;
const int8 AutoModeReset = 0xB2;
const int8 LCDModeSet  = 0x80;   // send this OR'd with the following
const int8 LCDMode_OR  = 0b0000;
const int8 LCDMode_XOR = 0b0001;
const int8 LCDMode_AND = 0b0010;
const int8 LCDMode_TA  = 0b0100; // TEXT ATTRIBUTE mode.
const int8 LCDMode_RAM = 0b1000; // 1=CG RAM, 0=internal CG ROM
const int8 LCDSetCursorPtr  = 0x21;  // cursor address
const int8 LCDSetCursorSize = 0xA0;  // 1 line cursor
const int8 LCDDispMode = 0x90;   // send this OR'd with the following
const int8 LCDDisp_BLK = 0b0001;
const int8 LCDDisp_CUR = 0b0010;
const int8 LCDDisp_TXT = 0b0100;
const int8 LCDDisp_GRH = 0b1000;

struct lcd_pin_def
{
   BOOLEAN unused1;    // C0
   BOOLEAN unused2;    // C1
   BOOLEAN unused3;  // C2
   BOOLEAN unused4;  // C3
   BOOLEAN w_bar;  // C4 Write bar active low
   BOOLEAN r_bar;  // C5 Read bar active low
   BOOLEAN cd;         // C6 Command/Data BAR   1=command 0=data
   BOOLEAN reset_bar;  // C7 Reset active low
   int  data    :  8;  // PortD=Data bus
};
struct lcd_pin_def  LCD;
#byte LCD = 7  

int   glcd_ReadByte(void);
void  glcd_WriteByte(int1 cd, int data);
void  glcd_WriteByteAuto(int data);
void  glcd_WriteCmd2(int16 data, int cmd);
void  glcd_WriteCmd1(int data, int cmd);
void  glcd_gotoxy(int x, int y, int1 text);
void SetPixel(int xpos, int ypos,  char mode);
glcd_pixel(int16 x,int16 y, int1 color);
unsigned char ConvertText(int ch);
void glcd_rect(int x1, int y1, int x2, int y2, int fill, int1 color) ;
void glcd_line(int x1, int y1, int x2, int y2, int1 color) ;
void glcd_circle(int x, int y, int radius, int1 fill, int1 color);
//*********************************************************
void glcd_init(void) {
  int16 counter;
  set_tris_lcd(0xff);   //TRIS DATA bus,note:control bus always outputs
  LCD.w_bar = 1;      // INITIAL STATES OF CONTROL PINS
  LCD.r_bar = 1;      //
  LCD.cd = 1;         // command
  LCD.reset_bar = 0;  // perform a reset
  delay_us(10);      // delay for a reset
  LCD.reset_bar = 1;  // run
    glcd_WriteCmd2(TextHome, 0x40);
  glcd_WriteCmd2(TextArea, 0x41);
glcd_WriteCmd2(GraphicsHome, 0x42);
glcd_WriteCmd2(GraphicsArea, 0x43);
glcd_WriteCmd2(0x0000, 0x24);
glcd_WriteCmd2(0x0000, 0x24);
  // Clear all RAM of LCD (8k)
  glcd_WriteByte(1, AutoModeWrite);
  for (counter = 0; counter < 0x1fff; counter++)
  {
    glcd_WriteByteAuto(0);    // fill everything with zeros
  delay_us(10);
}
  glcd_WriteByte(1, AutoModeReset);
}
//*********************************************************
void glcd_WriteByte(int1 cd, int data)
{
    int status = 0, temp = 0;
    set_tris_lcd(0xff);
    LCD.w_bar = 1;
    LCD.r_bar= 1;
    LCD.cd = 1;//defaults

    while (status != 0x03) {  // is LCD busy?
       LCD.r_bar= 0;
       temp = LCD.data;
       LCD.r_bar = 1;
       status = temp & 0x03;
    }
    set_tris_lcd(0x00);    // All outputs
    LCD.cd = cd;           // Command/Data bar
    LCD.data = data;
    LCD.r_bar = 1;         // not read
    LCD.w_bar = 0;         // write
    LCD.w_bar = 1;         // release
}
//*********************************************************
void glcd_WriteByteAuto(int data)
{
   int status = 0, temp = 0; // status bits ARE DIFFERENT BITS THAN NORMAL
   set_tris_lcd(0xff);
   LCD.w_bar = 1;
   LCD.r_bar = 1;
   LCD.cd = 1; // defaults
   while (status != 0x08) {  // is LCD busy?
     LCD.r_bar = 0;
     temp = LCD.data;
     LCD.r_bar = 1;
     status = temp & 0x08;
   }
   set_tris_lcd(0x00);     // All outputs
   LCD.cd = 0;             // This is always data, cd=0
   LCD.data = data;        // Put data on data bus
   LCD.w_bar = 0;          // write
   LCD.w_bar = 1;          // release
}
//*********************************************************
void glcd_WriteCmd1(int data, int cmd)
{
  glcd_WriteByte(0, data);
  glcd_WriteByte(1, cmd);
}
//*********************************************************
void glcd_WriteCmd2(int16 data, int cmd)
{
  glcd_WriteByte(0, data & 0xff);
  glcd_WriteByte(0, data>>8);
  glcd_WriteByte(1, cmd);
}
//*********************************************************
int glcd_ReadByte(void)
{
  int data = 0, status = 0, temp = 0;
  set_tris_lcd(0xff);
  LCD.w_bar = 1;
  LCD.r_bar = 1;
  LCD.cd = 1;  // defaults
  #asm nop nop #endasm
  while (status != 0x03) {  // is LCD busy?
    LCD.r_bar = 0;
    temp = LCD.data;
    LCD.r_bar = 1;
    status = temp & 0x03;
  }
  LCD.cd = 0;          // Command/Data bar
  LCD.r_bar = 0;        // read
  /////////////////////////////////////////////////////////
  #asm nop #endasm    // THIS PAUSE IS VERY NESSESARY !!!//
  /////////////////////////////////////////////////////////
  data = LCD.data;
  LCD.r_bar = 1;
  LCD.cd = 1;
  return data;        // Return the read data
}
//*********************************************************
void glcd_putc(char c) {
   glcd_WriteCmd1(c - 0x20, 0xc0);
}
//*********************************************************
void glcd_gotoxy(int x, int y, int1 text) { // sets memory location to screen location x, y
   // location 1,1 is upper left corner;  text = 1 (text area), text = 0 (graphics area)
   int16 location, home;
   int line;
   if (!text) {
      home = GraphicsHome;
      line = GraphicsArea;
   }
   else {
      home = TextHome;
      line = TextArea;
   }
   location = home + (((int16)y - 1) * line) + x - 1;
   glcd_WriteCmd2(location, 0x24);
}
//*********************************************************
//Holger Klabundes Code
void SetPixel(int xpos, int ypos,  char mode)
{
int adress;
char tmp, pixel;
if(xpos>=128) return;
if(ypos>=128) return;
adress=GraphicsHome;
adress+=16 * ypos;
adress+=xpos/8;
glcd_WriteByte(0,adress&0xFF);
glcd_WriteByte(0,adress>>8);
if(mode==0) pixel = 0xF0;
else pixel = 0xF8;
tmp=(8-1)-(xpos%8);
pixel|=tmp;
glcd_WriteByte(1,pixel);
}
//*********************************************************
//Code aus dem CCS Forum
glcd_pixel(int16 x,int16 y, int1 color)
{
int8 r=0,c=0;
c=color;
r=fmod(x,8);
glcd_WriteCmd2(GraphicsHome+(y*16+(x/8)),0x24);
glcd_WriteByte(1,0xf0|(c<<3) |(7-r));
}
//*********************************************************
void LCDText( char *txt, int xpos, int ypos)
{
  char ps;
glcd_WriteCMD2(xpos+(8)*ypos,0x24);

  while(ps = txt) //Solange Zeichen größer 0x00
  {
    txt++;
    if (ps== 0) break;
    ps=ConvertText(ps); //Übersetzungstabelle aufrufen
    glcd_WriteCMD1(ps,0xC0); //Write ps, Auto Inkrement
  }
}
//*********************************************************
unsigned char ConvertText(unsigned char ch)
{
unsigned char tmp;
tmp=ch;
switch(ch)
  {
    case 196: tmp=0x6E; break; // Ä
    case 228: tmp=0x64; break; // ä
  case 214: tmp=0x79; break; // Ö
  case 246: tmp=0x74; break; // ö
  case 220: tmp=0x7A; break; // Ü
  case 252: tmp=0x61; break; // ü
  case 223: tmp=223; break; // ß
  default: tmp-=0x20; break;
  }
return tmp;
}
//*********************************************************
void glcd_line(int x1, int y1, int x2, int y2, int1 color)
{
  signed int  x, y, addx, addy, dx, dy;
  signed long P;
  int i;
  dx = abs((signed int)(x2 - x1));
  dy = abs((signed int)(y2 - y1));
  x = x1;
  y = y1;
  if(x1 > x2)
    addx = -1;
  else
    addx = 1;
  if(y1 > y2)
    addy = -1;
  else
    addy = 1;
  if(dx >= dy)
  {
    P = 2*dy - dx;
    for(i=0; i<=dx; ++i)
    {
      glcd_pixel(x, y, color);
      if(P < 0)
      {
        P += 2*dy;
        x += addx;
      }
      else
      {
        P += 2*dy - 2*dx;
        x += addx;
        y += addy;
      }
    }
  }
  else
  {
    P = 2*dx - dy;
    for(i=0; i<=dy; ++i)
    {
      glcd_pixel(x, y, color);
if(P < 0)
      {
        P += 2*dx;
        y += addy;
      }
      else
      {
        P += 2*dx - 2*dy;
        x += addx;
        y += addy;
      }
    }
  }
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Purpose:       Draw a rectangle on a graphic LCD
// Inputs:        (x1, y1) - the start coordinate
//                (x2, y2) - the end coordinate
//                fill  - YES or NO
//                color - ON or OFF
// Dependencies:  glcd_pixel(), glcd_line()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
void glcd_rect(int x1, int y1, int x2, int y2, int fill, int1 color)
{
  if(fill)
  {
    int y, ymax;                          // Find the y min and max
    if(y1 < y2)
    {
      y = y1;
      ymax = y2;
    }
    else
    {
      y = y2;
      ymax = y1;
    }

    for(; y<=ymax; ++y)                    // Draw lines to fill the rectangle
    glcd_line(x1, y, x2, y, color);
  }
  else
  {
    glcd_line(x1, y1, x2, y1, color);      // Draw the 4 sides
    glcd_line(x1, y2, x2, y2, color);
    glcd_line(x1, y1, x1, y2, color);
    glcd_line(x2, y1, x2, y2, color);

  }
}
//*********************************************************
void glcd_circle(int x, int y, int radius, int1 fill, int1 color)
{
  signed int a, b, P;
  a = 0;
  b = radius;
  P = 1 - radius;

  do
  {
    if(fill)
    {
      glcd_line(x-a, y+b, x+a, y+b, color);
   glcd_line(x-a, y-b, x+a, y-b, color);
glcd_line(x-b, y+a, x+b, y+a, color);
   glcd_line(x-b, y-a, x+b, y-a, color);
    }
    else
    {
      glcd_pixel(a+x, b+y, color);
glcd_pixel(b+x, a+y, color);
   glcd_pixel(x-a, b+y, color);
   glcd_pixel(x-b, a+y, color);
   glcd_pixel(b+x, y-a, color);
   glcd_pixel(a+x, y-b, color);
   glcd_pixel(x-a, y-b, color);
   glcd_pixel(x-b, y-a, color);

    }

    if(P < 0)
      P+= 3 + 2*a++;
    else
      P+= 5 + 2*(a++ - b--);
  } while(a <= b);
}
//*********************************************************
#use fast_io(D)
void main() {
int i;
  set_tris_a(0);set_tris_b(0);set_tris_c(0);
set_tris_d(0);set_tris_e(0);
    set_tris_c(0x00);  // graphic lcd control lines all output
    glcd_init();
    glcd_WriteByte(1, (LCDModeSet|LCDMode_XOR));
    glcd_WriteByte(1, (LCDDispMode|LCDDisp_TXT|LCDDisp_GRH));
while(1)
{
delay_ms(100);
/*for (n = 0; n< 8; n++) {
    glcd_gotoxy(2,43+n,0);  // 0 = graphics memory area;  note that there
   // are still 30 columns (30 x 8 pixels = 240), but now there are now 64
   // rows so pixel location 9,43 translates into column 2, row 43.  A little
   // confusing, I know, but that's the way it works.
    glcd_WriteCmd1(0xFF,0xc0);
}  */
//glcd_gotoxy(1,1,0);
//SetPixel(50,50,1);
glcd_pixel(1,1,1);

delay_ms(1000);
glcd_rect(20, 20, 40, 40, 1, 1);
delay_ms(1000);
glcd_circle(70, 70, 20, 1,1);
glcd_gotoxy(1,2,1); // 1 = text area of memory; note that there are only
                             // 8 rows of text possible
glcd_putc("123456789abcdefg");
}
delay_ms(1000);
glcd_gotoxy(1,1,0);


}


Text mit glcd_putc, ein Pixel setzen mit glcd_pixel.
Allerdings benutzt die glcd_pixel Funktion die fmod() Funktion aus der math.h. Das ist sehr Speicherintensiv. Kann man das anders machen? Weder die Funktion SetPixel oder LCDText von Holger Klabunde funktionieren. Vielleicht könnte sich diese mal jemand anschauen.
Problem ist auch die Geschwindigkeit. Das obere Beispiel habe ich bei 4Mhz ohne Probleme getestet. So mit 20Mhz funktioniert es nicht. Manche Pixel sind dann einfach nicht an der richtigen Stelle

Gruß
Malte
Gespeichert
maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« Antworten #6 am: August 14, 2005, 11:08:40 »

Hallo,

dieses fmod(). Ist das nicht das gleiche wie %(modulo). Wenn ja, warum wird das Speicherintensive fmod() verwendet???

Malte
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #7 am: August 14, 2005, 12:02:08 »

Zitat
Hatte versucht mal im CCS Forum ein bisschen Hilfe zu erhalten

Hier erstmal der Link zu dem Thread.

Zitat
Außerdem verwendetder Code aus dem CCS Forum die math.h Libary. Damit schnellt die Größe des Codes von 5% auf 23%

Code:
//Code aus dem CCS Forum
glcd_pixel(int16 x,int16 y, int1 color)
{
int8 r=0,c=0;
c=color;
r=fmod(x,8); // Divisionsrest von zwei float-Zahlen?

Ich sehe überhaupt keinen Sinn darin, den Divisionsrest über die Funktion fmod zu bestimmen. Wie Du schon erwähnt hast, liefert der Modulo Operator ein identisches Ergebnis und spart Speicher und Zeit.
Code:
r = x % 8;

Den Rest könnte man alternativ auch durch
Code:
r = x & 0x07;

ermitteln.

Zitat
Problem ist auch die Geschwindigkeit. Das obere Beispiel habe ich bei 4Mhz ohne Probleme getestet. So mit 20Mhz funktioniert es nicht. Manche Pixel sind dann einfach nicht an der richtigen Stelle

Das deutet auf ein read-modify-write Problem hin oder das Timing ist für den LCD-Controller insgesamt zu schnell. Als erstes würde ich zwischen nacheinanderfolgenden Schreibzugriffen auf einzelne Portpins eines Ports tesweise ein oder zwei "nop" einfügen.


Viele Grüße

Bernd
Gespeichert

maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« Antworten #8 am: August 14, 2005, 18:54:11 »

Hallo,

das mit den 20Mhz scheint nicht zu funktionieren. Habe eine Funktion erstellt mit bis zu 10 nops und diese hinter jede Pinänderung gehängt - ohne Erfolg. Kann es sein, das diese nops wegoptimiert werden?
Mit einem delay_ms(1); wird nur noch Mist angezeigt(ganz abgesehen von der Geschwindigkeit).


Nächstes. Wie kann ich bei CCS ein riesen Array verarbeiten. C18 kennt dieses:
Code:
extern const rom unsigned char f8x8a[256][8];

Einfach
Code:
char f8x8a[256][8]
akzeptiert CCS nicht(Subscript out of range). Dieses Array soll für einen anderen Schriftfont dienen.

Problem 3. Die LCDTEXT Funktion mit dem pointer.
Code:
void LCDText( char *txt, int16 xpos, int16 ypos)
{
int ps;
strcpy(txt, "txt");
 
glcd_WriteCMD2(xpos+(8)*ypos,0x24);

  while(ps = txt) //Solange Zeichen größer 0x00
  {
    txt++;
    if (ps== 0) break;
    ps=ConvertText(ps); //Übersetzungstabelle aufrufen
    glcd_WriteCMD1(ps,0xC0); //Write ps, Auto Inkrement
  }
}
//*********************************************************
char ConvertText(char ch)
{
unsigned char tmp;
tmp=ch;
switch(ch)
  {
    case 196: tmp=0x6E; break; // Ä
    case 228: tmp=0x64; break; // ä
  case 214: tmp=0x79; break; // Ö
  case 246: tmp=0x74; break; // ö
  case 220: tmp=0x7A; break; // Ü
  case 252: tmp=0x61; break; // ü
  case 223: tmp=223; break; // ß
  default: tmp-=0x20; break;
  }
return tmp;
}
aufgerufen durch"LCDText("Hallo Welt",5,1)" ergibt "Bad expression syntax"
Habe zwar eine andere Funktion
Code:

void glcd_putc(char c)
{
    glcd_WriteCmd1(c - 0x20, 0xc0);
{
würde aber gerne die LCDText verwenden. muss man hier mit strncpy() arbeiten?

Letztens. Hatte zuerst in MPLAB mein gesamtes Beispiel unter den Dateine T6963C.c+.h Nun habe ich das ganze aufgeteilt in Draw - Funtkion, T6963.c(Grundfunktionen) T6963.h(Konstanten+ PIC Einstellungen) und schließlich einer main.c. Nur findet MPLAB nun die main() nicht mehr. Ich muss also manuell auf main.c gehen und compilieren. Damit ist eine Simulation nicht mehr möglich. Wo sucht den MPLAB zuerst nach der main() ?
Diese in .c und.h aufteilerei ist mir sowieso unverständlich. Was muß ich in der main.c alles per include einfassen. Ich schaffe es meist das ich mehrere hundert Fehlermeldungen bekomme, weil wieder eine Datei doppelt einbezogen worden ist(also duplicate #define... oder #device is needed)
Wie geht man da vor(bisher hatte ich es immer mit einer main.c und .h zu tun)
Gibt es da eine schöne Übersicht.

Gruß
Malte
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #9 am: August 14, 2005, 20:01:11 »

Zitat
Habe eine Funktion erstellt mit bis zu 10 nops und diese hinter jede Pinänderung gehängt - ohne Erfolg. Kann es sein, das diese nops wegoptimiert werden?

Meines Wissens werden eingefügte NOPs nicht wegoptimiert. Schau mal im Assemblerlisting nach, ob es doch der Fall ist. Da es mit 4MHz funktioniert und mit 20MHz nicht, ist es in jedem Fall ein Timing-Problem. Dies kann nicht nur das Verändern der Steuersignale betreffen, sondern auch die Zeiträume vor und nach dem Anlegen der 8-Bit Daten bzw. dem Auslesen dieser Daten.
 
Zitat
Einfach
Code:
char f8x8a[256][8]

akzeptiert CCS nicht(Subscript out of range). Dieses Array soll für einen anderen Schriftfont dienen.

Das ist ein Array im RAM. Versuche mal ein Array im ROM:
Code:
const char f8x8a[256][8]

Wenn das auch nicht funktioniert, könntest Du das Array aufteilen, z.B.
Code:
const char f8x8a_1[128][8];
const char f8x8a_2[128][8];


Zitat
Problem 3. Die LCDTEXT Funktion mit dem pointer.

Code:
char string[20];           // Speicher für String im RAM

strcpy (string, "Test");   // String vom ROM ins RAM kopieren
LCDText (string, 1, 2,);   // Aufruf der Funktion mit Zeiger auf den String im RAM

void LCDText( char *txt, int16 xpos, int16 ypos)
   {
      int ps;            
      glcd_WriteCMD2(xpos+(8)*ypos,0x24);

       while(ps = *txt)     // Nicht der Zeiger (also die Adresse), sondern der dereferenzierte Zeiger
                            // (also der Inhalt der Adresse, auf die der Zeiger zeigt)
          {
               txt++;
               if (ps== 0) break;
               ps=ConvertText(ps); //Übersetzungstabelle aufrufen
               glcd_WriteCMD1(ps,0xC0); //Write ps, Auto Inkrement
           }
   }


Zitat
Hatte zuerst in MPLAB mein gesamtes Beispiel unter den Dateine T6963C.c+.h Nun habe ich das ganze aufgeteilt in Draw - Funtkion, T6963.c(Grundfunktionen) T6963.h(Konstanten+ PIC Einstellungen) und schließlich einer main.c. Nur findet MPLAB nun die main() nicht mehr. Ich muss also manuell auf main.c gehen und compilieren. Damit ist eine Simulation nicht mehr möglich. Wo sucht den MPLAB zuerst nach der main() ?

Weniger ein Problem von MPLAB als vom CCS-Compiler. Der CCS-Compiler besitzt keinen "richtigen" Linker, d.h. er kann grundsätzlich nur eine Quelldatei verarbeiten. MPLAB geht von einem Compiler mit Linker aus, und versucht, die einzelnen .c-Dateien, die im Projekt enthalten sind, dem Compiler zur Übersetzung zuzuführen. Da das mit dem CCS nicht möglich ist, kommt die Fehlermeldung des Compilers. Auch wenn Du mehrere .c-Dateien verwendenden willst, darf im Projekt selbst nur die Datei enthalten sein, die main() enthält. Alle anderen Quelldateien müssen in diese .c-Datei über "include" eingebunden werden.

Doppelte "defines" kann man durch einen "Blocker" in .h-Dateien einfach vermeiden:
Code:
// test.h
#ifndef __testh
#define __testh

#define ...
...

#endif


Beim CCS ist es wichtig, die Header-Datei des PICs als erstes in das Hauptprogramm (enthält main) einzufügen und erst danach die anderen Dateien. Die Header-Datei des PICs darf außerdem nur im Hauptprogramm eingebunden werden.
Code:
#include <18F458.h>
#use delay ...
#include ...

Du solltest beachten, daß "include" nichts anderes ist als ein Textersatz, d.h. die eingebundene Datei wird an exaxt dieser Position in den Quellcode eingefügt. Der CCS-Compiler übersetzt nur eine einzige .c-Datei (die im MPLAB-Projekt enthalten sein muß).


Viele Grüße

Bernd
Gespeichert

maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« Antworten #10 am: August 15, 2005, 18:59:52 »

Hallo Bernd,

die Arrays funktionieren so. Auch die LCDText Funktion geht nun.

Das mit MPLAB finde ich zwar nicht so toll, werde wohl aber damit leben müssen

Das Problem mit den 20Mhz besteht immer noch. Habe anbei aus dem Datenblatt das "Signal Timing".

Was ist eine Set Up Time? Hold Time - OK(10ns min. halten), aber Setup Time?
Und dann gibt es noch Zeiten mit minimaler und maximaler Zeit.

z.B. hier in meiner glcd_WriteByte Funktion. Hatte mal versucht hinter jede Änderung ein Wait einzufügen(diese habe ich dann verändert von 2 nops bis zu delay_ns(20)). Nach der Methoder - viel hilft viel. war dann leider nicht so.

Und ganz wichtig(wahrscheinlich wieder was ganz einfaches). Mein 18F452 stürzt ab. Der 16F877a läuft perfekt mit den Testanwendungen. Ändere ich aber den Prozessor und die Register so stürzt er unregelmäßig ab. Es kann sein das mein PIC 20 durchläufe übersteht, aber auch das der PIC(oder besser gesagt das Display)  nicht mal die erste schleife übersteht bevor er neu startet. Der WDT ist doch standardmäßig ausgeschaltet?


Code:
void glcd_WriteByte(int1 cd, int data)
{
    int status = 0, temp = 0;
    set_tris_lcd(0xff);
    LCD.w_bar = 1; Wait();
LCD.r_bar= 1; Wait();
    LCD.cd = 1; Wait();
    while (status != 0x03)
{  // is LCD busy?
        LCD.r_bar= 0; Wait();
        temp = LCD.data;
        LCD.r_bar = 1; Wait();
        status = temp & 0x03;
    }
    set_tris_lcd(0x00);    
    LCD.cd = cd; //Wait();        
    LCD.data = data;
    LCD.r_bar = 1; Wait();        
    LCD.w_bar = 0;Wait();        
    LCD.w_bar = 1;Wait();
}

* 120241.pdf (31.59 KB - runtergeladen 167 Mal.)
Gespeichert
maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« Antworten #11 am: August 16, 2005, 13:07:23 »

Hallo,

und noch was. Kann nun verschieden Schriftarten auf dem Display darstellen Aber jeweils nur einen Font. Das möchte ich ändern.

Habe mehrere .h Dateien mit den entsprechenden Fonts erstellt. Dieses möchte ich nun auswählen können.
Die Fonts liegen als Array vor, z.B. F8x8a[127][8]
Meine Routine die das ganze aufs Display bringt arbeitet mit dem Variablennamen Text. Warum kann ich folgendes nicht schreiben:
Code:
void SelectFont(int num)
{
{
  switch(num)
  {
   
    case 2: fontwidth=8; fontheight=8; TEXT=F8x8a; break; //f8x8a
    case 3:
    default: fontwidth=0; fontheight=0; font=0; break;
  }
}

}



Und noch eine Hardware Frage. Habe hier ein gebrauchtes u-blox ms1e GPS Modul herumliegen. Möchte das mal per PIC auslesen. Dieses Modul will VDD von 3,3V. Der serielle Ausgang ist dementsprechend auch 3,3V. Später soll daran ein GLCD angeschlossen werden. Auch sollte man das ganze per Batterie betreiben können.

Was ist nun sinnvoller: Normalen 5V PIC samt einem 5V GLCD(die wo die neg. Kontrastspannung onboard bereitgestellt wie -> z.B. Electronic Assembly). Die RX Ausgänge direkt an den PIC(sollte ja schon bei 3,3V das als 1 erkennen - oder besser level shifter, und TX Eingänge des GPS Moduls mittels Spannungsteiler an den PIC.

Oder: 3,3V PIC direkt an GPS Modul. Nur wie mache ich das dann mit dem GLCD. Gibt es die auch für 3,3V

Auch möchte ich einfach mal das Modul am PC benutzen können. Gibt es auch die MAXxxx für diesen Spannungbereich?

Gruß
Malte
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #12 am: August 16, 2005, 17:07:27 »

Zu Deinem ersten Post:

Zitat
Was ist eine Set Up Time? Hold Time - OK(10ns min. halten), aber Setup Time?

Die Set Up Time ist die Zeit, die ein Signal stabil anliegen muß, bevor andere Signale verändert werden dürfen.

Beispiel t_DS: Die Daten an D0 bis D7 müssen schon mindestens 80ns angelegen haben, bevor CE und WR wieder von Low auf High gehen dürfen.

Zitat
Und dann gibt es noch Zeiten mit minimaler und maximaler Zeit.

Die maximale Zeit wird dort angegeben, wo sie entscheidend ist. Beim Auslesen (read) von D0 bis D7 dauert ist höchstens (maximal) 150ns, bis das LCD diese an den Bus legt. Um ein gültiges Ergebnis auszulesen, muß man also mindestens diese Zeit warten, bevor man die Daten ausliest. Gleiches gilt für die Output Hold Time.

Zitat
Der WDT ist doch standardmäßig ausgeschaltet?

Die Standardeinstellung (unprogrammiert) ist WDT an, d.h. in den Fuses muß NOWDT explizit angegeben werden. Das SWDTEN-Bit im WDTCON Register ist nach dem POR "0", der WDT also ausgeschaltet, wenn bei den Fuses NOWDT vorhanden ist. Da Du im Code bei den Fuses sowohl den WDT als auch LVP ausschaltest, würde ich beides als Absturzgrund ausschließen. Kurz gesagt, ich weiß auch nicht, woran es liegt.


Viele Grüße

Bernd
Gespeichert

Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #13 am: August 16, 2005, 18:02:17 »

Zum zweiten Post:

Zitat
Warum kann ich folgendes nicht schreiben:
Code:
TEXT=F8x8a;

Das ist das leidige Problem, daß CCS keine Zeiger auf Konstanten unterstützt. Normalerweise wäre es vollkommen zulässig, folgendes zu schreiben:
Code:
const char F8x8a[127][8];
const char *font_ptr;

font_ptr = &F8x8a[0][0]; font_ptr zeigt auf das erste Element von F8x8a

Durch den Zeiger verlierst Du aber den zweidimensionalen Charakter des Arrays, d.h. den Array Index müßtest Du dann "von Hand" berechnen:
Code:
x = *font_ptr;       // Zugriff auf [0][0]
x = *(font_ptr+7);   // Zugriff auf [0][7]
x = *(font_ptr+8);   // Zugriff auf [1][0]
                     // usw.

Wie man das geschickt ohne Zeiger auf Konstanten hinbekommen kann, weiß ich nicht.
 
Zitat
Die RX Ausgänge direkt an den PIC(sollte ja schon bei 3,3V das als 1 erkennen - oder besser level shifter

Bei 5V ist auf jeden Fall der Level-Shifter nötig. RX ist ein Schmitt-Trigger Eingang, d.h. für eine "1" sind mindestens 0,8*VDD, also 4V nötig. Spannungsteiler in die andere Richtung ist ok, wenn die Übertragungsrate nicht zu hoch ist.

Zitat
Oder: 3,3V PIC direkt an GPS Modul. Nur wie mache ich das dann mit dem GLCD. Gibt es die auch für 3,3V

Es gibt auch GLCDs für 3,3V. Wenn Du einfach an ein solches kommen kannst, würde ich dann komplett mit 3,3V arbeiten (-->LF-PIC). Ansonsten ist ein Level-Shifter und ein Spannungsteiler zusätzlich eigentlich kein allzugroßer Aufwand.

Zitat
Auch möchte ich einfach mal das Modul am PC benutzen können. Gibt es auch die MAXxxx für diesen Spannungbereich?

Ja, ungefähr 72 :yawinkle: .


Viele Grüße

Bernd
Gespeichert

maltejahn
Sr. Member
****
Offline Offline

Beiträge: 309



Profil anzeigen
« Antworten #14 am: August 16, 2005, 19:19:24 »

Hallo Bernd,

werde dann mal mehrere Zeitfunktionen erstellen und dann mal das Programm ändern.

Zitat
Das ist das leidige Problem, daß CCS keine Zeiger auf Konstanten unterstützt.

Und ich leider mit Pointer nichts anfangen kann. Dann erstelle ich mir für jeden Font eine neue Funktion(LCDSoftText_F8x8a()).

Wie ich das mit dem Aufbau mache muss ich mir noch überlegen. Wird wohl auf eine 5V Variante herauslaufen. RS und Farnell haben sowas scheinbar nicht. Ich frage mal bei Electronic Assembly an. Ich schau auch mal ob bei den 72 einer für mich dabei ist.

Eine ganz, ganz einfache Frage zum Schluß. Habe es nun hinbekommen das mir ein Bitmap ausgegeben wird. Nur leider mit einem Haken. Es sieht so aus, als ob nach der Hälfte des Bitmaps alles von vorne beginnt. Geht da eine Variable aus Ihrem Bereich? Habe das Bitmap als Array
Code:
int testbildbmp[512]=
{
0xFF,0x00,0xFF,0x00,0xFF,0x00,0x00,0xFF,

das war die erste Zeile..64x64 Pixel = 8x8 Byte

und der Code
Code:
void LoadBitmap(char *bitmap,int xpos , int ypos, int width, int height)
{
int bytewidth,byteheight;
int zeile,spalte,i;
int16 wert;
bytewidth=testbildWIDTH/testbildBYTEWIDTH;//=8 bei 64 bits
byteheight=testbildHEIGHT/testbildBYTEWIDTH;//=8 bei 64 bits
for(zeile=0;zeile<height;zeile++)
{
for(spalte=0; spalte<bytewidth;spalte++)
{
for(i=0; i<testbildBYTEWIDTH;i++)
{
if(bit_test(testbildbmp[zeile*8+spalte], i))

{
wert=spalte*8+i;
SetPixel(wert ,zeile , 1);
}
}
}
}
}
. Ich gehe in der ersten Splte von links nach rechts und lese den jeweiligen Byte des BMP ein. Dieses Byte wird mit bit_test untersucht und für jedes Bit wird die entscheidung getroffen ob ein Pixel gesetzt wird oder nicht. Und das ganze über die Anzahl der Zeilen.
Hatte auch schon eine Zwischenrechnung eingeführt(int16 wert). Auch hatte ich das Bitmap an sich verändert(int16 testbildbmp).
Oder gibt es eine Beschränkung der maximal möglichen Arrayelemente?(also wieder mit bmp1[127], bmp2[127] arbeiten?)

Gruß
Malte
Gespeichert
Seiten: [1] 2 3 Nach oben Drucken 
« vorheriges nächstes »
Gehe zu:  

Powered by MySQL Powered by PHP Made for Mozilla (Firefox) Made for Internet Explorer
Seite erstellt in 0.071 Sekunden mit 19 Zugriffen.
 
Top! Top!