|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
今天玩了会液晶屏,原来显示汉字都是也取模软件区模后在液晶屏上显示,显示内容改变以后还需要重新做字模,比较麻烦。这两天有时间,参考网友资料,实现了读取汉字的内码从SD卡的GB2312点阵字库读取点阵在液晶屏上显示,字库的生成软件用的是易木雨的点阵字库生成器。能生成很多种语言的字库。做完了读取显示后,我自己又琢磨了一下,简单的实现了从SD卡中读取txt文档然后再液晶屏上显示txt内容。: T; M; L5 T* o2 ~ U
取模过程注意点阵的宽、高和字体大小的关系,宽、高是我们在液晶屏上要显示的像素大小,字体是汉字大小,如果宽、高一定,字体大小太到的话,字在液晶屏上只能显示一部分,可以在左侧的预览区看出来,如果字体在宽高像素点的范围内则可以在液晶上显示完整的字,如果不能显示完整则可以调整宽高或者字体大小。& a8 e7 A) }2 h/ n5 P/ O) q
国标字有GB2312和GBK编码,GBK完全兼容GB2312包括内码的兼容,A而且GBK字库增加了很多字。汉字都是用的两个字节表示,第一个字节是区号,第二个字节是在区内的相对偏移位置。通过内码来获取字库内的偏移位置,偏移位置与内码和生成字库的宽高都有关系。我生成的GB2312字库是16*16个像素点显示一个汉字,那在字库内的偏移位置:9 |! z4 P3 M1 ]. }* l; N5 B6 C" s2 P
offset=32* ( (H-0xa1)*94+(L-0xa1) )3 L1 v2 b+ n# z9 D! y& N
H 表示内码的高字节,L表示内码的低字节。GB2312高字节是0xa1~0xfe表示区号,每个区有94个字节所以*94得到区的相对位置,L表示内码低字节也是从0xa1~0xfe,L-0xa1 得到的是在当前区内的偏移位置。 因为每个汉字有16*16=32个自己组成,所以最后乘以32得到在点阵字库中的偏移位置,从这个位置开始取出32个字节的点阵数据然后打点显示就可以把一个汉字显示出来了。
$ B7 Q; g' P o 获取点阵的代码如下6 \& F/ z5 z' p2 P. }- B
( w7 g! A+ N$ P, P& i: Q
- FATFS fs1; // 挂载SD卡的分区用 @5 D9 G' X4 W
- 0 S- A5 l( d2 C E: [
- FIL f1; // SD卡中字库的文件描述符
2 M: D+ N' |6 K0 Y6 }. J% y- r- y
) b9 X7 r. I2 ?, z" Q5 r' ]- FIL ftxt; // 要读取的txt文档的文件描述符9 T5 X( I J$ u4 K( ]6 m
( r# u# ]4 r( Y9 r: M- u8 fnGetChinese(u8 *p,u8 *buff) // 形参是要读取的汉字, F; p% l/ B% q: n
- : [- j, w& A. ~4 d2 J8 x
- {
) A# m u+ I* f% d4 S2 @9 V# P8 [
: L) A$ ?$ i' X- u8 res=0;
: O6 z, W3 R: K" `2 T. k) H - 7 _9 ]; j' ]! r, D( E# H* w
- u8 H8,L8;8 R' g! g- a8 Y
- - q, ^* N; o6 ]# R' V5 j5 }
- UINT num;
% J; x& Y8 H9 n; F* [7 x. b - 8 f. a% q, b6 Q' w5 a1 y
- H8=*p;5 G# ~1 b) c$ d7 `* b3 Q
6 k) n% B; ~$ u& C' m' i4 q8 V- L8=*(p+1); M% V) W4 J1 q" n
) G! B6 a6 c5 |* B5 J" y, e- f_mount(&fs1,"",1); // 挂载SD卡
( x" {% y2 S, B- G+ C" L
4 I% g |$ }. ]& l& Y) e/ P- res=f_open(&f1,ReadPath,FA_OPEN_EXIStiNG|FA_READ); // 打开SD卡下的点阵字库) D1 B H7 v' }. T
- 8 A1 ]' y0 w( y% _" b
- IF(res!=0) // 判断点阵字库是否打开成功
0 g) ^6 d+ c4 ] y" a& {2 U - 1 K) I& m5 p/ n" ?0 m" D
- {
: a7 w- T" J. D - # s$ P" W- _# C g5 f
- fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);
9 n& a* s" w* B" V' k+ a B; C0 \ - 3 g5 H; p- c; e1 Q* S1 v: i" W
- printf("res=%x",res);
9 i+ ^# k7 u( v' E0 b, O* M4 I - 3 ^9 v/ F" t' c7 c( a! n! D; `
- return 1;8 s7 O; h0 l1 b6 j# F9 b* p
+ N: l& C3 i9 K$ ]- }
( m! O; c% E' ?$ a, ~ - * X( \% T$ F+ F" M% _
- else
; @+ V( M8 F# _1 t/ ~2 R - " V4 h. E, `: w4 i+ f
- {
G- q# ^9 g# x6 T& j; J
2 R# [# H7 X( V1 H& w& ~! z- fnShowString(10,120,"open ok",16,RED,WHITE,0);
7 P! c- m- O' w9 @" @, @' w - 9 s. ]/ a4 f5 k* c2 r, K& h) ~) Z- X
- }% G8 W8 d; O7 Y" j8 |+ V) ]8 |
5 W# N$ v6 ~8 D- f_lseek(&f1,32*((H8-0xa0-1)*94+(L8-0xa0-1))); // 在字库文件中做偏移取出32个字节的点阵数据8 @+ o9 \* N' y. h5 r
- ! r# _2 l% c+ A5 Y
- res=f_read(&f1,buff,32,&num);
) P$ J7 K0 C, P9 Q
7 h( z0 m) H7 m7 F% Y1 r+ C& }4 F- f_close(&f1); // 读完后关闭点阵字库文件
$ q0 ^2 v& C1 o, F5 V& o9 r
( c i. J: M+ [ A- f_mount(&fs1,"",NULL); // 卸载SD卡
2 { k# N+ c0 |. D+ c2 P n" C - ! q6 X/ I1 I; I" Y) U
- return 0; z' O; L1 V( F( } _% L" L$ b
& A0 D: c; H( L( G' O- }
复制代码 3 v/ ]/ o: i0 A. H1 }
这个是得到汉字点阵的实现过程,得到点阵数据后就可以在液晶上打点实现汉字的显示,具体的底层驱动不再详细介绍。
& f9 r! l: X/ `1 f! F" w3 E3 | 实现了在单片内显示汉字串以后,能不能读取SD卡中的txt文档中的汉字在液晶屏上显示呢?这块是我自己想的,不知道与别人的一样不一样,反正是实现了。
( I/ N& W# R1 g 首先我读取SD卡上txt文档上的一个汉字,然后用串口打印出来,发现,读到的就是汉字的内码,百度了下说windows中txt文档的显示的用GB2312的字库。既然读到直接是内码,那就好办了。汉字内码用的是两个字节,字符用的是一个字节,这个一定要注意,因为在以后显示的过程中要用。
: E. U" c3 u& W; y2 B& c+ ?8 C1 M 下面直接贴代码:
$ {/ G5 N# w$ u- a, T! {4 W& d, [ |; x5 k, W1 H4 v
- // x,y在液晶屏上的显示位置,我的液晶屏是320*240 ,竖屏显示4 j* f$ o- F0 x0 M8 ?3 @7 Y
' R) F$ `7 U! ]5 L- // color 是画笔的颜色,BkColor 是背景颜色5 r. \% f7 @1 B, B5 o
- - m: H, H% k8 w
- u8 fnShowTxt( u16 x, u16 y , u16 color ,u16 BkColor ), Q$ E, I6 U, w z
0 v( n; i) s4 B; t5 a- {
$ F3 Z T# ?$ R& E9 X - $ n8 Y. d9 s9 a- @; _/ F) W
- u8 res=0; // SD卡函数的返回值
7 Y# K% T3 C8 T7 k
8 m- ?/ {# P- W. c8 z- u8 buff[100]={0}; // 存储从txt文档中读到的100个字节的内码) {( k7 J% J3 B/ M4 R
- d6 W1 N: O/ o1 n1 h2 f- u8 bitbuff[32]={0}; // 存储从点阵字库获得的32个字节的点阵数据4 u; j7 I: ^9 c0 P: c7 l
" V+ z6 M# W" r# C y9 E% {/ f- u8 NeiMaH,NeiMaL; // GB2312内码的高位和低位7 a: c, C- Z/ c. R! Y! S7 ^$ I
- a4 U3 A- I, v, ]
- u8 CntnuF=1; // 用来 判断是不是读到文档的末尾了,如果读到字节的个数小于100则表示读到末尾了; o, X- `2 c* V r/ h2 X _6 K6 b
9 ]5 W# r* X1 `( Z/ D7 p- ?- u16 offset=0; // 读txt文档的偏移地址" D# S3 m, ^) c1 A) t1 G
- ; n7 I+ n% \% _
- u8 i=0;1 X+ g2 a& P6 v" \9 M/ }- E7 H* g3 Q
; l' {% {. |5 D& v- UINT Hznum,bytenum; // 实际读回的内码字节个数、点阵字节个数$ G0 ~9 Y3 F& [
4 J t9 A. N* p% s: i; b- u16 x0,y0; // 点阵显示的位置. Z) J- E u+ {
$ X/ O& m" w1 o0 l1 g& U- u8 charCnt=0; // 读取的100个字节内码中有几个字符,如果字符个数是偶数则下次偏移再偏移100,如果是奇数,$ d' ^4 I: B: v+ d: n! }: u: U
- 4 i+ M$ O2 f- O* T7 e( P( `
- // 则读取的100个字节中的最后一个字节可能是下一个汉字的内码高位字节,则偏移99,下次再把这个字节读上。: D5 P0 W7 a/ r/ z" e/ H" f( r
' J# \8 h- I! F. [% F5 A% `3 v d- x0=x;$ w- N- @$ {; Z. I8 g/ ]8 m5 |
0 @1 B+ ]0 w+ M8 N- ]- y0=y;
; S1 i1 R# D3 S# F3 ^ - : s2 A! h% ]$ t1 p5 @: e# }+ }7 {) R
- f_mount(&fs1,"",1); // 挂载SD卡- O. V7 ?( L8 w
# X1 y$ ^8 j6 a c5 \* @. d# D- res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ); // 打开字库文件. ~5 ]! w2 v$ a" _3 d
- " X: f) R8 G8 Y
- if(res!=0)
' W5 l0 u1 V6 h$ c2 q - * r+ B/ i4 p! a# ~
- {
0 @& _6 v, [( ^! {$ k f2 t3 n - ) v" L* X3 B0 ~9 ~
- fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);
! D' N, Q# Y3 ]2 R( A' b7 M. f& ] - 5 ?/ `* w7 h' p; v& I. K% G
- printf("res=%x",res);' x/ ^/ e' n# ?1 r6 W! Q
- 8 _" j3 g5 ?$ p9 @( F5 A
- return 1;
- M; s# Q; T3 Q0 o
" B* e0 z1 Y" e- }- E' ]3 ~. y3 S& ?" K- ^
* C1 r% f, ^4 h' W- res=f_open(&ftxt,TxtPath,FA_OPEN_EXISTING|FA_READ); // 打开txt文档, k g' O* P* M5 m
- & @6 L' @! ?& [& y) @+ }
- if(res!=0)" G! m8 A {8 |; k
- . m- j) |! Z; L3 q
- {8 J5 B: S* H/ k8 P3 J- Q
9 w; D3 ?' ^& M3 ~- fnShowString(10,120,"open txt fail",16,RED,WHITE,0);( Z$ x7 i9 T F+ p4 T
- 4 `# u& a* J3 L( q' ]6 G6 Z. u
- printf("res=%x",res);* J% ~+ e) e4 M- D4 l
- / r! I3 `) A9 h' y' v8 w% r; Q
- return 1;
" Q) R3 u% \' D) U- H' Q( W0 G4 `
* E* T/ N+ |& L( |- }
& F* t0 V; q% d- o) Y& M
7 q( B# D6 Q& J- f_lseek(&ftxt,offset); // 初始化偏移为0从头开始读。
; B+ V$ ? [1 P - % D7 {$ i) R8 Y- ]2 k# H3 f( z
- res=f_read(&ftxt,buff,100,&Hznum); // 每次读100个内码字节6 N) ]. ?: _5 P
- ' d9 J; M% i5 t1 q7 m' [) `
- while(CntnuF) // 循环判断是不是读到文件末尾了
8 Y6 x& B8 J; R' W W* p
& C; J2 \5 Y+ [: V1 ~- {
+ b. Y# Y N% b4 r
7 }: C1 J* a0 |+ N- for(i=0;i( K) D( G0 w3 C m! c( X
- & T4 a' T/ Q: ]
- {
$ O( w: H9 X3 E, ]9 d, R9 a& b( s - " _$ t# P+ x/ q7 ]$ b4 h, n
- if(x>220) // 显示位置的判断
# m/ q$ Z- V" a' s: h% U - - p0 r X9 J4 o2 d/ u3 _
- {4 g, X' h4 N4 {7 H: b! F$ |
$ q8 ^, V; ^5 i8 R9 j- x=x0;
! z+ ?+ I! ^. z - 7 v$ o6 ~" M+ d
- y+=16;
$ `, i( ?% E0 l# q' U4 s0 Z9 b - 4 i: b* Q7 B% E. B
- }
9 K( ]7 E/ v$ F - 0 K! P6 M; L, X* G: K
- if((y>300)), u) l; R. Z: x1 c+ N, N$ Z( g
% [" N0 A% x1 M2 v8 E$ t- {
9 S" U% z" Q( s2 B9 {& e
7 X5 [. O6 ~! K- fnRefreshscreen(WHITE);
! b0 T- I9 h- W" V: ^
* |$ k) k" P& |, ~- x=x0;, W a4 c% o% w# p2 d
- ( e) n; E( H6 D8 `
- y=y0;# h5 t, x) \! d
! U3 w+ z1 g, a+ t' x: F/ e- }! k$ L$ |' \( f6 X3 B
# T* Z7 d! z! G- V* T- if(buff>0x80) // 是不是汉字0 ]3 Y6 J( g: {6 j4 d% k
- 9 |0 W$ ?1 B9 z1 A: ?& ~ h
- {
: y( M E! S4 D& K8 v! l9 P$ \4 K - 3 H9 |* U$ `/ o7 D, A/ P( b
- f_lseek(&f1,32*((buff-0xa0-1)*94+(buff[i+1]-0xa0-1))); // 点阵字库内的偏移' H& v( I- {4 ]6 R, S& `& P* _
+ h2 R7 {" t; |( Q- res=f_read(&f1,bitbuff,32,&bytenum);6 u+ d8 G1 M- V' |6 P% ~
- + N8 j( h! P6 N' c
- fnShowHzk(x,y,bitbuff,color,BkColor);
~. e7 f( [8 e# ]0 \ - 9 [3 Z/ t9 x! e& N) Z
- x+=16;! E6 R4 p, F4 U% c" A7 ?2 D1 D
- 0 }4 u9 w5 `2 W$ O2 Q5 F
- i++; // 这个i++非常重要,因为一个汉字两个字节,除了判断语句i++,7 p2 Q( I- e0 L T+ p% d) F
& i, O% v( N! [$ s8 d2 ?" i- // 这里需要还要一个) B3 C7 S- n# r* x) F" M! I
. S! Y' i K% N4 K& F- memset(bitbuff,0,sizeof(bitbuff)); m. {; m1 e c$ z [
0 e* {" Q, f1 X- }
$ m) _, b3 j$ Q3 i+ z9 _% g% R9 F
2 D+ I$ N) j/ f4 w& o- else // 可能是标点也可能是换行符+ S% G7 s& X$ ~; }# \. r8 s9 v4 U" A
W6 I% ^$ q5 Y( x" g- {
6 _ E6 G' m2 z8 j
& z4 @; J: P' N5 k- if(buff==0x0D) // 换行标志8 P; i e1 w% y1 k% }* f" v, i
; P" t. ?" r7 c! t) `8 ^7 [2 |- P- y+=16;. X1 G0 ?2 K- w; b; n
- S' L3 ^+ ?) f8 F- else2 [5 c7 p4 y. d' E0 V. d4 l
/ M) p2 O3 n( ]! ~% _# D+ `- fnShowChar( x,y,buff,16,color,BkColor,0); // 字符" L1 {5 h4 S9 @0 q
' M6 X2 ]& _ Z2 ~1 G4 |- x+=8;0 A ~8 ^6 ^( m0 }! y* E
4 e# Q3 C( S2 i) c- charCnt++; // 字符个数计算,用于判断下一次读txt文档的偏移地址
9 x* s% S- x% p1 l- Q- J( s: j9 k y4 X - , L# R0 ?( x: U( F5 A
- }" @, m9 g9 L* _9 V
- 8 \6 i/ w& ]( q. W$ v( }
- }
! I; x. r+ y" _% X8 K+ v - / k, a2 t: P' `# Z* ^" I( p
- // 计算txt文档的偏移地址# `5 @' A) o7 j0 B- F* ]- r" E7 l. K/ q
1 L5 A; \! B6 M2 Q. W" j- if(Hznum!=100) // 判断是不是读到文档末尾了; R5 k( d- I/ E, F# @& F1 I
- * b7 Q3 A( \( n4 Q! @8 I* ?, {
- {
( ?/ Y5 B. ]8 W
: T% o: V! H9 {- r( J& v; b' U0 q7 g- CntnuF=0;
+ ~: R5 w! Y" ~ - - X# [5 s e/ ~( q) t
- }4 `' o1 s j( l. T n2 v2 W: M
- / G* P! w) L7 E* ~$ S! W7 h, |8 K
- else // 没有读到末尾继续读) k6 h! k0 U- u/ ]
- . O. B% e8 ? E. z! m
- {2 c0 Y; Q& X+ m+ ?7 U0 I3 ~
3 S4 |* y9 \' n2 W. [ F- if(charCnt%2==0) // 字符个数是偶数,100个字节内码里边正好成对出现,地址偏移+100
, h% N: Q8 K2 P) S/ a# @. ^- _( j
7 G+ m$ r, T* F g- offset +=100;
) @0 K2 r: y: K* l5 ~: c" z. V - 9 U* I0 j8 \: C p1 I$ J' q
- else
3 ^% H/ { d* [4 @( ?5 ^
' b. G- f1 [. d1 T* X1 I) A- offset +=99;$ Z6 v1 l; M( a1 _, u- k7 J
4 H6 r9 L3 S T4 H- memset(buff,0,sizeof(buff));
- v# L9 J3 y+ p8 x
% ~/ t7 f! |4 i& Q1 k- f_lseek(&ftxt,offset); // txt 文档地址偏移
& [5 \* H! E& @6 Z7 ?4 Y1 ` - 5 q) a' H) |3 p
- res=f_read(&ftxt,buff,100,&Hznum); // 读内码数据
3 K. A0 F5 y/ ]( w; b - 5 q% C" E. D/ E/ p) w
- }6 j" b/ a% e H/ Z
- 2 H1 G4 P# i6 Q# D# [- a
- }, D$ d7 z$ `$ d. I( s( {
- 4 [: s# O( O9 b& P: h/ e
- f_close(&f1); // 关闭打开的点阵字库 G, s2 j- o* U
- 2 {8 N! x' [7 `- H; {
- f_close(&ftxt); // 关闭打开的txt文档
+ S& J. _# V4 J* v8 x - 5 d- W% i; k* ~) F
- f_mount(&fs1,"",NULL); // 卸载磁盘
- ^% w. u; k( _
) S* u0 F6 a9 G, Y: x: U- return 0;4 p6 B+ a" \5 F( W7 g
- " y: B6 p+ V5 p8 e. R1 Z+ ^- r
- }
复制代码
, W5 o0 Y6 V( _# u9 h 以上是简单的电子书的实现。
2 f8 M$ |" G+ R# l& Q6 m# b* l/ ~$ j& s 因为不同的系统有不同的编码这个要注意,比如我再Windows上的汉字拷贝到CSDN网页上就是乱码,这是因为使用的汉字的编码不同,对于不同的编码格式,还需要做内码的对应转换,把其他的格式转换成GB2312或者GBK格式然后调用字库显示。: {* J5 H2 H8 s
其他常用编码格式Unicode、utf-8等的具体介绍和转换成GB编码可以百度。( ]3 X! z2 o8 S2 f* S. H
SD卡注意事项:
# Y2 b* m8 j, ^ 对一个文件读,必须先打开文件,读完后关闭。- r: B& M, V5 J
对一个文件写,必须先打开文件,根据情况确定打开的权限,只读,读、写、创建等,先完后最好调用f_sync()函数,这是一个同步函数,类似于linux中的同步函数。SD卡中的写函数应该是带缓冲(猜的),在关闭之前调用这个函数将缓冲区的内容写入SD卡中,然后关闭文件,否则可能写入失败,不能将内容成功写到文件上。8 O. H( ?. T7 ^, H. k3 f
文件的打开路径,Windows中的文档可能是隐藏文件类型的,这个一定要注意,隐藏文件类型的a.txt和不隐藏文件类型的a.txt 不是同一个文件,这个一定要非常注意。' T: H, a$ q; W. y5 R" N+ \. h
- t' U: _, r* J. v. A' s) ?* q" U% i
|
|