|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
今天玩了会液晶屏,原来显示汉字都是也取模软件区模后在液晶屏上显示,显示内容改变以后还需要重新做字模,比较麻烦。这两天有时间,参考网友资料,实现了读取汉字的内码从SD卡的GB2312点阵字库读取点阵在液晶屏上显示,字库的生成软件用的是易木雨的点阵字库生成器。能生成很多种语言的字库。做完了读取显示后,我自己又琢磨了一下,简单的实现了从SD卡中读取txt文档然后再液晶屏上显示txt内容。
- `2 f% M! r1 ^# k% ]' F( o& X+ a! h 取模过程注意点阵的宽、高和字体大小的关系,宽、高是我们在液晶屏上要显示的像素大小,字体是汉字大小,如果宽、高一定,字体大小太到的话,字在液晶屏上只能显示一部分,可以在左侧的预览区看出来,如果字体在宽高像素点的范围内则可以在液晶上显示完整的字,如果不能显示完整则可以调整宽高或者字体大小。9 C% K; D9 H4 _+ y
国标字有GB2312和GBK编码,GBK完全兼容GB2312包括内码的兼容,A而且GBK字库增加了很多字。汉字都是用的两个字节表示,第一个字节是区号,第二个字节是在区内的相对偏移位置。通过内码来获取字库内的偏移位置,偏移位置与内码和生成字库的宽高都有关系。我生成的GB2312字库是16*16个像素点显示一个汉字,那在字库内的偏移位置:
5 E+ h$ O. ]" H+ n# C offset=32* ( (H-0xa1)*94+(L-0xa1) )
. R3 z, C; T$ I, T2 o H 表示内码的高字节,L表示内码的低字节。GB2312高字节是0xa1~0xfe表示区号,每个区有94个字节所以*94得到区的相对位置,L表示内码低字节也是从0xa1~0xfe,L-0xa1 得到的是在当前区内的偏移位置。 因为每个汉字有16*16=32个自己组成,所以最后乘以32得到在点阵字库中的偏移位置,从这个位置开始取出32个字节的点阵数据然后打点显示就可以把一个汉字显示出来了。
7 s" i5 Y9 y& T0 m0 R 获取点阵的代码如下
7 m6 Z# q8 X9 k8 _4 D# w6 X5 S3 E+ _
& F' I4 Y; F" l2 s5 E9 e- FATFS fs1; // 挂载SD卡的分区用
2 Q7 H" Z9 H" }
; O8 R! R! `( P5 x; z- FIL f1; // SD卡中字库的文件描述符4 k. Z2 r. p* k% n
- 2 t! ^+ E. z! o, ?+ Y5 y" S) R
- FIL ftxt; // 要读取的txt文档的文件描述符+ v6 b6 ]: k( U! K- H+ ]* D
$ l+ _9 s0 z1 W' n: O' q$ b; X5 F- u8 fnGetChinese(u8 *p,u8 *buff) // 形参是要读取的汉字- d5 E2 Q' n) C; Z. g1 h9 Q
- + D2 b3 b& E; f
- {! K3 h8 j3 w: O
- / M, `6 y$ q n8 Q+ [' B& n1 r
- u8 res=0;0 T# W) A+ S+ b5 o- Z
0 p- Z8 U5 b2 p4 q# H" h- u8 H8,L8;
, W( `* J4 t- [ - . L! f E3 B# t: P
- UINT num;
+ o7 a" P u" E' [+ Y4 l+ C - 9 }9 n x t" U6 ~: l- Z! Q9 j
- H8=*p;
( y1 n& G1 l6 @ - 7 \* r: S" q2 n
- L8=*(p+1);$ N/ ?1 @# ?. N3 E/ k6 _
, g2 h& I' G* }1 F- f_mount(&fs1,"",1); // 挂载SD卡5 d, \1 ]4 _6 G. G+ c" E. v$ r1 Q
- 8 y8 u( A+ y% U' y
- res=f_open(&f1,ReadPath,FA_OPEN_EXIStiNG|FA_READ); // 打开SD卡下的点阵字库0 {4 n8 y) k5 J- c- m
1 A- Q, ?/ a% a( x1 M& G8 E" p+ l- IF(res!=0) // 判断点阵字库是否打开成功. V% R Y* p( T
& t b5 k/ C# i- {
F% D9 G( G9 `. {
. J, q) n3 X8 x% m* f1 C- fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);
& [7 I5 R& t% b! H( N
( V! l6 @! k0 O, V- printf("res=%x",res);
8 x5 H! [8 |& y) D ~
^3 t4 e# D. h- K# ]8 ^$ `, @- return 1;
4 [% o% B4 `6 ?4 E
0 O2 Y/ g: v5 \% n2 @- }
6 O% R! n( D& k
, e. x+ D( D# j3 }# S3 E( o3 u- else" }& ~3 y% X/ S0 J, c: a9 z! h
- & {) u' R. e) G. K
- {
. I V0 y. H- Y
2 ^7 e* y% J# C, J; q* @- fnShowString(10,120,"open ok",16,RED,WHITE,0);5 l- q% s2 s& W* v3 t% A
]1 n# S# a# D- }
2 V$ r) [! v. z! i& _) v" M/ N - + o- E; R& ]: L) W( R
- f_lseek(&f1,32*((H8-0xa0-1)*94+(L8-0xa0-1))); // 在字库文件中做偏移取出32个字节的点阵数据
8 `/ o/ J0 d8 j1 n$ |* ]7 _. U$ W - # H; [: n4 v" T( W3 G* M% B, C
- res=f_read(&f1,buff,32,&num);# F: T0 B8 M& E
- ( R- y9 _; ~ `! f; T9 h1 L2 x' J
- f_close(&f1); // 读完后关闭点阵字库文件
( Y% ^/ @; y5 ~- F1 v" \ - - u3 } Q y& a- q/ d8 y/ i
- f_mount(&fs1,"",NULL); // 卸载SD卡5 D) ]5 K1 p0 _" H3 U' L4 B
H6 [3 S* g- ~$ l- return 0;
. i) t; I: r; K. i& e; o
% C3 _( B* ?9 t; e9 C# `- }
复制代码 8 B0 y2 ~+ ]$ D+ R v
这个是得到汉字点阵的实现过程,得到点阵数据后就可以在液晶上打点实现汉字的显示,具体的底层驱动不再详细介绍。6 c D6 R" k1 k' Z9 C' H
实现了在单片内显示汉字串以后,能不能读取SD卡中的txt文档中的汉字在液晶屏上显示呢?这块是我自己想的,不知道与别人的一样不一样,反正是实现了。
# G3 d* z( I0 d, J+ o# }' f 首先我读取SD卡上txt文档上的一个汉字,然后用串口打印出来,发现,读到的就是汉字的内码,百度了下说windows中txt文档的显示的用GB2312的字库。既然读到直接是内码,那就好办了。汉字内码用的是两个字节,字符用的是一个字节,这个一定要注意,因为在以后显示的过程中要用。
7 ]7 Q2 t: Z+ t0 {+ J6 L. u 下面直接贴代码:
4 w9 n; W" B) X+ N- K; f) ], M; d- W, x* O8 M0 f
- // x,y在液晶屏上的显示位置,我的液晶屏是320*240 ,竖屏显示
9 L6 b4 I$ N0 e8 Y3 I/ M0 ? - ( u2 R9 @( @* ^
- // color 是画笔的颜色,BkColor 是背景颜色( d4 G3 M3 o/ W% |7 j( I1 {6 q
- ! L* \- w6 p+ p5 x3 t
- u8 fnShowTxt( u16 x, u16 y , u16 color ,u16 BkColor )
P' z$ n6 I3 V% j$ n3 N - ( ?* g. t! a, Q5 g$ ^, H
- {
. u0 a8 I" ?8 J; U- ~
5 a5 K2 P6 `& `* M- u8 res=0; // SD卡函数的返回值
5 e: Z" Q& c/ Q2 }, o" n3 V - ; d' M6 M! H4 _7 d9 ]- z: z* Y
- u8 buff[100]={0}; // 存储从txt文档中读到的100个字节的内码
, P8 [* ~0 K6 T1 E/ H0 d& ? - $ @- p, W5 @8 T8 S
- u8 bitbuff[32]={0}; // 存储从点阵字库获得的32个字节的点阵数据' _" O. F9 c1 N0 F: m0 g
$ W ^/ h# z& s/ W4 U- u8 NeiMaH,NeiMaL; // GB2312内码的高位和低位" {1 ~# s! s" q; M2 V; L2 ]4 s- f, Q
- ; z, I/ ^7 X" R9 X7 a: Q$ I
- u8 CntnuF=1; // 用来 判断是不是读到文档的末尾了,如果读到字节的个数小于100则表示读到末尾了
* z$ j, r( }: ^8 v% X& } - & A; W! m1 t% t
- u16 offset=0; // 读txt文档的偏移地址
6 P' R* o; a j1 ^$ c5 V
3 o+ Y: W% q( e/ N3 S8 [* O, W- u8 i=0;
& L5 `) b/ H( h, e
: L! x' n/ y' ]% Q8 j- UINT Hznum,bytenum; // 实际读回的内码字节个数、点阵字节个数9 O. x& @+ a9 P* P% u% S- l1 D
- % R9 O3 G9 q+ {. T- i$ A3 D* n" m
- u16 x0,y0; // 点阵显示的位置
! x6 c" f" @3 T( ? - ! \' q. B+ O8 P. F0 M
- u8 charCnt=0; // 读取的100个字节内码中有几个字符,如果字符个数是偶数则下次偏移再偏移100,如果是奇数,
3 D8 [" k9 @. ^, r8 v4 y6 s
* R" q& Z D" Y$ m3 u# [- c9 X0 M- // 则读取的100个字节中的最后一个字节可能是下一个汉字的内码高位字节,则偏移99,下次再把这个字节读上。
* h, T: o; {; ~; e0 A# r ?5 e, D
3 Z* F* h+ f1 E: U/ [3 k- x0=x;% o% B) l. n6 V% G' K) ]
- % R5 r7 E2 O' e9 H/ _ R+ a
- y0=y;
% s" J, t# q4 H. l6 b6 h - ; M' B1 z1 @2 ~4 [3 a" U
- f_mount(&fs1,"",1); // 挂载SD卡
, G: m6 M3 {/ [7 p3 [* { } - 6 Q5 m1 q1 [ y
- res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ); // 打开字库文件) ^. y9 Z9 O2 E1 {
* Q y" n+ }' X( J! I- if(res!=0)- U! L! G; q9 G/ f; F; I4 m
. y4 h) N3 C% R- {
: s4 U0 z8 u1 w# P; p; S0 G% h3 V - 7 E0 K7 o0 f, ~6 a2 l% c, i
- fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);8 h( C; m0 t: h- }( v( e0 X
- y$ M6 J" ~. [% }# m9 |
- printf("res=%x",res);; _) q7 F2 @0 @# o. r$ j
- 5 j* ^4 x& Q' S6 I c! g
- return 1;
* v8 ~% o9 U7 i" ]. [2 Y6 w/ J
6 c; t) L8 b8 @+ K: L2 j- }3 B" W# o) W9 m, c
$ {' r4 T2 [6 I3 F3 l- res=f_open(&ftxt,TxtPath,FA_OPEN_EXISTING|FA_READ); // 打开txt文档
) L# F, Q# J/ T* u - & A8 z3 k; U/ M& y" @. V5 l
- if(res!=0)% T/ B; l& C1 l
/ R" s L, \4 U8 m4 o$ b% d- {5 N* Z" I. ^. j% L
& Q" C6 Q& u8 Z& |+ {( S- fnShowString(10,120,"open txt fail",16,RED,WHITE,0);$ }( f% x# S( O* f2 f3 w5 a
- ) k' B# Z/ M+ `/ v/ t" c* S
- printf("res=%x",res);
: M2 R" w# x5 t# D% J+ x
: A1 P' q6 ]1 I- M. x- return 1;
9 a0 L5 D4 L( Y# R- K$ u; Z) B! I' | - ! J1 Y: @% E- f- }9 n& C6 T" _
- }
# p# O, b7 c5 q# i
6 ?1 a% g8 e# P; n- f_lseek(&ftxt,offset); // 初始化偏移为0从头开始读。
" u, |8 j( K" H( A0 E" ?# K% g
' f( x( K5 o+ L X* \2 L- res=f_read(&ftxt,buff,100,&Hznum); // 每次读100个内码字节: \+ }* t8 T6 }! X+ [
- ' p5 D1 i! X$ z/ B7 j
- while(CntnuF) // 循环判断是不是读到文件末尾了. l" G$ `8 M$ z2 P8 y' i
- 2 C( x9 P* L8 d/ x
- {. C/ U6 G/ m9 n. m6 K+ x
- # D/ e+ d, A! j* r
- for(i=0;i8 {! u( X1 U) p& R4 }& X6 V
- ) _1 W. g: p9 [/ M
- {
0 h5 N- H) p; Q, a' R$ f% _1 f7 [
7 h6 t8 e8 ~3 a& z' b- if(x>220) // 显示位置的判断0 I' l# M( g0 |- a9 H$ V
% }! M3 S. r q0 Y G- {8 ]4 c" x3 b3 @9 w. w& y
- # J% e# ^2 C/ T0 O/ k1 M
- x=x0;
1 ?# S6 a/ }- z9 k; t
2 b; @ S2 f+ T6 s$ V- y+=16;9 r0 `7 n+ j1 L
' y1 r" w5 _5 G1 ]- }
; d& Y+ I% Z; W* I, u6 j - : B: o1 d }6 z" F+ m4 f( o
- if((y>300))
7 z. Y& Y1 v4 u
9 n2 r. c. |+ i) `8 s; E( V- {' X l, X: N/ M9 C" r
- 1 R% U8 f8 ?9 k8 q
- fnRefreshscreen(WHITE);
7 H- ^ U* b5 x% Z: A
4 }5 K) w& ~6 u! {2 p- x=x0;2 f* X8 l! J) W2 F
- / _( S: t; V, w% q; h8 V
- y=y0;+ y9 |7 K$ l" _6 M0 s# g' X
+ H4 G3 I: h0 f. l- }
9 j2 t9 [% j1 w# ~# c8 j3 b4 u) e - + g) `% K( a8 j( L4 F, _
- if(buff>0x80) // 是不是汉字& ?9 g7 A* _! u; A/ V" Z! I6 a
- . c( D- t; O' p
- {
. E$ A) Q% b' o) ]' |+ v
" t8 {. l& G& z8 K7 B2 |- f_lseek(&f1,32*((buff-0xa0-1)*94+(buff[i+1]-0xa0-1))); // 点阵字库内的偏移
) x. L; t v0 x8 ?: j - & x$ L6 m+ r7 Q8 B) i1 G
- res=f_read(&f1,bitbuff,32,&bytenum);
H" L& u$ g) E3 n" ^3 K
. ^6 y( N7 Q# u4 C1 `( `/ V$ m- fnShowHzk(x,y,bitbuff,color,BkColor); Y/ _, z1 {& b0 S
# |. g# p! M8 a% u7 k( j6 c# N" N1 |5 w- x+=16;
% P$ @; c8 F" N - ( F: s. I4 ?/ M# L1 U! ~
- i++; // 这个i++非常重要,因为一个汉字两个字节,除了判断语句i++,
; g, o" b* ~% ~" @) r( |2 f - - F S7 n" L' p) f. H" c6 Q
- // 这里需要还要一个
~ V0 D) V& q" N; O5 @8 @
$ e2 r1 p' e$ U6 d* V: [8 ]2 U- j- memset(bitbuff,0,sizeof(bitbuff));' y9 S7 e, w' [' B4 Q6 n
3 f" V9 x2 K% \- _+ B; }- }
- u; Y( \: Z1 `; F. } - & T% |: c! [- k
- else // 可能是标点也可能是换行符
. u8 q; F5 m5 h* w$ h" W8 ]: t - ' [/ X3 T& B; j! A0 U& g1 A% r
- {
. g+ K8 s g! B1 q# B' U - 5 A+ D T/ \! \" ^/ P. S: X
- if(buff==0x0D) // 换行标志
, J% l: s" E1 K* J1 n2 A
$ b; k2 e9 Z# S/ V) B- y+=16;& \4 I' Y/ r- e u: p
3 u- k1 _+ p& ~% \- else
* M/ {8 p2 l2 a" A4 U3 V
* J H, g# a4 l6 o; K% T- fnShowChar( x,y,buff,16,color,BkColor,0); // 字符
$ I3 |; s) |. N3 r8 E/ ? - ! v4 m v( f2 M
- x+=8;) Q4 t p, q" N ^5 V( S! j
- % Q2 W( n! _0 }$ M3 |) q/ `: \
- charCnt++; // 字符个数计算,用于判断下一次读txt文档的偏移地址- W8 {1 U3 M, w1 a( z Q# @7 c
/ N( O; d8 R; n1 m+ d X% i- }
9 ^# @8 O% c7 u' i% ?2 I3 h; P
, _8 f( ]& z& c; v6 N8 C- }
. k3 w/ R) W |, x% T& Z& Y
$ t0 H* ^) f; ^5 A; T! ?6 G4 A- // 计算txt文档的偏移地址
; u+ _" Z" b9 T2 R1 S
. ~; U1 C1 a/ s. w8 q& [- if(Hznum!=100) // 判断是不是读到文档末尾了
Z; G t# {3 V) ^; j) A& b9 P \
+ p9 g% ^" X2 G* e- {
6 c% B! M1 `2 e6 ^1 c
5 A2 `; d' a$ o2 m- CntnuF=0;' k, |4 O/ r# F* Y
- " t' Y# p0 L! `+ L
- }
/ f2 I+ Y5 }- u, y1 ` - 2 T6 |, V5 u: _' o4 H5 E- N3 f
- else // 没有读到末尾继续读& z2 G# ?2 T0 f3 O' N
- % m6 P* B% L+ L0 v" H$ s
- {
& l, w5 H# h( V - - R5 i2 T9 u/ w) n
- if(charCnt%2==0) // 字符个数是偶数,100个字节内码里边正好成对出现,地址偏移+100! z. A0 R1 w) S) _' @ O
- ! T( A/ l4 b2 }1 x! I9 L
- offset +=100;
5 w, T+ A( l* K: d$ g0 K! \
7 g3 P3 _1 A% K2 y; g- else1 ^$ @1 g3 {; K; f" \
- 8 L. Q0 N* t: n% c
- offset +=99;$ {9 F- Q( \8 j- D. n, k6 n0 K
* H* W# f6 ]' I' r( z- memset(buff,0,sizeof(buff));+ S4 L7 T$ N% Y
1 m. ^" W3 K0 ` _- N( u- f_lseek(&ftxt,offset); // txt 文档地址偏移6 ?: T( M- O; O
5 ~" a5 V! i. r3 R$ O4 V- res=f_read(&ftxt,buff,100,&Hznum); // 读内码数据
8 b/ }" x+ B4 C, C# z - / g4 t4 d9 O: K; O2 }
- }
) v' ]3 |2 M0 a l+ ?' ` - # u! h1 W6 y8 u6 y5 K
- }% R w, b7 o% B6 s/ Z* Q$ K: W' z
" ~9 W$ C9 b' c2 S* X- f_close(&f1); // 关闭打开的点阵字库
+ M4 \( c0 V# F0 s) X - 0 {6 S5 C! C: c+ j6 u" {
- f_close(&ftxt); // 关闭打开的txt文档
. a7 ^$ Z& o x6 z5 c
) K9 K" t, a& m& S& u- f_mount(&fs1,"",NULL); // 卸载磁盘8 g0 J+ |8 v/ }
5 S! X0 v" I: ?; o7 l- return 0;$ d/ @# b' D5 ?/ r! d* u
B! W7 _9 q( m$ X0 k5 L, d9 {- }
复制代码 # p4 S0 o: ]6 M) r
以上是简单的电子书的实现。
- n2 \; a: Y* |2 j$ ^ 因为不同的系统有不同的编码这个要注意,比如我再Windows上的汉字拷贝到CSDN网页上就是乱码,这是因为使用的汉字的编码不同,对于不同的编码格式,还需要做内码的对应转换,把其他的格式转换成GB2312或者GBK格式然后调用字库显示。* x4 \2 a4 o5 U# O A. [2 n
其他常用编码格式Unicode、utf-8等的具体介绍和转换成GB编码可以百度。* B; [ z3 Y8 K1 [) [& m! Q
SD卡注意事项:& m- D7 ?+ g, c0 a3 J3 W
对一个文件读,必须先打开文件,读完后关闭。1 r- k/ A/ ~- X0 y3 k4 j8 G
对一个文件写,必须先打开文件,根据情况确定打开的权限,只读,读、写、创建等,先完后最好调用f_sync()函数,这是一个同步函数,类似于linux中的同步函数。SD卡中的写函数应该是带缓冲(猜的),在关闭之前调用这个函数将缓冲区的内容写入SD卡中,然后关闭文件,否则可能写入失败,不能将内容成功写到文件上。7 z) [: }9 v( S. _4 Q
文件的打开路径,Windows中的文档可能是隐藏文件类型的,这个一定要注意,隐藏文件类型的a.txt和不隐藏文件类型的a.txt 不是同一个文件,这个一定要非常注意。1 @0 |4 z4 m7 K) E
: S/ ]( m: b+ j J
6 {1 `2 [& L: w- F4 _+ \ |
|