Crystalfontz makes serial port and USB programmable LCD displays for your PC. Lots of uses... Monitor resources, core temps, playlists, mail notification, messages, gaming ...
Even bigger, the same type of applications that can print to these devices, can talk to billboards, gas pumps, numerous other devices. It's not as hard as it looks. I started on one twenty years ago, and recently found it on an old backup CD. I've been taking it out and playing with it regularly.
There are a few bumps with these things. For example, some ansi characters didn't display properly. Those are ~ ` $ { } [ ] | \ These nine are reserved control chars built into the ROM and are substituted with random upper-ansi chars. But they were nice enough to give you eight spare character slots on the ROM, you can insert your own into. Yeah... and it's binary... it's either black or backlit.
So lately, after I hard-coded replacements for the replacement, I've been working on alternate sets of characters, I can call on demand - stuffed in a file, called up, displayed, and dumped, if needed. I mean, I have two hundred and fifty-five slots I can, fill 8 at a time.
The basic character array is an declared as : static unsigned char [ ] [8] [8] = ...
________________________________________
using this| shows as| so assign new char
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
` ¿ n/a (not used)
~ Ü '\000'
$ ¤ '\001'
{ ä '\002'
} ñ '\003'
[ Ä '\004'
] Ñ '\005'
| ö '\006'
\ Ö '\007'
________________________________________
static unsigned defaultcustchar [][8][8] =
{
{
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,1,1,0,0,1},
{0,0,1,0,0,1,1,0},// ~
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,1,0,0},
{0,0,0,0,1,1,1,0},// $
{0,0,0,0,1,0,0,0},
{0,0,0,0,0,1,0,0},
{0,0,0,0,0,0,1,0},
{0,0,0,0,1,1,1,0},
{0,0,0,0,0,1,0,0}
},
{
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0},// {
{0,0,0,1,0,0,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,0,1,0,0}
},
{
{0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0},// }
{0,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0},
{0,0,0,1,1,0,0,0},
{0,0,0,1,0,0,0,0},
{0,0,0,1,0,0,0,0},// [
{0,0,0,1,0,0,0,0},
{0,0,0,1,0,0,0,0},
{0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,1,1,0},
{0,0,0,0,0,0,1,0},
{0,0,0,0,0,0,1,0},// ]
{0,0,0,0,0,0,1,0},
{0,0,0,0,0,0,1,0},
{0,0,0,0,0,1,1,0},
{0,0,0,0,0,0,0,0}
},
{
{0,0,0,0,0,0,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0},// |
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0},
{0,0,0,0,1,0,0,0}
},
{
{0,0,0,0,0,0,0,0},
{0,0,1,0,0,0,0,0},
{0,0,0,1,0,0,0,0},
{0,0,0,0,1,0,0,0},// backslash
{0,0,0,0,0,1,0,0},
{0,0,0,0,0,0,1,0},
{0,0,0,0,0,0,0,1},
{0,0,0,0,0,0,0,0}
}
};
I'll assign them to the device with a button click (labeled "Default")
if(bRunning){
unsigned char cData[8];
int i, j;
for (i = 0; i < TOTAL_CUSTS; i++)//fill the array
{
for (j = 0; j < 8; j++)
{
cData[j] = (unsigned char) ((128 * defaultcustchar[i-1][j][0]) +
(64 * defaultcustchar[i][j][1]) + (32 * defaultcustchar[i][j][2]) +
(16 * defaultcustchar[i][j][3]) + (8 * defaultcustchar[i][j][4]) +
(4 * defaultcustchar[i][j][5]) + (2 * defaultcustchar[i][j][6]) +
defaultcustchar[i][j][7]);
}
if (LCD_RESULT_NOERROR != lcdSetCustomChar(i, cData))
{
lcdFree();
}
}
lcdClearDisplay();
lcdSetCursorPos(7,2);//LCD third line gets the first 8 chars
lcdSendCharacter('\000');
lcdSendCharacter('\001');
lcdSendCharacter('\002');
lcdSendCharacter('\003');
lcdSendCharacter('\004');
lcdSendCharacter('\005');
lcdSendCharacter('\006');
lcdSendCharacter('\007');
TestBtn->Enabled = true;
}//end of if(bRunning)
Pretty good likeness.
Okay, so those are hard into the .exe file. What about your artistic nature when you need, bars for graphs, inverse characters, sparkly things, or a battery indicator:
const unsigned char battery[8] =
{
0x0E, // .###. .
0x1F, // ##### .
0x11, // #___# .
0x11, // #___# .
0x1F, // ##### .
0x1F, // ##### .
0x1F, // ##### .
0x1F // ##### cursor row
};
So there's this character generator (dialog) I'm been working on. A matrix of 64 clickable TPanel objects - click=ON, click=OFF ... Each sets one of 64 declared booleans, pixal1-64. They also change color, and a second set of panels sized 2x2 in an "actual size" demo array. I added a TEdit control set with an alphanumeric font to mimic the device - wysiwyg, sort of.
void __fastcall TCharGenerator::Panel18Click(TObject *Sender)
{
//
TPanel *thispanel = (TPanel*)Sender;
if(thispanel->Color == clBlack)
{
thispanel->Color = Edit3->Color;
pixal17 = false;
thispanel->Hint = "|Off";
P18->Color= Edit3->Color;
}
else
{
thispanel->Color = clBlack;
pixal17 = true;
thispanel->Hint = "|On";
P18->Color = clBlack;
}
After the 64 OnClicks....

That monster of a piece I wrote a few days ago has something to do with that grid. You can see the return values in the right hand column. Those numbers are what I save to the disk and call up as needed:
TIniFile *CharsINI = new TIniFile(ExtractFilePath(Application->ExeName)+ "chars.ini");
if(Edit1->Text != "")//Character Name
{
unsigned char custchar[8] = {0,0,0,0,0,0,0,0};//initialize blank char
//read matrix data from panel1
custchar[0] = (unsigned char)GetCharLine(pixal49,pixal50,pixal1,pixal2,pixal3,pixal4,pixal5,pixal6);
custchar[1] = (unsigned char)GetCharLine(pixal51,pixal52,pixal7,pixal8,pixal9,pixal10,pixal11,pixal12);
custchar[2] = (unsigned char)GetCharLine(pixal53,pixal54,pixal13,pixal14,pixal15,pixal16,pixal17,pixal18);
custchar[3] = (unsigned char)GetCharLine(pixal55,pixal56,pixal19,pixal20,pixal21,pixal22,pixal23,pixal24);
custchar[4] = (unsigned char)GetCharLine(pixal57,pixal58,pixal25,pixal26,pixal27,pixal28,pixal29,pixal30);
custchar[5] = (unsigned char)GetCharLine(pixal59,pixal60,pixal31,pixal32,pixal33,pixal34,pixal35,pixal36);
custchar[6] = (unsigned char)GetCharLine(pixal61,pixal62,pixal37,pixal38,pixal39,pixal40,pixal41,pixal42);
custchar[7] = (unsigned char)GetCharLine(pixal63,pixal64,pixal43,pixal44,pixal45,pixal46,pixal47,pixal48);
CharsINI->WriteInteger(Edit1->Text, "line0",custchar[0]);
CharsINI->WriteInteger(Edit1->Text, "line1",custchar[1]);
CharsINI->WriteInteger(Edit1->Text, "line2",custchar[2]);
CharsINI->WriteInteger(Edit1->Text, "line3",custchar[3]);
CharsINI->WriteInteger(Edit1->Text, "line4",custchar[4]);
CharsINI->WriteInteger(Edit1->Text, "line5",custchar[5]);
CharsINI->WriteInteger(Edit1->Text, "line6",custchar[6]);
CharsINI->WriteInteger(Edit1->Text, "line7",custchar[7]);
CharsINI->ReadSections(ListBox1->Items);//reload listbox
Edit1->Text = "";
ListBox1->SetFocus();
Button3->Click();// next slide please
Label10->Caption = IntToStr( custchar[0]);// IntToStr((char)GetCharLine(pixal1,pixal2,pixal3,pixal4,pixal5,pixal6));
}
else
{
ShowMessage("You gotta name it first");
}
AnsiString s;
AnsiString sCustChar;
AnsiString s0,s1,s2,s3,s4,s5,s6,s7;
int iIndex;
iint i0,i1,i2,i3,i4,i5,i6,i7;
int ih0,ih1,ih2,ih3,ih4,ih5,ih6,ih7;
int iline0, iline1, iline2, iline3, iline4, iline5, iline6, iline7;
int iCount = ListBox1->Items->Count;
int iHex = iline0;
if(bRunning){
for(int iFill=0;iFill < iCount; ++iFill)
{
if(iCount >= 0)
{
if(ListBox1->ItemIndex >= 0)
{
s = ListBox1->Items->Strings[iFill];
//get the ints from the file
iline0 = CharsINI->ReadInteger(s,"line0",0);
iline1 = CharsINI->ReadInteger(s,"line1",0);
iline2 = CharsINI->ReadInteger(s,"line2",0);
iline3 = CharsINI->ReadInteger(s,"line3",0);
iline4 = CharsINI->ReadInteger(s,"line4",0);
iline5 = CharsINI->ReadInteger(s,"line5",0);
iline6 = CharsINI->ReadInteger(s,"line6",0);
iline7 = CharsINI->ReadInteger(s,"line7",0);
iIndex = ListBox1->Items->IndexOf(s);
}
}
sCustChar = IntToStr(iline0) + "," + IntToStr(iline1) +
"," + IntToStr(iline2) + "," + IntToStr(iline3) +
"," + IntToStr(iline4) + "," + IntToStr(iline5) +
"," + IntToStr(iline6) + "," + IntToStr(iline7);
iHex = iline0;
i0 = iline0;
i1 = iline1;
i2 = iline2;
i3 = iline3;
i4 = iline4;
i5 = iline5;
i6 = iline6;
i7 = iline7;
s0 = "0x"+ sCustChar.IntToHex(i0, 8);
s1 = "0x"+ sCustChar.IntToHex(i1, 8);
s2 = "0x"+ sCustChar.IntToHex(i2, 8);
s3 = "0x"+ sCustChar.IntToHex(i3, 8);
s4 = "0x"+ sCustChar.IntToHex(i4, 8);
s5 = "0x"+ sCustChar.IntToHex(i5, 8);
s6 = "0x"+ sCustChar.IntToHex(i6, 8);
s7 = "0x"+ sCustChar.IntToHex(i7, 8);
ih0 = StrToInt(s0);
ih1 = StrToInt(s1);
ih2 = StrToInt(s2);
ih3 = StrToInt(s3);
ih4 = StrToInt(s4);
ih5 = StrToInt(s5);
ih6 = StrToInt(s6);
ih7 = StrToInt(s7);
//----------------------------Now, lets make a custom char .
unsigned char custchar [8] = {ih0,ih1,ih2,ih3,ih4,ih5,ih6,ih7};
*custchar = (unsigned char) ( ih0,ih1,ih2,ih3,ih4,ih5,ih6,ih7 );
lcdSetCustomChar(iFill, custchar);
}//end of for
lcdClearDisplay();
lcdSetCursorPos(0,1);
lcdSendCharacter('\000');
lcdSendCharacter('\001');
lcdSendCharacter('\002');
lcdSendCharacter('\003');
lcdSendCharacter('\004');
lcdSendCharacter('\005');
lcdSendCharacter('\006');
lcdSendCharacter('\007');
String sHex2 = IntToHex(*custchar,8);
Edit3->Text = sHex2;//the big yellow label at the bottom
delete custchar;
TestBtn->Enabled = true;
} //end of if(bRunning)
delete CharsINI;
And out pops another character set for display
Next step - read them back into the panel array, ListBox-> OnClick, for editing. I'll blog some more about the LCD Controller next time.



No comments:
Post a Comment