stm32+lcd顯示漢字之DIY圖形及導入字庫

一、建立自己的點陣集

上一篇博客,給大家介紹了在LCD上顯示漢字/特殊圖形需要知道對應的顯示編碼(GBK碼/ASCII碼),顯示編碼對應着每個圖形的點陣集(數組),我們可以通過這個點陣集,將自己DIY的圖形顯示在LCD上面。現在先說一下怎麼做一個自己的點陣集。一般情況下,用PCtoLCD2002這個軟件,可以自動幫我們生成每個圖形對應着的點陣集。
​​​​
​​​​​​​​​​​​​​​​​​在這裏插入圖片描述
打開這個軟件先點1選擇字符模式,再點2,3設置每個圖形的大小,然後從4處在這裏插入圖片描述寫入我們的要顯示的圖形。生成字模之前點擊齒輪(設置)來設置我們生成字模的格式。
在這裏插入圖片描述
一般的我們選擇默認就好了,更改一下點陣大小和顯示格式就行。到這一步,我們就可以生成自己的圖形的點陣集了。
在這裏插入圖片描述
點擊生成字模後,我們便得到了這三個漢字的字模了。返回最開始,我們選擇模式時更改爲圖形模式,便可以DIY自己想要顯示的圖形,自己可以選擇圖形的大小,這裏我選擇64*64大小的點陣集來DIY。
在這裏插入圖片描述
至此,我們就得到了4個數組,每個數組顯示一個圖形。

二、將自定義圖形顯示在LCD上

我們先定義3個文件,show.c show.h graph.h,並且將上面的4個數組放在graph.h裏。
在這裏插入圖片描述
因爲特殊字符囧並沒有自己的顯示編碼,所以我們不採用顯示編碼方式顯示圖形,而是直接通過數組名來顯示。我們直接上函數:

//顯示一個DIY圖形
//x,y:圖形顯示的座標
//num:第幾個圖形
//size:圖形大小
//mode:0,正常顯示,1,疊加顯示	
void Show_Graph(u16 x,u16 y,u8 *num,u8 size,u8 mode)
{
	u8 temp;
	u16 t,t1;
	u16 y0 = y;
	u16 x0 = x;
	u16 csize=(size/8+((size%8)?1:0))*(size);//得到字體一個字符對應點陣集所佔的字節數	 
	for(t = 0;t < csize;t++)
	{
		temp = num[t];
		for(t1 = 0;t1 < 8;t1++)
		{
			if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);
			else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR); 
			temp<<=1;
			y++;
			if((y-y0) == size)
			{
				y=y0;
				x++;
				break;
			}
			if((x-x0) == size)
				{
					x = x0;
					break;
				}
		}
	}
}

這個函數是把原子的Show_Font()顯示漢字函數改了改,其實本質就是取得字模的差別,Show_Font()裏通過讀取W25Q128的相應地址來取得字模,這裏我們自己建立了字模,直接顯示即可。下面上主函數:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "show.h"
#include "graph.h"


int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2
	delay_init(168);      //初始化延時函數
	uart_init(115200);		//初始化串口波特率爲115200
	
	LED_Init();					  //初始化LED
 	LCD_Init();           //初始化LCD FSMC接口
	POINT_COLOR=RED;      //畫筆顏色:紅色
	
	Show_Graph(100,100,(u8*)jiong_64,64,0);
	Show_Graph(25,200,(u8*)str1,16,0);
	Show_Graph(75,200,(u8*)str2,16,0);
	Show_Graph(125,200,(u8*)str3,16,0);
	
  while(1);
}

在這裏插入圖片描述
通過圖片,我們可以看到,原來建立好的點陣集(數組),都已經顯示在了LCD上面。

三、通過GBK碼尋址顯示漢字

上面我們是通過自己建立字模,來顯示特定的幾個漢字,但是在一個完整的系統裏,可能需要大量的漢字來供我們使用。這裏就要用到我們的GBK庫了,通過對應漢字在這個庫的偏移量,找到相應漢字的字模,並且顯示出來。

大體的思路是,我打算用EEPROM存儲GBK庫,GBK庫我們可以從網上隨便找一個都行,這裏我還是用原子的SYSTEM文件夾下面自帶的GBK16這個庫來做。因爲探索者板載的24C02大小爲2K字節,不足以存儲常用的三種大小的庫,所以選擇一箇中間大小。我們這裏找到SD卡根目錄下SYSTEM/FONT文件夾裏的字庫:
在這裏插入圖片描述
我們可以看到3個不同大小的GBK字庫,和一個UNIGBK.BIN,這個文件一般用在FATFS文件系統時支持中文路徑來使用的。如果不需要支持中文路徑的話可以不加。GBK16的大小爲749k字節,大於24C02的2K字節。!!!!方案錯誤,24C02大小不足以存儲字庫!

我們這裏只能說一下步驟了(雖然實現不了,但是我想看看結果會是什麼樣。。):
1、基於FATFS文件系統,通過SD卡把GBK16這個庫的文件讀取出來,然後寫入到EEROM裏面。
2、編寫顯示漢字函數,其入口參數爲每個漢字字符的GBK碼。
3、調用顯示函數,將要顯示的漢字顯示在LCD上面。

理論上講,這三部有關文件的操作只在SD卡上運行,所以EEPROM可以不用移植到FATFS文件系統裏面,我們讀取SD卡上的數據,然後存入EEPROM當中即可。

首先FATFS文件管理,把SD卡里的文件讀取出來,然後寫入到24C02中,文件路徑爲:
u8*const GBK16_PATH="/SYSTEM/FONT/GBK16.FON";
這裏上一下相關程序:

u8 updata_fontx(u16 x,u16 y,u8 size,u8 *fxpath)
{
	u8 res,rval = 0;
	u16 bread;
	u32 flashaddr = 0,offset = 0;
	FIL* ftemp;
	u8* tempbuf;
	fupfont.upfont_OK = 0xFF;
	tempbuf = (u8*)mymalloc(SRAMIN,4096);
	if(tempbuf == NULL) rval = 1;
	ftemp = (FIL*)mymalloc(SRAMIN,sizeof(FIL));
	if(ftemp == NULL) rval = 1;
	res = f_open(ftemp,(const TCHAR*)fxpath,FA_READ);
	if(res) rval = 2;
	printf("f_open的res的值爲:%d\r\n",res);
	if(rval == 0)
	{
		fupfont.gbk16_addr = EERPOM_ADDR + sizeof(fupfont); //字庫開始地址
		fupfont.gbk16_size = ftemp->fsize; //字庫大小	
		flashaddr = fupfont.gbk16_addr ;//GBK16字庫起始地址
		while(res == FR_OK)
		{
			res = f_read(ftemp,tempbuf,4096,(UINT*)&bread);
			printf("bread的值爲:%d\r\n",bread);
			if(res != FR_OK) break;
			AT24CXX_Write(flashaddr + offset,tempbuf,4096);
			offset += bread;
			fupd_prog(x,y,size,ftemp->fsize,offset);	 			//進度顯示 fftemp->fsize具體每個文件的大小,我們可以掌握
			if(bread != 4096)break;
		}
		f_close(ftemp);
		fupfont.upfont_OK = 0xAA;
		AT24CXX_Write(EERPOM_ADDR,(u8*)&fupfont,sizeof(fupfont));	
	}
	myfree(SRAMIN,ftemp);	//釋放內存
	myfree(SRAMIN,tempbuf);	//釋放內存
	return res;
}

這裏要說一下這個結構體,_up_font fupfont :

//這個結構體使用關鍵字__packed取消了編譯器自動優化結構體地址,所以這個結構體總共9字節大小!
//我們把這個結構體存儲到EEPROM中,即可知道字庫是否更新,和存儲字庫地址
__packed typedef struct
{
	u8 upfont_OK;   // 設定這個值爲0xAA時,更新字庫成功!否則爲0xFF
	u32 gbk16_addr; // GBK16字庫的地址
	u32 gbk16_size; // GBK16字庫的大小
}_up_font;

這個結構體標註了字庫地址,字庫大小和是否更新標誌位,因爲我們加了__packed關鍵字,所以我們結構體變量佔用了9字節空間。我們把這9字節空間放進24C02的首地址中,幫助我們標識字庫基本信息。那麼我們的字庫數據就要放在這9字節數據後面,AT24CXX_Write(flashaddr + offset,tempbuf,4096);//flashaddr 即爲9字節大小

至此,我們通過SD卡根據文件路徑讀取文件信息,並將信息寫入24C02中,然後我們根據入口參數(一般爲字符串)GBK碼的大小,算出其偏移,根據偏移在GBK庫中找到相應的字模讀取出來,然後通過將其打印在LCD屏幕上。通過入口參數(字符串等)得到GBK碼的方法可以參照我的上一篇博客,裏面有很詳細的演示:
stm32+lcd顯示漢字(一)

因爲打印字模數組的方法我們上面演示過了,所以我們直接上從24C02中,取出字模的函數:

//這個函數其實就是讀取到字符後,取出其GBK碼,然後通過GBK碼,找到其對應的字模數組。
//code:輸入的字符,通過*運算,可以取其GBK碼
//mat:通過GBK碼,判斷每個漢字的字模數據
void Get_Font_Mat(unsigned char* code,unsigned char* mat,u8 size)
{
	unsigned char qh,ql;
	unsigned char i;					  
	unsigned long foffset;
	u8 csize=(size/8+((size%8)?1:0))*(size);//得到字體一個字符對應點陣集所佔的字節數	 
	qh = *code;
	ql = *(code+1);
	if(qh<0x81||ql<0x40||ql==0xff||qh==0xff)//非 常用漢字
	{   		    
	    for(i=0;i<csize;i++)*mat++=0x00;//填充滿格
	    return; //結束訪問
	}
	if(ql<0x7f)ql-=0x40;//注意!
	else ql-=0x41;
	qh-=0x81;   
	foffset=((unsigned long)190*qh+ql)*csize;	//得到字庫中的字節偏移量  		  

	AT24CXX_Read(foffset+fupfont.gbk16_addr,mat,csize);
}

fupfont.gbk16_addr 就是剛纔說的結構體大小,字模存儲在這個大小後面,我們通過入口參數,算出偏移,然後用偏移+fupfont.gbk16_addr得到一個地址,從這個地址開始取出csize大小的字模,把它放到mat中去。至此,通過GBK尋址顯示漢字的方法我們已經說完了。
在這裏插入圖片描述
實驗的結果如下:
在這裏插入圖片描述
在這裏插入圖片描述
第一幅圖是在更新字庫,第二幅圖即爲將對應字符顯示在LCD上面,因爲24C02的大小限制,導致我白忙活了一下午加一晚上,這也是粗心導致把。正常的顯示如下:
在這裏插入圖片描述

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