PIC 单片机 C 语言编程简介(2)

发布者:耿高良最新更新时间:2016-03-28 来源: eefocus关键字:PIC  单片机  C语言编程 手机看文章 扫描二维码
随时随地手机看文章
11.5.7     PICC 中变量的绝对定位

 

 

 

首先必须强调,在用  语言写程序时变量一般由编译器和连接器最后定位,在写程序

之时无需知道所定义的变量具体被放在哪个地址(除了 bank 必须声明)。

 

真正需要绝对定位的只是单片机中的那些特殊功能寄存器,而这些寄存器的地址定位在

PICC 编译环境所提供的头文件中已经实现,无需用户操心。编程员所要了解的也就是 PICC

是如何定义这些特殊功能寄存器和其中的相关控制位的名称。好在 PICC 的定义标准基本上

按照芯片的数据手册中的名称描述进行,这样就秉承了变量命名的一贯性。一个变量绝对定

位的例子如下:

unsigned char tmpData @ 0x20; //tmpData 定位在地址 0x20

千万注意,PICC 对绝对定位的变量不保留地址空间。换句话说,上面变量 tmpData 的

地址是 0x20,但最后 0x20 处完全有可能又被分配给了其它变量使用,这样就发生了地址冲

突。因此针对变量的绝对定位要特别小心。从笔者的应用经验看,在一般的程序设计中用户

自定义的变量实在是没有绝对定位的必要。

 

如果需要,位变量也可以绝对定位。但必须遵循上面介绍的位变量编址的方式。如果一

个普通变量已经被绝对定位,那么此变量中的每个数据位就可以用下面的计算方式实现位变

量指派:

unsigned char tmpData @ 0x20; //tmpData 定位在地址 0x20

bit tmpBit0 @ tmpData*8+0;      //tmpBit0 对应于 tmpData 第 0 位

bit tmpBit1 @ tmpData*8+1;      //tmpBit0 对应于 tmpData 第 1 位

bit tmpBit2 @ tmpData*8+2;      //tmpBit0 对应于 tmpData 第 2 位

 

 

如果 tmpData 事先没有被绝对定位,那就不能用上面的位变量定位方式。

 

11.5.8     PICC 的其它变量修饰关键词

 

&O1540;    extern  —  外部变量声明

 

如果在一个 C  程序文件中要使用一些变量但其原型定义写在另外的文件中,那么在本

文件中必须将这些变量声明成“extern”外部类型。例如程序文件 code1.c 中有如下定义:


bank1 unsigned char var1, var2;  


//定义了 bank1 中的两个变量


在另外一个程序文件 code2.c 中要对上面定义的变量进行操作,则必须在程序的开头定义:

extern bank1 unsigned char var1, var2;       //声明位于 bank1 的外部变量

 

 

&O1540;    volatile  — 易变型变量声明

 

PICC  中还有一个变量修饰词在普通的  语言介绍中一般是看不到的,这就是关键词

“volatile”。顾名思义,它说明了一个变量的值是会随机变化的,即使程序没有刻意对它进

行任何赋值操作。在单片机中,作为输入的 IO 端口其内容将是随意变化的;在中断内被修

改的变量相对主程序流程来讲也是随意变化的;很多特殊功能寄存器的值也将随着指令的运

行而动态改变。所有这种类型的变量必须将它们明确定义成“volatile”类型,例如:

volatile unsigned char STATUS @ 0x03;

volatile bit commFlag;

 

 

“volatile”类型定义在单片机的      C 语言编程中是如此的重要,是因为它可以告诉编译

器的优化处理器这些变量是实实在在存在的,在优化过程中不能无故消除。假定你的程序定

义了一个变量并对其作了一次赋值,但随后就再也没有对其进行任何读写操作,如果是非

volatile  型变量,优化后的结果是这个变量将有可能被彻底删除以节约存储空间。另外一种

情形是在使用某一个变量进行连续的运算操作时,这个变量的值将在第一次操作时被复制到

中间临时变量中,如果它是非 volatile 型变量,则紧接其后的其它操作将有可能直接从临时

变量中取数以提高运行效率,显然这样做后对于那些随机变化的参数就会出问题。只要将其

定义成 volatile 类型后,编译后的代码就可以保证每次操作时直接从变量地址处取数。

 

&O1540;    const —  常数型变量声明

 

如果变量定义前冠以“const”类型修饰,那么所有这些变量就成为常数,程序运行过

程中不能对其修改。除了位变量,其它所有基本类型的变量或高级组合变量都将被存放在程

序空间(ROM 区)以节约数据存储空间。显然,被定义在 ROM 区的变量是不能再在程序

中对其进行赋值修改的,这也是“const”的本来意义。实际上这些数据最终都将以“retlw”

的指令形式存放在程序空间,但 PICC 会自动编译生成相关的附加代码从程序空间读取这些

常数,编程员无需太多操心。例如:

const unsigned char name[]=”This is a demo”;  //定义一个常量字符串

如果定义了  “const”类型的位变量,那么这些位变量还是被放置在 RAM 中,但程序

不能对其赋值修改。本来,不能修改的位变量没有什么太多的实际意义,相信大家在实际编

程时不会大量用到。

 

&O1540;    persistent  —   非初始化变量声明

 

按照标准  语言的做法,程序在开始运行前首先要把所有定义的但没有预置初值的变

量全部清零。PICC 会在最后生成的机器码中加入一小段初始化代码来实现这一变量清零操

作,且这一操作将在 main 函数被调用之前执行。问题是作为一个单片机的控制系统有很多

变量是不允许在程序复位后被清零的。为了达到这一目的,PICC  提供了“persistent”修饰

词以声明此类变量无需在复位时自动清零,编程员应该自己决定程序中的那些变量是必须声

明成“persisten”类型,而且须自己判断什么时候需要对其进行初始化赋值。例如:

persistent unsigned char hour,minute,second;  //定义时分秒变量

经常用到的是如果程序经上电复位后开始运行,那么需要将 persistent 型的变量初始化,

如果是其它形式的复位,例如看门狗引发的复位,则无需对 persistent 型变量作任何修改。

PIC  单片机内提供了各种复位的判别标志,用户程序可依具体设计灵活处理不同的复位情

形。

 

11.5.9     PICC 中的指针

 

PICC 中指针的基本概念和标准 C 语法没有太多的差别。但是在 PIC 单片机这一特定的

架构上,指针的定义方式还是有几点需要特别注意。

 

&O1540;    指向 RAM 的指针

 

如果是汇编语言编程,实现指针寻址的方法肯定就是用 FSR 寄存器,PICC 也不例外。

为了生成高效的代码,PICC 在编译 C 原程序时将指向 RAM 的指针操作最终用 FSR 来实现

间接寻址。这样就势必产生一个问题:FSR 能够直接连续寻址的范围是 256 字节(bank0/1

或 bank2/3),要覆盖最大 512 字节的内部数据存储空间,又该如何让定义指针?PICC 还是

将这一问题留给编程员自己解决:在定义指针时必须明确指定该指针所适用的寻址区域,例

如:

unsigned char *ptr0; //①定义覆盖 bank0/1 的指针

bank2 unsigned char *ptr1;  //②定义覆盖 bank2/3 的指针

bank3 unsigned char *ptr2;  //③定义覆盖 bank2/3 的指针

上面定义了三个指针变量,其中①指针没有任何 bank 限定,缺省就是指向 bank0 和 bank1;

②和③一个指明了 bank2,另一个指明了 bank3,但实际上两者是一样的,因为一个指针可

以同时覆盖两个 bank 的存储区域。另外,上面三个指针变量自身都存放在 bank0 中。我们

将在稍后介绍如何在其它 bank 中存放指针变量。

 

既然定义的指针有明确的 bank 适用区域,在对指针变量赋值时就必须实现类型匹配,

下面的指针赋值将产生一个致命错误:


unsigned char *ptr0;

bank2 unsigned char buff[8];

程序语句:


//定义指向 bank0/1 的指针

//定义 bank2 中的一个缓冲区


ptr0 = buff;  //错误!试图将 bank2 内的变量地址赋给指向 bank0/1 的指针

若出现此类错误的指针操作,PICC 在最后连接时会告知类似于下面的信息:

Fixup overflow in expression_r(...)

 

 

同样的道理,若函数调用时用了指针作为传递参数,也必须注意 bank 作用域的匹配,

而这点往往容易被忽视。假定有下面的函数实现发送一个字符串的功能:

void SendMessage(unsigned char *);

那么被发送的字符串必须位于 bank0 或 bank1 中。如果你还要发送位于 bank2 或 bank3 内的

字符串,必须再另外单独写一个函数:

void SendMessage_2(bank2 unsigned char *);

这两个函数从内部代码的实现来看可以一模一样,但传递的参数类型不同。

 

按笔者的应用经验体会,如果你看到了“Fixup overflow”的错误指示,几乎可以肯定

是指针类型不匹配的赋值所至。请重点检查程序中有关指针的操作。

 

&O1540;    指向 ROM 常数的指针

 

如果一组变量是已经被定义在 ROM 区的常数,那么指向它的指针可以这样定义:


const unsigned char company[]=”Microchip”;

const unsigned char *romPtr;

程序中可以对上面的指针变量赋值和实现取数操作:

romPtr      = company;  //指针赋初值

data = *romPtr++;  //取指针指向的一个数,然后指针加 1


//定义 ROM 中的常数

//定义指向 ROM 的指针


反过来,下面的操作将是一个错误,因为该指针指向的是常数型变量,不能赋值。

*romPtr = data; //往指针指向的地址写一个数

&O1540;    指向函数的指针

 

单片机编程时函数指针的应用相对较少,但作为标准 C 语法的一部分,PICC 同样支持

函数指针调用。如果你对编译原理有一定的了解,就应该明白在  PIC  单片机这一特定的架

构上实现函数指针调用的效率是不高的:PICC 将在 RAM 中建立一个调用返回表,真正的

调用和返回过程是靠直接修改 PC 指针来实现的。因此,除非特殊算法的需要,建议大家尽

量不要使用函数指针。

 

&O1540;    指针的类型修饰

 

前面介绍的指针定义都是最基本的形式。和普通变量一样,指针定义也可以在前面加上

特殊类型的修饰关键词,例如“persistent”、“volatile”等。考虑指针本身还要限定其作用域,

因此 PICC 中的指针定义初看起来显得有点复杂,但只要了解各部分的具体含义,理解一个

指针的实际用图就变得很直接。

 

㈠ bank 修饰词的位置含义

前面介绍的一些指针有的作用于 bank0/1,有的作用于 bank2/3,但它们本身的存放位置

全部在 bank0。显然,在一个程序设计中指针变量将有可能被定位在任何可用的地址空间,

这时,bank 修饰词出现的位置就是一个关键,看下面的例子:

//定义指向 bank0/1 的指针,指针变量为于 bank0 中

unsigned char *ptr0;

//定义指向 bank2/3 的指针,指针变量为于 bank0 中

bank2 unsigned char *ptr0; 

//定义指向 bank2/3 的指针,指针变量为于 bank1 中

bank2 unsigned char * bank1 ptr0; 

从中可以看出规律:前面的 bank 修饰词指明了此指针的作用域;后面的 bank 修饰词定义了

此指针变量自身的存放位置。只要掌握了这一法则,你就可以定义任何作用域的指针且可以

将指针变量放于任何 bank 中。

 

㈡ volatile、persistent 和 const 修饰词的位置含义

如果能理解上面介绍的 bank 修饰词的位置含义,实际上 volatile、persistent 和 const 这

些关键词出现在前后不同位置上的含义规律是和 bank 一词相一致的。例如:

//定义指向 bank0/1 易变型字符变量的指针,指针变量位于 bank0 中且自身为非易变型

volatile unsigned char *ptr0;

//定义指向 bank2/3 非易变型字符变量的指针,指针变量位于 bank1 中且自身为易变型

bank2 unsigned char * volatile bank1 ptr0;

//定义指向 ROM 区的指针,指针变量本身也是存放于 ROM 区的常数

const unsigned char * const ptr0;

亦即出现在前面的修饰词其作用对象是指针所指处的变量;出现在后面的修饰词其作用对象

就是指针变量自己。

11.6


PICC 中的子程序和函数

 

中档系列的 PIC 单片机程序空间有分页的概念,但用 C 语言编程时基本不用太多关心


 

代码的分页问题。因为所有函数或子程序调用时的页面设定(如果代码超过一个页面)都由

编译器自动生成的指令实现。

 

11.6.1     函数的代码长度限制

 

PICC 决定了 C 原程序中的一个函数经编译后生成的机器码一定会放在同一个程序页面

内。中档系列的 PIC 单片机其一个程序页面的长度是 2K 字,换句话说,用 C 语言编写的任

何一个函数最后生成的代码不能超过 2K 字。一个良好的程序设计应该有一个清晰的组织结

构,把不同的功能用不同的函数实现是最好的方法,因此一个函数 2K 字长的限制一般不会

对程序代码的编写产生太多影响。如果为实现特定的功能确实要连续编写很长的程序,这时

就必须把这些连续的代码拆分成若干函数,以保证每个函数最后编译出的代码不超过一个页

面空间。

 

11.6.2     调用层次的控制

 

中档系列 PIC 单片机的硬件堆栈深度为 8 级,考虑中断响应需占用一级堆栈,所

有函数调用嵌套的最大深度不要超过 7 级。编程员必须自己控制子程序调用时的嵌套深

度以符合这一限制要求。

 

PICC 在最后编译连接成功后可以生成一个连接定位映射文件(*.map),在此文件

中有详细的函数调用嵌套指示图“call graph”,建议大家要留意一下。其信息大致如下

(取自于一示范程序的编译结果):

Call graph:

*_main size 0,0 offset 0

     _RightShift_C

   _Task size 0,1 offset 0

     lwtoft

     ftmul size 0,0 offset 0

         ftunpack1

         ftunpack2

     ftadd size 0,0 offset 0

         ftunpack1

         ftunpack2

         ftdenorm

例 11-4  C 函数调用层次图

上面所举的信息表明整个程序在正常调用子程序时嵌套最多为两级(没有考虑中断)。因为

main  函数不可能返回,故其不用计算在嵌套级数中。其中有些函数调用是编译代码时自动

加入的库函数,这些函数调用从 C 原程序中无法直接看出,但在此嵌套指示图上则一目了

然。

 

11.6.3     函数类型声明

 

PICC 在编译时将严格进行函数调用时的类型检查。一个良好的习惯是在编写程序代码

前先声明所有用到的函数类型。例如:

void Task(void);

unsigned char Temperature(void);

void BIN2BCD(unsigned char);

void TimeDisplay(unsigned char, unsigned char);

这些类型声明确定了函数的入口参数和返回值类型,这样编译器在编译代码时就能保证生成

 

正确的机器码。笔者在实际工作中有时碰到一些用户声称发现 C 编译器生成了错误的代码,

最后究其原因就是因为没有事先声明函数类型所致。

 

建议大家在编写一个函数的原代码时,立即将此函数的类型声明复制到原文件的起始

处,见例 11-1;或是复制到专门的包含头文件中,再在每个原程序模块中引用。

 

11.6.4     中断函数的实现

 

PICC 可以实现 C 语言的中断服务程序。中断服务程序有一个特殊的定义方法:

void interrupt ISR(void);

其中的函数名“ISR”可以改成任意合法的字母或数字组合,但其入口参数和返回参数类型

必须是“void”型,亦即没有入口参数和返回参数,且中间必须有一个关键词“interrupt”。

 

中断函数可以被放置在原程序的任意位置。因为已有关键词“interrupt”声明,PICC 在

最后进行代码连接时会自动将其定位到 0x0004 中断入口处,实现中断服务响应。编译器也

会实现中断函数的返回指令“retfie”。一个简单的中断服务示范函数如下:

void  interrupt  ISR(void) //中断服务程序

{


 

   if (T0IE &&  T0IF) 

   {

T0IF = 0;

      //在此加入 TMR0 中断服务

   }


//判 TMR0 中断

 

 

//清除 TMR0 中断标志


 

   if (TMR1IE && TMR1IF)       //判 TMR1 中断

   {


 

TMR1IF0;

      //在此加入 TMR1 中断服务

   }

}


//清除 TMR1 中断标志

 

 

 

//中断结束并返回


关键字:PIC  单片机  C语言编程 引用地址:PIC 单片机 C 语言编程简介(2)

上一篇:PIC 单片机 C 语言编程简介(3)
下一篇:PIC单片机C语言编程教程(1)

推荐阅读最新更新时间:2024-03-16 14:48

51单片机串行口及存储器工作原理分析
一、 51单片机串行口工作原理 MCS-51系列单片机片内有一个串行I/O端口,通过引脚RXD(P3.0)和TXD(P3.1)可与外设电路进行全双工的串行异步通信。 1.串行端口的基本特点 8031单片机的串行端口有4种基本工作方式,通过编程设置,可以使其工作在任一方式,以满足不同应用场合的需要。其中,方式0主要用于外接移位寄存器,以扩展单片机的I/O电路;方式1多用于双机之间或与外设电路的通信;方式2,3除有方式l的功能外,还可用作多机通信,以构成分布式多微机系统。 串行端口有两个控制寄存器,用来设置工作方式、发送或接收的状态、特征位、数据传送的波特率(每秒传送的位数)以及作为中断标志等。 串行端口有一个数据寄存器S
[单片机]
51<font color='red'>单片机</font>串行口及存储器工作原理分析
有关51单片机有关晶振的问题总结(干货)
在初学51单片机的时候,总是伴随很多有关于晶振的问题,其实晶振就是如同人的心脏,是血液的脉搏,把单片机的晶振问题搞明白了,51单片机的其他问题迎刃而解…… 有关51单片机有关晶振的问题一并总结出来,希望对学51的童鞋来说能有帮助。 一、为什么51单片机爱用11.0592MHZ晶振? 其一:因为它能够准确地划分成时钟频率,与UART(通用异步接收器/发送器)量常见的波特率相关。特别是较高的波特率(19600,19200),不管多么古怪的值,这些晶振都是准确,常被使用的。 其二:用11.0592晶振的原因是51单片机的定时器导致的。用51单片机的定时器做波特率发生器时,如果用11.0592Mhz的晶振,根据公式算下来需要定时器
[单片机]
基于单片机的FIash存储器坏块自动检测
  随着电子技术飞速发展,智能电子产品随处可见,如PC机、移动电话、PDA、数码相机、游戏机、数字电视等,而诸如此类的电子产品的核心器件往往离不开存储器。无论是从存储器的物理结构、存储容量、数据读写速度、可靠性、耐用性,还是产品的实用性方面。其种类繁多。然而由于种种原因,越来越多的电子产品采用数据传输快、容量大的NAND型Flash存储器。虽然NAND型Flash具有许多优点,但其有随机产生不可避免的坏块,如果不能很好解决该坏块将导致高故障率。因此,这里提出一种基于DSP的Flash存储器坏块自动检测系统。    1 系统设计方案   图l为Flash存储器坏块自动检测系统结构框图。   本系统设计采用AT89C51自动
[单片机]
MCS - 51单片机寄存器功能
21个特殊功能寄存器(52系列是26个)不连续地分布在128个字节的SFR存储空间中,地址空间为80H-FFH,在这片SFR空间中,包含有128个位地址空间,地址也是80H-FFH,但只有83个有效位地址,可对11个特殊功能寄存器的某些位作位寻址操作(这里介绍一个技巧:其地址能被8整除的都可以位寻址)。 在51单片机内部有一个CPU用来运算、控制,有四个并行I/O口,分别是P0、P1、P2、P3,有ROM,用来存放程序,有RAM,用来存放中间结果,此外还有定时/计数器,串行I/O口,中断系统,以及一个内部的时钟电路。在单片机中有一些独立的存储单元是用来控制这些器件的,被称之为特殊功能寄存器(SFR)。这样的特殊功能寄存器51单片机
[单片机]
MCS - 51<font color='red'>单片机</font>寄存器功能
Atmel推出面向汽车的Cortex-M7 MCU
Atmel面向汽车、物联网和工业市场推出最高性能的ARM Cortex-M7系列MCU,具备优越的内存架构和连接能力 拓展了Atmel | SMART MCU产品系列,超越行业最高性能的ARM Cortex -M处理器系列MCU,CoreMark评分高达1500分 具备性能卓越的连接能力和独特内存架构,针对实时决定性代码执行和低延迟外设数据访问实现了优化 业内首款符合汽车使用要求的Cortex-M7系列MCU,为实现汽车联网和音频应用程序提供了以太网AVB和媒体LB外设功能 全球微控制器(MCU)和触控解决方案领域的领导者Atmel 公司(NASDAQ:ATML)近日发布了4个新系列产品,均
[汽车电子]
8051单片机指令定义详解——AJMP addr11(4)
8051单片机指令定义详解 (AJMP addr11) AJMP addr11 功能:绝对跳转。 描述:AJMP指令用于将程序转到相应的目的地址去执行,该地址在程序执行过程之中产生,由PC值(两次递增之后)的高5位、操作码的7-5位和指令的第2字节连接形成。要求跳转的目的地址和AJMP指令的后一条指令的第1字节位于同一2KB的程序存储页内。 示例:假设标号AJMADR位于程序存储器的0123H,指令 AJMP JMPADR 位于0345H,执行完该指令后PC值变为0123H。 AJMP addr11 字节数:2 执行周期:2 机器码:aaa00001 aaaaaaaa 注意:目的地
[单片机]
MCU价格腰斩,汽车芯片慌“拐点”已至?
一度价格攀高的半导体芯片近日出现拐点。据媒体报道,半导体芯片砍单降价风暴愈演愈烈,即便是之前供不应求的MCU的报价也开始出现大幅度降价。更有报道直指,全球前五大MCU厂出厂产品价格腰斩。至于台湾芯片代工行业的龙头老大——台积电更是下调了其营收目标。而背后的原因是台积电的前三大客户——苹果、AMD和英伟达纷纷下调了订单。 曾经不起眼的汽车MCU为什么突然会短缺? 其实之前车企普遍缺少的是制程较低的MCU芯片,相反被三星、台积电等少数芯片代工企业掌握的高制程芯片产能反倒非常充足。其实之前汽车芯片短缺是由多个因素共同作用的结果: 不期而至的新冠疫情撕开了芯片短缺的口子。全球大部分汽车芯片的产能都位于东南亚以及日韩、台湾
[汽车电子]
<font color='red'>MCU</font>价格腰斩,汽车芯片慌“拐点”已至?
单片机开发调试应注意的问题
1、使用总线不外引的单片机 ·是最正统的单片机使用模式 ·符合小型、简单、可靠、廉价的单片机设计初衷 ·总线封闭的产品最可靠 2、使用单片机C语言编程 * C语言是简洁、高效、而又最贴近硬件的高级编程语言 * 90年代初单片机C语言就已成熟为专业水平的高级语言,不应再有顾虑 * 当前厂商在推出新的单片机产品时纷纷配套C语言编译器 3、使用中、高档的单片机仿真工具 * 只有中、高档仿真工具才能仿真总线封闭式的单片机 * 仿真器必须使用band-out chip或hooks chip * 应支持高级语言的调试,提供全数据类型的查看和修改 * 支持多家软件公司汇编和编译产生的目标代码格式 * 中档仿真器的起步要求是至少解决了上
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved