到目前為止,似乎如果我們要想做一個電話號碼記事本之類的電子助手已經萬事俱備了,但真正開始做的時候才發現,我們還沒有教會AVR如何去寫字。如果說,我們前面已經能在LCD上畫出“壁畫”的話,那么要想讓別人看懂你記錄的到底是什么鬼畫符還需要一點點關于“甲骨文”的掃盲。事實上,大家約定俗成的固定大小的圖片集或其子集就是一個被尊稱為字庫的神圣典籍。在這個圣經里面記錄的是一種被稱之為“字模碼”的東西,對于我們,這種信息可能相當抽象,但是借助LCD,那么字模碼就是一個我們能看懂的字符在顯存中存在的模式。
不得不承認,到目前為止,似乎如果我們要想做一個電話號碼記事本之類的電子助手已經萬事俱備了,但真正開始做的時候才發現,我們還沒有教會AVR如何去寫字。如果說,我們前面已經能在LCD上畫出“壁畫”的話,那么要想讓別人看懂你記錄的到底是什么鬼畫符還需要一點點關于“甲骨文”的掃盲。事實上,大家約定俗成的固定大小的圖片集或其子集就是一個被尊稱為字庫的神圣典籍。在這個圣經里面記錄的是一種被稱之為“字模碼”的東西,對于我們,這種信息可能相當抽象,但是借助LCD,那么字模碼就是一個我們能看懂的字符在顯存中存在的模式。
關于這些字模碼是如何排列的,自古以來就有數不清的模式。終于有一天,一群中國人伴隨著新中國站了起來,制定了一個叫做國標的標準(GB),根據這個標準,祖國大地的字模碼才有了統一的目錄,而查詢這個目錄的方法已經逐漸被人們所淡忘,吹落那源自電報碼的書籍紅色封皮上的滄桑,用手輕輕撫摸封皮上的的文字:“區位碼”,我們發現,其實他包含了6000個漢字的一級字庫其他一些由非常用字組成的多級字庫。
在西方,埃尼阿克的故鄉,一群依靠技術侵略世界的瘋子根據自己半通不同的習慣制定了一個由128個字符組成的交換標準稱之為ASCII碼,由于技術大潮的沖擊,世界妥協了。
這一切的一切都無法改變字庫只不過是圖片集和的本質。所以,敢于抵抗強權的人們在自己的領土上堅持著自己的信念——我們稱之為“小字庫技術”。甚至有些人堅持使用圖片記事,那么自然的被視作是“無字庫技術”。
世界在前進,即便后來世界技術的格局發生了怎樣的變化,即便一些曾經約定的不合理的東西也會作為最底層的協議支持者新世界,就像是烏龜駝著的世界。任何觸動這些底層的行為都會受到世界的背叛,所以,拋棄情感上的東西,我們來研究一下ACSII的構成原理和實現方法。
對不起大家,我寫這些東西的目的就是面向初學者。事實上,如各位所說,我并非高手,所以很多地方漏出了類似“內存映射”之類的馬腳。這里我只想做一點解釋,只有我弄懂了的東西,我才能用通俗的方法和大家解釋,我一竅不通的東西就只好原樣照搬打腫臉充胖子了。呵呵。還請原諒。事實上,就拿“內存映射”這個問題來說,我使用的大段大段的文字來解釋這個概念,因為即便是羅嗦,我也最多只能用“屏幕的一塊區域對應內存的一塊區域”這樣仍然抽象的話語來解釋,反而顯得我騙稿費一般,所以不如先提出一個名詞,把解釋溶化在后面的文字中。
本來,開篇就說得很清楚,我寫這些東西的目的不是等大家來喊牛,姑妄言之,姑妄聽之,水平有限,沒有刻意去追求什么文本格式上的東西,自然可能不對大家胃口,我以后注意就是了。但是,說回來,寫這些東西的心情和大家寫伯克的時候差不多,多半是吐吐心中不吐不快的東西罷了,所以,由著性子,演繹也罷,說明書也罷,文檔整理稿也罷,那要看那一陣子我正在看什么書了,如果哪天我不幸開始看小說,來一個欲知后事請聽下回分解也說不定。
我的專業本來就是軟件工程,所以寫出這些文字,非常自然。
1 ASCII字符集
ASCII(American Standard Code forInformation InterChange)——美國通用信息交換編碼。他是現在流行的眾多編碼的榜樣,雖然使用僅僅7位二進制表示(通常用一個字節表示),但是卻是眾多編碼系統的基礎,比方說16位二進制為組成的Unicode編碼,證據就是,只要在ASCII碼前面加9個零就成完成了轉換。當然,仍然有不聽話的,比方說IBM老大的EBCDIC碼(大型計算機系統上用的)。
大家都注意到了7位二進制表示的編碼顯然只能有128個字符的容量,那么,用一個字節256個字符的容量豈不是造成了浪費?于是,現在PC機上普遍通用的IBM擴展ASCII碼從128~255開始擴展了128個字符——注意,這128個字符并不是通用的,即便在我們能接觸的大部分場合他們都有效,但是記住他們的“非常任理事國”的身份是擁有重大意義的。
比方說,我們的顯示系統只需要顯示E文字母和數字還有一些標點符號,那么,干什么要這些無用的字符充數呢?要知道,一個字母存儲起來需要至少8*7的點陣(7個字節)啊!事實上,由于幾乎所有通用單片機內部都不帶有ASCII字庫(字模碼),所以,我們必須把他們存儲起來,并且還不能打破原有的存儲模式,不然通過ASCII碼作為索引我們就找不到他們了。為了完成對字模庫的簡化,我們需要知道他們的構成方式,然后再考慮如何去獲取一個已知的標準字模庫,并按照我們設計的方法去簡化他……可憐的AVR,存儲器又要吃緊了。
從古老的教科書上,很容易獲得一張ASCII編碼表。因為大家都是搞Embedded System開發的(為了顯示大家工作的高深程度,請允許我掉書袋),所以,這里我更多的要講述一下ASCII編碼一些不太被人注意的特性,一些只有從二進制角度才容易看出的特性。
1)ASCII碼由7位二進制組成;
[6][5][4][3][2][1][0]
2)[6:5]為用來表示ASCII編碼的組分類
控制字符組(顯示不需要顯示的東西)
數字字符和標點符號組
大寫字符和特殊字符
小寫字符和特殊字符
3)只要把大寫字母的第6位也就是[5]置位就是現了到小寫字母的轉換,反之亦然;
4)數字的ASCII碼[3:0]位的值與它要表示的數值相同;
例如:
“0” 0x30
“1”0x31
依照上面的編碼規則,ASCII碼的字模碼文件存儲的方式為:
char c;
……
fAddress = c* 8 * 16;//超級簡單哈,這是計算機系統上標準8*16的ASCII字符集
fAddress = c* 8 * 8; //這是計算機系統使用的8*8小字符集
聰明的大家已經知道如何在存儲器中獲得字模碼了吧?
就是訪問存儲的“基地址+fAddress”就可以了。
為了便于后面大家實現漢字顯示時候的代碼移植(回避全角和半角問題),我們使用8*16的大字符集,至于你想使用小字符集,那么就看你的愛好了。
2 How toget them?
這里我們來順手說說字模碼獲得的問題。
不可否認,現在網上很多兄弟寫的字模制作軟件水平之高,已經到了令人嘆為觀止的地步,只可惜當時我學習字庫問題的時候,尚且沒有解決溫飽,更不用說上網了。而且,這些字模軟件無不在客觀上支持了字模的“無政府主義”,小字庫和無字庫技術在一些不恰當的場合也被大量濫用,嚴重影響了接著寫你代碼同志的心情……鬼知道原來跳槽的家伙如何定義那該死的字庫的,所以,提倡在何時的場合使用標準的字模庫還是非常有必要的。
首先說說一種簡單的獲取字模的方法。
不知道還有多少人記得UCDOS,中國漢字操作系統的“希望”。金山WPS,CCED……TX.com,這些東西讓人難忘啊。我們的字模庫很容易從這樣具有我國獨立知識產權的系統中獲得。所有的東西都放在
UCDOS
目錄下面。我們選取這次需要的文件“ASC16”。順手說下,漢字庫也可以從里面獲得“HZK16”。其他的字模庫在
UCDOSFNT
目錄下面。
還有一種BT的方法可以獲得8*8的字庫。大家記得BIOS吧……呵呵,利用TC寫一個中斷程序,直接讀出來……哈哈。后面有機會我會附上代碼,如果我能記得地址的話。
3 字庫減肥
查看一下Mega8的Datasheet,上面赫然寫著8K Flash,再看看ASC16的大小4K,我不知道有多少人不會打寒顫。更不用說260多K的漢字庫了,看來要么外擴存儲器,要么只能選擇西文顯示,并且對ASC16庫進行減肥。
其實,減肥并不是一個可以稱之為技術的行為,總原則就是丟棄無用的部分,同時修改索引方式以保證外界使用減肥前方文字魔窟文件的索引方式不至于出錯就可以了。就拿ASC16的減肥工作來說吧,很顯然,我們并不需要擴展字符128~255的那個部分,可以減小大小為16*128 = 2K的大小,再加上基本字符基的四個區中,控制字符區顯然也是可以舍棄的,所以,還可以減少16*32 = 512B的大小,也就是說,剩下的文件只有1.5K大小了,哈哈,總算可以接受了。當然如果你選擇了8*8的字模,就更小了。
以上完成的只是第一步,借助類似UltraEdit這樣的編輯工具都可以做到,然后我們再把字模庫寫成數組的形式,比方說:
const charASC_Lib[][16] = {
……
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
……
}
包含入頭文件,就可以了。
下面我們需要一個訪問函數,用來安全的有效的訪問到我們需要的字模庫:
char*getASCLIB(char ASC)
{
if ((ASC <32 )|| (ASC > 127))
{
returnASC_Lib[CharStringNULL]; //需要一個空字符串作為安全返回
}
returnASC_Lib[ASC];
}
配合12864頭文件中公版中都有的那個顯示圖片的函數,就可以顯示字符了。例如:
voidDispBITMap(const char *String,char StringLength,char X,char Y,char DispModel);
我們還可以再對這個函數包裝一下,實現16 * 4的文本模式。使用CLocate(x,y)來定位字符,用Print("")來顯示字符串,用PrintN()來顯示數字……哈哈。這一部分就留給大家自己來做了,不過是幾個函數加宏定義罷了,相信自己簡單的。
至于如何實現任意位置顯示字符,還有一些字符特效的實現,在下一節里面具體說明。
這是我寫的函數
/********************************************************
* 函數說明:讀取顯示數據指令 *
* 輸出: 顯示數據 *
********************************************************/
chargetLCD12864Data(void)
{
char TempData= 0;
char a = 0;
LCD12864_SetModel_Data;
LCD12864_SetModel_Read;
LCD12864_SetEnable;
LCD12864_SetDisable;
LCD12864_SetEnable;
asm("nop");
TempData =ReadDataPORT;
評論
查看更多