今天玩了會液晶屏,原來顯示漢字都是也取模軟件區模后在液晶屏上顯示,顯示內容改變以后還需要重新做字模,比較麻煩。這兩天有時間,參考網友資料,實現了讀取漢字的內碼從SD卡的GB2312點陣字庫讀取點陣在液晶屏上顯示,字庫的生成軟件用的是易木雨的點陣字庫生成器。能生成很多種語言的字庫。做完了讀取顯示后,我自己又琢磨了一下,簡單的實現了從SD卡中讀取txt文檔然后再液晶屏上顯示txt內容。
取模過程注意點陣的寬、高和字體大小的關系,寬、高是我們在液晶屏上要顯示的像素大小,字體是漢字大小,如果寬、高一定,字體大小太到的話,字在液晶屏上只能顯示一部分,可以在左側的預覽區看出來,如果字體在寬高像素點的范圍內則可以在液晶上顯示完整的字,如果不能顯示完整則可以調整寬高或者字體大小。
國標字有GB2312和GBK編碼,GBK完全兼容GB2312包括內碼的兼容,而且GBK字庫增加了很多字。漢字都是用的兩個字節表示,第一個字節是區號,第二個字節是在區內的相對偏移位置。通過內碼來獲取字庫內的偏移位置,偏移位置與內碼和生成字庫的寬高都有關系。我生成的GB2312字庫是16*16個像素點顯示一個漢字,那在字庫內的偏移位置:
offset=32* ( (H-0xa1)*94+(L-0xa1) )
H 表示內碼的高字節,L表示內碼的低字節。GB2312高字節是0xa1~0xfe表示區號,每個區有94個字節所以*94得到區的相對位置,L表示內碼低字節也是從0xa1~0xfe,L-0xa1 得到的是在當前區內的偏移位置。 因為每個漢字有16*16=32個自己組成,所以最后乘以32得到在點陣字庫中的偏移位置,從這個位置開始取出32個字節的點陣數據然后打點顯示就可以把一個漢字顯示出來了。
獲取點陣的代碼如下
FATFS fs1; // 掛載SD卡的分區用
FIL f1; // SD卡中字庫的文件描述符
FIL ftxt; // 要讀取的txt文檔的文件描述符
u8 fnGetChinese(u8 *p,u8 *buff) // 形參是要讀取的漢字
{
u8 res=0;
u8 H8,L8;
UINT num;
H8=*p;
L8=*(p+1);
f_mount(&fs1,"",1); // 掛載SD卡
res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ); // 打開SD卡下的點陣字庫
if(res!=0) // 判斷點陣字庫是否打開成功
{
fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);
printf("res=%x",res);
return 1;
}
else
{
fnShowString(10,120,"open ok",16,RED,WHITE,0);
}
f_lseek(&f1,32*((H8-0xa0-1)*94+(L8-0xa0-1))); // 在字庫文件中做偏移取出32個字節的點陣數據
res=f_read(&f1,buff,32,&num);
f_close(&f1); // 讀完后關閉點陣字庫文件
f_mount(&fs1,"",NULL); // 卸載SD卡
return 0;
}
這個是得到漢字點陣的實現過程,得到點陣數據后就可以在液晶上打點實現漢字的顯示,具體的底層驅動不再詳細介紹。
實現了在單片內顯示漢字串以后,能不能讀取SD卡中的txt文檔中的漢字在液晶屏上顯示呢?這塊是我自己想的,不知道與別人的一樣不一樣,反正是實現了。
首先我讀取SD卡上txt文檔上的一個漢字,然后用串口打印出來,發現,讀到的就是漢字的內碼,百度了下說windows中txt文檔的顯示的用GB2312的字庫。既然讀到直接是內碼,那就好辦了。漢字內碼用的是兩個字節,字符用的是一個字節,這個一定要注意,因為在以后顯示的過程中要用。
下面直接貼代碼:
// x,y在液晶屏上的顯示位置,我的液晶屏是320*240 ,豎屏顯示
// color 是畫筆的顏色,BkColor 是背景顏色
u8 fnShowTxt( u16 x, u16 y , u16 color ,u16 BkColor )
{
u8 res=0; // SD卡函數的返回值
u8 buff[100]={0}; // 存儲從txt文檔中讀到的100個字節的內碼
u8 bitbuff[32]={0}; // 存儲從點陣字庫獲得的32個字節的點陣數據
u8 NeiMaH,NeiMaL; // GB2312內碼的高位和低位
u8 CntnuF=1; // 用來 判斷是不是讀到文檔的末尾了,如果讀到字節的個數小于100則表示讀到末尾了
u16 offset=0; // 讀txt文檔的偏移地址
u8 i=0;
UINT Hznum,bytenum; // 實際讀回的內碼字節個數、點陣字節個數
u16 x0,y0; // 點陣顯示的位置
u8 charCnt=0; // 讀取的100個字節內碼中有幾個字符,如果字符個數是偶數則下次偏移再偏移100,如果是奇數,
// 則讀取的100個字節中的最后一個字節可能是下一個漢字的內碼高位字節,則偏移99,下次再把這個字節讀上。
x0=x;
y0=y;
f_mount(&fs1,"",1); // 掛載SD卡
res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ); // 打開字庫文件
if(res!=0)
{
fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);
printf("res=%x",res);
return 1;
}
res=f_open(&ftxt,TxtPath,FA_OPEN_EXISTING|FA_READ); // 打開txt文檔
if(res!=0)
{
fnShowString(10,120,"open txt fail",16,RED,WHITE,0);
printf("res=%x",res);
return 1;
}
f_lseek(&ftxt,offset); // 初始化偏移為0從頭開始讀。
res=f_read(&ftxt,buff,100,&Hznum); // 每次讀100個內碼字節
while(CntnuF) // 循環判斷是不是讀到文件末尾了
{
for(i=0;i if(x>220) // 顯示位置的判斷 { x=x0; y+=16; } if((y>300)) { fnRefreshscreen(WHITE); x=x0; y=y0; } if(buff[i]>0x80) // 是不是漢字 { f_lseek(&f1,32*((buff[i]-0xa0-1)*94+(buff[i+1]-0xa0-1))); // 點陣字庫內的偏移 res=f_read(&f1,bitbuff,32,&bytenum); fnShowHzk(x,y,bitbuff,color,BkColor); x+=16; i++; // 這個i++非常重要,因為一個漢字兩個字節,除了判斷語句i++, // 這里需要還要一個 memset(bitbuff,0,sizeof(bitbuff)); } else // 可能是標點也可能是換行符 { if(buff[i]==0x0D) // 換行標志 y+=16; else fnShowChar( x,y,buff[i],16,color,BkColor,0); // 字符 x+=8; charCnt++; // 字符個數計算,用于判斷下一次讀txt文檔的偏移地址 } } // 計算txt文檔的偏移地址 if(Hznum!=100) // 判斷是不是讀到文檔末尾了 { CntnuF=0; } else // 沒有讀到末尾繼續讀 { if(charCnt%2==0) // 字符個數是偶數,100個字節內碼里邊正好成對出現,地址偏移+100 offset +=100; else offset +=99; memset(buff,0,sizeof(buff)); f_lseek(&ftxt,offset); // txt 文檔地址偏移 res=f_read(&ftxt,buff,100,&Hznum); // 讀內碼數據 } } f_close(&f1); // 關閉打開的點陣字庫 f_close(&ftxt); // 關閉打開的txt文檔 f_mount(&fs1,"",NULL); // 卸載磁盤 return 0; } 以上是簡單的電子書的實現。 因為不同的系統有不同的編碼這個要注意,比如我再Windows上的漢字拷貝到CSDN網頁上就是亂碼,這是因為使用的漢字的編碼不同,對于不同的編碼格式,還需要做內碼的對應轉換,把其他的格式轉換成GB2312或者GBK格式然后調用字庫顯示。 其他常用編碼格式Unicode、utf-8等的具體介紹和轉換成GB編碼可以百度。 SD卡注意事項: 對一個文件讀,必須先打開文件,讀完后關閉。 對一個文件寫,必須先打開文件,根據情況確定打開的權限,只讀,讀、寫、創建等,先完后最好調用f_sync()函數,這是一個同步函數,類似于linux中的同步函數。SD卡中的寫函數應該是帶緩沖(猜的),在關閉之前調用這個函數將緩沖區的內容寫入SD卡中,然后關閉文件,否則可能寫入失敗,不能將內容成功寫到文件上。 文件的打開路徑,Windows中的文檔可能是隱藏文件類型的,這個一定要注意,隱藏文件類型的a.txt和不隱藏文件類型的a.txt 不是同一個文件,這個一定要非常注意。
上一篇:stm32 各頭文件或C文件功能
下一篇:秉火429筆記之十八 ETH--以太網
推薦閱讀
史海拾趣