找回密码
 注册
关于网站域名变更的通知
查看: 397|回复: 1
打印 上一主题 下一主题

基于STM32的简单电子书的实现

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-9-10 14:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
  今天玩了会液晶屏,原来显示汉字都是也取模软件区模后在液晶屏上显示,显示内容改变以后还需要重新做字模,比较麻烦。这两天有时间,参考网友资料,实现了读取汉字的内码从SD卡的GB2312点阵字库读取点阵在液晶屏上显示,字库的生成软件用的是易木雨的点阵字库生成器。能生成很多种语言的字库。做完了读取显示后,我自己又琢磨了一下,简单的实现了从SD卡中读取txt文档然后再液晶屏上显示txt内容。8 i# z/ U" P9 G4 D
  取模过程注意点阵的宽、高和字体大小的关系,宽、高是我们在液晶屏上要显示的像素大小,字体是汉字大小,如果宽、高一定,字体大小太到的话,字在液晶屏上只能显示一部分,可以在左侧的预览区看出来,如果字体在宽高像素点的范围内则可以在液晶上显示完整的字,如果不能显示完整则可以调整宽高或者字体大小。
6 @! d# P# U, E' q) t  国标字有GB2312和GBK编码,GBK完全兼容GB2312包括内码的兼容,A而且GBK字库增加了很多字。汉字都是用的两个字节表示,第一个字节是区号,第二个字节是在区内的相对偏移位置。通过内码来获取字库内的偏移位置,偏移位置与内码和生成字库的宽高都有关系。我生成的GB2312字库是16*16个像素点显示一个汉字,那在字库内的偏移位置:
, G3 k* ?* @6 K4 D  offset=32* ( (H-0xa1)*94+(L-0xa1) )0 ~8 t! n9 E. n6 e
  H 表示内码的高字节,L表示内码的低字节。GB2312高字节是0xa1~0xfe表示区号,每个区有94个字节所以*94得到区的相对位置,L表示内码低字节也是从0xa1~0xfe,L-0xa1 得到的是在当前区内的偏移位置。 因为每个汉字有16*16=32个自己组成,所以最后乘以32得到在点阵字库中的偏移位置,从这个位置开始取出32个字节的点阵数据然后打点显示就可以把一个汉字显示出来了。
6 k/ |  S0 Y) t" p% t+ _+ ~  获取点阵的代码如下& X" e* J0 f0 a! {4 c9 ?/ E

8 T# ?9 D3 O1 c/ D
  1. FATFS fs1; // 挂载SD卡的分区用
    2 u$ w" K9 v) P7 X( Y# K6 ~

  2. 7 C. t. w! {" Z; \7 \' [* w* y
  3.   FIL f1; // SD卡中字库的文件描述符; g8 l* |/ h  j: K3 {& T) l
  4. ! `% J% K+ ?5 R" U; d& x( u
  5.   FIL ftxt; // 要读取的txt文档的文件描述符
      w2 u* W/ z; K. c' X# Y0 m) u
  6. % G8 ?  N2 B) D0 ~
  7.   u8 fnGetChinese(u8 *p,u8 *buff) // 形参是要读取的汉字- G8 L$ C/ z4 p& O' ~

  8. - e; H/ `& J+ `, J4 l  O( `
  9.   {% m9 u1 Z+ O: F  m. D5 H3 C8 v

  10. : E; H2 ^5 G& z6 t) E5 Q
  11.   u8 res=0;$ Y. H* e; G2 ?5 v

  12. 3 s+ O3 \0 w/ ^9 K$ ]4 N8 u
  13.   u8 H8,L8;
    1 g9 F% A0 T0 d( N& B5 E8 B

  14. . \' [" U4 R+ w) ^
  15.   UINT num;/ T# W: \: Z8 k

  16. - G) K. A1 z3 ^' Q  r! B6 [
  17.   H8=*p;) O  ^* L1 l/ y/ O7 y$ |
  18. ; Q& C" ^6 t  v$ n4 `
  19.   L8=*(p+1);
    % Q  _! O; ]4 t! i

  20. $ O% ?1 o3 x2 p1 X% I
  21.   f_mount(&fs1,"",1); // 挂载SD卡  _* ~0 W/ c7 w7 y' j: ?( B7 d1 ~
  22. " R; x+ q# F& p& J; Y6 y; ?! y
  23.   res=f_open(&f1,ReadPath,FA_OPEN_EXIStiNG|FA_READ); // 打开SD卡下的点阵字库
    . o) u. {0 D6 w1 u* g5 U" E6 z
  24. ( x% Y( h& e) X: x
  25.   IF(res!=0) // 判断点阵字库是否打开成功
    9 V/ e  l6 y# j2 _
  26. # b* P# \& U5 v2 x1 E- j/ |
  27.   {
    / u2 e6 o& X) n* P. v7 T+ j6 Z( U

  28. % a9 E: W7 x* }+ Q
  29.   fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);. I) ?7 S6 R3 u0 a. m$ q

  30.   _7 N9 j2 L: I/ v
  31.   printf("res=%x",res);
    6 D  f/ K3 k* N9 N; _9 Z1 B
  32. , {8 L. t5 `& H* J8 v3 \
  33.   return 1;
    + M# I  M5 o7 J2 }2 t0 ]5 R" I

  34. & f% c8 R7 i7 R
  35.   }: E) y/ O2 t* a9 H- K8 c9 P
  36. $ R1 V2 h7 G: q+ ?' s# t0 Z: C6 [
  37.   else
    - p0 ^% y; t3 f: A/ S" [/ X
  38. # X# S  y( \, s- q3 ^0 Q0 q
  39.   {
    7 f: D6 C- L" G  C

  40. . o, C7 ]! E1 M* R9 t
  41.   fnShowString(10,120,"open ok",16,RED,WHITE,0);6 h+ Q# B2 ?8 U8 C0 T1 Q- ]

  42. * F8 s% j8 u7 T; n% M/ d
  43.   }
    * z6 O% q3 m7 n3 T* D9 Q
  44. + f3 a6 C9 o% ?
  45.   f_lseek(&f1,32*((H8-0xa0-1)*94+(L8-0xa0-1))); // 在字库文件中做偏移取出32个字节的点阵数据
    9 l# {4 I* w: |  N
  46. - N8 E* q) X) U. W
  47.   res=f_read(&f1,buff,32,&num);
    ' s" b  W1 p* M2 O

  48. . h6 W: S/ I; s& `, S+ C2 |+ _
  49.   f_close(&f1); // 读完后关闭点阵字库文件
    ) w( Q/ A) R8 E% I5 ?
  50. ' x! Z. R$ p& G% C  p
  51.   f_mount(&fs1,"",NULL); // 卸载SD卡
    0 _0 C& n5 q, o% G

  52. , f, w5 e/ a  z7 @. N# F/ y# N) _4 E2 O
  53.   return 0;
    9 Z$ b, k2 W1 c. ]' j6 a
  54. : N( e% t2 k! S% v/ ~' y
  55.   }
复制代码

( N$ g$ \& R! B  这个是得到汉字点阵的实现过程,得到点阵数据后就可以在液晶上打点实现汉字的显示,具体的底层驱动不再详细介绍。1 _3 X7 V3 i5 A4 Z1 m
  实现了在单片内显示汉字串以后,能不能读取SD卡中的txt文档中的汉字在液晶屏上显示呢?这块是我自己想的,不知道与别人的一样不一样,反正是实现了。  p* ~, y9 @8 n
  首先我读取SD卡上txt文档上的一个汉字,然后用串口打印出来,发现,读到的就是汉字的内码,百度了下说windows中txt文档的显示的用GB2312的字库。既然读到直接是内码,那就好办了。汉字内码用的是两个字节,字符用的是一个字节,这个一定要注意,因为在以后显示的过程中要用。& q3 P0 k, C4 V0 b9 G
  下面直接贴代码:) d% [2 D5 p% A$ C# X' b
9 Q& v$ l4 [. u1 E9 S  B
  1. // x,y在液晶屏上的显示位置,我的液晶屏是320*240 ,竖屏显示( N; ]' t+ f8 p6 c) A: ~

  2. 9 m- t/ M$ u- u7 b- l4 L. h4 F
  3.   // color 是画笔的颜色,BkColor 是背景颜色
    6 S) [/ v$ t- [7 b! Q2 A1 s, A5 d- z
  4. ! n9 M- D6 H( T/ H2 F$ e. d6 a+ B" z9 @
  5.   u8 fnShowTxt( u16 x, u16 y , u16 color ,u16 BkColor )  @1 E' g9 c/ T6 r- ^  y
  6. , Q4 S8 ]  ^/ p8 E; x) h9 e% R
  7.   {# I3 _6 K, |8 c
  8. $ T$ q+ z6 R2 y
  9.   u8 res=0; // SD卡函数的返回值' Q7 i5 B; r' P
  10. 9 g- n9 i+ d+ U- v7 r# e+ n' Z. b
  11.   u8 buff[100]={0}; // 存储从txt文档中读到的100个字节的内码$ L8 d* c$ X/ q+ y5 w& H

  12. ! G. |3 o+ t: n" A. f4 d# |
  13.   u8 bitbuff[32]={0}; // 存储从点阵字库获得的32个字节的点阵数据2 d, Y# G5 W) U

  14. % Y! \2 N  G6 h. W9 m& P' U' D
  15.   u8 NeiMaH,NeiMaL; // GB2312内码的高位和低位
    6 C  Q5 E/ M; U+ U3 l( ^

  16. ' P7 Q- X. b- {' _
  17.   u8 CntnuF=1; // 用来 判断是不是读到文档的末尾了,如果读到字节的个数小于100则表示读到末尾了
    7 x* F4 O3 J" R9 K2 v
  18. ! I8 [. G3 a+ t/ o
  19.   u16 offset=0; // 读txt文档的偏移地址
    4 w4 |9 G: v6 D: t

  20. + L& x$ w) V+ M7 I5 q9 }; p5 X
  21.   u8 i=0;: c8 z  {! g. ?8 `( R; v, B2 p
  22. 8 x3 M7 y2 X8 l7 a# q+ Q
  23.   UINT Hznum,bytenum; // 实际读回的内码字节个数、点阵字节个数/ \- s; U; M, E' V
  24. ' A( n/ ]) p4 q! t& L) F
  25.   u16 x0,y0; // 点阵显示的位置
    * \6 J9 a; E7 g& @

  26. 3 B- M0 ]2 m. p3 S) v
  27.   u8 charCnt=0; // 读取的100个字节内码中有几个字符,如果字符个数是偶数则下次偏移再偏移100,如果是奇数,! Z9 m# e( Q$ q
  28. 6 \+ g# |! V) h- `  ~7 q" J
  29.   // 则读取的100个字节中的最后一个字节可能是下一个汉字的内码高位字节,则偏移99,下次再把这个字节读上。8 H5 w  j4 U7 `  u' N% L+ R
  30. 9 A+ r. Z$ U3 I. b: L. I8 }. ?
  31.   x0=x;
    6 {: c9 U) h% C8 r
  32. & B' G  |- w2 R' Q5 ^7 e. n
  33.   y0=y;
    $ i. y4 n4 G) E7 |  w+ p) A
  34. + n( E) W' a$ G. G) j, ]
  35.   f_mount(&fs1,"",1); // 挂载SD卡
    5 m5 K- G! @# O9 b! e9 I/ J
  36. ) M3 h1 S$ h3 r0 U$ L
  37.   res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ); // 打开字库文件
    ( O/ B6 P9 _" _! E8 E
  38. * H; L; X  O  O
  39.   if(res!=0)4 M6 |6 C2 ^. R2 o' g& Y

  40. - A% X* n' Q/ @, x! F) J1 |
  41.   {! d8 S) {& _- B- b

  42. " r2 o, p& X% Z+ j- G$ n
  43.   fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);
    " ]% k% |0 k3 b& [/ R0 H- m
  44. 3 I* [+ k7 e0 p& s1 r
  45.   printf("res=%x",res);' c" g: [  @' F+ J/ b$ c# }

  46. # L( N6 N4 C7 y1 B; R3 N% G7 M. }
  47.   return 1;
    7 j) v/ |; i# C

  48. * T0 [; s+ F; Y: z# ^- I* _! J, ]
  49.   }
    " s4 R6 Y5 p3 A! C4 l2 c/ T
  50. ) A/ X/ q6 _0 U+ M2 a1 Y
  51.   res=f_open(&ftxt,TxtPath,FA_OPEN_EXISTING|FA_READ); // 打开txt文档
    8 B/ o$ i$ l: g$ ~  x$ ], e

  52. 8 h9 C- `2 R, o/ D2 T2 Z
  53.   if(res!=0)
    ' x) u1 T: W0 e# i

  54. ( u3 m+ u' R# ]5 C8 @+ b6 x/ V& |, r
  55.   {
    . J4 ~' ~( B* `

  56. * Q4 k# u8 y8 Y1 @* V
  57.   fnShowString(10,120,"open txt fail",16,RED,WHITE,0);
    4 J( n; c# ~0 W, |0 K6 J; @' ^6 J
  58. ) H7 a' b! J3 l% Y
  59.   printf("res=%x",res);$ w3 _: O$ C5 v
  60. 2 i8 Y  Q0 J( t9 ^
  61.   return 1;
    ! d- p' m& x; b+ Y
  62. 8 `( G3 [& e$ Z! ?$ J% l
  63.   }
    : B- \- L& l$ t% v2 ?# p$ l1 o; W
  64. / r2 {' |; }5 B9 e  p" ]
  65.   f_lseek(&ftxt,offset); // 初始化偏移为0从头开始读。
    $ Q: ?. e* H& x3 Z2 K+ i$ s& d
  66. - E1 j; W* [2 F
  67.   res=f_read(&ftxt,buff,100,&Hznum); // 每次读100个内码字节
    ) b& |5 k. H# f1 d! B" y
  68. $ c, ~& \0 a7 \5 p. v
  69.   while(CntnuF) // 循环判断是不是读到文件末尾了
    " R0 d4 s+ E9 I% Y' Y+ v
  70. ' F9 C! |! D, {) ?: n( S: O+ f
  71.   {
    * c* Z- z+ C4 c' z$ _5 ~% N, N

  72. : r" g: x: F0 b3 z" m0 E0 }
  73.   for(i=0;i
    ! a8 c/ a6 q# T  {
  74. " O& {2 j5 ?  L) h; j! Z  n+ Y
  75.   {
    9 V8 W  r6 D2 ^% E9 J" a/ k
  76. ' `! v, f3 x' S% A1 F( F: j2 G
  77.   if(x>220) // 显示位置的判断8 `) x* S7 W. O; d+ _) D$ I' a

  78. ( T& i* P# {6 M! @
  79.   {: z& A& I" e. `& [8 }

  80. ! |" ]; ^/ R! G" G/ N+ \
  81.   x=x0;
    9 {3 r9 t: ^' t  I" m7 z
  82. , Y4 K2 X0 z6 v) G
  83.   y+=16;: h* i( y" O' A* S* g. W9 l$ ]
  84. * O2 U9 e" f& q& X
  85.   }
    4 L8 A8 S, a: K' J* W: w  B

  86. # a% _' F- x7 @
  87.   if((y>300))+ c% p! b7 l( r! |

  88. 7 X/ @9 j) n5 e  Z; r; K
  89.   {
    + s9 [; u$ s0 J4 ^9 q5 F

  90. 4 m: V9 g1 Q6 q) H' [# f
  91.   fnRefreshscreen(WHITE);
    ( R: D3 R( T' B4 N1 g9 z0 \

  92. - M& N& A( e- V$ i
  93.   x=x0;8 A9 f: d8 r9 |$ f/ S* H" n$ O: P

  94. 2 }+ n! Y5 g# L1 m) l' H- g6 B  U
  95.   y=y0;" x" G6 J5 [- e0 n) S! k- a& G# ^

  96. - G' f1 U& u/ Z1 R4 x  L
  97.   }
    ( K# N& k. [# D+ W
  98. + \0 b, n8 v' t* e' @7 Y3 m* C6 {
  99.   if(buff>0x80) // 是不是汉字
    . D9 {2 ~% X3 \) D
  100. 7 \7 D. y" W0 k& W% R
  101.   {
    4 o% H4 U. i: a) M3 g

  102. - f4 }' D9 m( M* ~6 I8 r- k$ c
  103.   f_lseek(&f1,32*((buff-0xa0-1)*94+(buff[i+1]-0xa0-1))); // 点阵字库内的偏移! A% H2 }- R, h! F3 O
  104. # v: J- a/ k: R! P
  105.   res=f_read(&f1,bitbuff,32,&bytenum);- c9 E. O5 ]6 B' k" U# K- L, D

  106.   a% Y1 G% H* I( {* A" `* H& w: P
  107.   fnShowHzk(x,y,bitbuff,color,BkColor);8 p  v+ T7 u8 }5 P
  108. $ c! o" S& e8 ^+ H! Z
  109.   x+=16;4 E7 r  I- S+ @  V" e2 l) r

  110. . I4 L6 F7 O& h3 B0 m) K/ o, y6 M: l
  111.   i++; // 这个i++非常重要,因为一个汉字两个字节,除了判断语句i++,4 y' V. ?) K" `  i/ a

  112. 9 |# H1 ^+ b  w
  113.   // 这里需要还要一个
    5 V- C- r2 L7 Q' m! t: y

  114. 9 M6 C2 p. W9 H7 G  s
  115.   memset(bitbuff,0,sizeof(bitbuff));
    " G0 x, _0 C+ T5 A  B

  116. . T0 T8 s" r6 G! D
  117.   }
    2 d, P  z. J" }

  118. 7 X3 V+ }+ U: G1 B& X: {( X& d
  119.   else // 可能是标点也可能是换行符% d- X) J3 m; q2 J. _! w- J
  120. ( u7 o+ N5 w8 R4 _/ \
  121.   {
    . ?& i6 z9 Y0 ^( e$ U( N; W

  122. % e2 F5 L) R! d' Y5 v# q/ Y
  123.   if(buff==0x0D) // 换行标志
    " F0 N( [, z& F$ f0 i

  124. & h: Z5 `$ z3 |$ r- d
  125.   y+=16;4 ^/ N6 C/ _! J1 C6 {

  126. 3 e# p1 [- @8 B7 w! g
  127.   else# K* ?0 r4 u, d' f' g- r5 R: `5 q" C

  128. 6 \5 D( J9 T5 C2 k; }' W3 F" Y+ z
  129.   fnShowChar( x,y,buff,16,color,BkColor,0); // 字符
    7 _8 h+ {0 C5 h& J" Z+ ^
  130.   ~. r  U/ w6 t% y+ ]
  131.   x+=8;) ]5 w# f3 c% s% W
  132. " q2 z# X. Q, b9 z* |- a
  133.   charCnt++; // 字符个数计算,用于判断下一次读txt文档的偏移地址
    & b: s5 p6 p9 |3 K9 s

  134. : d$ A8 [9 c! V' E  J
  135.   }
    3 N% g1 ~  L' u& X1 P9 s
  136. 8 Z- m5 U* e" N8 t* S! ]; \
  137.   }
    0 g! R4 B( G: i) |
  138. ' ~9 f6 ?0 j5 S, \7 b! E* X
  139.   // 计算txt文档的偏移地址: G: e! z1 S$ c' N; J

  140. , D, J$ p7 u7 G6 F! N3 ~0 h
  141.   if(Hznum!=100) // 判断是不是读到文档末尾了1 @/ U. q& Y( w8 e
  142. 7 C& _. Y2 ^# W
  143.   {
    6 c2 A+ U* t% A, e* S! `

  144. 9 ^/ h" E- q2 L7 I# Y' D
  145.   CntnuF=0;
    5 s7 ]! H8 p- p8 p, b# b

  146. ; W1 q# G7 O. E1 O) p5 k
  147.   }0 O' l1 L& M/ B  v  c

  148. . t! g1 W  \& U0 ^0 C
  149.   else // 没有读到末尾继续读
    5 n& {" X$ d$ C+ P4 |. @
  150. 5 R8 _! m) y) P& j" W" U! a
  151.   {4 Z  s# Q7 g% ^" w/ C- x

  152. $ w0 c+ b- w+ x9 M; {' u0 V
  153.   if(charCnt%2==0) // 字符个数是偶数,100个字节内码里边正好成对出现,地址偏移+100
    , P% t* T: i7 J

  154. $ p; @5 U- s8 C1 U/ [4 a* E, F
  155.   offset +=100;
    6 M! y8 J% H+ C: ]4 h2 g& r0 A

  156.   Q' C* z( m3 Y8 s2 G2 M
  157.   else
    7 P0 C- S6 ~/ t

  158. - L) o5 }. d: B( v* N: B' R  {
  159.   offset +=99;
    / a# Z9 ]6 K8 ]# o
  160. & b- Q1 L9 [0 @, r. F' G7 R2 O
  161.   memset(buff,0,sizeof(buff));% j1 j- l7 _9 b$ i' ~; O

  162. 6 J0 s+ \( t* f" X5 @" Z( g
  163.   f_lseek(&ftxt,offset); // txt 文档地址偏移& n  I% v8 p3 u" \4 ^  c% l& V

  164. % }! D: s+ ~( x6 M
  165.   res=f_read(&ftxt,buff,100,&Hznum); // 读内码数据7 H0 Y- |# ?1 z( Q3 X* V( j
  166. 6 m8 p7 E# }% _) M
  167.   }& `5 f, i5 B. B4 r: U  m) o5 X. T
  168. " q" B" g! A: [6 e+ z% p
  169.   }- ]' W4 t1 D5 s6 i8 m
  170. / b7 U* \1 Y, n" q+ L  v
  171.   f_close(&f1); // 关闭打开的点阵字库
    * L! ]) G( M' ]9 E! L% F
  172. ' M/ A8 x. w- ~" g$ Y' X0 A8 b
  173.   f_close(&ftxt); // 关闭打开的txt文档* K2 m) M- y' P% J* f

  174. ) m! W" ^6 M; C, [0 d6 [; E) ]& z- ~! L
  175.   f_mount(&fs1,"",NULL); // 卸载磁盘2 B/ R4 B) e0 L! K% n# Q
  176. % S% k3 _5 K) }: @8 M. ?
  177.   return 0;- s+ b5 [9 F# i" w

  178. ' V8 e; n1 {- G% k5 M+ Z( S! y
  179.   }
复制代码
% ], p7 h9 v- m- |
  以上是简单的电子书的实现。
/ b$ m4 U2 q( Q6 k  因为不同的系统有不同的编码这个要注意,比如我再Windows上的汉字拷贝到CSDN网页上就是乱码,这是因为使用的汉字的编码不同,对于不同的编码格式,还需要做内码的对应转换,把其他的格式转换成GB2312或者GBK格式然后调用字库显示。( j9 a! f, n; {  D( g  p. |
  其他常用编码格式Unicode、utf-8等的具体介绍和转换成GB编码可以百度。( ~4 \. e6 f: z% J- U2 i
  SD卡注意事项:$ [# @1 y) U# `1 N
  对一个文件读,必须先打开文件,读完后关闭。
4 q, t9 k/ `/ n+ V/ h( O' _7 K. y  H  对一个文件写,必须先打开文件,根据情况确定打开的权限,只读,读、写、创建等,先完后最好调用f_sync()函数,这是一个同步函数,类似于linux中的同步函数。SD卡中的写函数应该是带缓冲(猜的),在关闭之前调用这个函数将缓冲区的内容写入SD卡中,然后关闭文件,否则可能写入失败,不能将内容成功写到文件上。
3 r) A$ x; f; [# M$ _! V1 \  文件的打开路径,Windows中的文档可能是隐藏文件类型的,这个一定要注意,隐藏文件类型的a.txt和不隐藏文件类型的a.txt 不是同一个文件,这个一定要非常注意。. h6 F0 ^) }+ s' J) k9 g

, ]7 O7 _. ]3 X3 ?0 c" c0 T$ g8 O7 q8 h7 C5 ]. V' h
  • TA的每日心情
    开心
    2023-5-15 15:25
  • 签到天数: 1 天

    [LV.1]初来乍到

    2#
    发表于 2020-4-20 10:29 | 只看该作者
    现在STM32单片机用得人很多,资料也很详细
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-6-9 17:15 , Processed in 0.093750 second(s), 23 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表