|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
今天玩了会液晶屏,原来显示汉字都是也取模软件区模后在液晶屏上显示,显示内容改变以后还需要重新做字模,比较麻烦。这两天有时间,参考网友资料,实现了读取汉字的内码从SD卡的GB2312点阵字库读取点阵在液晶屏上显示,字库的生成软件用的是易木雨的点阵字库生成器。能生成很多种语言的字库。做完了读取显示后,我自己又琢磨了一下,简单的实现了从SD卡中读取txt文档然后再液晶屏上显示txt内容。; f- v" h' @4 C8 G+ C' @+ R5 Z
取模过程注意点阵的宽、高和字体大小的关系,宽、高是我们在液晶屏上要显示的像素大小,字体是汉字大小,如果宽、高一定,字体大小太到的话,字在液晶屏上只能显示一部分,可以在左侧的预览区看出来,如果字体在宽高像素点的范围内则可以在液晶上显示完整的字,如果不能显示完整则可以调整宽高或者字体大小。. h( q% F& ~: l$ F3 _
国标字有GB2312和GBK编码,GBK完全兼容GB2312包括内码的兼容,A而且GBK字库增加了很多字。汉字都是用的两个字节表示,第一个字节是区号,第二个字节是在区内的相对偏移位置。通过内码来获取字库内的偏移位置,偏移位置与内码和生成字库的宽高都有关系。我生成的GB2312字库是16*16个像素点显示一个汉字,那在字库内的偏移位置:
3 v& E/ i# M9 m: z1 l9 X offset=32* ( (H-0xa1)*94+(L-0xa1) )
" m( [+ T# s1 `- U! C, O+ a8 ~ H 表示内码的高字节,L表示内码的低字节。GB2312高字节是0xa1~0xfe表示区号,每个区有94个字节所以*94得到区的相对位置,L表示内码低字节也是从0xa1~0xfe,L-0xa1 得到的是在当前区内的偏移位置。 因为每个汉字有16*16=32个自己组成,所以最后乘以32得到在点阵字库中的偏移位置,从这个位置开始取出32个字节的点阵数据然后打点显示就可以把一个汉字显示出来了。$ S& _% ?+ X" l" D _
获取点阵的代码如下
% K8 U( j: Q" g# t6 m1 A- i+ v0 R8 i0 I Y5 t% C; G1 }) E/ u
- FATFS fs1; // 挂载SD卡的分区用
( Z2 E, \; q) R' G
H: g/ B; t& {- FIL f1; // SD卡中字库的文件描述符
) j" B- S+ x* {( ?* o - 6 }7 |: y+ s# I8 u
- FIL ftxt; // 要读取的txt文档的文件描述符
! W2 T7 L1 z. {- \3 G l7 r; U - 3 I+ W9 h% H4 n* W6 i
- u8 fnGetChinese(u8 *p,u8 *buff) // 形参是要读取的汉字3 K9 i3 n) F0 B* s$ D1 e9 D
- & X3 J( L. [ {" G b
- {
/ P; U: G5 Q3 P& C
, [& `7 F4 S' l3 ^- u8 res=0;
4 |2 { A* ]7 o3 Z - 4 X3 c, U) V" D' j( b1 l
- u8 H8,L8;3 d/ O$ n( s' f; C
- 9 W, O7 Z3 b/ q# `$ Z/ t2 h: G# F
- UINT num;: e4 \- j o9 w; |. U5 n( O
' ?5 J' C$ a4 [: q7 F- H8=*p;
- m# N! q7 ]/ u$ I8 ^3 Q4 W2 o - ) B0 }9 L4 K$ b& S
- L8=*(p+1);
( ?, _4 w* \! g% b - ! E3 r3 R9 z: {( E# N
- f_mount(&fs1,"",1); // 挂载SD卡
4 ]' c1 n0 h" E* u( X6 B - 5 U3 J! c2 C, Z8 i1 h+ R
- res=f_open(&f1,ReadPath,FA_OPEN_EXIStiNG|FA_READ); // 打开SD卡下的点阵字库
$ A1 t' S( r3 i, u
6 n4 n q3 E/ H9 V, O- IF(res!=0) // 判断点阵字库是否打开成功
: A/ p' r' I7 V. L0 C- p2 j
3 W% i: T2 d/ [, |* U+ }% C- {3 a K f% B6 S5 H: I
# Q7 B& U+ l) _) a) s- fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);
$ P* o! Z$ Q! L# Y3 Q3 m - * D0 b7 ]7 E7 u
- printf("res=%x",res);
3 @7 y( J# ^3 ]( q4 t
7 g }5 N" k) s1 R. L- return 1;* `: k. f3 m' p2 y
- ! Z) y1 ?, Z8 b0 r
- }$ y# D/ {7 N/ \ p
- ! q: \1 F/ Y& G( D# c& r
- else% G$ o' V" C* j4 G- \5 C; G
; k+ r c. I: D0 H- {5 \% O' r$ s; s
- 2 J% O$ L' n5 z2 ]# ?
- fnShowString(10,120,"open ok",16,RED,WHITE,0);
( i4 x( h" S8 l- T& ?: M
/ N4 | Z/ U h t- }
& F4 t+ `4 c8 ^. n" b- |) Z - 0 ] @; w1 L8 l6 X A
- f_lseek(&f1,32*((H8-0xa0-1)*94+(L8-0xa0-1))); // 在字库文件中做偏移取出32个字节的点阵数据
" V, _* g7 A+ U0 a - ' `+ |4 S# u. M; b! T
- res=f_read(&f1,buff,32,&num);) ` j# y Q: q( Y( E0 R
- ], W1 A0 j' E+ K
- f_close(&f1); // 读完后关闭点阵字库文件
$ K3 X& H/ H* o ^1 z4 \* J
3 q, {* M! e7 G+ P" ?- f_mount(&fs1,"",NULL); // 卸载SD卡$ Z k e* N7 C8 }1 e. B, \
0 g, |+ J$ F) }, ]- return 0;
0 ~3 K* }7 k5 u+ q7 G - " ~- q( J' u% p( _ n7 c9 m
- }
复制代码 ( _4 w2 N, r5 V3 Z
这个是得到汉字点阵的实现过程,得到点阵数据后就可以在液晶上打点实现汉字的显示,具体的底层驱动不再详细介绍。" y4 `6 [: K( a& `* M5 [
实现了在单片内显示汉字串以后,能不能读取SD卡中的txt文档中的汉字在液晶屏上显示呢?这块是我自己想的,不知道与别人的一样不一样,反正是实现了。+ P3 ~: i) k8 E$ R3 R
首先我读取SD卡上txt文档上的一个汉字,然后用串口打印出来,发现,读到的就是汉字的内码,百度了下说windows中txt文档的显示的用GB2312的字库。既然读到直接是内码,那就好办了。汉字内码用的是两个字节,字符用的是一个字节,这个一定要注意,因为在以后显示的过程中要用。; i7 w5 w2 @$ @% P- l' g
下面直接贴代码:) Y3 T1 [: p- b( ?& r
& \. o% H9 ]3 o8 q& b5 P- // x,y在液晶屏上的显示位置,我的液晶屏是320*240 ,竖屏显示2 K. v! P( y7 J5 x
- 4 u+ V8 g$ G+ a% d" Y0 [
- // color 是画笔的颜色,BkColor 是背景颜色
3 B- N* L' W4 P* u. N6 W
! b$ o3 N* P$ R3 O' H, \/ m4 ~- u8 fnShowTxt( u16 x, u16 y , u16 color ,u16 BkColor )
- g3 G2 \% C3 z/ A
" o7 |8 d3 I9 \7 w, o u! {8 }- {0 W' U( A" q. n6 o( S4 V
- 0 O$ V& p6 I) a3 ]
- u8 res=0; // SD卡函数的返回值
8 x# f) h) U8 C' j
: R9 N3 Y( ?3 V& M4 o' F- u8 buff[100]={0}; // 存储从txt文档中读到的100个字节的内码) Y3 |, O2 x. B" D( a
7 ] |% N' s6 b( D/ H- u8 bitbuff[32]={0}; // 存储从点阵字库获得的32个字节的点阵数据
0 Z* l& q+ m9 R! q6 ~) A( o
- X. z2 V6 _' d4 N" ]- u8 NeiMaH,NeiMaL; // GB2312内码的高位和低位$ l% S& x ]9 G
- 6 }7 |0 D% `' K( ~; n3 C5 g) }6 w
- u8 CntnuF=1; // 用来 判断是不是读到文档的末尾了,如果读到字节的个数小于100则表示读到末尾了
4 j; P* |( ^- q' u
: R' |3 N. w6 O& p q$ O& y( }- u16 offset=0; // 读txt文档的偏移地址
" }5 E8 g) y' E* J, [
* u' J- R- U7 b/ O' x' i- u8 i=0;) r$ O4 {7 F2 u
- : Q9 N8 z$ Q/ N, ]( |
- UINT Hznum,bytenum; // 实际读回的内码字节个数、点阵字节个数
, T6 ^# ?) ?: q; V
) p3 D! {7 z1 Y, t0 u7 K& {4 {- u16 x0,y0; // 点阵显示的位置
' T. B2 s0 ]: D* f, O
1 V) D- d4 S' a4 I! M' R- u8 charCnt=0; // 读取的100个字节内码中有几个字符,如果字符个数是偶数则下次偏移再偏移100,如果是奇数,6 p9 p' D8 q) I+ X9 N' v
- 0 h- O' D: p Y
- // 则读取的100个字节中的最后一个字节可能是下一个汉字的内码高位字节,则偏移99,下次再把这个字节读上。
' R; T) X( C( J
' Z" l5 d# O) B: o5 S) S) d+ }- x0=x;
S7 v) K: |9 o4 R' M) P; i - I& j7 h; q' d- q1 _8 T" Y3 W E
- y0=y;
. ?2 \( H# @3 V
9 g0 p0 a' O7 ^- r+ J7 H- f_mount(&fs1,"",1); // 挂载SD卡( N8 S" y( `: |# i$ T" u
- - a- b0 v/ j8 Z# U
- res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ); // 打开字库文件% ?: h/ b3 p1 k" B9 F8 o+ `
- % s$ Z" F0 Y# P5 Z; s E0 h
- if(res!=0)% i1 d3 `6 N% F2 @) ` M0 G4 e3 n
0 r0 e: B& ?! Q/ g+ c- {0 B& b6 V* p6 ~! E, N. r
- : W+ U- V: r, e; @& Z
- fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);
4 t* ^' B$ f' W. Y5 h8 U
/ s/ W% i4 l$ ^- printf("res=%x",res);1 v7 t; v9 S5 o+ ~; e, f
- ' z8 w0 d) I4 o* I$ I3 _8 m; {
- return 1;
. k( w c; H4 G6 S2 T
; f8 C3 ]3 j! j6 p O }( L- }
( @- `9 o) W/ Z1 {
5 o8 ~& t0 a: b4 O2 B, s- res=f_open(&ftxt,TxtPath,FA_OPEN_EXISTING|FA_READ); // 打开txt文档( f0 l2 c3 g* x5 X4 i
- 0 E/ v7 W) @9 b
- if(res!=0)- ^- I I* z7 f; ^6 {( ^. y# {
- ; F# x5 {% b) ~0 l; ] M' Z! g: X* n. s
- {
) R/ F- `& K2 @0 W+ O2 b - 0 _7 N! e- R( J
- fnShowString(10,120,"open txt fail",16,RED,WHITE,0);" z9 x3 X% C, Q7 L
- 4 O) N' c3 e- R3 x! C4 H2 d6 e P
- printf("res=%x",res); t2 r: b: f# _/ s2 v5 y
- % A/ j, k4 S- J
- return 1;+ \( o# O% r% ^7 \* Y& F# o
1 h1 \( C- v, U9 K4 @) _5 X3 G- }3 u; D6 [ L( O" \; f/ P! x
6 C' {# z5 C/ z% l2 Q8 D" |- f_lseek(&ftxt,offset); // 初始化偏移为0从头开始读。9 V% q; H! [4 m6 V* W# m
- 6 F, X: |! L4 u+ ] D
- res=f_read(&ftxt,buff,100,&Hznum); // 每次读100个内码字节6 e. ]1 i0 t1 z7 q4 m( w
- : T( @ g$ M8 T2 ]
- while(CntnuF) // 循环判断是不是读到文件末尾了1 D/ l3 z+ j8 {* t) g# b1 d
- : F+ n* H) ~0 q' W" b
- {
* {. \% l% z+ O, \0 j" ~
% u. l" v# K. F- for(i=0;i
( V% U3 B2 H/ K9 ` - ; w o4 n, H8 w1 C3 v4 \
- {2 I8 d4 @5 l1 G; D% i
- 8 M) `% p2 x. k+ g
- if(x>220) // 显示位置的判断
% ~% H0 k- I( T* U! k
( |0 p( k' h/ s9 s I/ N1 A& a# U- {5 _ m7 {7 q4 z8 d/ S- W6 J
- 4 v; [) a" _9 f6 x6 N
- x=x0;
& l. a Y3 k& J5 d
3 X% q4 I1 y' K* [- y+=16;/ S' w# \* B# |2 j0 h8 n
- : d, O6 z" ?5 d5 P5 J4 I
- }
" l# O2 F) M2 O
3 d" i& F+ ?/ x7 B- if((y>300))
5 R( Q7 }" K& j$ d! y$ a+ t: z, h - : G6 P+ i+ V* E) B# ], c9 e$ f
- {9 I* z" b* @- d
- 6 {; B5 x ~% y& P
- fnRefreshscreen(WHITE);, r# g- @- J# G4 q }8 e( N! r
2 ^9 O; Z' p2 Z& x# w8 j- x=x0;
. S2 e& H" K4 e! U2 X; C6 Z' m9 R - & a7 S1 E& M2 i* b
- y=y0;
5 \* K) C, Q8 N2 P. @5 d
@- o2 k: H8 z1 J8 U/ ~- }
& A" u" Y3 {; q# s) T4 [3 Z
3 O) D: v4 e5 y, G& c P- if(buff>0x80) // 是不是汉字
. }! }7 @+ K& h. a" }* H; d- N - 1 q4 b. b& v- E' t, ]
- {" ^3 Z8 b9 P \0 Y7 P1 l7 m
- ! h) x# `; K, I0 D
- f_lseek(&f1,32*((buff-0xa0-1)*94+(buff[i+1]-0xa0-1))); // 点阵字库内的偏移
0 A! ^. j" m7 A- }6 Y- X. }
4 W3 s% T% w6 \7 E/ B- res=f_read(&f1,bitbuff,32,&bytenum);: `# l( i( i) E5 f6 [, p6 K: u& O# a
- . R% k& a" T; S1 i! o
- fnShowHzk(x,y,bitbuff,color,BkColor);
% k" q5 n0 o/ b0 L
- o, X5 W9 n9 _/ g- v- x+=16;
: G) [$ ]( t) p - & d1 c5 w* i, b' [
- i++; // 这个i++非常重要,因为一个汉字两个字节,除了判断语句i++,
9 g% Q9 S; e+ n0 t' \ - % p! p4 P4 T$ ?! M- l6 g& F4 i! g
- // 这里需要还要一个
5 \& A8 ^, n7 M d5 d* I9 k% m - 9 t( _' h* s' f% X" C3 Z! [
- memset(bitbuff,0,sizeof(bitbuff));, `4 o3 ]/ U3 N, C# a
- 2 B3 V7 k- c, o1 E. x: D+ k9 l
- }" X* W9 D, F) m) ]& w j
5 \7 ]" G( B( I2 d7 Q) V) m8 @$ D' L- else // 可能是标点也可能是换行符# a! U9 A1 j6 |0 H, X' |0 T
& ?4 s( Y: ?: r7 F2 e1 M) V7 w- {: ~# l, q1 O; x1 s( V o
- 7 p4 z4 c* b }9 A9 i6 O% Z3 [
- if(buff==0x0D) // 换行标志9 ~ L/ R7 V W8 g' F! \7 W& S4 u
- 1 Q; f3 N# z' s% E& g9 s1 s
- y+=16;$ S- X- @; B# G1 F
- 5 z4 t/ R* L5 C) N
- else9 c5 h9 D. _/ j$ d% i
- U, p- x9 n* }( t% a) g# L
- fnShowChar( x,y,buff,16,color,BkColor,0); // 字符4 p% j4 j, E3 c+ C
- $ }* ~$ o+ Z; U) ], B; n2 f
- x+=8;+ [) Q) o9 g1 X( p! J
- ) V) v7 B, g+ F. j
- charCnt++; // 字符个数计算,用于判断下一次读txt文档的偏移地址) A3 i! p- T: H3 _! j1 ~
) |, `. r6 V) Q+ N- }
. l6 E7 z% H& b% T$ S - 7 {1 I; Q9 C! S( M
- }- ~" Z2 a9 u j n# ?. ]+ t @; R
- 5 Q7 l6 n" Q. q+ h3 E0 c( k
- // 计算txt文档的偏移地址$ J* B# y8 W0 Q$ q
- / W* y0 z3 A3 V4 h' y
- if(Hznum!=100) // 判断是不是读到文档末尾了
8 f3 ~% L& C7 O/ S2 T+ a$ V+ @ - ) f* I8 P% J& ~; P' `: H( t2 B
- {9 c. t( A1 U' G& f) R( \
+ G4 [0 |- F" I2 y6 {* O- n3 a- CntnuF=0;
+ S. S" R# @- i, \
: F) ~6 y- U% q# L) I! y6 \- }
c' O w' j r! m/ J; i" V" N
5 R9 x& v+ d) G5 f: o* H- else // 没有读到末尾继续读
; N, N0 H& C3 v' Z3 P. @6 T! }& M - ' h, x$ e. D# P- ]5 O( D
- {& O* y$ {$ X: ^1 q
% D$ R5 w) o) w0 A0 j( _3 {( N- if(charCnt%2==0) // 字符个数是偶数,100个字节内码里边正好成对出现,地址偏移+100, {* I" X4 n3 S/ |/ G$ R- ~# {4 p
8 m7 b* p6 a/ Y* i8 Q; J7 P- offset +=100;4 X4 q$ s1 h( N% W
A+ V/ r U5 Q4 O* r. @) ~- else
! b4 d h; P& f, M0 Y. Z) D - / I$ o S4 f' D* {8 Q
- offset +=99;
! F6 ^6 {; r9 G# `9 X - 2 w: l4 u7 l& h* A4 s" t' r( k3 z# o
- memset(buff,0,sizeof(buff));0 K Y- @+ c2 n7 n ?, D2 F
- & O- N7 Z) f: K( g$ S( ^8 `
- f_lseek(&ftxt,offset); // txt 文档地址偏移
9 P5 w) Y7 o% u/ H
7 r6 k4 |4 K: x- res=f_read(&ftxt,buff,100,&Hznum); // 读内码数据
9 n z7 v2 p7 V/ W" K
3 v' e0 ^3 L7 H g% ]- }
" F7 Q5 i6 s J- A! s5 R
2 Z! w m C8 h6 E) D, H- }# g9 c. m& ~: X) b: v% b" ]
) R+ t! ]) t1 j+ X- f_close(&f1); // 关闭打开的点阵字库
5 P$ J# K# C, B: P& o) `, i
8 e5 |" T/ }" o- f_close(&ftxt); // 关闭打开的txt文档
: I0 t9 ]) v/ f7 c3 c
- ]; A2 t0 v2 w6 z# d/ z! x- f_mount(&fs1,"",NULL); // 卸载磁盘5 L; }% [: b- o* i c. d" n* M
- 7 i5 J9 ~% {' D+ Q
- return 0;% ]8 n5 H8 k/ U1 f8 F
1 a# l- u% `: B B: H2 o- }
复制代码 6 x0 W3 {1 T( a1 o) z' _
以上是简单的电子书的实现。
+ @' Z0 I) N4 `0 o. j! X) @ 因为不同的系统有不同的编码这个要注意,比如我再Windows上的汉字拷贝到CSDN网页上就是乱码,这是因为使用的汉字的编码不同,对于不同的编码格式,还需要做内码的对应转换,把其他的格式转换成GB2312或者GBK格式然后调用字库显示。' o1 h4 _) {, O# E" F- i2 Z# z3 ?
其他常用编码格式Unicode、utf-8等的具体介绍和转换成GB编码可以百度。! V/ k q5 `$ H1 S' R( A; o( F+ Y
SD卡注意事项:
. T1 ~0 Q; {& ^! X. c 对一个文件读,必须先打开文件,读完后关闭。1 A: Q3 f6 O) m; n& Q4 h) S. k
对一个文件写,必须先打开文件,根据情况确定打开的权限,只读,读、写、创建等,先完后最好调用f_sync()函数,这是一个同步函数,类似于linux中的同步函数。SD卡中的写函数应该是带缓冲(猜的),在关闭之前调用这个函数将缓冲区的内容写入SD卡中,然后关闭文件,否则可能写入失败,不能将内容成功写到文件上。: o/ T2 Z3 S+ o9 j5 y5 @3 R/ N
文件的打开路径,Windows中的文档可能是隐藏文件类型的,这个一定要注意,隐藏文件类型的a.txt和不隐藏文件类型的a.txt 不是同一个文件,这个一定要非常注意。
@2 u8 S( i& U4 j. k0 N* G8 ]& q) Y; G8 V/ { Z
. s- `- k7 [; A; r |
|