带字库的图形点阵LCD模块价格要比不带字库的贵很多,但是使用不带字库的LCD模块,往往在编程上要麻烦许多。最近我做一个PAC控制器的时候,使用不带字库的12864LCD模块,发现在程序上使用一些技巧,能使不带字库的模块用起来和带字库的一样方便。
首先要感谢下面这篇博文:
http://bbs.ednchina.com/BLOG_ARTICLE_20371.HTM
但是我用其中的代码移植到飞思卡尔的编译环境下出现很多错误,不能直接使用。
下面是演示LCD显示的代码,只需要在函数disp_str()输入显示字符串的位置和字符串就可以了。这样不是和带字库的LCD模块一样方便使用吗?
void LCD_Demo() {
uchar i,j,len;
uchar Char_Index; //字符所在的行
uchar x,y;
Lcd_Init();
ClearScreen();
disp_str(16,4,"液晶显示MCR MOTOR"); //显示字符串
}
这其中的关键奥秘在于,输入到函数中的字符串会被编译成ASCII代码,其中汉字占两位uchar,其他字符占一位uchar.请看disp_str()函数内容:
void disp_str(uchar x,uchar y,uchar str[]){
uchar i=0;
uchar List_X;
List_X=x;
while(str>0) //遍历字符串数组。
{
if (str < 128) //非汉字的字符被编译为小于128的数值
{ /* ASCII */
disp_char(List_X,y,str);
List_X+=ASC_CHR_WIDTH;
MDelay(500);
}
else //汉字的字符被编译为大于128的数值,并且占两位uchar
{ /* 中文 */
disp_hz(List_X,y,str,str[i+1]);
i++; //跳一位,因为汉字站两位数组位。
List_X+=ASC_HZ_WIDTH;
MDelay(500);
}
i++;
}
}
从字符串中解析出来ASCII码后,就可以根据这个来找对应的字模。字模还是要做的,但是字模的格式与一般的不太一样。如下面的代码。
typedef struct typFNT_ASC16 /* 字符字模显示数据结构 */
{
char Index[1];
char Msk[ASC_CHR_WIDTH*2];
};
struct typFNT_ASC16 const ASC_16[] = {
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
"0",0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,
"1",0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
"2",0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,
"3",0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,
"4",0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,
"5",0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,
"6",0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,
"7",0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,
"8",0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,
"9",0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,
"A",0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,
"B",0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,
"C",0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,
"D",0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,
"E",0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,
"F",0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,
"G",0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,
"H",0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,
"I",0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
"J",0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,
"K",0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,
"L",0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,
"M",0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,
"N",0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,
"O",0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,
"P",0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,
"Q",0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,
"R",0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,
"S",0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,
"T",0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,
"U",0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,
"V",0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,
"W",0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,
"X",0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,
"Y",0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,
"Z",0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,
" ",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
ASC_16数组的每一行的第一位都是字符,编译是会转变为对应的ASCII码,如果现在要显示的字符是“A”,程序会到ASC_16[] 数组中去找第一位的ASCII代码与"A"相等的。找到后显示后面的字模。下面是disp_char()函数
void disp_char(uchar x, uchar y, uchar c)
{
uchar i,j,len;
uchar Char_Index; //字符所在的行
//x <<= 1;
//y <<= 3;
if (x & 0x40)
{
LCD_CS1 = 0;
LCD_CS2 = 1;
}
else
{
LCD_CS1 = 1;
LCD_CS2 = 0;
}
//先找到字符是在数据表里面的哪一行Index=?
len=sizeof(ASC_16)/sizeof(ASC_16[0]); //字符表的行数
for(i=0;i<len;i++)
{
if(c == ASC_16.Index[0] ) break; //找到字符是在哪一行
}
Char_Index=i;
if (Char_Index<len){
//显示上半部分
Lcd_WriteCmd(PAGE_ADD|y);
Lcd_WriteCmd(LIST_ADD|x);
for (j = 0; j < ASC_CHR_WIDTH ; j++)
{
Lcd_WriteData(ASC_16[Char_Index].Msk[j]);
}
//显示下半部分
Lcd_WriteCmd((PAGE_ADD+1)|y);
Lcd_WriteCmd(LIST_ADD|x);
for (j = ASC_CHR_WIDTH ; j < ASC_CHR_WIDTH+ ASC_CHR_WIDTH ; j++)
{
Lcd_WriteData(ASC_16[Char_Index].Msk[j]);
}
}
}
汉字显示的代码也与之相似,只是需要判断两个uchar变量是否与字库数组中相等。
汉字字库:
#define ASC_HZ_WIDTH 12
#define ASC_HZ_HEIGHT 16
typedef struct typFNT_GB16 /*12*16 汉字字模显示数据结构 */
{
char Index[2];
char Msk[24];
};
struct typFNT_GB16 const GB_16[] = { /* 宋体 9小五 显示为12*16 */
"液",0x19,0xE2,0x14,0x42,0xF2,0x2E,0x72,0x8F,0xAA,0x7A,0x02,0x00,0x01,0x07,0x00,0x00,0x07,0x04,0x04,0x02,0x01,0x02,0x04,0x00,
"晶",0x00,0xC0,0x40,0x5F,0xD5,0x15,0xD5,0x55,0x5F,0x40,0xC0,0x00,0x00,0x07,0x05,0x05,0x07,0x00,0x07,0x05,0x05,0x05,0x07,0x00,
"显",0x00,0x40,0x9F,0x15,0xD5,0x15,0xD5,0x15,0x1F,0xC0,0x00,0x00,0x04,0x04,0x05,0x04,0x07,0x04,0x07,0x06,0x05,0x04,0x04,0x00,
"示",0x10,0x12,0x92,0x52,0x12,0xF2,0x12,0x12,0x53,0x92,0x10,0x00,0x02,0x01,0x00,0x04,0x04,0x07,0x00,0x00,0x00,0x00,0x03,0x00,
"的",0xFC,0x44,0x46,0x45,0xFC,0x10,0x2C,0xC7,0x04,0x04,0xFC,0x00,0x07,0x02,0x02,0x02,0x07,0x00,0x00,0x04,0x04,0x04,0x03,0x00,
"第",0x04,0xEA,0xAB,0xAE,0xAA,0xFC,0xAA,0xAB,0xAE,0xBA,0x82,0x00,0x04,0x04,0x02,0x01,0x00,0x07,0x00,0x02,0x02,0x02,0x01,0x00,
"一",0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
"行",0x48,0x24,0xF3,0x08,0x09,0x09,0x09,0x09,0xF9,0x09,0x08,0x00,0x00,0x00,0x07,0x00,0x00,0x04,0x04,0x04,0x07,0x00,0x00,0x00,
"二",0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x06,0x04,0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,
"三",0x00,0x02,0x22,0x22,0x22,0x22,0x22,0x22,0x23,0x02,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x06,0x04,0x00,
"四",0x00,0xFF,0x81,0x41,0x3F,0x01,0x01,0xFF,0x81,0x81,0xFF,0x00,0x00,0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x07,0x00,
"五",0x00,0x11,0x11,0x91,0x7F,0x11,0x11,0x11,0xF1,0x01,0x00,0x00,0x04,0x04,0x04,0x07,0x04,0x04,0x04,0x04,0x07,0x04,0x04,0x00,
};
汉字显示函数:
void disp_hz(uchar x, uchar y, uchar hz0,uchar hz1)
{
uchar i,j,len;
uchar Char_Index; //字符所在的行
//x <<= 1;
//y <<= 3;
if (x & 0x40)
{
LCD_CS1 = 0;
LCD_CS2 = 1;
}
else
{
LCD_CS1 = 1;
LCD_CS2 = 0;
}
len=sizeof(GB_16)/sizeof(GB_16[0]);
//先找到汉字是在数据表里面的哪一行Index=?问题是找不到汉字
for(i=0;i<len;i++)
{
if(hz0 ==(256+GB_16.Index[0]) && hz1 ==(256+GB_16.Index[1])) //发现变成了hz0+GB16=256
break;
}
Char_Index=i;
if (Char_Index<len){
//显示上半部分
Lcd_WriteCmd(PAGE_ADD|y);
Lcd_WriteCmd(LIST_ADD|x);
for (j = 0; j < ASC_HZ_WIDTH; j++)
{
Lcd_WriteData(GB_16[Char_Index].Msk[j]);
}
//显示下半部分
Lcd_WriteCmd((PAGE_ADD+1)|y);
Lcd_WriteCmd(LIST_ADD|x);
for (j = ASC_HZ_WIDTH; j < ASC_HZ_WIDTH+ASC_HZ_WIDTH; j++)
{
Lcd_WriteData(GB_16[Char_Index].Msk[j]);
}
}
}
很奇怪的是,飞思卡尔编译器系统把字库数组中的汉字编译成ASCII码,编成了负数。所以判断条件和非汉字的不一样。if(hz0 ==(256+GB_16.Index[0]) && hz1 ==(256+GB_16.Index[1])) 也许别的编译系统又不一样。
以上就是图形点阵编程的技巧。
用户377235 2013-5-17 23:09
用户403664 2012-6-21 10:04
ash_riple_768180695 2007-5-23 16:11