
一個(gè)漢字占用字節數:12÷8=1····4也就是占用了2×12=24個(gè)字節。
編碼排序A0A0→A0FE A1A0→A2FE依次排列。
以12×12字庫的“我”為例:“我”的編碼為CED2,所以在漢字排在CEH-AOH=2EH區的D2H-A0H=32H個(gè)。所以在12×12字庫的起始位置就是[{FE-A0}*2EH+32H]*24=104976開(kāi)始的24個(gè)字節就是我的點(diǎn)陣模。
其他的類(lèi)推即可。
英文點(diǎn)陣也是如此推理。
首先需要理解的是點(diǎn)陣字庫是一個(gè)數據文件,在這個(gè)數據文件里面保存了所有文字的點(diǎn)陣數據.至于什么是點(diǎn)陣,我想我不講大家都知道 的,使用過(guò)"文曲星"之類(lèi)的電子辭典吧,那個(gè)的液晶顯示器上面顯示的漢子就能夠明顯的看出"點(diǎn)陣"的痕跡.在 PC 機上也是如此,文字也是由點(diǎn)陣來(lái)組成了,不同的是,PC機顯示器的顯示分辨率更高,高到了我們肉眼無(wú)法區分的地步,因此"點(diǎn)陣"的痕跡也就不那么明顯了.
點(diǎn)陣、矩陣、位圖這三個(gè)概念在本質(zhì)上是有聯(lián)系的,從某種程度上來(lái)講,這三個(gè)就是同義詞.點(diǎn)陣從本質(zhì)上講就是單色位圖,他使用一個(gè)比特來(lái)表示一個(gè)點(diǎn),如果這 個(gè)比特為0,表示某個(gè)位置沒(méi)有點(diǎn),如果為1表示某個(gè)位置有點(diǎn).矩陣和位圖有著(zhù)密不可分的聯(lián)系,矩陣其實(shí)是位圖的數學(xué)抽象,是一個(gè)二維的陣列.位圖就是這種 二維的陣列,這個(gè)陣列中的 (x,y) 位置上的數據代表的就是對原始圖形進(jìn)行采樣量化后的顏色值.但是,另一方面,我們要面對的問(wèn)題是,計算機中數據的存放都是一維的,線(xiàn)性的.因此,我們需要 將二維的數據線(xiàn)性化到一維里面去.通常的做法就是將二維數據按行順序的存放,這樣就線(xiàn)性化到了一維.
那么點(diǎn)陣字的數據存放細節到底是怎么樣的呢.其實(shí)也十分的簡(jiǎn)單,舉個(gè)例子最能說(shuō)明問(wèn)題.比如說(shuō) 16*16 的點(diǎn)陣,也就是說(shuō)每一行有16個(gè)點(diǎn),由于一個(gè)點(diǎn)使用一個(gè)比特來(lái)表示,如果這個(gè)比特的值為1,則表示這個(gè)位置有點(diǎn),如果這個(gè)比特的值為0,則表示這個(gè)位置沒(méi) 有點(diǎn),那么一行也就需要16個(gè)比特,而8個(gè)比特就是一個(gè)字節,也就是說(shuō),這個(gè)點(diǎn)陣中,一行的數據需要兩個(gè)字節來(lái)存放.第一行的前八個(gè)點(diǎn)的數據存放在點(diǎn)陣數 據的第一個(gè)字節里面,第一行的后面八個(gè)點(diǎn)的數據存放在點(diǎn)陣數據的第二個(gè)字節里面,第二行的前八個(gè)點(diǎn)的數據存放在點(diǎn)陣數據的第三個(gè)字節里面,…,然后后 面的就以此類(lèi)推了.這樣我們可以計算出存放一個(gè)點(diǎn)陣總共需要32個(gè)字節.看看下面這個(gè)圖形化的例子:
| |1| | | | | | | | | | |1| | | |
| | |1|1| |1|1|1|1|1|1|1|1|1| | |
| | | |1| | | | | | | | |1| | | |
|1| | | | | |1| | | | | |1| | | |
| |1|1| | | |1| | | | | |1| | | |
| | |1| | | |1| | | | |1| | | | |
| | | | |1| | |1| | | |1| | | | |
| | | |1| | | |1| | |1| | | | | |
| | |1| | | | | |1| |1| | | | | |
|1|1|1| | | | | | |1| | | | | | |
| | |1| | | | | |1| |1| | | | | |
| | |1| | | | |1| | | |1| | | | |
| | |1| | | |1| | | | | |1| | | |
| | |1| | |1| | | | | | |1|1|1| |
| | | | |1| | | | | | | | |1| | |
| | | | | | | | | | | | | | | | |
可以看出這是一個(gè)"漢"字的點(diǎn)陣,當然文本的方式效果不是很好.根據上面的原則,我們可以寫(xiě)出這個(gè)點(diǎn)陣的點(diǎn)陣數 據:0x40,0x08,0x37,0xfc,0x10,0x08,…, 當然寫(xiě)這個(gè)確實(shí)很麻煩所以我不再繼續下去.我這樣做,也只是為了向你說(shuō)明,在點(diǎn)陣字庫中,每一個(gè)點(diǎn)陣的數據就是按照這種方式存放的.
當然也存在著(zhù)不規則的點(diǎn)陣,這里說(shuō)的不規則,指的是點(diǎn)陣的寬度不是8的倍數,比如 12*12 的點(diǎn)陣,那么這樣的點(diǎn)陣數據又是如何存放的呢?其實(shí)也很簡(jiǎn)單,每一行的前面8個(gè)點(diǎn)存放在一個(gè)字節里面,每一行的剩下的4點(diǎn)就使用一個(gè)字節來(lái)存放,也就是說(shuō) 剩下的4個(gè)點(diǎn)將占用一個(gè)字節的高4位,而這個(gè)字節的低4位沒(méi)有使用,全部都默認的為零.這樣做當然顯得有點(diǎn)浪費,不過(guò)卻能夠便于我們進(jìn)行存放和尋址.對于 其他不規則的點(diǎn)陣,也是按照這個(gè)原則進(jìn)行處理的.這樣我們可以得出一個(gè) m*n 的點(diǎn)陣所占用的字節數為 (m+7)/8*n.
在明白了以上所講的以后,我們可以寫(xiě)出一個(gè)顯示一個(gè)任意大小的點(diǎn)陣字模的函數,這個(gè)函數的功能是輸出一個(gè)寬度為w,高度為h的字模到屏幕的 (x,y) 坐標出,文字的顏色為 color,文字的點(diǎn)陣數據為 pdata 所指:
/*輸出字模的函數*/
void _draw_model(char *pdata, int w, int h, int x, int y, int color)
{
int i; /* 控制行 */
int j; /* 控制一行中的8個(gè)點(diǎn) */
int k; /* 一行中的第幾個(gè)"8個(gè)點(diǎn)"了 */
int nc; /* 到點(diǎn)陣數據的第幾個(gè)字節了 */
int cols; /* 控制列 */
BYTE static mask[8]={128, 64, 32, 16, 8, 4, 2, 1}; /* 位屏蔽字 */
w = (w + 7) / 8 * 8; /* 重新計算w */
nc = 0;
for (i=0; i<h; i++)
{
cols = 0;
for (k=0; k<w/8; k++)
{
for (j=0; j<8; j++)
{
if (pdata[nc]&mask[j])
putpixel(x+cols, y+i, color);
cols++;
}
nc++;
}
}
}
代碼很簡(jiǎn)單,不用怎么講解就能看懂,代碼可能不是最優(yōu)化的,但是應該是最易讀懂的.其中的 putpixel 函數,使用的是TC提供的 Graphics 中的畫(huà)點(diǎn)函數.使用這個(gè)函數就可以完成點(diǎn)陣任意大小的點(diǎn)陣字模的輸出.
接下來(lái)的問(wèn)題就是如何在漢子庫中尋址某個(gè)漢子的點(diǎn)陣數據了.要解決這個(gè)問(wèn)題,首先需要了解漢字在計算機中是如何表示的.在計算機中英文可以使用 ASCII 碼來(lái)表示,而漢字使用的是擴展 ASCII 碼,并且使用兩個(gè)擴展 ASCII 碼來(lái)表示一個(gè)漢字.一個(gè) ASCII 碼使用一個(gè)字節表示,所謂擴展 ASCII 碼,也就是 ASCII 碼的最高位是1的 ASCII 碼,簡(jiǎn)單的說(shuō)就是碼值大于等于 128 的 ASCII 碼.一個(gè)漢字由兩個(gè)擴展 ASCII 碼組成,第一個(gè)擴展 ASCII 碼用來(lái)存放區碼,第二個(gè)擴展 ASCII 碼用來(lái)存放位碼.在 GB2312-80 標準中,將所有的漢字分為94個(gè)區,每個(gè)區有94個(gè)位可以存放94個(gè)漢字,形成了人們常說(shuō)的區位碼,這樣總共就有 94*94=8836 個(gè)漢字.在點(diǎn)陣字庫中,漢字點(diǎn)陣數據就是按照這個(gè)區位的順序來(lái)存放的,也就是最先存放的是第一個(gè)區的漢字點(diǎn)陣數據,在每一個(gè)區中有是按照位的順序來(lái)存放 的.在漢字的內碼中,漢字區位碼的存放實(shí)在擴展 ASCII 基礎上存放的,并且將區碼和位碼都加上了32,然后存放在兩個(gè)擴展 ASCII 碼中.具體的說(shuō)就是:
第一個(gè)擴展ASCII碼 = 128+32 + 漢字區碼
第二個(gè)擴展ASCII嗎 = 128+32 + 漢字位碼
如果用char hz[2]來(lái)表示一個(gè)漢字,那么我可以計算出這個(gè)漢字的區位碼為:
區碼 = hz[0] - 128 - 32 = hz[0] - 160
位碼 = hz[1] - 128 - 32 = hz[1] - 160.
這樣,我們可以根據區位碼在文件中進(jìn)行殉職了,尋址公式如下:
漢字點(diǎn)陣數據在字庫文件中的偏移 = ((區碼-1) * 94 + 位碼) * 一個(gè)點(diǎn)陣字模占用的字節數
在尋址以后,即可讀取漢字的點(diǎn)陣數據到緩沖區進(jìn)行顯示了.以下是實(shí)現代碼:
/* 輸出一個(gè)漢字的函數 */
void _draw_hz(char hz[2], FILE *fp, int x, int y, int w, int h, int color)
{
char fontbuf[128]; /* 足夠大的緩沖區,也可以動(dòng)態(tài)分配 */
int ch0 = (BYTE)hz[0]-0xA0; /* 區碼 */
int ch1 = (BYTE)hz[1]-0xA0; /* 位碼 */
/* 計算偏移 */
long offset = (long)pf->_hz_buf_size * ((ch0 - 1) * 94 + ch1 - 1);
fseek(fp, offset, SEEK_SET); /* 進(jìn)行尋址 */
fread(fontbuf, 1, (w + 7) / 8 * h, fp); /* 讀入點(diǎn)陣數據 */
_draw_model(fontbuf, w, h, x, y, color); /* 繪制字模 */
}
以上介紹完了中文點(diǎn)陣字庫的原理,當然還有英文點(diǎn)陣字庫了.英文點(diǎn)陣字庫中單個(gè)點(diǎn)陣字模數據的存放方式與中文是一模一樣的,也就是對我們所寫(xiě)的 _draw_model 函數同樣可以使用到英文字庫中.唯一不同的是對點(diǎn)陣字庫的尋址上.英文使用的就是 ASCII 碼,其碼值是0到127,尋址公式為:
英文點(diǎn)陣數據在英文點(diǎn)陣字庫中的偏移 = 英文的ASCII碼 * 一個(gè)英文字模占用的字節數
可以看到,區分中英文的關(guān)鍵就是,一個(gè)字符是 ASCII 碼還是擴展 ASCII 碼,如果是 ASCII 碼,其范圍是0到127,這樣是使用的英文字庫,如果是擴展 ASCII 碼,則與其后的另一個(gè)擴展 ASCII 碼組成漢字內碼,使用中文字庫進(jìn)行顯示.只要正確區分 ASCII 碼的類(lèi)型并進(jìn)行分別的處理,也就能實(shí)現中英文字符串的混合輸出了.
我們都只知道,各種字符在電腦屏幕上都是以一些點(diǎn)來(lái)表示的,因此也叫點(diǎn)陣.最早的字庫就是直接把這些點(diǎn)存儲起來(lái),就是點(diǎn)陣字庫.常見(jiàn)的漢字點(diǎn)陣字庫有 16x16, 24x24 等.點(diǎn)陣字庫也有很多種,主要區別在于其中存儲編碼的方式不同.點(diǎn)陣字庫的最大缺點(diǎn)就是它是固定分辨率的,也就是每種字庫都有固定的大小尺寸,在原始尺寸下使用,效果很好,但如果將其放大或縮小使用,效果就很糟糕了,就會(huì )出現我們通常說(shuō)的鋸齒現象.因為需要的字體大小組合有無(wú)數種,我們也不可能為每種大小都定義一個(gè)點(diǎn)陣字庫.于是就出現了矢量字庫.
矢量字庫
矢量字庫是把每個(gè)字符的筆劃分解成各種直線(xiàn)和曲線(xiàn),然后記下這些直線(xiàn)和曲線(xiàn)的參數,在顯示的時(shí)候,再根據具體的尺寸大小,畫(huà)出這些線(xiàn)條,就還原了原來(lái)的字符.它的好處就是可以隨意放大縮小而不失真.而且所需存儲量和字符大小無(wú)關(guān).矢量字庫有很多種,區別在于他們采用的不同數學(xué)模型來(lái)描述組成字符的線(xiàn)條.常見(jiàn)的矢量字庫有 Type1字庫和Truetype字庫.
在點(diǎn)陣字庫中,每個(gè)字符由一個(gè)位圖表示(如圖2.5所示),并把它用一個(gè)稱(chēng)為字符掩膜的矩陣來(lái)表示,其中的每個(gè)元素都是一位二進(jìn)制數,如果該位為1表示字符的筆畫(huà)經(jīng)過(guò)此位,該像素置為字符顏色;如果該位為0,表示字符的筆畫(huà)不經(jīng)過(guò)此位,該像素置為背景顏色.點(diǎn)陣字符的顯示分為兩步:首先從字庫中將它的位圖檢索出來(lái),然后將檢索到的位圖寫(xiě)到幀緩沖器中.
在實(shí)際應用中,同一個(gè)字符有多種字體(如宋體、楷體等),每種字體又有多種大小型號,因此字庫的存儲空間十分龐大.為了減少存儲空間,一般采用壓縮技術(shù).
矢量字符記錄字符的筆畫(huà)信息而不是整個(gè)位圖,具有存儲空間小,美觀(guān)、變換方便等優(yōu)點(diǎn).例如:在A(yíng)utoCAD中使用圖形實(shí)體-形(Shape)-來(lái)定義矢量字符,其中,采用了直線(xiàn)和圓弧作為基本的筆畫(huà)來(lái)對矢量字符進(jìn)行描述. 對于字符的旋轉、放大、縮小等幾何變換,點(diǎn)陣字符需要對其位圖中的每個(gè)象素進(jìn)行變換,而矢量字符則只需要對其幾何圖素進(jìn)行變換就可以了,例如:對直線(xiàn)筆畫(huà)的兩個(gè)端點(diǎn)進(jìn)行變換,對圓弧的起點(diǎn)、終點(diǎn)、半徑和圓心進(jìn)行變換等等.
矢量字符的顯示也分為兩步.首先從字庫中將它的字符信息.然后取出端點(diǎn)坐標,對其進(jìn)行適當的幾何變換,再根據各端點(diǎn)的標志顯示出字符.
輪廓字形法是當今國際上最流行的一種字符表示方法,其壓縮比大,且能保證字符質(zhì)量.輪廓字形法采用直線(xiàn)、B樣條/Bezier曲線(xiàn)的集合來(lái)描述一個(gè)字符的輪廓線(xiàn).輪廓線(xiàn)構成一個(gè)或若干個(gè)封閉的平面區域.輪廓線(xiàn)定義加上一些指示橫寬、豎寬、基點(diǎn)、基線(xiàn)等等控制信息就構成了字符的壓縮數據.
我的程序現在只能預覽一個(gè)漢字的不同字體的點(diǎn)陣表達.
界面很簡(jiǎn)單: 一個(gè)輸出點(diǎn)陣大小的選擇列表(8x8,16x16,24x24等),一個(gè)系統中已有的字體名稱(chēng)列表,一個(gè)預覽按鈕,一塊畫(huà)圖顯示區域.
得到字體列表的方法:(作者稱(chēng)這一段是用來(lái)取回系統的字體,然后添加到下拉框中)
//取字體名稱(chēng)列表的回調函數,使用前要聲明一下該方法
int CALLBACK MyEnumFontProc(ENUMLOGFONTEX* lpelf,NEWTEXTMETRICEX* lpntm,DWORD nFontType,long lParam)
{
CFontPeekerDlg* pWnd=(CFontPeekerDlg*) lParam;
if(pWnd)
{
if( pWnd->m_combo_sfont.FindString(0, lpelf->elfLogFont.lfFaceName) <0 )
pWnd->m_combo_sfont.AddString(lpelf->elfLogFont.lfFaceName);
return 1;
}
return 0;
}
//說(shuō)明:CFontPeekerDlg 是我的dialog的類(lèi)名, m_combo_sfont是列表名稱(chēng)下拉combobox關(guān)聯(lián)的control變量
//調用的地方 (******問(wèn)題1:下面那個(gè)&lf怎么得到呢……)
{
::EnumFontFamiliesEx((HDC) dc,&lf, (FONTENUMPROC)MyEnumFontProc,(LPARAM) this,0);
m_combo_sfont.SetCurSel(0);
}
字體預覽:
如果點(diǎn)陣大小選擇16,顯示的時(shí)候就畫(huà)出16x16個(gè)方格.自定義一個(gè)類(lèi)CMyStatic繼承自CStatic,用來(lái)畫(huà)圖.在CMyStatic的OnPaint()函數中計算并顯示.
取得字體:
常用的方法:用CreateFont創(chuàng )建字體,把字TextOut再用GetPixel()取點(diǎn)存入數組. 缺點(diǎn):必須把字TextOut出來(lái),能在屏幕上看見(jiàn),不爽.
我的方法,用這個(gè)函數:GetGlyphOutline(),可以得到一個(gè)字的輪廓矢量或者位圖.可以不用textout到屏幕,直接取得字模信息
函數原型如下:
DWORD GetGlyphOutline(
HDC hdc, //畫(huà)圖設備句柄
UINT uChar, //將要讀取的字符/漢字
UINT uFormat, //返回數據的格式(字的外形輪廓還是字的位圖)
LPGLYPHMETRICS lpgm, // GLYPHMETRICS結構地址,輸出參數
DWORD cbBuffer, //輸出數據緩沖區的大小
LPVOID lpvBuffer, //輸出數據緩沖區的地址
CONST MAT2 *lpmat2 //轉置矩陣的地址
);
說(shuō)明:
uChar字符需要判斷是否是漢字還是英文字符.中文占2個(gè)字節長(cháng)度.
lpgm是輸出函數,調用GetGlyphOutline()是無(wú)須給lpgm 賦值.
lpmat2如果不需要轉置,將 eM11.value=1; eM22.value=1; 即可.
cbBuffer緩沖區的大小,可以先通過(guò)調用GetGlyphOutline(……lpgm, 0, NULL, mat); 來(lái)取得,然后動(dòng)態(tài)分配lpvBuffer,再一次調用GetGlyphOutline,將信息存到lpvBuffer. 使用完畢后再釋放lpvBuffer.
程序示例:(***問(wèn)題2:用這段程序,我獲取的字符點(diǎn)陣總都是一樣的,不管什么字……)
……前面部分省略……
GLYPHMETRICS glyph;
MAT2 m2;
memset(&m2, 0, sizeof(MAT2));
m2.eM11.value = 1;
m2.eM22.value = 1;
//取得buffer的大小
DWORD cbBuf = dc.GetGlyphOutline( nChar, GGO_BITMAP, &glyph, 0L, NULL, &m2);
BYTE* pBuf=NULL;
//返回GDI_ERROR表示失敗.
if( cbBuf != GDI_ERROR )
{
pBuf = new BYTE[cbBuf];
//輸出位圖GGO_BITMAP 的信息.輸出信息4字節(DWORD)對齊
dc.GetGlyphOutline( nChar, GGO_BITMAP, &glyph, cbBuf, pBuf, &m2);
}
else
{
if(m_pFont!=NULL)
delete m_pFont;
return;
}
編程中遇到問(wèn)題:
一開(kāi)始,GetGlyphOutline總是返回-1,getLastError顯示是"無(wú)法完成的功能",后來(lái)發(fā)現是因為調用之前沒(méi)有給hdc設置Font.
后來(lái)能取得pBuf信息后,又開(kāi)始郁悶,因為不太明白bitmap的結果是按什么排列的.后來(lái)跟蹤漢字"一"來(lái)調試(這個(gè)字簡(jiǎn)單),注意到了glyph.gmBlackBoxX 其實(shí)就是輸出位圖的寬度,glyph.gmBlackBoxY就是高度.如果gmBlackBoxX=15,glyph.gmBlackBoxY=2,表示輸出的pBuf中有這些信息:位圖有2行信息,每一行使用15 bit來(lái)存儲信息.
例如:我讀取"一":glyph.gmBlackBoxX = 0x0e,glyph.gmBlackBoxY=0x2; pBuf長(cháng)度cbBuf=8 字節
pBuf信息: 00 08 00 00 ff fc 00 00
字符寬度 0x0e=14 則 第一行信息為: 0000 0000 0000 100 (只取到前14位)
第二行根據4字節對齊的規則,從0xff開(kāi)始 1111 1111 1111 110
看出"一"字了嗎?呵呵
直到他的存儲之后就可以動(dòng)手解析輸出的信息了.
我定義了一個(gè)宏#define BIT(n) (1<<(n)) 用來(lái)比較每一個(gè)位信息時(shí)使用
后來(lái)又遇到了一個(gè)問(wèn)題,就是小頭和大頭的問(wèn)題了.在我的機器上是little endian的形式,如果我用
unsigned long *lptr = (unsigned long*)pBuf;
//j from 0 to 15
if( *lptr & BIT(j) )
{
//這時(shí)候如果想用j來(lái)表示寫(xiě)1的位數,就錯了
}
因為從字節數組中轉化成unsigned long型的時(shí)候,數值已經(jīng)經(jīng)過(guò)轉化了,像上例中,實(shí)際上是0x0800 在同BIT(j)比較.
不多說(shuō)了,比較之前轉化一下就可以了if( htonl(*lptr) & BIT(j) )
點(diǎn)陣字庫包含兩部分信息.首先是點(diǎn)陣字庫文件頭信息,它包含點(diǎn)陣字庫文字的字號、多少位表示一個(gè)像素,英文字母與符號的size、起始和結束unicode編碼、在文件中的起始偏移,漢字的size、起始和結束unicode編碼、在文件中的起始偏移.然后是真實(shí)的點(diǎn)陣數據,即一段段二進(jìn)制串,每一串表示一個(gè)字母、符號或漢字的點(diǎn)陣信息.
要生成點(diǎn)陣字庫必須有文字圖形的來(lái)源,我的方法是使用ttf字體.ttf字體的顯示采用的是SDL_ttf庫,這是開(kāi)源圖形庫SDL的一個(gè)擴展庫,它使用的是libfreetype以讀取和繪制ttf字體.
它提供了一個(gè)函數,通過(guò)傳入一個(gè)Unicode編碼便能輸出相應的文字的帶有alpha通道的位圖.那么我們可以?huà)呙柽@個(gè)位圖以得到相應文字的點(diǎn)陣信息.由于帶有alpha通道,我們可以在點(diǎn)陣信息中也加入權值,使得點(diǎn)陣字庫也有反走樣效果.我采用兩位來(lái)表示一個(gè)點(diǎn),這樣會(huì )有三級灰度(還有一個(gè)表示透明).
點(diǎn)陣字庫的顯示首先需要將文件頭信息讀取出來(lái),然后根據unicode編碼判斷在哪個(gè)區間內,然后用unicode編碼減去此區間的起始unicode編碼,算出相對偏移,并加上此區間的文件起始偏移得到文件的絕對偏移,然后讀出相應位數的數據,最后通過(guò)掃描這段二進(jìn)制串,在屏幕的相應位置輸出點(diǎn)陣字型.
顯示點(diǎn)陣字體需要頻繁讀取文件,因此最好做一個(gè)固定大小的緩存,采用LRU置換算法維護此緩存,以減少磁盤(pán)讀取.
標準點(diǎn)陣字庫芯片的特點(diǎn):
1.內涵全國信標委授權的標準點(diǎn)陣字型數據、
2.支持國標字符集GB2312(6,763漢字),GB18030(27,484漢字).
3.支持多種點(diǎn)陣字型,包括11×12點(diǎn),15×16點(diǎn),24×24點(diǎn),32×32點(diǎn).
4.免除了字庫燒錄和測試工序,并節省了2%以上的燒錄損耗.
5.價(jià)格相當于空白FLASH價(jià)格


我們歷時(shí)數載,開(kāi)發(fā)成"51單片機13×14點(diǎn)陣縮碼漢卡",適用于目前國內外應用最為廣泛的MCSX-51及其兼容系列單片機.
與此同時(shí),還開(kāi)發(fā)了13×14點(diǎn)陣漢字字模.13×14點(diǎn)陣字模,可完全與目前通用的16×16點(diǎn)陣漢字字模媲美,其在單片機和嵌入式系統的漢字顯示應用中也具有明顯的經(jīng)濟價(jià)值和實(shí)用意義.
1.單片機目前的漢字顯示
信息交流的最主要方式之一即文字交流,但由于我國方塊漢字數量繁多,構形迥異,使漢字顯示一直是我國計算機普及的障礙.隨著(zhù)計算機技術(shù)的迅速發(fā)展,PC機的漢字顯示已不成問(wèn)題.但對于成本低、體積小、應用靈活且用量極為巨大的單片機而言,因其結構簡(jiǎn)單,硬件資源十分有限,其漢字顯示仍面對著(zhù)捉襟見(jiàn)肘,力不從心的窘境.
目前單片機的漢字顯示有三種基本方法.
①采用標準字庫法.即將國標漢字庫固人ROM中,將單片機的硬件和軟件進(jìn)行特別擴展后以顯示漢字.眾所周知,即使是16×16點(diǎn)陣標準字庫,也須占用200KB以上的單元內存,而就目前主流5l系列單片機而言,最大尋址范圍僅64KB,即使程序區與數據區合起來(lái)也僅128KB內存.因此,若不加特別的擴展設計,不要說(shuō)檢字程序和用戶(hù)空間,僅字庫都裝不下.這種方法雖然可以方便地使用現成標準字庫,但卻需占用大量的硬件和軟件資源,增加很大一部分成本和設計難度,所以不經(jīng)常使用.
②字模直接固化法.即將所顯示的漢字,依先后順序將其字模一一從標準字庫中提取后,重新固化,予以顯示.此法雖為簡(jiǎn)捷,但只適于顯示少量漢字,且字模的制取繁瑣,軟件的修改維護都很困難.
③帶索引小字庫法.即將欲顯示文件中的漢字字模,從標準字庫中逐一提取固化,制成小型字庫,并按其在小字庫中的位置制成索引表,顯示時(shí)從索引表查出其新的字模取碼地址,取碼顯示.此方法雖比較靈活,可顯示較多的漢字,但仍然局限于只能顯示固定文件內容,且字模制取同樣麻煩.
一種較新的單片機"漢字動(dòng)態(tài)編碼與顯示方案"(見(jiàn)《單片機與嵌入式系統應用》雜志
由上可見(jiàn),目前單片機各種漢字顯示方案均不理想.標準字庫法,單片機不堪重負;而其它方法最大且又無(wú)法克服的缺點(diǎn)是,所顯示文字皆有局限.顯示內容也皆須專(zhuān)業(yè)人員設計而定,用戶(hù)難于更改.這便極大地限制了單片機在各個(gè)領(lǐng)域的開(kāi)拓和應用.究其原因,皆為單片機本身無(wú)漢卡,而這也正是我們致力于"51漢卡"開(kāi)發(fā)的初衷.
2.13×14點(diǎn)陣漢字字模
為墊定"5l漢卡"的字型基礎,首先開(kāi)發(fā)成了l3×14點(diǎn)陣漢字字模.在目前通用的漢字字模中,最簡(jiǎn)單的是16×16點(diǎn)陣字模.在微型打字機中,也偶見(jiàn)有12×12點(diǎn)陣字模,但實(shí)用中不多見(jiàn).字模點(diǎn)陣數直接決定著(zhù)每一漢字所占單元內存值,能否在保證字模準確、美觀(guān)的基礎上,尋找一種較少的點(diǎn)陣字模呢?這便是我們最初的想法.于是我們經(jīng)過(guò)反復選擇比較,終于在國內首個(gè)推出了13×14點(diǎn)陣字模.此設計,一是基于我國漢字為方塊字,故其行、列值需相近;二是漢字多有對稱(chēng)1生,故其列值宜奇不宜偶.設計實(shí)際表明,若行、列值很少,則難保證字模的準確性和美觀(guān)性.?
13×14點(diǎn)陣字模,是以我國現行簡(jiǎn)化字為準,并在此基礎上設計而成.與目前通用的漢字16×l6點(diǎn)陣字模相比,其準確性和美觀(guān)性并不遜色.然而其單字所占內存卻由32個(gè)單元降至26個(gè)單元;另外使得每個(gè)單字顯示由原來(lái)的256個(gè)像素降至l82個(gè)像素,使顯示成本和空間均減少近三分之一.100×200點(diǎn)陣LED字屏,可顯示16×l6點(diǎn)陣漢字72個(gè),而l3×14點(diǎn)陣漢字便可顯示l05個(gè),且顯示效果并無(wú)太大差異.這無(wú)疑對單片機和嵌入式系統漢字顯示產(chǎn)品的開(kāi)發(fā)和應用,具有明顯的經(jīng)濟價(jià)值和實(shí)用意義.
3.51單片機13×14點(diǎn)陣縮碼漢卡
"51漢卡"依據我國的漢字特點(diǎn)和單片機的快速構字功能,在13×14點(diǎn)陣字?;A上,以縮碼形式開(kāi)發(fā)而成單片機漢卡的開(kāi)發(fā),應以目前通用的主流單片機為研發(fā)對象,還應在囊括國標一、二級漢字及常用字符的前提下,使內存占用必須降至主流單片機可尋址范圍內,且需留有足夠的檢字程序和用戶(hù)應用空間.另外,字模設計必須準確、美觀(guān).字模提取速度也必須滿(mǎn)足實(shí)用要求."51漢卡"的開(kāi)發(fā)正是依據原則,并達到了以上各項要求.
顧名思義,"51漢卡,即以MCS-51系列及其兼容單片機為研發(fā)對象.以51系列為代表的8位單片機,在過(guò)去、現在以及可以予見(jiàn)的將來(lái),都將是嵌入式系統低端應用的主流機型.此乃業(yè)界專(zhuān)家的共識.
"51漢卡"囊括了"GB2312-80"國標字庫的全部一、二級漢字,并增補漢字86個(gè);同時(shí)包括了大、小英文字母、阿拉伯數字等160個(gè)常用字符和不到4KB的構字程序,卻僅總共占用了不足66KB的內存.每字平均約占9.8個(gè)單元,相對于16×16點(diǎn)陣每字占32單兀內存而言,尚不到其三分之一.這對于具有相互獨立的64KB程序區和64KB數據區的51系列單片機而言,若適當配置內存,可為檢字程序和用戶(hù)留出90%以上的程序空間及相當數量的數據空間,對于一般用戶(hù)的應用,都將綽綽有余.
另外,為使"51漢卡''更便于使用和進(jìn)一步節省內存,在上述基礎上又開(kāi)發(fā)成一套簡(jiǎn)化版本,刪去了部分較偏僻的二級漢字.簡(jiǎn)化版本包括約5580個(gè)漢字,共占用內存58KB.實(shí)際上,按有關(guān)權威部門(mén)的統計,一般文本99%的文字是由2400個(gè)字寫(xiě)成的,因此使用簡(jiǎn)化版本,并配以簡(jiǎn)單的造字程序,一般亦可滿(mǎn)足我們的使用要求.
"51漢卡"所用字模,即我們開(kāi)發(fā)的完全可與16×16點(diǎn)陣字模媲美的I3×14點(diǎn)陣漢字字模.字模提取速度是我們最為關(guān)心的問(wèn)題之一.經(jīng)測試及實(shí)際使用表明,"51漢卡''的提模速度完全可滿(mǎn)足單片機漢字顯示的實(shí)用要求.
我們使用INTEL公司MCS-51經(jīng)典系列87C51單片機在24MHz頻率下測試,平均字模提取速度為2.1ms/字.因人的視覺(jué)暫留時(shí)間為0.1s,無(wú)論理論還是實(shí)際使用都表明,50字字模提取并顯示,并無(wú)遲滯和待機之感.即使在1?2MHz頻率下,20字取模,即點(diǎn)即出,在一般拼音檢字和少量漢字顯示中,完全可滿(mǎn)足使用要求.隨著(zhù)單片機技術(shù)的迅速發(fā)展,目前,
4."51漢卡"設計依據及說(shuō)明
"51漢卡"設計依據是,我國漢字雖然數量繁多,字型各異,但其中復合結構者占大部分,并素有"偏旁取義,正字取音"之說(shuō).如"寸"字與不同偏旁可組成"村"、"付"、"討"、"守"、"過(guò)"等字.因此"51漢卡"除單結構字基本以全碼設計外,復臺結構字多用相應的單體字及其偏旁,以結構代碼寫(xiě)成.利用單片機快速的單元積木式構字程序,便可迅速生成字模代碼.這既保證了提碼速度,又節省了大量的漢卡內存.
有關(guān)"51漢卡"的幾點(diǎn)說(shuō)明如下:
①凡漢字庫中簡(jiǎn)、繁體字都有的用簡(jiǎn)體.如"後"以"后"代,"馀"以"余"代等;
②《新華字典》未收入字,多未收入,如"酏"、"鼽"等字,但"婧"、"弳"等字仍收入;
③對于多體字,一般以常用字代,如"摺"以"折"代,"鏇"以"旋,代等,但"吒"不以"咤"代,"讎"不以"仇"代等;
④對通常已由其它字取代的字,都以這些字代替,如"崠"以"東"代,"肛''以"船"代等;
⑤二級漢字中,不單獨構成漢字的偏旁未收入;
⑥依據名篇名著(zhù),生活用語(yǔ)等,增補漢字86個(gè);
⑦收編大、小寫(xiě)英文字母、阿拉伯數字、標點(diǎn)符號等各種常用字符160個(gè).
5."51單片機漢卡"應用舉例
利用"51單片機漢卡",將使51系列單片機的漢字顯示輕而易舉,并可大為降低成本、體積和設計開(kāi)發(fā)的難度,為單片機在生產(chǎn)控制、信息通信、文化教育和日常生活等領(lǐng)域,特別是計算機終端和手持產(chǎn)品的開(kāi)發(fā)提供極大的便利和支持.?
我們現已初步開(kāi)發(fā)成"51漢卡"的"區位碼輸入法"和"拼音輸入法,檢字程序,并利用"51漢卡"成功地開(kāi)發(fā)了帶有廉價(jià)單片機控制器的LED漢字顯示屏.這不僅大幅度降低了成本費用.而且用戶(hù)可以通過(guò)單片機控制器,隨心所欲地改變顯示內容.
51硬件設計
CPU--87C51、12MHz晶振.


程序存儲器一1片EPROM?27C512.
數據存儲器一1片EPROM?27C512;1片EEPROM28C64A;1片6116.
控制器顯示屏一LCD?HY一19264B(深圳秋田視佳實(shí)業(yè)有限公司).
LED屏選240×16點(diǎn)陣.
本系統用標準小鍵盤(pán)檢字,一次可予選4000字;控制器LCD滿(mǎn)屏顯示l3×14點(diǎn)陣漢字56個(gè);LED屏滿(mǎn)屏顯示漢字19個(gè).
地址分配及用途如表l所列.

5.2程序設計框圖
程序設計流程如圖1所示.本系統采用12MHz晶振,若LCD取滿(mǎn)屏56字,換屏時(shí)有約0.1s的延時(shí),這對人的實(shí)際視覺(jué)并無(wú)大影響.
1 概述
GT23L24M1W是一款內含24X24點(diǎn)陣的漢字庫芯片,支持GB18030國標漢字(含有國家信標委合法授
權)及ASCII字符.排列格式為橫置橫排.用戶(hù)通過(guò)字符內碼,利用本手冊提供的方法計算出該字符點(diǎn)陣
在芯片中的地址,可從該地址連續讀出字符點(diǎn)陣信息.
1.1 芯片特點(diǎn)
● 數據總線(xiàn): SPI 串行總線(xiàn)接口
PLII 精簡(jiǎn)地址并行總線(xiàn)接口
● 點(diǎn)陣排列方式:字節橫置橫排
訪(fǎng)問(wèn)速度:SPI 時(shí)鐘頻率:20MHz(max.)
PLII 訪(fǎng)問(wèn)速度:130ns(max.) @3.3V
● 工作電壓:2.7V~3.6V
● 電流:工作電流:12mA
待機電流:10uA
● 封裝:SO20W
● 尺寸(SO20W):12.80mmX10.30mm
● 工作溫度:-20℃~85℃(SPI 模式下);-10℃~85℃(PLII 模式下)

1.2 字庫內容

字型樣張

2 引腳描述與接口連接
2.1 引腳名稱(chēng)

2.2 SPI 接口引腳描述
串行數據輸出(SO):該信號用來(lái)把數據從芯片串行輸出,數據在時(shí)鐘的下降沿移出.
串行數據輸入(SI):該信號用來(lái)把數據從串行輸入芯片,數據在時(shí)鐘的上升沿移入.
串行時(shí)鐘輸入(SCLK):數據在時(shí)鐘上升沿移入,在下降沿移出.
片選輸入(CS#):所有串行數據傳輸開(kāi)始于CE#下降沿,CE#在傳輸期間必須保持為低電平,在兩條
指令之間保持為高電平.
總線(xiàn)掛起輸入(HOLD#):
2.3 SPI 接口與主機接口電路示意圖
SPI 與主機接口電路連接可以參考下圖(#HOLD管腳建議接 2K 電阻 3.3V 拉高).

若是采用系統電壓為 5V的,則需要進(jìn)行電平轉換匹配連接 GT23 芯片,可以參考下圖(#HOLD 管腳建議接 2K 電阻 3.3V 拉高).

2.4 PLII 接口引腳描述

2.5 PLII 接口與主機接口電路示意圖
SPI/PLII_SEL(管腳內部有 100K 上拉電阻)接地,字庫芯片選擇 PLII 接口模式,與主機接口電路連接可以參考下圖.

2.6 PLII 總線(xiàn)接口尋址說(shuō)明
在 PLII 總線(xiàn)模式下,芯片內部有 3個(gè)地址寄存器,主機需要把要讀取數據的地址寫(xiě)入這 3個(gè)地址寄存器,然后再從數據寄存器中讀出數據.主機每讀一次數據寄存器,芯片內部的地址寄存器會(huì )自動(dòng)增一,從而使主機只寫(xiě)一次首地址,就可以連續讀取數據.

3 字庫調用方法
3.1 漢字點(diǎn)陣排列格式
每個(gè)漢字在芯片中是以漢字點(diǎn)陣字模的形式存儲的,每個(gè)點(diǎn)用一個(gè)二進(jìn)制位表示,存 1的點(diǎn),當顯示
時(shí)可以在屏幕上顯示亮點(diǎn),存 0的點(diǎn),則在屏幕上不顯示.點(diǎn)陣排列格式為橫置橫排:即一個(gè)字節的高位
表示左面的點(diǎn),低位表示右面的點(diǎn)(如果用戶(hù)按 word mode讀取點(diǎn)陣數據,請注意高低字節的順序),排
滿(mǎn)一行的點(diǎn)后再排下一行.這樣把點(diǎn)陣信息用來(lái)直接在顯示器上按上述規則顯示,則將出現對應的漢字.
3.1.1 24X24點(diǎn)漢字排列格式
24X24 點(diǎn)漢字的信息需要 72個(gè)字節(BYTE 0 – BYTE 71)來(lái)表示.該 24X24 點(diǎn)漢字的點(diǎn)陣數據是
橫置橫排的,其具體排列結構如下圖:

命名規則:

最大字符集及字數
S:GB2312 6,763漢字
M:GB18030 27,484漢字
T:GB12345 6,866漢字
BIG5 5,401 / 13,060漢字
U:Unicode V3.0 27,484漢字
聯(lián)系客服