在做一个项目时选用的是带字库的12864液晶,液晶控制型号是ST7920 这种估计是最常用的了,带有汉字字库,可串并行通信。
在使用这款型号液晶时,由于显示数据地址固定
所以函数都整成下面这个形式:
void LcdDispChar(u8 addr,u8 chr);
void LcdDispString(u8 addr,u8 *pStr);
显示字符串和单个字符时入口参数就是 显示地址和数据。
下面主角来啦....
在做同一系列的一个项目时,由于结构问题,需要选用尺寸小一点的液晶咯。1602液晶实在是太小了就被排除咯,最终选定的是一个无字库的12864液晶,液晶控制型号是KS0108
左半屏和右半屏操作时写的地址其实是一样的,那么只能通过片选CS1和CS2来选择哪半个屏了,相当于两块64x64的液晶了
同一系列的项目,程序整体结构改动不大,现在就需要能够像操作有字库液晶那样来操作这块无字库的12864液晶。那么就开工了,在Proteus上仿真实验,保证显示函数的形式不变。
首先定义了一个这样的结构体来做地址转换
typedef enum
{
LCD_None,
LCD_A,
LCD_B,
LCD_All,
}LCD_Select;
typedef struct
{
u8 LCD_Address;
u8 LCD_AddrRow;
u8 LCD_AddrPage;
LCD_Select LCD_AddrSelect;
}LCD_AddrTypedef;
code LCD_AddrTypedef gLcdAddrTable[32] =
{
{0x80,0,0,LCD_A},
{0x81,16,0,LCD_A},
{0x82,32,0,LCD_A},
{0x83,48,0,LCD_A},
{0x84,0,0,LCD_B},
{0x85,16,0,LCD_B},
{0x86,32,0,LCD_B},
{0x87,48,0,LCD_B},
{0x88,0,4,LCD_A},
{0x89,16,4,LCD_A},
{0x8a,32,4,LCD_A},
{0x8b,48,4,LCD_A},
{0x8c,0,4,LCD_B},
{0x8d,16,4,LCD_B},
{0x8e,32,4,LCD_B},
{0x8f,48,4,LCD_B},
{0x90,0,2,LCD_A},
{0x91,16,2,LCD_A},
{0x92,32,2,LCD_A},
{0x93,48,2,LCD_A},
{0x94,0,2,LCD_B},
{0x95,16,2,LCD_B},
{0x96,32,2,LCD_B},
{0x97,48,2,LCD_B},
{0x98,0,6,LCD_A},
{0x99,16,6,LCD_A},
{0x9a,32,6,LCD_A},
{0x9b,48,6,LCD_A},
{0x9c,0,6,LCD_B},
{0x9d,16,6,LCD_B},
{0x9e,32,6,LCD_B},
{0x9f,48,6,LCD_B},
};
将带有字库的12864液晶的显示地址与无字库液晶上的像素点联系起来。
开始完成显示字符和字符串函数:
void LcdDispChar(u8 addr,u8 chr)
{
u8 i,j;
u8 page = gLcdAddrTable[(addr - 0x80)].LCD_AddrPage;
u8 row = gLcdAddrTable[(addr - 0x80)].LCD_AddrRow;
LcdSelectScreen(gLcdAddrTable[(addr - 0x80)].LCD_AddrSelect);
//根据结构体数组里面的信息得出行列地址以及选择左或右半屏
for(i = 0;i < 2;i++)
{
LcdSetPageRow(page + i,row);
for(j = 0;j < 8;j++)
{
LcdWriteFuncion(ASCII816[chr - 0x20][(i * 8 + j)],LCD_Data);
}
}
}
在显示字符串中会有汉字的出现,所以需要判断一个字符串中,哪些是汉字哪些是字符。下面是显示字符串的函数,字符串中可以汉字与字符并存。
void LcdDispString(u8 addr,u8 *pStr)
{
u8 cntChr = 0;
u8 wCnt,n1,n2;
while(*pStr != '\0')
{
if(*pStr & 0x80)
{
n1 = *pStr;
pStr++;
if(*pStr & 0x80)
{
n2 = *pStr;
pStr++;
wCnt = GDKtoNumber(n1,n2);
if(wCnt != ERR_NUMBER)
{
LcdGotoXY((addr + cntChr / 2));
LcdWriteWord(gHZTable[wCnt * 2]);
cntChr += 2;
}
}
}
else
{
if((cntChr % 2) == 0)
{
LcdDispChar((addr + cntChr / 2),*pStr);
}
else
{
LcdGotoXY2(addr + (cntChr / 2));
LcdWriteChar(*pStr);
}
pStr++;
cntChr++;
}
}
}
还有一点就是,汉字的字模怎么与汉字对应呢,采用了如下方法:
#define MAX_WORD_NUMBER (84) //汉字个数
#define ERR_NUMBER (MAX_WORD_NUMBER + 1)
code u8 gHZTable[MAX_WORD_NUMBER * 2][16] =
{
{0x20,0x20,0x20,0x3C,0x28,0x68,0xD9,0x56,0x74,0x94,0x9C,0x94,0x10,0x10,0x00,0x00},
{0x00,0x20,0x24,0x15,0x15,0x0D,0x04,0x7F,0x06,0x0A,0x12,0x32,0x20,0x20,0x00,0x00},/*"案",1*/
//添加字模
}
code u8 GBKCodeTable[MAX_WORD_NUMBER][2] =
{
{"案"},
//添加所填加的汉字,与字模的顺序一致
};
下面是根据汉字查找字模:
u8 GDKtoNumber(u8 n1,u8 n2)
{
u8 i = 0;
for(i = 0;i < MAX_WORD_NUMBER;i++)
{
if(n1 == GBKCodeTable[i][0])
{
if(n2 == GBKCodeTable[i][1])
{
return i;
}
}
}
return ERR_NUMBER;
}
下面是主函数内容,与仿真效果:
void main()
{
LcdInitConfig();
LcdDispString(0x90,"www.eepw.com.cn ");
LcdDispString(0x88,"信息------------");
LcdDispString(0x98,"****************");
while(1)
{
}
}
用无字库12864替换带字库液晶.rar
我要赚赏金
