1. 程式人生 > >跟著原子學習stm32之漢字顯示

跟著原子學習stm32之漢字顯示

       學習stm32有2年的時間了,但是也只是有些基礎的瞭解。為了深入的學習stm32應用,從新拿起原子寫的《stm32開發指南》來深入的學習,所以這裡太基本的東西不講。文中有可能會搬一些原子大神的東西。

       字型檔顯示的整個過程可以概括為:

       根據漢字的GBK碼找字型檔碼。根據字型檔碼以bit的形式在顯示屏上顯示出來。

       整個過程主要包括兩個難點:

1、GBK碼和字型檔碼的儲存。

2、如何根據漢字查詢碼值,然後顯示出來

       解決第一個問題。

       本節的應用是將UNIGBK檔案、GBK12檔案、GBK16檔案從SD卡中移植到W25Q64中,首先關於各個檔案的生成請看原子寫的《stm32開發指南》中46章介紹。然後程式的開始首先要檢測SD卡中各個檔案是否存在,如果存在的話,則根據要求做移植,那麼問題是移植到哪裡呢。對於W25Q64,我的觀點是它是一個死的儲存機構。你可以隨心所遇的選擇移植的位置。但有個問題,如果你使用了某個區域做其它用途,如實驗資料的記錄等,千萬不要覆蓋了它們的位置。另外要計算下你選取的首地址到W25Q64的最後地址能否足夠大盛的下這幾個檔案。考慮了這兩點,你就可以做接下的操作了,那就是判斷移植!這裡有個小問題,就是在第一次完成移植後,W25Q64中有了字型檔檔案。可以設定一個地址為標誌為地址,用來表明當前W25Q64中是否存在字型檔,這樣每次初始化判斷一下可以避免字型檔的重複寫入。

       解決第二個問題。

       GBK碼是漢字內碼擴充套件規範,字型檔碼(需要自己製作,詳細製作方法見原子stm32開發指南)對應GBK碼的編碼形式的存在。即GBK碼中一個漢字佔兩個位元組,第一個位元組為 0X81~0XFE,第二個位元組分為兩部分,一是 0X40~0X7E,二是 0X80~0XFE。
共有23940個漢字。而字型檔碼中一個漢字所佔位元組數是不固定的,他根據漢字的大小來確定(即使用軟體生成字型檔檔案時設定的寬和高決定的)。它是以bit的形式將漢字拼出來,如果要顯示的漢字大,則該漢字佔用的位元組數就多。由於字型檔碼是根據GBK碼來製作的,所與兩個檔案中的漢字順序是相同的。當我們使用GBK碼去查詢他對應的要顯示的漢字時,需要先通過GBK碼計算他在字型檔中是第幾個漢字,然後根據單個字的大小計算字的編碼偏移首地址。

       這是漢字顯示部分我讀原子《stm32開發指南》的一些整理。沒涉及到具體。

       在使用漢字顯示時,原子在文中還提到了CC936的改編,其中的兩個UNI2GBK和GBK2UNI陣列單獨放在一個檔案中生成了一個UNI2GBK.BIN檔案。這兩個資料有個特點:即4個位元組表示一個漢字(uni20em陣列是前兩個位元組為unicode碼,後兩個位元組為其對應的GBK碼;oem2uni陣列是前兩個位元組為GBK碼,後兩個位元組為其對應的unicode碼),所以除以4,代表一共有多少漢字,然後在srcsrc == p[i * 2]中乘以2 是因為兩個位元組為一個數組元素,即一個漢字佔陣列的兩個元素。所以對應第N個漢字,它在陣列中位置為N*2。最後的輸出為c = n ? p[i * 2 + 1] : 0;表明輸出查詢到的GBK碼(unicode碼)後面對應的unicode碼(GBK碼)。

      它的程式碼是

<span style="font-size:14px;">WCHAR ff_convert (	/* Converted code, 0 means conversion error */
	WCHAR	src,	/* Character code to be converted */
	UINT	dir		/* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
)
{
	WCHAR t[2];
	WCHAR c;
	u32 i, li, hi;
	u16 n;			 
	u32 gbk2uni_offset=0;		  
						  
	if (src < 0x80)c = src;//ASCII,直接不用轉換.
	else 
	{
 		if(dir)	//GBK 2 UNICODE
		{
			gbk2uni_offset=ftinfo.ugbksize/2;	 
		}else	//UNICODE 2 GBK  
		{   
			gbk2uni_offset=0;
		}
		//if(UK_FLAG)//存在 		    
		{
			/* Unicode to OEMCP */
			hi=ftinfo.ugbksize/2;//對半開.
			hi =hi / 4 - 1;
			li = 0;
			for (n = 16; n; n--)
			{
				i = li + (hi - li) / 2;	
				SPI_Flash_Read((u8*)&t,ftinfo.ugbkaddr+i*4+gbk2uni_offset,4);//讀出8個位元組  
				if (src == t[0]) break;
				if (src > t[0])li = i;  
				else hi = i;    
			}
			c = n ? t[1] : 0;  
 		}
		//else c=0;
	}
	return c;
}		   </span>

       我查看了程式的程式碼,在原子的例程中,除了改編後的mycc936呼叫了UNI2GBK檔案其它地方沒有呼叫他,程式中也沒有間接呼叫。那麼UNI2GBK檔案存在的意義是什麼?

       在FATFS中存在這樣的定義:

<span style="font-size:14px;">#define	_USE_LFN	2		/* 0 to 3 */
#define	_MAX_LFN	255		/* Maximum LFN length to handle (12 to 255) */
/* The _USE_LFN option switches the LFN support.
/
/   0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
/   1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
/   2: Enable LFN with dynamic working buffer on the STACK.
/   3: Enable LFN with dynamic working buffer on the HEAP.
/
/  The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
/  Unicode handling functions ff_convert() and ff_wtoupper() must be added
/  to the project. When enable to use heap, memory control functions
/  ff_memalloc() and ff_memfree() must be added to the project. */


#define	_LFN_UNICODE	0	/* 0:ANSI/OEM or 1:Unicode */
/* To switch the character code set on FatFs API to Unicode,
/  enable LFN feature and set _LFN_UNICODE to 1. */</span>

       其中的_USE_LFN表示是否支援長檔名,在支援長檔名的情況下,可選擇是否把長檔名的的字元資料在FATFS介面上轉為UNICODE碼。可以看到這是在FATFS中用到了UNI2GBK檔案的地方,實際上如果我們僅僅測試將中文名列印到顯示屏上的話,是用不到UNI2GBK檔案檔案的。

       在ARM中文字是以GBK編碼存在,但是在WINDOWS系統值,文字的存在形式是UNICODE編碼,這樣,當應用到FATFS時,UNICODE與GBK的轉換就必不可少了!

以上為看原子講義的小總結,比較籠統,歡迎批評指正