在做一个项目时选用的是带字库的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