找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

巢课
电巢直播8月计划
查看: 0|回复: 0
打印 上一主题 下一主题

[硬件] 吴坚鸿单片机程序风格赏析——(四)“鸿哥三宝”之74HC165(按键扫描篇)

[复制链接]

551

主题

1470

帖子

3万

积分

EDA365管理团队

Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9

积分
39487
跳转到指定楼层
1#
发表于 2019-9-27 15:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您!

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

x
(1)开场白:
$ h% {  c/ D  ]" A( u4 V 这节将要跟大家介绍一下鸿哥的“三宝”,它们分别是74HC165,74HC595,ULN2003A.之所以它们在我心中的地位那么高,是因为很多工控 小项目经常用到它。74HC165使我们从此不再为单片机的输入口不足而烦恼,我们用3根IO口就可以检测100多路的输入信号。74HC595使我们从 此不再为单片机的输出口不足而烦恼,我们用4根IO口就可以驱动100多个继电器或者LED。而ULN2003A则大大简化了我们的三极管驱动电路,一个 芯片就集成了7个三极管,它有500mA的驱动能力,内部自带续流二极管,用来驱动继电器的时候,二极管也省了。74HC165对静电很敏感,很脆弱,在 通电的情况,绝对不要用手摸到他的引脚,我曾经用非绝缘的镊子来短接其输入口,烧坏了很多个,因此对于74HC165我们要懂得怜香惜玉,小心呵护。总 之,“鸿哥三宝”实乃电子工程师居家旅行之必备良药。5 F0 K, t* ~! Y; W/ ]+ e
(2)功能需求:每按一个按键,蜂鸣器就响一次。
2 M4 L7 Q! d& k! F (3)硬件原理:
6 P3 R$ n3 ?8 g2 \+ I. Q (a)把两个74HC165联级起来,就可以达到用3根IO口来检测16个按键的目的。此电路的本质是并入串出的原理。具体的电路读者只要下载芯片资料一看就明。还是那句话,按键那里记得接20K左右的上拉电阻。; x2 T0 O; W+ ?( p/ U7 K# _# u
(b)用1个IO经过8050三极管来驱动有源蜂鸣器,有源蜂鸣器通电就一直响,断电就停止。- w. ~4 L1 y" i1 q4 e! J" l2 J
(4)源码适合的单片机IC18f4520,晶振为22.1184MHz& A7 W9 _+ F7 p  A$ r) w
(5)源代码讲解如下:
' ~5 I" v( `2 U5 v #include<pic18.h>         //包含芯片相关头文件. u: H# U+ S% G
5 P: u' o3 ~* d4 [3 V
//补充说明:吴坚鸿程序风格是这样的,凡是输出IO后缀都是_dr,凡是输入的//IO后缀都//是_sr1 M. U5 N+ ^8 e
# M0 U0 `3 F! B* q! I- r
#define  beep_dr  LATA2  //蜂鸣器输出$ y$ i  k& Q) v* g- p3 l; i
# define hc165_cp_dr    LATA0    //74hc165的3根驱动IO之一 9 W" t% P8 I7 u8 l2 z+ z6 B
# define hc165_pl_dr     LATA1    //74hc165的3根驱动IO之一
5 ~+ D( O% z4 S2 d # define hc165_q7_sr     RE0       //74hc165的3根驱动IO之一
# a* f' y- `- d
( ?$ c6 V! T3 |! F* p$ C4 l, [& { //补充说明:吴坚鸿程序风格是这样的,凡是做延时计数阀值的常量
! n+ n* U' t# c3 I  l7 L2 | //前缀都用cnt_表示。
2 w! Q1 G- j% V+ a1 ~/ h #define cnt_delay_cnt1   40   //按键去抖动延时阀值) a. r: N" @- v/ ], P+ x3 c
#define cnt_voice_time   150  //蜂鸣器响的声音长短的延时阀值! h( L/ _& `9 U* p' y$ R8 |0 @, B' _6 V

$ @3 r- N& C" @! @ //补充说明:吴坚鸿程序风格是这样的,凡是按键扫描函数都放在定时中, m) U* X( T5 F& l4 j2 Y2 d0 z! {
//断里,凡是按键服务程序都是放在main函数循环里。有人说不应该把子程序//放在中断里,别听他们,信鸿哥无坎坷。
7 Z9 P# X  `0 O, z+ V% f void key_scan();                         //按键扫描函数,放在定时中断里7 b6 t! ], z+ k! C; o, z5 G
void key_service();                            //按键服务函数,放在main函数循环里5 s: i  Y( ~  E  U5 U

' o, G3 K0 z' F6 u& @5 b0 W! n9 u9 W' ?" M3 y) X/ R- L" R
//补充说明:吴坚鸿程序风格是这样的,凡是switch()语句括号里面的变量名1 i$ ~; e! j! H
//后缀都用_step表示。9 E3 o8 H) D5 _- E

5 |3 o# T: _# P% | unsigned char key_step=1;      //按键扫描步骤变量,在switch()语句的括号里& `+ l6 t4 h5 F2 j
//补充说明:吴坚鸿程序风格是这样的,凡是按键或者感应输入的自锁变量名
+ t2 o" l( x: m) W //后缀都用_lock表示。
7 E; K( _  N2 ]* m) \- y unsigned char key_lock1=0;   //按键自锁标志
* J& a; f- H3 S unsigned char key_lock2=0;   //按键自锁标志9 y% H+ u; t+ `" h1 E
unsigned char key_lock3=0;   //按键自锁标志7 L5 |( M; [- x+ }4 ^' X' D
unsigned char key_lock4=0;   //按键自锁标志  F0 f  N# T6 W( Y8 \; P& k

7 I& C1 S) K: O3 Q- f* Q0 t //补充说明:吴坚鸿程序风格是这样的,凡是计数器延时的变量2 O3 L: e( F- N8 d8 z
//后缀都用_cnt表示。) p- \1 o* A& X
unsigned int  delay_cnt1=0;     //延时计数器的变量
$ K$ A7 g! P! r8 P0 Y unsigned int  delay_cnt2=0;     //延时计数器的变量, F  o: s- _0 M/ U
unsigned int  delay_cnt3=0;     //延时计数器的变量3 b1 o. C$ U; ?: U$ }& \) O
unsigned int  delay_cnt4=0;     //延时计数器的变量
5 }3 k+ U6 L6 z* h# a  a& n* v% t% \9 X7 u1 j0 S$ S9 v5 d
unsigned int voice_time_cnt;        //蜂鸣器响的声音长短的计数延时: z* F# v1 Y2 W; @7 H
) K+ q* {8 r, a# Q
//补充说明:吴坚鸿程序风格是这样的,凡是做类型的变量的分类$ i& n7 s& j+ R! \9 I7 n
//后缀都用_sec表示。" y! u% s; `. w5 F% T) m6 c! A
Unsigned char key_sec=0;  //哪个按键被触发
! n9 R6 ^& R4 a* f" _  `9 \ Unsigned int   key_status=0;  //一个字节8位,此处2个字节,共16位,每一位代表一////个按键的状态
  t; e- {+ ^( F5 ^0 N% y5 c' [) _) T9 S( ~6 [6 b
//主程序" F4 v- X( S! `0 P5 D  W" e4 Q( {
main()
! h1 l/ P1 g- Z1 ]! _ {" N8 k2 C4 @- g# L
ADCON0=0x00;  
& \, c. a) w9 b4 n$ d ADCON1=0x0f;                               //全部为数字信号7 H: T% Z- d( c- C4 c
     ADCON2=0xa1;                               //右对齐; w& h! s, T% C; ^% {) M
     RBPU=0;                                      //上拉电阻2 m0 e6 b/ v, M; \
     SSPEN=0;                                    //决定RA5不作为串口
' U$ x* F4 N3 I! G1 o1 a0 B' Z, T5 g3 A2 t
    TRISA2=0;  //蜂鸣器输出6 U3 }5 o# R+ ~2 L

9 Q: g" L' g$ X! }) I* ]    TRISA0=0;    //74hc165的3根驱动IO之一
9 M' T4 X* k1 \7 [( |$ e$ c TRISA1=0;   //74hc165的3根驱动IO之一: A6 F7 i' k, k( }: N, A* `
TRISE0=1;  //74hc165的3根驱动IO之一: p- |, t' o/ M4 D; z$ S

! M$ n/ w- I( [3 `1 u* Q  e' V9 b2 t8 l4 Z' b/ w
     T1CON=0x24;     //定时器中断配置+ n) i* P6 ?) x/ s
     TMR1H=0xFE;8 B/ ?5 g% ?3 d$ J# @
TMR1L=0xEF;/ `9 D0 Z( \2 I( g
     TMR1IF=0;
4 u* L5 R/ _% ~+ {     TMR1IE=1;
$ w1 @7 k/ `9 ?$ Q     TMR1ON=1;& x3 u1 h5 U6 H, J
     TMR1IE=1;8 H* a- T! Y( C! M: y! H
//补充说明,以上的内容为寄存器配置,每种不同的单片机会有点差异,; I  c! h9 d9 [- _: ^
//大家不用过度关注以上寄存器的配置,只要知道有这么一回事即可6 T2 ~: v4 ]: X: {! G

: {4 X9 ]* l& @; z7 b     beep_dr=0;                               //关蜂鸣器,上电初始化IO
4 I: B- a+ X6 G5 h3 ]3 X+ w, X* t: g1 V# ~, B8 w
    while(1)   
  f/ l- E4 W; b# k5 A    {9 E+ U2 @4 e1 {# z; d7 l( F
                      CLRWDT(); //喂看门狗,大家不用过度关注此行
4 ^6 E, Q( v# k. [$ I5 G( g                 key_service();        //按键服务. H7 G! h# o( D+ s+ e
}$ l' H0 ?; j: S: G

. \8 m0 G2 T) k9 A+ q4 N+ e }
, l+ b2 A, y9 t$ P        
" h/ b3 Q; v' q, G& y9 K+ W: \( N+ {8 b' h# W/ |% r
void key_scan()                                //按键扫描函数
/ p7 N" i6 ^: ^0 w# |1 M* w {  
# o1 y" K4 n  C, S; K     unsigned char j;    //中间循环变量
5 ]! h( J4 I- B3 s- ^! ~4 z4 m# _/ @: ]% ^' f: J3 A( S( m

; S( f0 Q7 N7 B6 N     Key_status =0x0000;   //每个按键的电平状态,共16个4 z# E) r( n: ~$ E

" N& x; k' o! F% d2 a     hc165_pl_dr=0;
. L! `8 l( T# f: W, b     asm(&quot;nop&quot;);0 N4 Y5 f/ r. L  e9 \
     asm(&quot;nop&quot;);7 r# A1 Z  W. x3 ^5 s3 ^" ~
  q( k2 M- Q3 t4 Y2 c0 W- {
     hc165_pl_dr=1;5 D, Y$ n# M: Z
     asm(&quot;nop&quot;);" l- \1 b. o# L7 J1 D
     asm(&quot;nop&quot;);9 \; Q5 D5 U4 h" q, u( {+ `
     for(j=0;j<16;j++)
' N6 n% j( o9 }$ [* K& O5 ?* E     {               
$ x# p( l* ~! [" e% C7 `2 j) d
% Z% p0 C" z% |9 g: P1 g& }         hc165_cp_dr=0;        
4 W+ S! T" O1 `* W% ^& G
; i* E3 S0 q, L: U# Y: i         asm(&quot;nop&quot;);
' _$ U& I5 D. r; Y; A8 u7 |6 F         asm(&quot;nop&quot;);
' V9 T; `- A9 i9 R4 }, K# Q% H. R; s& _, t! M) i9 f7 K
         key_status=key_status<<1;+ h! j6 ^) I1 m. F9 U
         if(hc165_q7_sr==1)key_status=key_status+1;2 Y+ L' C" A6 T  j. U

, ^) D2 u% W# N         hc165_cp_dr=1;2 \0 J8 n: \( v$ A

# G5 }8 c) Y0 g3 _! c         asm(&quot;nop&quot;);" H8 ^+ h" c( X2 d7 E2 [# \
         asm(&quot;nop&quot;);5 [( ]# R2 ?, z+ {; C! r
      }        //以上一小段代码是通过驱动2个74HC165来获取16个按键的电平状态' E# ~4 d3 J4 S8 W9 b, j
//key_status
1 L2 s4 i& B6 `# v+ ~
" `7 q0 r4 k; O, z
8 ?1 _. t# M- U& F: w) z' T  H1 ]$ E    //以下代码通过解析每一位电平状态来确定哪个按键被触发
1 u8 c  e0 o" _5 ^. ?$ I% x      if((key_status &0x0001)==0x0001)
" t; B4 C! ?! ^7 E, _ {
. S% t' s2 ^" s; f  O key_lock1=0;  //按键自锁标志清零
! q, B1 J5 Q$ \' I$ b/ [  Q! [ delay_cnt1=0; //按键去抖动延时计数器清零,此行非常巧妙        ; h: l0 Q! G1 P8 x& M! U8 D3 q: x
}7 n" J( A4 K: X1 r1 u' }9 S2 V
      else if(key_lock1==0)
4 k, H  z8 M% H0 N+ l* I      {% J* u2 f+ U0 M( F: l
           ++ delay_cnt1;  8 H: a7 l1 q/ P6 n
           if(delay_cnt1> cnt_delay_cnt1)    //延时计数去抖动2 z1 f1 {6 N+ V! C* S
           {1 \' R  A$ X: m
               delay_cnt1=0;6 x% N! i; W4 U9 z2 i6 x  I
key_lock1=1; ! a" ^8 G2 e/ l, L/ V1 C4 A. l3 A( E
   key_sec=1;         //触发1号键
, j4 |6 v: f6 _  o! u3 J! K# m2 d           }8 }% `4 B) w. V1 J

! l# _! D" Z$ ~8 Z5 S      }; Q, r" M" v* [  O6 F/ R
/ o+ T% w/ B5 e. z5 c
3 p" u* H$ q, `  o; ^- t& a
      if((key_status &0x0002)==0x0002)
- \5 n3 Y% n3 H/ x, [- e {! }' Q1 z* c! T! Y9 J0 |1 C0 R2 E9 S5 q4 M
key_lock2=0;  //按键自锁标志清零
2 U' }  h9 |- F* q2 B% V delay_cnt2=0; //按键去抖动延时计数器清零,此行非常巧妙        8 W7 s+ S% n% O8 M/ ]8 w, u) \8 B
}
  ~' [% I5 z/ H( L2 l, w      else if(key_lock2==0)
% v. f) @- a5 l6 M4 J) V% h      {3 X  m# b/ M# {
           ++ delay_cnt2;  , w! P: y% [2 O$ {# i; ?
           if(delay_cnt2> cnt_delay_cnt1)    //延时计数去抖动
, [7 G% C# ~+ |5 c) f1 h           {
: f) b# P1 j  A' q, u% z               delay_cnt2=0;
) B! ]- Q; ~$ C- w* C0 U: T3 m$ U. T$ } key_lock2=1;
2 z8 n' k+ j# o) A   key_sec=2;         //触发2号键: |& t5 [- ~# S' @' i
           }  y3 Y3 x. U$ E. I, ~4 Y0 h( F
) K4 q) u- ^+ ]5 L) |% W) x& z
      }5 {" ]# b; X( a4 }

6 z  p) x7 p! L& i- {7 S6 ]% V9 e# w0 m9 C4 j
      if((key_status &0x0004)==0x0004), V4 r; E" q0 A
{
2 ~+ T0 j) Q" T5 e3 C( I# n1 |8 t# D2 s key_lock3=0;  //按键自锁标志清零6 L3 V& Q9 ?# E0 Q
delay_cnt3=0; //按键去抖动延时计数器清零,此行非常巧妙        
. U2 M& w: h' f5 H0 D7 M" [ }; @+ |* p7 a; |) [0 p3 z
      else if(key_lock3==0)( r- d" N6 U7 x
      {
& k! w4 \" H, X" k3 ]% y           ++ delay_cnt3;  
5 G9 L: P0 f9 T9 h# w9 y. D           if(delay_cnt3> cnt_delay_cnt1)    //延时计数去抖动1 i) C% @9 P& C: U# F
           {; O6 u) e# y) |& g
               delay_cnt3=0;) K7 R; }3 B8 T8 I) [
key_lock3=1; $ e: i+ H2 B2 t" ]
   key_sec=3;         //触发3号键5 v# d/ t. ]4 J" U1 F
           }, I  q% \, i; m7 _/ Q7 I
- \$ A2 I1 h1 s; ~. F
      }
' h' [. }8 b; e1 P  Z# D$ `& o2 m  l# K$ a& q
      if((key_status &0x0008)==0x0008); j$ @9 W7 ~. F3 Z0 X  w
{
% s6 ]4 Z: l8 |$ p% d key_lock4=0;  //按键自锁标志清零
( i/ O8 U6 C) \' l7 S) x; @ delay_cnt4=0; //按键去抖动延时计数器清零,此行非常巧妙        
2 I: c, S/ H7 @! _ }: ?/ Y4 I: w2 e; {: ~( i$ x8 F
      else if(key_lock4==0)0 X: L) J: g+ n: }7 X" L% z
      {
- w% t) p' ?2 _7 ?           ++ delay_cnt4;  
. F- P1 d6 g/ [. x' U% a9 l           if(delay_cnt4> cnt_delay_cnt1)    //延时计数去抖动+ w$ K! G4 ^, D$ f/ d! E
           {
. M& Q4 r+ h6 x* R                delay_cnt4=0;5 N  P0 a/ V. t8 s8 T% Z, z
key_lock4=1;
4 A7 `, w9 a8 b. A5 y9 ?9 {$ Q   key_sec=4;         //触发4号键
7 e5 D" D. K, N, j! r& Y' B1 G           }2 i% v- Y7 s  G( W0 G, z5 _

$ j  m% t4 q5 z8 t      }
" L0 }" v6 y# b0 p9 f! t$ q4 _ //如果要接16个按键,读者可以继续往下添加类似的代码,本例只触发4个按键作为演示6 p! \' C& o' p1 b8 N
     + R! c. d' P2 K* k( ]6 Y! W# L
}
. W9 n4 d- b7 Z7 w8 `3 z
1 p) ]" J# v& f void key_service()                //按键服务函数
. m0 m3 }# \" M7 B {
- [0 `9 S0 r( e3 h6 {         switch(key_sec)                //按键服务状态切换/ B, C; }% U+ Z$ [% N# m
         {
* J* g8 |4 [6 a. f* V                 case 1:// 1号键
! s+ s5 q4 ?& I) g
- P- A" L; @9 S; I" p
5 U8 Q* R% M* S) b7 l // 补充说明:voice_time_cnt只要不为0蜂鸣器就会响,中断里判断voice_time_cnt不为0
3 x6 U/ S, u9 l) k& r //时,会不断自减,一直到它为0时,自动把蜂鸣器关闭
* Q" E) ]+ {3 A; \                                   voice_time_cnt= cnt_voice_time;    //蜂鸣器响“滴”一声就停
: G3 G) a! ]3 ~0 i# }# \                                                                                          
7 r3 a2 F( v- U( H                         key_sec=0;   //相应完按键处理程序之后,把按键选择变量清零,+ B9 I5 z- P+ H( T
//避免一直触发+ b  ]+ Q- B1 s. m8 F
                         break;        ) ~" g: s9 _3 ]) [- O6 Z$ W" c
                 case 2:// 2号键
' V. k( Z/ }- S5 \                                  voice_time_cnt= cnt_voice_time;    //蜂鸣器响“滴”一声就停
6 E4 @' ^" n. r$ @* g; v                         key_sec=0;   //相应完按键处理程序之后,把按键选择变量清零,) b- A/ B# X8 S7 k* \
//避免一直触发, O! m8 g5 Z# o2 F
                         break;        % E, q% G0 B4 U( @
                 case 3://3号键
( V/ R8 f' E" y: v4 m9 b& c
* k5 c9 Q3 C6 `& i# p                                  voice_time_cnt= cnt_voice_time;    //蜂鸣器响“滴”一声就停6 M# d; R" X8 k  M, K. j
                         key_sec=0;   //相应完按键处理程序之后,把按键选择变量清零,
3 W; S+ g% p1 J- @ //避免一直触发( L9 a1 c* X( g8 \% ?3 f4 C
                         break;        $ e) S, Q: Y( L
                 case 4://4号键5 ?: N0 |# d: P% _3 P+ F

% g  A/ s7 w% J# Y# k" t! W, Q' i                                  voice_time_cnt= cnt_voice_time;    //蜂鸣器响“滴”一声就停0 I1 s( G7 ]- }5 n+ T
                         key_sec=0;   //相应完按键处理程序之后,把按键选择变量清零,
# o. P2 m5 W  R: w //避免一直触发
5 |7 _+ g9 U+ t) g! `9 J7 ]% i2 g                         break;        
2 z2 @% H/ H1 E2 p4 B+ N
5 q) _9 D! K# g
' V1 `2 W5 L$ f2 k
. c% g* [8 C% i                        
7 z7 Y2 A$ F" s         }                + e  J9 O3 r; y
}$ {# l9 w. }6 t$ `' W$ J) N1 ~

% K4 b, p2 S5 H! Q0 j9 K+ c" K# ~6 l6 B" ~0 n
//中断- \' f8 a+ z4 W
void interrupt timer1rbint(void)7 e$ E, H: F+ k3 w
{6 D- c6 V) E! F! T
     if(TMR1IE==1&&TMR1IF==1)    //定时中断$ I. r" |" B( i0 j' W" u
         {/ f. b( j. i" e* N
          ( X$ g2 n: l$ G" m& W
                TMR1IF=0;     //定时中断标志位关闭
: @3 ?' {$ A9 {7 _1 _+ c9 ?                 TMR1ON=0;    //定时中断开关关闭7 U" k- |0 n, c) p9 t
7 Q. K, ^- G9 f5 d: ~' R
                  key_scan();                    //按键扫描函数; Q  ~7 R* s3 c: T% B: U
       if(voice_time_cnt)                       //控制蜂鸣器声音的长短$ H5 q" |$ L8 `$ ~; \7 b
                  {
# g9 C. o. d8 t2 b+ {                         beep_dr=1;         //蜂鸣器响, Z0 E4 g% ~. E; l
                       --voice_time_cnt;        //蜂鸣器响的声音长短的计数延时
/ |# W6 Y6 G6 e* X                  }
4 o5 H" y$ \5 M7 b6 M$ F5 I                 else # J* O. i9 s' O6 e1 w% Y* M9 x
                 {
$ A0 j" c8 S( ?) l5 `) w5 \; H beep_dr=0;      //蜂鸣器停止( H4 b, g: q% S4 @/ P4 z/ j& a3 w5 ]3 L# t
                 }8 _2 t6 i& {' R
8 A4 `/ }/ @8 g1 o
       TMR1H=0xFe;   //重新设置定时时间间隔, O5 f) d# V7 v
     TMR1L=0x00;- v7 r& Q8 D- C
       TMR1ON=1;        //定时中断开关打开( e( I  m% l  E; }% x2 b
     }
+ A: w3 j2 D! t; i- h9 _# d }
2 X% E! L  b0 t- p8 e1 o
$ z+ _7 u/ p7 y0 [  `
& m( a9 s) k. R! x5 } (6)小结:7 M. R4 y9 T6 d. I  @
有一些人咋看我的程序,觉得不咋地,甚至有人觉得臃肿多余,还不够精简。我在这里多分享一下这方面的经验。只要单片机ROM允许的情况下,写程序最重要的 不是精简,因为刚开发一个项目的时候,把过多的时间用在精简优化上,反而会影响开发效率。应该像记流水账一样,想到哪一步就写哪一步的代码即可,代码多占 点程序容量没关系,关键是不要影响程序运行效率,而且程序哪怕是记流水账也要有它的规律性。因为精简就意味着要用循环,要用数组这些元素,而程序一旦加入 这些元素,其实后续的可读性与可改性就没有那么强。比如说我上面按键扫描那段程序key_scan(),其实4个按键的扫描程序都很有规律性,代码相似度 有百分之九十。如果因为单片机ROM确实不够,我非要去优化,我只要加一个循环就可以大概省了四分之三的容量,但是一般容量允许的情况下,我没必要去优化 容量。因为优化容量并不等于优化运行效率,而且影响易读性与可改性。(未完待续)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 支持!支持! 反对!反对!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

巢课

技术风云榜

关于我们|手机版|EDA365 ( 粤ICP备18020198号 )

GMT+8, 2025-4-12 02:54 , Processed in 0.058016 second(s), 32 queries , Gzip On.

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

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

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