stm32+lcd顯示漢字之GBK編碼

一、整體思路

最近在搞LCD顯示漢字、特殊圖形的問題。以前玩1602的時候自己做過字模,就是通過1602自帶的用戶DIY的一個存儲點陣區CGROM,把做好的字模轉化成點陣的數據存儲在CGROM中,最後把漢字顯示在1602上面。但是當時是用51做的,而且字模地址是固定存儲在1602中的,我們不用去管。在stm32+TFTLCD顯示漢字這個實驗上面,我的思路還是這個樣子,就是做好字模,然後根據地址找到對應漢字的點陣數據。那麼問題來了,在1602中每個字模都有自己的顯示編碼,那麼在stm32中,漢字有自己的顯示編碼嗎?

二、數組和字符串的關係

在說漢字的顯示編碼之前,我想先講一下數組和字符串的關係。字符串我們可以把它當成一種特殊的數組,編譯器識別到字符串時,會自動把它的地址分配到stm32的Flash裏面,這就意味着字符串本身就是一個常量。字符串的定義是用雙引號括起來的一段字符數據,這段數據最後會自動加上一個空字符爲結尾(‘\0’)。我們這裏直接上程序:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "string.h"

char arrBuf_1[3] = {'f','a','t'};
char arrBuf_2[4] = {'f','a','t','\0'};
char strBuf_1[]  = "fat";


int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2
	delay_init(168);  //初始化延時函數
	uart_init(115200);//初始化串口波特率爲115200
 	
	if(!strcmp(arrBuf_1,strBuf_1))
		{printf("arrBuf_1 與 strBuf_1 相等\r\n");}
	else if(!strcmp(arrBuf_2,strBuf_1))
		{printf("arrBuf_2 與 strBuf_1 相等\r\n");}
	else
		{printf("數組與字符串均不相等\r\n");}
		
	printf("arrBuf_1的地址爲:0x%x\r\n",arrBuf_1);
	printf("arrBuf_2的地址爲:0x%x\r\n",arrBuf_2);
	printf("strBuf_1的地址爲:0x%x\r\n",strBuf_1);
	
	printf("arrBuf_1中'f'字符常量的地址爲:0x%x\r\n",*arrBuf_1);
	printf("arrBuf_2中'f'字符常量的地址爲:0x%x\r\n",*arrBuf_2);
	printf("strBuf_1中'f'字符常量的地址爲:0x%x\r\n",*strBuf_1);
		
	
	while(1);
	
	return 0;
}

在這裏插入圖片描述
一個數組的數組名,就是指向該數組第一位成員的地址的指針,所以我們打印數組名,就是打印該數組第一個成員的地址,解除該指針則打印的是該地址裏保存的值,對應程序而言就是’f’的ASCII碼值,以16進制形式體現。

通過簡單的比較我們可以看到,字符串就是把每個字符轉化成單引號字符常量,存儲在對應的數組成員中,且最後一位自動加入’\0’空字符表示結尾。上面三個數組的地址是不同的,但是每個數組中存儲的單引號字符常量的值卻是相同的,這就說明單引號字符常量在keil編譯器下,被自動識別爲對應的ASCII碼值。ASCII碼值我們大可以理解爲每個字符的顯示編碼。

三、GBK碼

keil這個編譯器會自動把有ASCII碼值的字符常量識別爲對應的ASCII碼值,沒有對應ASCII碼值的常量比如漢字日語等,我們也有一套特殊的編碼來表示,這個編碼就是GBK碼。

GBK碼有16位,兩個字節組成。
在這裏插入圖片描述
高字節的範圍爲:0x81~0xFE,每一位都稱爲一個區,總共有126個區。
低字節的範圍爲:0x40~0x7E , 0x80~0xFE,低字節總共由兩部分構成,每一位都稱爲一個段,總共有190個段。

GBK碼有126個區,190個段,每一個區的每一個段都可以表示一個漢字,那麼GBK碼總共可以表示126 * 190 = 23940 個漢字。足以滿足我們大多數場景下的使用。在keil環境下,編譯器自動的將漢字識別爲對應的GBK碼。

但是GBK碼只是一個顯示編碼,每個顯示編碼對應的字模還是要由我們來做,做好以後我們把存儲漢字字符的字模(點陣)的數組稱爲GBK庫(這個有很多軟件可以幫我們生成)。但是要從這個庫裏找到對應的漢字,就需要知道每個漢字在這個庫裏的偏移量,通過每個漢字的GBK碼,我們可以算出來對應的偏移量:
當GBKL < 0x7F時,HP = ((GBKH - 0x81)*190+GBKL-0x40) * (size * 2)
當GBKL > 0x7F時,HP = ((GBKH - 0x81)*190+GBKL-0x41) * (size * 2)
GBKH 爲高字節,GBKL 爲低字節,低字節的兩部分中間有個斷層0x7F,所以要分情況判斷其偏移。HP即爲求出的漢字顯示編碼在GBK庫中的偏移量,size爲顯示漢字的大小。

我們這裏舉個例子,以字符串“你好啊”爲例,分析每個漢字的GBK碼:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "string.h"

char arrBuf_1[3] = {'f','a','t'};
char arrBuf_2[4] = {'f','a','t','\0'};
char strBuf_1[]  = "fat";
const char* strBuf_2 = "你好啊";

int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2
	delay_init(168);  //初始化延時函數
	uart_init(115200);//初始化串口波特率爲115200
 	
	if(!strcmp(arrBuf_1,strBuf_1))
		{printf("arrBuf_1 與 strBuf_1 相等\r\n");}
	else if(!strcmp(arrBuf_2,strBuf_1))
		{printf("arrBuf_2 與 strBuf_1 相等\r\n");}
	else
		{printf("數組與字符串均不相等\r\n");}
		
	printf("arrBuf_1的地址爲:0x%x\r\n",arrBuf_1);
	printf("arrBuf_2的地址爲:0x%x\r\n",arrBuf_2);
	printf("strBuf_1的地址爲:0x%x\r\n",strBuf_1);
	
	printf("arrBuf_1中'f'字符常量的地址爲:0x%x\r\n",*arrBuf_1);
	printf("arrBuf_2中'f'字符常量的地址爲:0x%x\r\n",*arrBuf_2);
	printf("strBuf_1中'f'字符常量的地址爲:0x%x\r\n",*strBuf_1);
		
	printf("strBuf_2漢字常量‘你’的GBK碼高位碼爲:0x%x\r\n",*strBuf_2);
	printf("strBuf_2漢字常量‘你’的GBK碼低位碼爲:0x%x\r\n",*(strBuf_2+1));
	printf("strBuf_2漢字常量‘好’的GBK碼高位碼爲:0x%x\r\n",*(strBuf_2+2));
	printf("strBuf_2漢字常量‘好’的GBK碼低位碼爲:0x%x\r\n",*(strBuf_2+3));
	printf("strBuf_2漢字常量‘啊’的GBK碼高位碼爲:0x%x\r\n",*(strBuf_2+4));
	printf("strBuf_2漢字常量‘啊’的GBK碼低位碼爲:0x%x\r\n",*(strBuf_2+5));
	
	while(1);
	
	return 0;
}

在這裏插入圖片描述
strBuf_2爲指針名(數組名),指向第一個成員的地址,解除運算以後就是第一個成員的值,對應漢字即爲GBK碼,因爲GBK碼爲16位,所以我們連續打印6個字節的數據,每兩個組合即爲對應漢字的GBK碼值。然後我們根據得到的GBK碼值,帶入上面的公式,算出來每個漢字在GBK庫裏的偏移量,根據每個漢字在GBK庫中的偏移量,我們就可以定位到具體的漢字。

以上就是漢字顯示的基本原理了,下一篇文章給大家介紹一下顯示漢字的步驟,在EEPROM上建立自己的字庫,以及如何在LCD上顯示特殊圖形(自己DIY)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章