stm32 读取sd卡图片显示_「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验...
1)實驗平臺:正點原子STM32mini開發板
2)摘自《正點原子STM32 不完全手冊(HAL 庫版)》關注官方微信號公眾號,獲取更多資料:正點原子
第三十五章 漢字顯示實驗
漢字顯示在很多單片機系統都需要用到,少則幾個字,多則整個漢字庫的支持,更有甚者
還要支持多國字庫,那就更麻煩了。本章,我們將向大家介紹,如何用 STM32 控制 LCD 顯示
漢字。在本章中,我們將使用外部 FLASH 來存儲字庫,并可以通過 SD 卡更新字庫。STM32
讀取存在 FLASH 里面的字庫,然后將漢字顯示在 LCD 上面。本章分為如下幾個部分:
35.1 漢字顯示原理簡介
35.2 硬件設計
35.3 軟件設計
35.4 下載驗證
35.1 漢字顯示原理簡介
常用的漢字內碼系統有 GB2312,GB13000,GBK,BIG5(繁體)等幾種,其中 GB2312
支持的漢字僅有幾千個,很多時候不夠用,而 GBK 內碼不僅完全兼容 GB2312,還支持了繁體
字,總漢字數有 2 萬多個,完全能滿足我們一般應用的要求。
本實例我們將制作三個 GBK 字庫,制作好的字庫放在 SD 卡里面,然后通過 SD 卡,將字
庫文件復制到外部 FLASH 芯片 W25Q64 里,這樣,W25Q64 就相當于一個漢字字庫芯片了。
漢字在液晶上的顯示原理與前面顯示字符的是一樣的。漢字在液晶上的顯示其實就是一些
點的顯示與不顯示,這就相當于我們的筆一樣,有筆經過的地方就畫出來,沒經過的地方就不
畫。所以要顯示漢字,我們首先要知道漢字的點陣數據,這些數據可以由專門的軟件來生成。
只要知道了一個漢字點陣的生成方法,那么我們在程序里面就可以把這個點陣數據解析成一個
漢字。
知道顯示了一個漢字,就可以推及整個漢字庫了。漢字在各種文件里面的存儲不是以點陣
數據的形式存儲的(否則那占用的空間就太大了),而是以內碼的形式存儲的,就是
GB2312/GBK/BIG5 等這幾種的一種,每個漢字對應著一個內碼,在知道了內碼之后再去字庫
里面查找這個漢字的點陣數據,然后在液晶上顯示出來。這個過程我們是看不到,但是計算機
是要去執行的。
單片機要顯示漢字也與此類似:漢字內碼(GBK/GB2312)→查找點陣庫→解析→顯示。
所以只要我們有了整個漢字庫的點陣,就可以把電腦上的文本信息在單片機上顯示出來了。
這里我們要解決的最大問題就是制作一個與漢字內碼對得上號的漢字點陣庫。而且要方便單片
機的查找。每個 GBK 碼由 2 個字節組成,第一個字節為 0X81~0XFE,第二個字節分為兩部分,
一是 0X40~0X7E,二是 0X80~0XFE。其中與 GB2312 相同的區域,字完全相同。
我們把第一個字節代表的意義稱為區,那么 GBK 里面總共有 126 個區(0XFE-0X81+1),
每個區內有 190 個漢字(0XFE-0X80+0X7E-0X40+2),總共就有 126*190=23940 個漢字。我
們的點陣庫只要按照這個編碼規則從 0X8140 開始,逐一建立,每個區的點陣大小為每個漢字
所用的字節數*190。這樣,我們就可以得到在這個字庫里面定位漢字的方法:
當 GBKL<0X7F 時:Hp=((GBKH-0x81)*190+GBKL-0X40)*csize;
當 GBKL>0X80 時:Hp=((GBKH-0x81)*190+GBKL-0X41)*csize;
其中 GBKH、GBKL 分別代表 GBK 的第一個字節和第二個字節(也就是高位和低位),Hp
為對應漢字點陣數據在字庫里面的起始地址(假設是從 0 開始存放),csize 代表一個漢字點陣所
占的字節數。假定采用與 15.3 節 ASCII 字庫一樣的提取方法(從上到下,從左到右),可以得
出字體大小與點陣所占字節數的對應關系為:
csize=(size/8+((size%8)?1:0))*size;
size 為字體大小,比如 12(12*12)、16(16*16)、24(24*24)等。
這樣我們只要得到了漢字的 GBK 碼,就可以得到該漢字點陣在點陣庫里面的位置,從而
獲取其點陣數據,顯示這個漢字了。
上一章,我們提到要用 cc936.c,以支持長文件名,但是 cc936.c 文件里面的兩個數組太大
了(172KB),直接刷在單片機里面,太占用 flash 了,所以我們必須把這兩個數組存放在外部
flash。cc936 里面包含的兩個數組 oem2uni 和 uni2oem 存放 unicode 和 gbk 的互相轉換對照表,
這兩個數組很大,這里我們利用 ALIENTEK 提供的一個 C 語言數組轉 BIN(二進制)的軟件:
C2B 轉換助手 V1.1.exe,將這兩個數組轉為 BIN 文件,我們將這兩個數組拷貝出來存放為一個
新的文本文件,假設為 UNIGBK.TXT,然后用 C2B 轉換助手打開這個文本文件,如圖 35.1.1
所示:
圖 35.1.1 C2B 轉換助手
然后點擊轉換,就可以在當前目錄下(文本文件所在目錄下)得到一個 UNIGBK.bin 的文
件。這樣就完成將 C 語言數組轉換為.bin 文件,然后只需要將 UNIGBK.bin 保存到外部 FLASH
就實現了該數組的轉移。
在 cc936.c 里面,主要是通過 ff_convert 調用這兩個數組,實現 UNICODE 和 GBK 的互轉,
該函數原代碼如下:
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 */
)
{
const WCHAR *p;
WCHAR c;
int i, n, li, hi;
if (src < 0x80) {
/* ASCII */
c = src;
} else {
if (dir) {
/* OEMCP to unicode */
p = oem2uni;
hi = sizeof(oem2uni) / 4 - 1;
} else {
/* Unicode to OEMCP */
p = uni2oem;
hi = sizeof(uni2oem) / 4 - 1;
}
li = 0;
for (n = 16; n; n--) {
i = li + (hi - li) / 2;
if (src == p[i * 2]) break;
if (src > p[i * 2]) li = i;
else hi = i;
}
c = n ? p[i * 2 + 1] : 0;
}
return c;
}
此段代碼,通過二分法(16 階)在數組里面查找 UNICODE(或 GBK)碼對應的 GBK(或
UNICODE)碼。當我們將數組存放在外部 flash 的時候,將該函數修改為:
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) gbk2uni_offset=ftinfo.ugbksize/2;
//GBK 2 UNICODE
else gbk2uni_offset=0;
//UNICODE 2 GBK
/* 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);//讀出 4 個字節
if (src == t[0]) break;
if (src > t[0])li = i;
else hi = i;
}
c = n ? t[1] : 0;
}
return c;
}
代碼中的 ftinfo.ugbksize 為我們剛剛生成的 UNIGBK.bin 的大小,而 ftinfo.ugbkaddr 是我們
存放 UNIGBK.bin 文件的首地址。這里同樣采用的是二分法查找,關于 cc936.c 的修改,我們就
介紹到這。
字庫的生成,我們要用到一款軟件,由易木雨軟件工作室設計的點陣字庫生成器 V3.8。該
軟件可以在 WINDOWS 系統下生成任意點陣大小的 ASCII,GB2312(簡體中文)、GBK(簡體中
文)、BIG5(繁體中文)、HANGUL(韓文)、SJIS(日文)、Unicode 以及泰文,越南文、俄文、烏克
蘭文,拉丁文,8859 系列等共二十幾種編碼的字庫,不但支持生成二進制文件格式的文件,也
可以生成 BDF 文件,還支持生成圖片功能,并支持橫向,縱向等多種掃描方式,且掃描方式
可以根據用戶的需求進行增加。該軟件的界面如圖 35.1.1 所示:
圖 35.1.2 點陣字庫生成器默認界面
本章,我們總共要生成 3 個字庫:12*12 字庫、16*16 字庫和 24*24 字庫。這里以 16*16
字庫為例進行介紹,其他兩個字庫的制作方法類似。
要生成 16*16 的 GBK 字庫,則選擇:936 中文 PRC GBK,字寬和高均選擇 16,字體大小
選擇 12,然后模式選擇縱向取模方式二(字節高位在前,低位在后),最后點擊創建,就可以
開始生成我們需要的字庫了(.DZK 文件)。具體設置如圖 35.1.3 所示:
圖 35.1.3 生成 GBK16*16 字庫的設置方法
注意:電腦端的字體大小與我們生成點陣大小的關系為:
fsize=dsize*6/8
其中,fsize 是電腦端字體大小,dsize 是點陣大小(12、16、24 等)。所以 16*16 點陣大小
對應的是 12 字體。
生成完以后,我們把文件名和后綴改成:GBK16.FON。同樣的方法,生成 12*12 的點陣庫
(GBK12.FON)和 24*24 的點陣庫(GBK24.FON),總共制作 3 個字庫。
另外,該軟件還可以生成其他很多字庫,字體也可選,大家可以根據自己的需要按照上面
的方法生成即可。該軟件的詳細介紹請看軟件自帶的《點陣字庫生成器說明書》,關于漢字顯示
原理,我們就介紹到這。
35.2 硬件設計
本章實驗功能簡介:開機的時候先檢測 W25Q64 中是否已經存在字庫,如果存在,則按次
序顯示漢字(兩種字體都顯示)。如果沒有,則檢測 SD 卡和文件系統,并查找 SYSTEM 文件夾
下的 FONT 文件夾,在該文件夾內查找 UNIGBK.BIN、GBK12.FON、GBK16.FON 和
GBK24.FON(這幾個文件的由來,我們前面已經介紹了)。在檢測到這些文件之后,就開始
更新字庫,更新完畢才開始顯示漢字。通過按按鍵 KEY0,可以強制更新字庫。同樣我們也是
用 DS0 來指示程序正在運行。
所要用到的硬件資源如下:
1) 指示燈 DS0
2) KEY0 按鍵
3) 串口
4) TFTLCD 模塊
5) SD 卡
6) SPI FLASH
這幾部分分,在之前的實例中都介紹過了,我們在此就不介紹了。
35.3 軟件設計
打開上一章的工程,首先在 HARDWARE 文件夾所在的文件夾下新建一個 TEXT 的文件夾。
在 TEXT 文件夾下新建 fontupd.c、fontupd.h、text.c、text.h 這 4 個文件。并將該文件夾加入頭
文件包含路徑。
打開 fontupd.c,在該文件內輸入如下代碼:
//字庫區域占用的總扇區數大小(3 個字庫+unigbk 表+字庫信息=3238700 字節,
//約占 791 個 W25QXX 扇區)
#define FONTSECSIZE
791
//字庫存放起始地址
#define FONTINFOADDR 1024*1024*12
//Explorer STM32F4 是從 12M 地址以后開始存放字庫前面 12M 被 fatfs 占用了.
//12M 以后緊跟 3 個字庫+UNIGBK.BIN,總大小 3.09M,被字庫占用了,不能動!
//15.10M 以后,用戶可以自由使用.建議用最后的 100K 字節比較好.
//用來保存字庫基本信息,地址,大小等
_font_info ftinfo;
//字庫存放在 sd 卡中的路徑
const u8 *GBK24_PATH="0:/SYSTEM/FONT/GBK24.FON"; //GBK24 的存放位置
const u8 *GBK16_PATH="0:/SYSTEM/FONT/GBK16.FON"; //GBK16 的存放位置
const u8 *GBK12_PATH="0:/SYSTEM/FONT/GBK12.FON"; //GBK12 的存放位置
const u8 *UNIGBK_PATH="0:/SYSTEM/FONT/UNIGBK.BIN";//UNIGBK.BIN 的存放位置
//顯示當前字體更新進度
//x,y:坐標
//size:字體大小
//fsize:整個文件大小
//pos:當前文件指針位置
u32 fupd_prog(u16 x,u16 y,u8 size,u32 fsize,u32 pos)
{
float prog; u8 t=0XFF;
prog=(float)pos/fsize;
prog*=100;
if(t!=prog)
{
LCD_ShowString(x+3*size/2,y,240,320,size,"%");
t=prog;
if(t>100)t=100;
LCD_ShowNum(x,y,t,3,size);//顯示數值
}
return 0;
}
//更新某一個
//x,y:坐標
//size:字體大小
//fxpath:路徑
//fx:更新的內容 0,ungbk;1,gbk12;2,gbk16;3,gbk24;
//返回值:0,成功;其他,失敗.
u8 updata_fontx(u16 x,u16 y,u8 size,u8 *fxpath,u8 fx)
{
u32 flashaddr=0; u16 bread; u32 offx=0;
FIL * fftemp;
u8 *tempbuf; u8 res; u8 rval=0;
fftemp=(FIL*)mymalloc(sizeof(FIL)); //分配內存
if(fftemp==NULL)rval=1;
tempbuf=mymalloc(4096); //分配 4096 個字節空間
if(tempbuf==NULL)rval=1;
res=f_open(fftemp,(const TCHAR*)fxpath,FA_READ);
if(res)rval=2;//打開文件失敗
if(rval==0)
{
switch(fx)
{
case 0:
//更新 UNIGBK.BIN
ftinfo.ugbkaddr=FONTINFOADDR+sizeof(ftinfo);// UNIGBK 轉換碼表
ftinfo.ugbksize=fftemp->fsize;
//UNIGBK 大小
flashaddr=ftinfo.ugbkaddr;
break;
case 1:
ftinfo.f12addr=ftinfo.ugbkaddr+ftinfo.ugbksize; //GBK12 字庫地址
ftinfo.gbk12size=fftemp->fsize;
//GBK12 字庫大小
flashaddr=ftinfo.f12addr;
//GBK12 的起始地址
break;
case 2:
ftinfo.f16addr=ftinfo.f12addr+ftinfo.gbk12size; // GBK16 字庫地址
ftinfo.gbk16size=fftemp->fsize;
//GBK16 字庫大小
flashaddr=ftinfo.f16addr;
//GBK16 的起始地址
break;
case 3:
ftinfo.f24addr=ftinfo.f16addr+ftinfo.gbk16size; // GBK24 字庫地址
ftinfo.gkb24size=fftemp->fsize;
//GBK24 字庫大小
flashaddr=ftinfo.f24addr;
//GBK24 的起始地址
break;
}
while(res==FR_OK)//死循環執行
{
res=f_read(fftemp,tempbuf,4096,(UINT *)&bread); //讀取數據
if(res!=FR_OK)break;
//執行錯誤
SPI_Flash_Write(tempbuf,offx+flashaddr,4096); //從 0 開始寫入 4096 個數據
offx+=bread;
fupd_prog(x,y,size,fftemp->fsize,offx);
//進度顯示
if(bread!=4096)break;
//讀完了.
}
f_close(fftemp);
}
myfree(fftemp);
//釋放內存
myfree(tempbuf); //釋放內存
return res;
}
//更新字體文件,UNIGBK,GBK12,GBK16,GBK24 一起更新
//x,y:提示信息的顯示地址
//size:字體大小
//提示信息字體大小
//返回值:0,更新成功;
//
其他,錯誤代碼.
u8 update_font(u16 x,u16 y,u8 size)
{
u8 *gbk24_path=(u8*)GBK24_PATH;
u8 *gbk16_path=(u8*)GBK16_PATH;
u8 *gbk12_path=(u8*)GBK12_PATH;
u8 *unigbk_path=(u8*)UNIGBK_PATH;
u8 res;
res=0XFF;
ftinfo.fontok=0XFF;
SPI_Flash_Write((u8*)&ftinfo,FONTINFOADDR,sizeof(ftinfo));
//清除之前字庫成功的標志.防止更新到一半重啟,導致的字庫部分數據丟失.
SPI_Flash_Read((u8*)&ftinfo,FONTINFOADDR,sizeof(ftinfo));
//重新讀出 ftinfo 結構體數據
LCD_ShowString(x,y,240,320,size,"Updating UNIGBK.BIN");
res=updata_fontx(x+20*size/2,y,size,unigbk_path,0);
//更新 UNIGBK.BIN
if(res)return 1;
LCD_ShowString(x,y,240,320,size,"Updating GBK12.BIN ");
res=updata_fontx(x+20*size/2,y,size,gbk12_path,1);
//更新 GBK12.FON
if(res)return 2;
LCD_ShowString(x,y,240,320,size,"Updating GBK16.BIN ");
res=updata_fontx(x+20*size/2,y,size,gbk16_path,2);
//更新 GBK16.FON
if(res)return 3;
LCD_ShowString(x,y,240,320,size,"Updating GBK24.BIN ");
res=updata_fontx(x+20*size/2,y,size,gbk24_path,3);
//更新 GBK24.FON
if(res)return 4;
ftinfo.fontok=0XAA; //全部更新好了
SPI_Flash_Write((u8*)&ftinfo,FONTINFOADDR,sizeof(ftinfo));
//保存字庫信息
return 0;//無錯誤.
}
//初始化字體
//返回值:0,字庫完好.
//
其他,字庫丟失
u8 font_init(void)
{
SPI_Flash_Init();
SPI_Flash_Read((u8*)&ftinfo,FONTINFOADDR,sizeof(ftinfo));//讀出 ftinfo 結構體數據
if(ftinfo.fontok!=0XAA)return 1;
//字庫錯誤.
return 0;
}
此部分代碼主要用于字庫的更新操作(包含 UNIGBK 的轉換碼表更新),其中 ftinfo 是我
們在 fontupd.h 里面定義的一個結構體,用于記錄字庫首地址及字庫大小等信息。因為我們將
W25Q64 的前 4.8M 字節給 FATFS 管理(用做本地磁盤),然后又預留了 100K 字節給用戶自己
使用,最后的 3.1M 字節(W25Q64 總共 8M 字節),才是 UNIGBK 碼表和字庫的存儲空間,所
以,我們的存儲地址是從(4916+100)*1024 處開始的。最開始的 33 個字節給 ftinfo 用,用于保
存 ftinfo 結構體數據,之后依次是:UNIGBK.BIN、GBK12.FON、GBK16.FON 和 GBK24.FON。
保存該部分代碼,并在工程里面新建一個 TEXT 的組,把 fontupd.c 加入到這個組里面,然
后打開 fontupd.h 在該文件里面輸入如下代碼:
#ifndef __FONTUPD_H__
#define __FONTUPD_H__
#include
//前面 4.8M 被 fatfs 占用了.
//4.8M 以后緊跟的 100K 字節,用戶可以隨便用.
//4.8M+100K 字節以后的字節,被字庫占用了,不能動!
//字體信息保存地址,占 33 個字節,第 1 個字節用于標記字庫是否存在.后續每 8 個字節一組
//分別保存起始地址和文件大小
extern u32 FONTINFOADDR;
//字庫信息結構體定義
//用來保存字庫基本信息,地址,大小等
__packed typedef struct
{
u8 fontok;
//字庫存在標志,0XAA,字庫正常;其他,字庫不存在
u32 ugbkaddr;
//unigbk 的地址
u32 ugbksize;
//unigbk 的大小
u32 f12addr;
//gbk12 地址
u32 gbk12size;
//gbk12 的大小
u32 f16addr;
//gbk16 地址
u32 gbk16size;
//gbk16 的大小
u32 f24addr;
//gbk24 地址
u32 gkb24size;
//gbk24 的大小
}_font_info;
extern _font_info ftinfo; //字庫信息結構體
u32 fupd_prog(u16 x,u16 y,u8 size,u32 fsize,u32 pos);
//顯示更新進度
u8 updata_fontx(u16 x,u16 y,u8 size,u8 *fxpath,u8 fx);
//更新指定字庫
u8 update_font(u16 x,u16 y,u8 size);
//更新全部字庫
u8 font_init(void);
#endif
這里,我們可以看到 ftinfo 的結構體定義,總共占用 25 個字節,第一個字節用來標識字庫
是否 OK,其他的用來記錄地址和文件大小。保存此部分代碼,然后打開 text.c 文件,在該文件
里面輸入如下代碼:
#include "sys.h"
#include "fontupd.h"
#include "flash.h"
#include "lcd.h"
#include "text.h"
#include "string.h"
//code 字符指針開始
//從字庫中查找出字模
//code 字符串的開始地址,GBK 碼
//mat 數據存放地址 (size/8+((size%8)?1:0))*(size) bytes 大小
//size:字體大小
void Get_HzMat(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);
if(qh<0x81||ql<0x40||ql==0xff||qh==0xff)//非 常用漢字
{
for(i=0;i
return; //結束訪問
}
if(ql<0x7f)ql-=0x40;//注意!
else ql-=0x41;
qh-=0x81;
foffset=((unsigned long)190*qh+ql)*csize; //得到字庫中的字節偏移量
switch(size)
{
case 12:SPI_Flash_Read(mat,foffset+ftinfo.f12addr,24);break;
case 16:SPI_Flash_Read(mat,foffset+ftinfo.f16addr,32);break;
case 24:SPI_Flash_Read(mat,foffset+ftinfo.f24addr,72);break;
}
}
//顯示一個指定大小的漢字
//x,y :漢字的坐標
//font:漢字 GBK 碼
//size:字體大小
//mode:0,正常顯示,1,疊加顯示
void Show_Font(u16 x,u16 y,u8 *font,u8 size,u8 mode)
{
u8 temp,t,t1;
u16 y0=y;
u8 dzk[72];
u8 csize=(size/8+((size%8)?1:0))*(size);//得到字體一個字符對應點陣集所占的字節數
if(size!=12&&size!=16&&size!=24)return; //不支持的 size
Get_HzMat(font,dzk,size); //得到相應大小的點陣數據
for(t=0;t
{
temp=dzk[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; }
}
}
}
//在指定位置開始顯示一個字符串
//支持自動換行
//(x,y):起始坐標
//width,height:區域
//str :字符串
//size :字體大小
//mode:0,非疊加方式;1,疊加方式
void Show_Str(u16 x,u16 y,u16 width,u16 height,u8*str,u8 size,u8 mode)
{
……此處代碼省略
}
//在指定寬度的中間顯示字符串
//如果字符長度超過了 len,則用 Show_Str 顯示
//len:指定要顯示的寬度
void Show_Str_Mid(u16 x,u16 y,u8*str,u8 size,u8 len)
{
……//此處代碼省略
}
此部分代碼總共有 4 個函數,我們省略了兩個函數(Show_Str_Mid 和 Show_Str)的代碼,
另外兩個函數,Get_HzMat 函數用于獲取 GBK 碼對應的漢字字庫,通過我們 35.1 節介紹的辦
法,在外部 flash 查找字庫,然后返回對應的字庫點陣。Show_Font 函數用于在指定地址顯示一
個指定大小的漢字,采用的方法和 LCD_ShowChar 所采用的方法一樣,都是畫點顯示,這里就
不細說了。保存此部分代碼,并把 text.c 文件加入 TEXT 組下。text.h 里面都是一些函數申明,
這里我們就不貼出來了,詳見光盤本例程源碼。
前面提到我們隊 cc936.c 文件做了修改,我們將其命名為 mycc936.c,并保存在 exfuns 文件
夾下,將工程 FATFS 組下的 cc936.c 刪除,然后重新添加 mycc936.c 到 FATFS 組下,mycc936.c
的源碼就不貼出來了,其實就是在 cc936.c 的基礎上去掉了兩個大數組,然后對 ff_convert 進行
了修改,詳見光盤本例程源碼。
最后,我們在 main.c 里面修改 main 函數如下:
int main(void)
{
u32 fontcnt;
u8 i,j,key,t;
u8 fontx[2];//gbk 碼
HAL_Init();
//初始化 HAL 庫
Stm32_Clock_Init(RCC_PLL_MUL9); //設置時鐘,72M
delay_init(72);
//初始化延時函數
uart_init(115200);
//初始化串口
usmart_dev.init(84);
//初始化 USMART
LED_Init();
//初始化 LED
KEY_Init();
//初始化按鍵
LCD_Init();
//初始化 LCD
mem_init();
//初始化內存池
exfuns_init();
//為 fatfs 相關變量申請內存
f_mount(fs[0],"0:",1);
//掛載 SD 卡
f_mount(fs[1],"1:",1);
//掛載 FLASH.
while(font_init())
//檢查字庫
{
UPD:
LCD_Clear(WHITE);
//清屏
POINT_COLOR=RED;
//設置字體為紅色
LCD_ShowString(60,50,200,16,16,"Mini STM32");
while(SD_Initialize())
//檢測 SD 卡
{
LCD_ShowString(60,70,200,16,16,"SD Card Failed!");
delay_ms(200);
LCD_Fill(60,70,200+60,70+16,WHITE);
delay_ms(200);
}
LCD_ShowString(60,70,200,16,16,"SD Card OK");
LCD_ShowString(60,90,200,16,16,"Font Updating...");
key=update_font(20,110,16);//更新字庫
while(key)//更新失敗
{
LCD_ShowString(60,110,200,16,16,"Font Update Failed!"); delay_ms(200);
LCD_Fill(20,110,200+20,110+16,WHITE); delay_ms(200);
}
LCD_ShowString(60,110,200,16,16,"Font Update Success!");
delay_ms(1500);
LCD_Clear(WHITE);//清屏
}
POINT_COLOR=RED;
Show_Str(30,50,200,16,"Mini STM32 開發板",16,0);
Show_Str(30,70,200,16,"GBK 字庫測試程序",16,0);
Show_Str(30,90,200,16,"正點原子@ALIENTEK",16,0);
Show_Str(30,110,200,16,"2019 年 11 月 18 日",16,0);
Show_Str(30,130,200,16,"按 KEY0,更新字庫",16,0);
POINT_COLOR=BLUE;
Show_Str(30,150,200,16,"內碼高字節:",16,0);
Show_Str(30,170,200,16,"內碼低字節:",16,0);
Show_Str(30,190,200,16,"漢字計數器:",16,0);
Show_Str(30,220,200,24,"對應漢字為:",24,0);
Show_Str(30,244,200,16,"對應漢字(16*16)為:",16,0);
Show_Str(30,260,200,12,"對應漢字(12*12)為:",12,0);
while(1)
{
fontcnt=0;
for(i=0x81;i<0xff;i++)
{
fontx[0]=i;
LCD_ShowNum(148,150,i,3,16);
//顯示內碼高字節
for(j=0x40;j<0xfe;j++)
{
if(j==0x7f)continue;
fontcnt++;
LCD_ShowNum(148,170,j,3,16); //顯示內碼低字節
LCD_ShowNum(148,190,fontcnt,5,16);//漢字計數顯示
fontx[1]=j;
Show_Font(60+132,220,fontx,24,0);
Show_Font(60+144,244,fontx,16,0);
Show_Font(60+108,260,fontx,12,0);
t=200;
while(t--)//延時,同時掃描按鍵
{
delay_ms(1);
key=KEY_Scan(0);
if(key==KEY0_PRES)goto UPD;
}
LED0=!LED0;
}
}
}
}
此部分代碼就實現了我們在硬件描述部分所描述的功能,至此整個軟件設計就完成了
35.4 下載驗證
本例程支持 12*12、16*16 和 24*24 等三種字體的顯示,在代碼編譯成功之后,我們通過下
載代碼到 ALIENTEK MiniSTM32 開發板上,可以看到 LCD 開始顯示三種大小的漢字及漢字內
碼,如圖 35.4.1 所示:
圖 35.4.1 漢字顯示實驗顯示效果
一開始就顯示漢字,是因為 ALIENTEK MiniSTM32 開發板在出廠的時候都是測試過的,
里面刷了綜合測試程序,已經把字庫寫入到了 W25Q64 里面,所以并不會提示更新字庫。如果
你想要更新字庫,那么則必須先找一張 SD 卡,把:光盤5,SD 卡根目錄文件 文件夾下面的
SYSTEM 文件夾拷貝到 SD 卡根目錄下,插入開發板,并按復位,之后,在顯示漢字的時候,
按下 KEY0,就可以開始更新字庫了。字庫更新界面如圖 35.4.2 所示:
圖 35.4.2 漢字字庫更新界面
我們還可以通過 USMART 來測試該實驗,我們可以通過 USMART 調用 Show_Str 函數,
來實現任意位置顯示任何字符串,有興趣的朋友可以測試一下。
總結
以上是生活随笔為你收集整理的stm32 读取sd卡图片显示_「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫学的好,牢饭吃得好(爬虫实例)
- 下一篇: 机器学习系列(4)_机器学习算法一览,应