|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
今天玩了会液晶屏,原来显示汉字都是也取模软件区模后在液晶屏上显示,显示内容改变以后还需要重新做字模,比较麻烦。这两天有时间,参考网友资料,实现了读取汉字的内码从SD卡的GB2312点阵字库读取点阵在液晶屏上显示,字库的生成软件用的是易木雨的点阵字库生成器。能生成很多种语言的字库。做完了读取显示后,我自己又琢磨了一下,简单的实现了从SD卡中读取txt文档然后再液晶屏上显示txt内容。% |0 N- l, H9 d
取模过程注意点阵的宽、高和字体大小的关系,宽、高是我们在液晶屏上要显示的像素大小,字体是汉字大小,如果宽、高一定,字体大小太到的话,字在液晶屏上只能显示一部分,可以在左侧的预览区看出来,如果字体在宽高像素点的范围内则可以在液晶上显示完整的字,如果不能显示完整则可以调整宽高或者字体大小。1 p6 P" E9 v& S% \/ F2 y+ Z
国标字有GB2312和GBK编码,GBK完全兼容GB2312包括内码的兼容,A而且GBK字库增加了很多字。汉字都是用的两个字节表示,第一个字节是区号,第二个字节是在区内的相对偏移位置。通过内码来获取字库内的偏移位置,偏移位置与内码和生成字库的宽高都有关系。我生成的GB2312字库是16*16个像素点显示一个汉字,那在字库内的偏移位置:0 T9 u, j6 E/ x
offset=32* ( (H-0xa1)*94+(L-0xa1) )
9 H5 L' t( m# p: f$ y H 表示内码的高字节,L表示内码的低字节。GB2312高字节是0xa1~0xfe表示区号,每个区有94个字节所以*94得到区的相对位置,L表示内码低字节也是从0xa1~0xfe,L-0xa1 得到的是在当前区内的偏移位置。 因为每个汉字有16*16=32个自己组成,所以最后乘以32得到在点阵字库中的偏移位置,从这个位置开始取出32个字节的点阵数据然后打点显示就可以把一个汉字显示出来了。% s: y/ R+ L) |: v8 {- v
获取点阵的代码如下3 `# l( u( b4 v+ q j3 V+ r3 v% l
, j( X+ d( O3 Z1 ]9 t1 ~. t: ]+ r- FATFS fs1; // 挂载SD卡的分区用( s) \' D P& Y) |: J
- 6 B6 A, e8 h8 A% w H" x
- FIL f1; // SD卡中字库的文件描述符+ U4 u$ [. n& Z Y, `
9 a9 K' E' p0 F+ t8 l3 a- FIL ftxt; // 要读取的txt文档的文件描述符
7 \; Z( R( g9 G4 Q5 j0 o: b
, {# P( N1 @" E: [- u8 fnGetChinese(u8 *p,u8 *buff) // 形参是要读取的汉字# F6 f0 X# T6 q6 S) y2 E7 W0 Z
& {& [/ |$ [8 K! m l! ]! Y- {1 m+ i- o' G& d8 J' X* }
" n5 q5 s& Y$ d# ]- u8 res=0;! |7 O, R: U# Y" T+ K! Q9 a. c
. O$ p# l. W' o9 }- u8 H8,L8;2 M q+ g: ~2 \
6 A" L) p1 j1 F- UINT num;# t1 l6 b# B9 C7 g) ^ y0 n1 t
" V# ^( m; @/ R5 [# A# Z- H8=*p;/ j/ v1 C+ f& M0 i/ ~
- 7 g' z8 R8 [, e4 l# y: B. r
- L8=*(p+1);
. d4 U6 o3 R7 E. k6 w0 b4 Y3 U3 k8 X - ! u& X8 k1 c- |* x
- f_mount(&fs1,"",1); // 挂载SD卡
) |! Q1 k. P8 Z2 Q+ _% x8 o! E
: l! C- S# o: g9 e5 A* t- res=f_open(&f1,ReadPath,FA_OPEN_EXIStiNG|FA_READ); // 打开SD卡下的点阵字库
1 ?) C$ n" X0 a1 @ c8 Y4 W7 @# V - 5 w( m- {4 e/ o# j ~
- IF(res!=0) // 判断点阵字库是否打开成功
. w$ Q5 T4 S& ~9 n" Q+ s
! T2 m$ C: I8 k+ ]# \/ p- {
5 D8 S' G7 W( t- V- M
& e! R& F6 V+ T9 k8 f- fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);" y( W- [! v1 p* I/ a8 J% ~
- 2 a9 E; `2 O8 b7 T$ ]
- printf("res=%x",res);
+ b' a5 g) t; V% [- z
7 _; [/ Q: ~# e0 v1 {/ X/ K- return 1;
& d: ^- g1 m% m" p) @
/ j" l% v# Y" D9 [- }. r2 P, E6 n) I! c C; c
1 @! G# X3 o( o, q- else+ `1 L" S) p! M* t( W4 _
- 6 V2 \) ~1 r& l6 b
- {
, z) w; d% }+ G3 {
8 d% C; ?7 I6 u- fnShowString(10,120,"open ok",16,RED,WHITE,0);
) |- P" r4 S4 d7 q b/ e
5 d( X" o; h/ n# H% r- }
4 t9 K4 v$ f/ {% } w& C5 y- h) Z/ b - + K, A: _. {2 K1 F
- f_lseek(&f1,32*((H8-0xa0-1)*94+(L8-0xa0-1))); // 在字库文件中做偏移取出32个字节的点阵数据
% _3 ~( ]+ x. v0 D3 m' h, ^ - 6 z3 p: Q5 |. K0 U
- res=f_read(&f1,buff,32,&num);* E8 k( S8 W4 o
! Z0 Z' h4 ]+ V( j9 _# E- f_close(&f1); // 读完后关闭点阵字库文件& G6 C# O- d9 ?4 e" W* ^# U
- : y' p9 @; S: e, ~: B
- f_mount(&fs1,"",NULL); // 卸载SD卡
; v. ?* t2 z/ n+ I - * F/ h* F1 o+ O3 { e& h8 g b3 N& C
- return 0;! Q0 f8 G, d- _* [; \9 q6 Y
- . P! o+ u. O1 e
- }
复制代码
9 N8 J ?$ c7 D R 这个是得到汉字点阵的实现过程,得到点阵数据后就可以在液晶上打点实现汉字的显示,具体的底层驱动不再详细介绍。
+ a5 R {" R# x+ H7 p% | 实现了在单片内显示汉字串以后,能不能读取SD卡中的txt文档中的汉字在液晶屏上显示呢?这块是我自己想的,不知道与别人的一样不一样,反正是实现了。
( \8 t6 ?" o, J1 j8 x 首先我读取SD卡上txt文档上的一个汉字,然后用串口打印出来,发现,读到的就是汉字的内码,百度了下说windows中txt文档的显示的用GB2312的字库。既然读到直接是内码,那就好办了。汉字内码用的是两个字节,字符用的是一个字节,这个一定要注意,因为在以后显示的过程中要用。5 E+ B4 u7 `. P: t, |1 \( k/ s
下面直接贴代码:8 k! N" _* t: w- E
& |$ J/ y% Y# u' u$ n# [4 |
- // x,y在液晶屏上的显示位置,我的液晶屏是320*240 ,竖屏显示% n% R# B" ~/ ]" h' O+ b7 S
2 V2 @" v' j" a# U- // color 是画笔的颜色,BkColor 是背景颜色
& E" s- F* y9 \% L T- f+ u - ! B8 l/ Z' h* c
- u8 fnShowTxt( u16 x, u16 y , u16 color ,u16 BkColor )0 |# G i) B" H2 J |# q2 R' ]
0 D$ u$ B/ Y) y3 j- {
# X+ W) B# L/ E) X# e
1 s; y3 A4 s5 N: Z+ E C- q- u8 res=0; // SD卡函数的返回值
9 K# R! E+ y- t: `) v - ) r" H4 Y5 D3 r5 o" P- t3 P
- u8 buff[100]={0}; // 存储从txt文档中读到的100个字节的内码, G( b) X, M0 Y
- 7 f& r. M3 T1 C, D% s; F( y
- u8 bitbuff[32]={0}; // 存储从点阵字库获得的32个字节的点阵数据) K% C: J/ q& | N" {9 S, _6 ~
/ {( D( D& X u$ Z- u8 NeiMaH,NeiMaL; // GB2312内码的高位和低位5 K1 O4 z: ` M0 Z z% l
# p- Q, A5 E0 U, I1 K. f- u8 CntnuF=1; // 用来 判断是不是读到文档的末尾了,如果读到字节的个数小于100则表示读到末尾了3 ^* H, }$ Z1 I: W8 N9 [
; O6 ?2 v! o1 r- u16 offset=0; // 读txt文档的偏移地址. Q* j* U4 C( [/ g) Q1 g
- + j6 M5 }$ N0 h3 M, b ]- N
- u8 i=0;/ d6 Z7 g) e* g# L2 j6 D
- j& U. W8 R! C* x1 c
- UINT Hznum,bytenum; // 实际读回的内码字节个数、点阵字节个数3 o' _" S, ~8 }
- 0 b3 r+ C& T k6 D: S5 \( ~
- u16 x0,y0; // 点阵显示的位置" o' M. \7 R' R6 }- b
- + w4 [' E- f* u& }! |
- u8 charCnt=0; // 读取的100个字节内码中有几个字符,如果字符个数是偶数则下次偏移再偏移100,如果是奇数,
# d |! h& v, S
, r: G# c7 [' J' O- q- // 则读取的100个字节中的最后一个字节可能是下一个汉字的内码高位字节,则偏移99,下次再把这个字节读上。
7 G7 A2 w0 X# Z/ a7 Y2 y- t - 0 U2 c7 } ]3 O8 M0 C; [" X
- x0=x;- g8 ^: |( Z0 f2 I* p/ U* @( Q: [
- 7 ~0 l$ Z# H8 z a/ v" G' T
- y0=y;
. F- e/ ]4 T2 D - # ?' y0 ^2 d* p7 H- G& u
- f_mount(&fs1,"",1); // 挂载SD卡! G& Z& t5 a- ~; Z& ?
- 3 l- i w" P I, |
- res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ); // 打开字库文件
* n7 e& L# ^- A- ] - ; R# B% Z4 E% H- u& e; e2 Y
- if(res!=0)4 F4 I% X6 g% b8 m
8 I' ?7 v G9 O- {" W, \! b' ~0 D4 h; t* R
- * {+ k4 D. V( S7 B6 m3 j
- fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);1 z8 y l- y. C9 o0 G7 _& u
- + X6 \7 C. a! ]) F# P
- printf("res=%x",res);
% T0 ?' X5 X) h# ~2 S6 H" ]) O - + B: g! x( t8 \ _5 e
- return 1;
7 R5 v. i; s% A9 Q5 A+ a
2 ^2 V% e3 s# _* D; E2 @8 c- }
/ l: |: ^7 s4 D
, H( f# f/ b5 z9 z h+ A- res=f_open(&ftxt,TxtPath,FA_OPEN_EXISTING|FA_READ); // 打开txt文档 V( ^5 \% r: `6 A' b Z! S% Y
9 X9 T% s; b+ @- J( e- if(res!=0)
g7 f$ f7 i6 `6 _3 u - : P2 k- h v6 ?0 t
- {5 t4 \+ }6 o5 c: a
( V9 ~7 a2 v$ J( s- fnShowString(10,120,"open txt fail",16,RED,WHITE,0);& I. q4 q8 ^8 S$ |2 f* y6 g& _
- & S0 a& H) w P/ J4 U! H. k
- printf("res=%x",res);
8 Y9 D/ V {2 J3 v( t
$ {5 }9 F0 ]' K# [# g S- return 1;) B; |2 h; g( V# t. K- i9 \
- % {2 M! s1 d- X2 X- b9 E6 o; t
- }( u2 |" b8 ^, s* D
- 6 L# |% Q3 n1 O+ S7 h$ L0 _6 k
- f_lseek(&ftxt,offset); // 初始化偏移为0从头开始读。
* x5 t0 o3 h$ q" A3 B9 i0 R
2 _. l2 M M/ A9 e/ S0 J- res=f_read(&ftxt,buff,100,&Hznum); // 每次读100个内码字节0 D! S% p8 h& h& o4 ~
8 ]+ ]# X6 u8 G- while(CntnuF) // 循环判断是不是读到文件末尾了
, Z) h# o& E: e' Z: y
5 a5 ^8 a4 {1 r" R- {
+ X3 v' C2 a4 ~
; k0 T* x) B: i! f9 S- for(i=0;i
# {! x7 z1 l* F1 Q- G
' a: s5 {2 g* l- {$ S& {' c% b3 I/ P
# ] ~, v |& j) B& P( R- if(x>220) // 显示位置的判断: L/ i+ E. B/ _
, y: H4 p( q% v: m) y- {+ Q9 i! a$ _3 T; p
" s: z0 ^3 x: \& `& f) {- Y- x=x0;) I' l# v h* b$ L/ U
/ N; e: D: s+ e7 n. T# e9 M- y+=16;$ J4 d) _) b5 R
- + Q3 v9 v4 ]/ t* R% p
- }1 p8 Y1 w2 u% O" m7 T- H' M* W
- ) W& J# i5 |. ~& J \' s# h
- if((y>300))
" o. y; M3 w1 @* w$ S& y - 9 v' _, X' l6 m" q% q4 E( B: e
- {
3 t- P6 {- j# b5 R5 C# X) D - # w# U R! k. a5 y
- fnRefreshscreen(WHITE); t5 q* k% u0 s; q# C
* M* E' U/ F" L1 i' o- x=x0;
3 [" ^% N% L7 c! @
5 K! d3 ]9 Y* c/ x! z' E% ~2 N- y=y0;6 d8 T# d" H) B# I+ u+ p% F* j* |# R
) Q, n+ J# W. g2 a2 Z8 ]0 Y- }; r" X9 m* |* b2 v( C
" B& j: e3 b# m' n: x. Y7 C- if(buff>0x80) // 是不是汉字; _# V: x% u0 V8 Z% T' `. v+ {
1 b/ G$ M* G7 t7 ~( l) j- {4 ?! T7 `( e. h- G4 b
- 9 W- R5 H0 d8 `# u8 R
- f_lseek(&f1,32*((buff-0xa0-1)*94+(buff[i+1]-0xa0-1))); // 点阵字库内的偏移* h: \+ H. o& I9 k" d5 d+ m: H' z
+ P3 t2 i5 E9 V# e9 Z- res=f_read(&f1,bitbuff,32,&bytenum);
+ p0 Q1 N8 `" t, P, m |
( s* d) B' A' k) v3 u4 \" ?: \& i- fnShowHzk(x,y,bitbuff,color,BkColor);: d" N- x2 e2 E7 r6 i# l# l
4 ]* o4 F3 G( E( l. ^; f9 X- x+=16;* f5 M) w4 i! b* q
- 9 f' C- f, {( b G0 |2 ]# k
- i++; // 这个i++非常重要,因为一个汉字两个字节,除了判断语句i++,( Q$ L% s5 i: X5 \0 p
- + M& q6 n, H- T" |% T- v% P, ^
- // 这里需要还要一个* _/ j* c) `$ [6 Z1 P5 g" d
! Z7 h! a# J) P1 v) h- memset(bitbuff,0,sizeof(bitbuff));/ [. T& S2 w' }* R1 u
- % T+ M, I- y6 A$ T8 [0 L
- }
* }) d6 t, E" b1 \+ X) h - * j, D/ f3 G* z( |
- else // 可能是标点也可能是换行符2 f# A4 @; x0 m# ?# I
* \, N2 d/ u3 q7 i- l2 g: g- {& p; D3 T3 b+ M$ k: W0 X0 N! w
- 4 K/ \1 v9 h+ f7 x& N
- if(buff==0x0D) // 换行标志
. B5 ~. i& b5 D8 o$ h
D- {/ |( O- F. l% x$ r" _) n- y+=16;
5 K+ R8 \1 ~* |$ f5 G* k% I
- f i$ J- L4 d% S% i- T8 [+ p. q- else* X" \8 g% P N
- 9 q% G% {8 Q# O" F
- fnShowChar( x,y,buff,16,color,BkColor,0); // 字符
. q- N( W/ z8 Q+ I, u: }* |
, D7 q6 I* D4 q) z0 e* T% g. U% K- x+=8;
* U7 `! k) s% `! f2 C& b4 ] - # n7 r0 Z3 n& T' v
- charCnt++; // 字符个数计算,用于判断下一次读txt文档的偏移地址
0 j/ N# Z! I" G" U2 i
" Z; I: y! G7 ~: z" A- }* p9 q1 M; I1 a' X) E4 ]
8 }; B# ] C8 V( I! H u9 F: U- j- }7 r2 \# K# `. K) a! j$ Z' K0 j
3 U# G0 {* i; b) a* b- // 计算txt文档的偏移地址
6 `* T$ s3 g1 X& u1 C
3 x4 x+ h' d5 j- M1 }- if(Hznum!=100) // 判断是不是读到文档末尾了
& y1 t* _: Q* g- o* X8 ~2 y
: v# i) u4 N, r+ Q6 h- {, ?6 W; a4 A' N1 d5 m* G6 T' U
- % q' n( O9 f6 d6 _) k1 b
- CntnuF=0;
5 y6 L1 L# K, o9 B' w0 l - 5 r# P- s( w p; n
- }4 D) n1 ^3 d0 T+ T8 }: Z
- h e$ e! X4 o
- else // 没有读到末尾继续读
! F8 y4 A# S2 W8 j; n
4 N3 ^1 h( V. }$ M+ m2 I$ |* o- {
2 y; f7 P6 \' a: o0 H8 @ - - V( f' n: t6 O; z' M5 D- J c
- if(charCnt%2==0) // 字符个数是偶数,100个字节内码里边正好成对出现,地址偏移+100
% Q1 W1 z6 o7 f9 v - / S) s4 g4 t6 k: `$ `& M; h, V
- offset +=100;- H$ N" E) _$ c! z5 y. h
' P) ~4 t9 h& l) e( D! w- else
- u9 d$ X# Z! M* x2 A - 2 @: v5 m# ^, o6 {: C, D
- offset +=99;, m. I2 p: I/ M# }1 b r! v0 j& f t5 R
7 l. o( u( w/ v% |* K1 Y- memset(buff,0,sizeof(buff));
. f( ^* c8 o9 W- X. J" l - . [4 P, ~; H# u1 ]! T: F" M5 U
- f_lseek(&ftxt,offset); // txt 文档地址偏移" v+ a' [3 u' m7 ?/ X: C
7 r( K$ Y/ ^, Y- h1 M- res=f_read(&ftxt,buff,100,&Hznum); // 读内码数据, ~, u/ M8 c& ^8 Q! G5 d; D2 K
- 1 \& ~! e% ~1 P+ ?
- }
1 s& D: J3 j- }. Z9 l9 J
* B$ L! g) l; E) @% D- }, j3 Q* w3 R" h1 _* \3 Y: U
- 7 u! M8 _5 _2 q" ?' N* ^! }
- f_close(&f1); // 关闭打开的点阵字库$ A; e" w% j/ U% {$ @
- ; [+ [% C9 B( K
- f_close(&ftxt); // 关闭打开的txt文档; ^& P u5 n8 ~1 l5 Z# v8 ~5 Z" k
9 d6 P" _ n2 C4 g3 V( R0 G3 F- f_mount(&fs1,"",NULL); // 卸载磁盘
! \$ z) \' B n' f* c) C - 4 A* A3 A. W: [5 `4 Y
- return 0;% ]6 T+ f. [1 S, X4 b2 k7 b
3 o: t2 q2 m! s# J( l* X, a7 x- }
复制代码
( W" x# {0 L0 Q+ g* N) d1 E 以上是简单的电子书的实现。
' N% c% l- d" m { 因为不同的系统有不同的编码这个要注意,比如我再Windows上的汉字拷贝到CSDN网页上就是乱码,这是因为使用的汉字的编码不同,对于不同的编码格式,还需要做内码的对应转换,把其他的格式转换成GB2312或者GBK格式然后调用字库显示。
; ~* t! I2 t6 j7 Y: U' e4 q- m v 其他常用编码格式Unicode、utf-8等的具体介绍和转换成GB编码可以百度。- o" \9 N7 P. A, s0 b
SD卡注意事项:. ~5 I/ O* a, b: F- E
对一个文件读,必须先打开文件,读完后关闭。* c4 X1 x- v& u# N6 F
对一个文件写,必须先打开文件,根据情况确定打开的权限,只读,读、写、创建等,先完后最好调用f_sync()函数,这是一个同步函数,类似于linux中的同步函数。SD卡中的写函数应该是带缓冲(猜的),在关闭之前调用这个函数将缓冲区的内容写入SD卡中,然后关闭文件,否则可能写入失败,不能将内容成功写到文件上。4 r( g1 g! G. s: G, v4 p* r5 E
文件的打开路径,Windows中的文档可能是隐藏文件类型的,这个一定要注意,隐藏文件类型的a.txt和不隐藏文件类型的a.txt 不是同一个文件,这个一定要非常注意。
4 h5 g# f6 g9 m9 @
/ Q1 C+ W* ~2 Q' S
* q; `$ M- m8 l# c3 t |
|