Torello
Joined: 29 Sep 2006 Posts: 120
|
Rich featured graphic LCD driver PG12864 |
Posted: Sun Oct 07, 2012 10:31 am |
|
|
This post contains code for the Powertip PG12864 graphic LCD screen. It uses the Serial interface.
This code is pretty compact with a lot of graphic features:
- Fixed and variable font use
- Single, double and quadrupple height
- Single and double width
- Toplined, bottomlined
- Boxed
- Inverted
- Any sensible combination of the above
It makes use of just 1 font array. This is a 7*5 font.
The buildup of this font is "byte-vertically". This buildup makes al the graphic features possible.
Indeed, the LCD buildup is byte-horizontally. Thus the code rotates each 8*8 pixels before writing.
An advantage of this mechanism is that although the screen is adressed byte columns (thus addres 0-16) now it is also possible to start text a each of the 0-127 pixels!
A limitation is printing text too close to the previous text on the same line. The new text must fall in a new column, otherwise some pixels of the previous text will be cleared.
I think this code is easy adaptable for other LCD drivers.
Have Fun!
Example program:
Code: |
/******************************************************************************/
/* program : Pg12864
/* module :
/* file : PgSerTest.c
/******************************************************************************/
#include <18F6722.H>
#FUSES NOWDT,INTRC_IO, NOPUT, NOLVP, Nobrownout
#use Delay(Clock=32Mhz)
//--- IO assignment for LCD PG12864 --------------------------------------------
#use fast_io(D)
#byte PortD=0xF83
#bit RS = portD.1
#bit CS = portD.2
#bit CLK = portD.0
#bit SD = portD.3
#bit RST = portD.4
//--- Add modules headers ------------------------------------------------------
#include "Pg_Ser.h"
#include "font_eb.h"
//--- Add module code ----------------------------------------------------------
#include "Pg_Ser.c"
//##############################################################################
// MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN
//##############################################################################
void main() {
char item0[30]="Hello!";
char item1[30]="A rather long line this is.";
char item2[32]="Boxed";
char item3[30]="Hi!";
char item4[30]="Hi-di-ho!";
setup_oscillator(OSC_32MHZ );
Set_tris_d(0x00); // data: graphic lcd control lines all output
glcd_Init();
glcd_DispClr();
glcd_printf(0,0,item0, gVar+gH4+gW2);
glcd_printf(0,75,item3,gVar+gH2+gW2+gBox);
glcd_printf(17,75,item4,gVar+gH2+gInvert);
glcd_printf(32,5,item1,gVar);
glcd_printf(40,5,item1,gFix);
glcd_printf(48,5,item2,gVar+gBox+gH2);
glcd_printf(48,43,item2,gVar+gBox+gW2);
glcd_printf(56,43,item2,gVar+gBox);
while (1) {};
}
|
module PG_ser.h
Code: |
//--- Global Function definitions ----------------------------------------------
void glcd_WriteData(int8 data);
void glcd_WriteCmd(int8 data);
void glcd_Init();
void glcd_printf(int8 row, int8 col, char *cstring, int8 mode);
void glcd_SetRowCol(int8 row, int8 col);
void glcd_DispClr();
#define nop(x) delay_cycles(x);
#define gFix 0 //fixed font
#define gVar 0x01 //variable font
#define gH2 0x02 //2x font height
#define gH4 0x04 //4x font heigt
#define gW2 0x08 //2x font weight
#define gInvert 0x10 //invert font
#define gTL 0x20 //Topline (merges with top pix of font)
#define gBL 0x40 //BottomLine H1: touches font H2&H4: free underline
#define gBox 0x80 //Box
Typedef struct { // This structure typedef can be used for easy acces
int1 var; //var=1, fix=0; (bit0)
int1 h2; //2x font height
int1 h4; //4x font heigt
int1 w2; //2x font weight
int1 inv; //invert font
int1 tl; //TopLine
int1 bl; //BottomLine
int1 box; //boxing
} gbf; //"graphic bitfield"
//specific bittest macro for function glcd_printf()
#define dBT(x) (((gbf)mode).x)
typedef struct{
int1 b0,b1,b2,b3,b4,b5,b6,b7;
} BitField8;
typedef union {
BitField8 bit;
int8 All;
} BitUnion8;
|
module Pg_ser.c
Code: |
void glcd_WriteData(int8 data) {
int8 i;
CS=0; // chip enable
RS=0; // select RAM data write
for (i=0; i<8; i++) {
CLK = 0;
SD = 0; if (bit_test(data,7)) SD=1; //fastest compiled bit copy
data<<=1; //shift left D0->1.. D6->7
CLK = 1;
}
CLK=0;
CS=1; // chip disable
}
void glcd_WriteCmd(int8 data) {
int8 i;
CS=0; // chip enable
RS=1; // select REGISTER write
for (i=0; i<8; i++) {
CLK = 0;
SD=0; if (bit_test(data,7)) SD=1; //Out D7
data<<=1; //shift left D0->1.. D6->7
CLK = 1;
}
CLK=0;
CS=1; // chip disable
}
void glcd_Init() {
CS=1; RST=0; CLK=0; SD=0; RS=0; // init IO levels, screen in hardware reset
delay_ms(10);
RST=1; // release reset
delay_ms(10); // startup display??
glcd_WriteCmd(0xB1); // Power Control reg1: ALC initialization on
delay_ms(10);
glcd_WriteCmd(0xB2); // Power Control reg1: Pon, ALC off
delay_ms(1);
glcd_WriteCmd(0x89); // Display control register, Shift=1, display ON
delay_ms(1);
glcd_WriteCmd(0xDC); // Power Control reg2: drive voltage some about "have to set this"
delay_ms(1);
glcd_WriteCmd(0xA2); // auto increment Y ONLY
delay_ms(1);
glcd_WriteCmd(0x92); // Swap=1="normal" mode
delay_ms(1);
glcd_WriteCmd(0x40); // set the Startline(=0) Low nibble
glcd_WriteCmd(0x50); // set the Startline(=0) Hi nibble
}
void glcd_DispClr() {
int16 i;
glcd_WriteCmd(0xA3); // auto increment XY cooperative
delay_ms(1);
glcd_WriteCmd(0x00); // row=0
glcd_WriteCmd(0x20); // column=0
glcd_WriteCmd(0x30);
for(i=0; i<1024; i++) { // 16 bytes per line 64 lines
glcd_WriteData(0); // write empty byte
}
glcd_WriteCmd(0xA2); // auto increment Y only
delay_ms(1);
}
void glcd_SetRowCol(int8 row, int8 col) { // Col=0..15, Row=0..63
int8 rw;
glcd_WriteCmd(col&0x0F); // set the X adr=0 (0-15)
rw=(row&0x0F)+ 0x20; // concat command to Ynibble low
glcd_WriteCmd(rw); // set the Yadr low nibble (0-63)
rw=(swap(row)&0x0F)+0x30; // concat command to Ynibble high
glcd_WriteCmd(rw); // set the Yadr hi nibble (0-63)
}
void glcd_printf(int8 row, int8 col, char *cstring, int8 mode) {
int8 cl,c,i,j; // col counter
int8 si; // string index
int8 bi; // font byte index
int8 fi; // font array index
int8 ri; // ri rotatie index
BitUnion8 rf[8]; // rotated font buffer
int8 BoxSm; // box State machine 0=no box
int8 W2Sm; // width2 state machine
int8 Lmax; // number of lines in casde of magnify
Lmax=1; //H1 line
if ( dBT(h2) ) Lmax=2; //H2 line
if ( dBT(h4) ) Lmax=4; //H4 line
for(i=0; i<Lmax; i++) { // line loop
rf[0]=rf[1]=rf[2]=rf[3]=0; // new line: clear rotated font buffer
rf[4]=rf[5]=rf[6]=rf[7]=0;
cl=col>>3; // load current col with start colum
ri=1;
for (j=col&0x7; j<7; j++) ri<<=1; // calc ri from col.b2-b0 (000:ri=128, 111:ri=1)
si=0; // clear string index
bi=0; // clear font byte line index
fi=0; // clear from 255;
w2Sm=0; // clear width state machine
boxSm=0; if dBT(box) BoxSm=1; // arm box statemachine
if dBT(inv) BoxSm=1; // invert mode add 1 vertical black line (more readable)
do {
if dBT(w2) W2Sm=2; // arm width2 statemachine
if (!bi) {
if (BoxSm==1) {
BoxSm=2; // advance state machine "print chars"
if dBT(inv) BoxSm=3; // invert mode add 1 vertical black line then stop BoxSM.
si--; // need to correct the bi==5 increment.
bi=5; // force next line to be a space line
c=0xFF; // load the vertical line
goto pf_next_bx; // skip font[]{bi] reading stuff
} else {
fi = cstring[si]; // get string character
if (fi==0) { // string end read. But:
if (BoxSm==2) {
BoxSm=3; // advance state machine
c=0xFF; // load the vertical line
goto pf_next_bx; // skip font[]{bi] reading stuff
} else {
fi=255; // load sting end value need to exit while
if (ri) goto pf_next1; // ri<>0 thus still need to print 'left over' set
goto pf_next2; // ri==0 thus we are done for this line
}
}
fi-=32; // substract font array offset
}
}
if (bi<5) { // still reading font
c = font5x7[fi][bi]; // read font data
bi++;
if (c==0x99) { // T: font end marker detected
c=0; // replace with empty
if dBT(var) { // var font requested..
bi=0; si++; // so 0x99 ends character
}
}
} else {
c=0; // bi=5 always a space line
bi=0; si++; // clear byte line index and increase character index.
}
pf_next_bx:
if dBT(h2) { // T: double magnefy character
if (i) swap(c); // line2; need upper nible as magnefy index
c&=0x0F; // get rid of unwanted nibble
c = mgnfy2[c]; // get the magnefied font byte
}
if dBT(h4) { // T: quadruplle magnefy character
if (i&0x2) swap(c); // line2 or 3; need upper nible as magnefy index
if (i&0x1) c>>=2; // need b3&2 on spot b1&0
c&=0x03; // get rid of unwanted bits
c = mgnfy4[c]; // get the magnefied font byte
}
//===== linestuf
//Toplines:
if (i==0) {
if dBT(box) c|=0x01; // add boxing topline
if dBT(tl) c|=0x01; // add just topline
if (!dBT(h2) && !dBT(h4) ) { // T: Height -SINGLE-
if dBT(box) c|=0x80; // add boxing botline
if dBT(bl) c|=0x80; // add touching botline
}
}
if ((i==1) && dBT(h2)) { // last line Height -DOUBLE-
if dBT(box) c|=0x80; // add boxing botline (free botline)
if dbt(bl) c|=0x80; // add free botline
}
if ((i==3) && dBT(h4)) { // last line Height -QUADRO-
if (c==0xFF) c=0x3F; // correct left right vertical boxing line for i==3
if dBT(box) c|=0x20; // add boxing botline
if dBT(bl) c|=0x20; // add free botline
if dBT(inv) c|=0xC0; // correct inversion to come
}
pf_next3:
if dBT(inv) c=~c; // T: invert font.
do {
if (c&1) rf[0].all += ri; //if c.b0==1 then rf[0]+=ri //font rotation
if (c&2) rf[1].all += ri; //if c.b1==1 then rf[1]+=ri
if (c&4) rf[2].all += ri; //if c.b2==1 then rf[2]+=ri
if (c&8) rf[3].all += ri; //if c.b3==1 then rf[3]+=ri
if (c&16) rf[4].all += ri; //if c.b4==1 then rf[4]+=ri
if (c&32) rf[5].all += ri; //if c.b5==1 then rf[5]+=ri
if (c&64) rf[6].all += ri; //if c.b6==1 then rf[6]+=ri
if (c&128) rf[7].all += ri; //if c.b7==1 then rf[7]+=ri
ri>>=1; //shift the single bit mask
if (!ri) { //rotated byte ready
pf_next1:
glcd_SetRowCol(row,cl++); //set printing adress and increase cl.
glcd_WriteData(rf[0].all); //8 separate calls compiles
glcd_WriteData(rf[1].all); //shorter than putting
glcd_WriteData(rf[2].all); //it in an for-loop
glcd_WriteData(rf[3].all);
glcd_WriteData(rf[4].all);
glcd_WriteData(rf[5].all);
glcd_WriteData(rf[6].all);
glcd_WriteData(rf[7].all);
rf[0]=rf[1]=rf[2]=rf[3]=0; // clear rotated font buffer
rf[4]=rf[5]=rf[6]=rf[7]=0;
ri=128;
}
if (w2Sm) w2Sm--; //countdown w2 state machine
} while (w2Sm>0);
} while( (cl<16) && (fi!=255)); // until colum 16 is written or end sign set
pf_next2:
row+=8; // next line
}
} |
module font_eb.h
Code: |
// Font below is called 5*7. Buildup each byte -vertically printed left to right
// It is adapted to be used fixed (5+1 space) size and as variable font
// special codes:
// - 0x99 = variable font end code
// when printed as fixed font, code is replaced by '0x00'
int8 const Mgnfy2[16] = {0x00,0x03,0x0C,0x0F,0x30,0x33,0x3C,0x3F,
0xC0,0xC3,0xCC,0xCF,0xF0,0xF3,0xFC,0xFF};
int8 const Mgnfy4[4] = {0x00,0x0F,0xF0,0xFF};
int8 const Font5x7[97][5] =
{0x00, 0x00, 0x99, 0x99, 0x99, // SPACE
0x00, 0x5F, 0x99, 0x99, 0x99, // !
0x00, 0x03, 0x00, 0x03, 0x99, // "
0x14, 0x3E, 0x14, 0x3E, 0x14, // #
0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
0x43, 0x33, 0x08, 0x66, 0x61, // %
0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x05, 0x03, 0x99, 0x99, // '
0x00, 0x1C, 0x22, 0x41, 0x99, // (
0x00, 0x41, 0x22, 0x1C, 0x99, // )
0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x50, 0x30, 0x99, 0x99, // ,
0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x60, 0x60, 0x99, 0x99, // .
0x20, 0x10, 0x08, 0x04, 0x02, // /
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x04, 0x02, 0x7F, 0x99, // 1
0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x22, 0x41, 0x49, 0x49, 0x36, // 3
0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x3E, 0x49, 0x49, 0x49, 0x32, // 6
0x01, 0x01, 0x71, 0x09, 0x07, // 7
0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x26, 0x49, 0x49, 0x49, 0x3E, // 9
0x00, 0x36, 0x36, 0x99, 0x99, // :
0x00, 0x56, 0x36, 0x99, 0x99, // ;
0x08, 0x14, 0x22, 0x41, 0x99, // <
0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x41, 0x22, 0x14, 0x08, // >
0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x3E, 0x41, 0x59, 0x55, 0x5E, // @
0x7E, 0x09, 0x09, 0x09, 0x7E, // A
0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x7F, 0x41, 0x41, 0x41, 0x3E, // D
0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x3E, 0x41, 0x41, 0x49, 0x3A, // G
0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x41, 0x7F, 0x41, 0x99, // I
0x30, 0x40, 0x40, 0x40, 0x3F, // J
0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x7F, 0x02, 0x04, 0x08, 0x7F, // N
0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x1E, 0x21, 0x21, 0x21, 0x5E, // Q
0x7F, 0x09, 0x09, 0x09, 0x76, // R
0x26, 0x49, 0x49, 0x49, 0x32, // S
0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x7F, 0x20, 0x10, 0x20, 0x7F, // W
0x41, 0x22, 0x1C, 0x22, 0x41, // X
0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x61, 0x51, 0x49, 0x45, 0x43, // Z
0x00, 0x7F, 0x41, 0x99, 0x99, // [
0x02, 0x04, 0x08, 0x10, 0x20, // \
0x00, 0x41, 0x7F, 0x99, 0x99, // ]
0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x01, 0x02, 0x04, 0x99, // `
0x20, 0x54, 0x54, 0x54, 0x78, // a
0x7F, 0x44, 0x44, 0x44, 0x38, // b
0x38, 0x44, 0x44, 0x44, 0x44, // c
0x38, 0x44, 0x44, 0x44, 0x7F, // d
0x38, 0x54, 0x54, 0x54, 0x18, // e
0x04, 0x04, 0x7E, 0x05, 0x05, // f
0x08, 0x54, 0x54, 0x54, 0x3C, // g
0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x44, 0x7D, 0x40, 0x99, // i
0x20, 0x40, 0x44, 0x3D, 0x99, // j
0x7F, 0x10, 0x28, 0x44, 0x99, // k
0x00, 0x41, 0x7F, 0x40, 0x99, // l
0x7C, 0x04, 0x78, 0x04, 0x78, // m
0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x38, 0x44, 0x44, 0x44, 0x38, // o
0x7C, 0x14, 0x14, 0x14, 0x08, // p
0x08, 0x14, 0x14, 0x14, 0x7C, // q
0x00, 0x7C, 0x08, 0x04, 0x04, // r
0x48, 0x54, 0x54, 0x54, 0x20, // s
0x04, 0x04, 0x3F, 0x44, 0x44, // t
0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x1C, 0x20, 0x40, 0x20, 0x1C, // v
0x3C, 0x40, 0x30, 0x40, 0x3C, // w
0x44, 0x28, 0x10, 0x28, 0x44, // x
0x0C, 0x50, 0x50, 0x50, 0x3C, // y
0x44, 0x64, 0x54, 0x4C, 0x44, // z
0x00, 0x08, 0x36, 0x41, 0x41, // {
0x00, 0x7F, 0x00, 0x99, 0x99, // |
0x41, 0x41, 0x36, 0x08, 0x99, // }
0x02, 0x01, 0x02, 0x04, 0x02 // ~
};
|
_________________ Regards, Edwin. PCWHD v5.114 |
|