——单片机C语言编程屈剑锋.pptx

上传人:一*** 文档编号:71939943 上传时间:2023-02-07 格式:PPTX 页数:41 大小:721.30KB
返回 下载 相关 举报
——单片机C语言编程屈剑锋.pptx_第1页
第1页 / 共41页
——单片机C语言编程屈剑锋.pptx_第2页
第2页 / 共41页
点击查看更多>>
资源描述

《——单片机C语言编程屈剑锋.pptx》由会员分享,可在线阅读,更多相关《——单片机C语言编程屈剑锋.pptx(41页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、第四章 单片机C语言编程51系列单片机支持三种高级语言,即PL/M,C和BASIC。C语言是一种通用的程序设计语言,其代码率高,数据类型及运算符丰富,并具有良好的程序结构,适用于各种应用的程序设计,是目前使用较广的单片机编程语言。MCS-51系列单片机采用的C语言,简称C51。C51符合C语言的ANSI标准,并根据单片机的特性进行了扩展,C51所产生的目标代码短、运行速度高、所需存储空间小、第1页/共41页第四章 单片机C语言编程主要内容4.1C51程序结构4.2C51的数据类型与运算符存储类型存储模式数据类型的指针对扩展外设的访问运算符4.3C51的函数函数的定义函数的参数传递及返回值传递函

2、数的调用库函数与宏定义4.4程序设计程序设计方法程序设计实例第2页/共41页4.1 C51的程序结构同ANSIC一样,C51的程序由一个个函数组成,这里的函数和其他语言的“子程序”或“过程”具有相同的意义。必须有一个主函数main(),程序的执行从main()函数开始,调用其他函数后返回主函数main(),最后在主函数中结束整个程序而不管函数的排列顺序如何。第3页/共41页组成结构:全局变量说明/*可被各函数引用*/main()/*主函数*/局部变量说明 /*只在本函数引用*/执行语句(包括函数调用语句)fun1(形式参数表)/*函数1*/形式参数说明局部变量说明 执行语句(包括调用其他函数语

3、句)funn(形式参数表)/*函数n*/形式参数说明 局部变量说明 执行语句第4页/共41页 4.1 C51的程序结构C语言的语句规则:1.每个变量必须先说明后引用,变量名英文大小写是有差别的。2.C语言程序一行可以书写多条语句,但每个语句必须以“;”结尾,一个语句也可以多行书写。3.C语言的注释用/*/表示。4.“”花括号必须成对,位置随意,可在紧挨函数名后,也可另起一行,多个花括号可以同行书写,也可逐行书写,为层次分明,增加可读性,同一层的“”花括号对齐,采用逐层缩进方式书写。第5页/共41页4.2 C51的数据类型与运算符 的存储类型1数据存储区1)内部数据存储区dataidatabda

4、ta2)外部数据存储区xdatapdata2程序存储器code第6页/共41页4.2 C51的数据类型与运算符 的存储模式存贮器模式决定了变量的默认存贮器类型、参数传递区和无明确存贮区类型的说明。#pragma small(largecompact)C51的存贮器模式有SMALL、LARGE和COMPACT。在固定的存贮器地址进行变量参数传递是C51的一个标准特征,SMALL模式下参数在内部数据存贮区中传递,默认的存储区类别为data;COMPACT模式下参数在外部存贮器中传递,默认的存储区类别为pdata;LARGE模式下参数在外部存贮器中传递,默认的存储区类别为xdata。第7页/共41页

5、4.2 C51的数据类型与运算符 的数据类型无论哪种数据都是存放在存贮单元中的,每一个数据究竟要占用几个单元(即数据的长度)都要提供给编译系统,编译系统以此为根据预留存贮单元,这就是定义数据类型的意义.C51支持的数据类型有常量、变量、指针。C51支持的ANSIC的数据类型存储时先高后低原则;常量const位置与定义说明有关,code一般放在程序存储区。第8页/共41页4.2 C51的数据类型与运算符 的数据类型1)C51扩展的数据类型第9页/共41页变量说明举例 data char var;/*字符变量var定位在片内数据存贮区*/char code MSG =PARAMETER:;/*字

6、符 数 组 MSG 定 位 在 程 序 存贮区*/unsigned long xdata array 100;/*无符号长型数组定位在片外 RAM区,每元素占4bytes*/float idata x,y,z;/*实型变量 x,y,z,定位在片内用间址访问 的内部RAM区*/bit lock;/*位变量Lock定位在片内RAM可位寻址区*/unsigned int pdata sion;/*无符号整型变量 sion定位在分页的外部RAM*/unsigned char xdata vector10 4 4/*无符号字符型三维数 组,定位在片外RAM区*/sfr P0=0 x80;/*定义P0口,

7、地址为80H*/char bdata flags;/*字符变量flags定位在可位寻址内部RAM区*/sbit flag0=flags0;/*定义flag0为flags.0*/第10页/共41页说明:1.字符型(char)、整型(int)和长整型(long)均有符号型(signed)和无符号型(unsigned)两种,如果不是必须,尽可能选择unsigned型,这将会使编译器省却符号位的检测,使生成的程序代码比signed类型短得多。2.程序编译时,C51编译器会自动进行类型转换,例如将一个位变量赋值给一个整型变量时,位型值自动转换为整型值;当运算符两边为不同类型的数据时,编译器先将低级的数据

8、类型转换为较高级的数据类型,运算后,运算结果为高级数据类型。3.51单片机内部数据存贮器的可寻址位(20H2FH)定义为bit型,而特殊功能寄存器的可寻址位(即地址为X0H和X8H的SFR的各位)只能定义为sbit类型。4.如果在变量说明时略去存贮器类型标志符,编译器会自动选择默认的存贮器类型。默认的存贮器类型由控制指令SMALL、COMPACT和LARGE限制。例如如果声明char var,则默认的存贮器模式为SMALL,var放在data存贮区;如果使用COMPACT模式,var放入idata存贮区;在使用LARGE模式的情况下,var被放入外部数据存贮区(xdata存贮区)。4.2C51

9、的数据类型与运算符的数据类型的数据类型第11页/共41页(1)关于指针型变量 在汇编语言程序中,要取存贮单元m的内容可用直接寻址方式,也可用寄存器间接寻址方式,如果用R1寄存器指示m的地址,用R1取m单元的内容。相对应的在C语言中用变量名表示取变量的值(相当于直接寻址),也可用另一个变量(如P)存放m的地址,P就相当于R1寄存器。用*P取得m单元的内容(相当于汇编的间接寻址方式)这里P即为指针型变量。下面表格表示两种语言将m单元的内容送n单元的对照语句。注:上表省略了汇编语言程序中对符号地址n和m用EQU伪指令进行具体地址定义的语句以及C语言对变量n、m和指针变量P进行类型定义的语句,实际程序

10、设计中,此步是不可缺少的。表中&为取地址运算符,*为取内容运算符。汇编语言和汇编语言和C语言的对照语言的对照 表表直接寻址间接寻址汇编语言C语言汇编语言C语言movn,m传送语句n=m;赋值语句movR1,#m;m的地址送R1movn,R1;m的内容送nP=&m/*m的地址送P*/n=*P/*m的内容送n*/4.2C51的数据类型与运算符的指针的指针第12页/共41页(2)指针型数据的类型 由于C51是结合51单片机硬件的,51单片机的不同存贮空间,有不同的地址范 围,即 使 对 于 同 一 外 部 数 据 存 贮 器,又 有 用 Ri分 页 寻 址(Ri为 八 位)和 用DPTR寻址(DPT

11、R为十六位)两种寻址方式,而指针本身也是一个变量,有它存放的存贮区和数据长度。因此,在指针类型的定义中要说明:被指的变量的数据类型和存贮类型;指针变量本身的数据类型(占几个字节)和存贮类型(即指针本身存放在什么存贮区)。例如类型定义为data或idata,表示指针指示内部数据存贮器;而pdata表示指针指向外部数据存贮器,用Ri间址。以上均为八位地址;而类型code/xdata表示指针指向外部程序存贮器或外部数据存贮器指针,本身(即被指示地址)应为十六位长度。如果想使指针能适用于指向任何存贮空间,则可以定义指针为通用型,此时指针长度为3字节,第一字节表示存贮器类型编码,第二、三字节分别表示所指

12、 地址的高位和低位。第一字节表示的存贮器类型编码见下表:通用型指针的存贮类型编码表通用型指针的存贮类型编码表 存储器类型idataidataxdataxdatapdatapdatadatadatacodecode编 码1 12 23 34 45 5第13页/共41页4.2 C51的数据类型与运算符 的指针1)指向不同存储区变量的通用指针指针能适用于指向任何存贮空间,此时指针长度为3字节,第一字节表示存贮器类型编码,第二、三字节分别表示所指地址的高位和低位。unsigned char *ptr;/通用指针ptr,指针存放在默认存储区unsigned char *idata iptr;/通用指针i

13、ptr,指针存放在idata存储区2)指向固定存储区变量的指针定义为data或idata,表示指针指示内部数据存贮器;定义为pdata,表示指针指向外部数据存贮器,用Ri间址。以上均为八位地址;定义为类型code/xdata,表示指针指向外部程序存贮器或外部数据存贮器指针,本身(即被指示地址)应为十六位长度。int code*ptr/指向code存储区的指针ptr,指针存放在默认存储区 int idata *pdata iptr/指向idata存储区的指针ptr,指针存放在pdata存储区第14页/共41页指针变量说明longxdata*px;/*指针px指向long型xdata区(每个数据占

14、四个单元,指针自身在默认存贮器(如不指定编译模式在data区),指针长度为2个字节*/char xdata*data pd;/*指 针 pd指 向 字 符 型 xdata区,自 身 在 data区,长度2字节*/datacharxdata*pd;/*与上例等效*/data int*pn;(和int*data pn及int*pn等效)/*定义一个类型为int型的通用型指针,指针自身在data区长度为3字节*/第15页/共41页在上例的指针声明中包含如下几个内容:1)指针变量名(如px)前面冠以“*”,表示px为指针型变量,此处*不带取内容之意。2)指针指向的存贮类型,即指向哪个存贮区,它决定了指

15、针本身的长度(见数据类型表)。存贮类型声明的位置在数据类型和指针名(如*px)之间,如无此项声明,则此指针型变量为通用型。3)指针指向的存贮区的数据类型,即被指向的存贮区以多少个单元作一个数据单位,当程序通过指针对该区操作时,将按此规定的单元个数的内容作为一个数据操作。4)指针变量自身的存贮类型,即指针处于什么区与自身的长度无关,该声明可位于声明语句的开头,也可在“*”和变量名之间。此项由编译模式放在默认区,如无规定编译模式,通常在data区。第16页/共41页C51对SFR、可寻址位、存储器和I/O口的定义 1.特殊功能寄存器SFR定义 C51提供了一种自主形式的定义方式,使用特定关键字sf

16、r 如 sfr SCON=0 x98;/*串行通信控制寄存器地址98H*/sfr TMOD=0 x89;/*定时器模式控制寄存器地址89H*/sfr ACC=0 xe0;/*A累加器地址E0H*/sfr P1=0 x90;/*P1端口地址90H*/定义了以后,程序中就可以直接引用寄存器名。C51也建立了一个头文件reg51.h(增强型为reg52.h),在该文件中对所有的特殊功能寄存器的进行了sfr定义,对特殊功能寄存器的有位名称的可寻址位进行了sbit定义,因此,只要用包含语句#include,就可以直接引用特殊功能寄存器名,或直接引用位名称。要特别注意:在引用时特殊功能寄存器或者位名称必须

17、大写。第17页/共41页2.对位变量的定义 C51对位变量的定义有三种方法:将变量用bit类型的定义符定义为bit类型:如 bit mn;mn为位变量,其值只能是“0”或“1”,其位地址C51自行安排在可位寻址区的bdata区。采用字节寻址变量.位的方法:如 bdata int ibase;/*ibase定义为整型变量*/sbit mybit=ibase15;/*mybit定义为ibase的D15位*/这里位是运算符“”相当于汇编中的“”,其后的最大取值依赖于该位所在的字节寻址变量的定义类型,如定义为char最大值只能为7。第18页/共41页 对特殊功能寄存器的位的定义 方法1:使用头文件及s

18、bit定义符;多用于无位名的可寻址位。例如#include sbit P1-1=P11;/*P1-1为P1口的第1位*/sbit ac=ACC7;/*ac定义为累加器A的第7位*/方法2:使用头文件reg51.h,再直接用位名称。例如#include RS1=1;RS0=0;方法3:用字节地址位表示 例如 sbit OV=0 xD02;方法4:用寄存器名.位定义 例如 sfr PSW=0 xd0;/*定义PSW地址为d0H*/sbit CY=PSW7;/*CY为PSW7*/第19页/共41页3.C51对存贮器和外接I/O口的绝对地址访问对存贮器的绝对地址访问 利用绝对地址访问的头文件absac

19、c.h可对不同的存贮区进行访问。该头文件的函数有:CBYTE (访问code区字符型)DBYTE (访问data区字符型)PBYTE (访问pdata或I/O区字符型)XBYTE (访问xdata或I/O区字符型)还有CWORD、DWORD、PWORD和XWORD四个函数,它们的访问区域同上,只是访问的类型为int型。例:#include#define com XBYTE0 x07ff 那么后面程序com变量出现的地方,就是对地址为07ffH的外部RAM或I/O口进行访问。第20页/共41页例:XWORD0=0 x9988;即将9988H(int类型)送入外部RAM的0号和1号单元。使用中要注

20、意:absacc.h一定要包含进程序,XWORD必须大写。对外部I/O口的访问 由于单片机的I/O口和外部RAM统一编址,因此对I/O口地址的访问可用XBYTE(MOVX DPTR)或PBYTE(MOVX Ri)进行。例:XBYTE0Xefff=0 x10;将10H输出到地址为EFFFH端口 第21页/共41页4.2 C51的数据类型与运算符 对扩展外设的访问定义变量时,使用_at_关键词指定变量的绝对地址,格式为:数据类型存储类型变量名_at_绝对地址;关键词volatile:表示不希望编译器对相关变量进行优化,或优化器用到这个变量时需要小心的读取,而不是直接读取保存在寄存器中的备份。例:v

21、olitile unsigned char xdata IOPORT8 _at_0 xE000;/定义变量定义变量IOPORT8,地址,地址0 xE000volitile unsigned int xdata IOPORT16 _at_0 xE004;/定义变量定义变量IOPORT16,地址,地址0 xE004第22页/共41页4.2 C51的数据类型与运算符 的运算符 1赋值运算符:将“”的右边的值赋值给左边的变量.2.C51的算术运算符:(加或正号);(减或负号);*(乘号);/(除号);%(求余)优先级:先乘除,后加减,先括号内,再括号外3.C51的关系运算符有六种:(小于);(大于);

22、=(小于等于);=(大于等于);=(相等);!=(不相等)优先级:前四个高,后二个“=”和“!=”级别低。第23页/共41页4.2 C51的数据类型与运算符 的运算符4C51的逻辑运算符有三种:&(逻辑与);|(逻辑或);!(逻辑非);逻辑表达式和关系表达式的值相同,以0代表假,以1代表真。以上三种运算的优先级见图。5C51的按位操作的运算符有六种:&(按位与);(按位或);(按位异或);(位取反);(位右移)(注:补零移位)例1.a=0 xf0H;表达式a=a值为0FH例2.a=0 xea;表达式a2值为A8H,即a值左移两位,移位后空白位补0。6.自增、自减运算符:+i,-i(在使用i之前

23、,先使i值加1,减1)i+,i-(在使用i之后,再使i值加1.,减1)例:设i原值为5j=+i则j值为6,i值也为6j=i+则j值为5,i值为6!(非)算术运算关系运算&和|=(赋值运算)第24页/共41页4.3 C51的函数C51程序由函数组成。从用户使用角度划分,函数分为库函数和用户自定义函数 库函数是编译系统为用户设计的一系列标准函数用户只需调用,而无需自己去编写这些复杂的函数,如前面所用到的头文件reg51.h等,有的头文件中包括一系列函数,要使用其中的函数必须先使用#include包含语句,然后才能调用。用户自定义函数是用户根据任务编写的函数。从参数形式上函数分为无参函数和有参函数。

24、有参函数即是在在调用时,调用函数用实际参数代替形式参数,调用完返回结果给调用函数。第25页/共41页4.3 C51的函数 函数的定义C51中函数的定义格式与标准C相似,增加了一下内容:1)将函数定义为中断服务子程序;2)选择函数所使用的寄存器体;3)选择存储模式;4)说明函数是一个可重入函数。函数的定义格式:返回值类型 函数名(参数)存储模式 reentrant interrupt using n1)可省略2)返回值类型:无返回值时应声明为void;省略时默认为int.3)存储模式:说明函数的存储模式,可以为small、compact、large,省略时使用程序设定的存储模式。4)reentr

25、ant:说明函数为可重入函数。当中断或者多个函数同时调用同一个函数时使用。可重入堆栈为减址,初始化时为内部数据区最大值+1;可重入堆栈和可重入堆栈指针与函数的存储模式相关,使用时须修改启动代码中对应存储模式的可重入堆栈宏定义。第26页/共41页4.3 C51的函数 函数的定义5)interruptn:说明函数是中断类型n的中断服务子程序C51编译器支持32个中断函数,中断类型号为031(地址参照教材P101,表4.5)。函数定义为中断函数后,编译器会在对应的中断服务程序入口处,生成LJMP指令,直接跳到中断函数。中断函数不能带参数,不能定义函数返回值,且程序不能直接调用中断函数。编译器会自动为

26、中断函数添加保护现场的代码,进入函数后,压栈保护函数中使用了的ACC、B、DPTR、PSW寄存器的值,返回前弹栈恢复。第27页/共41页6)usingn:指定函数使用第n个寄存器组,n可以为0、1、2、3,函数声明中不包括usingn选项。定义了usingn选项后,编译器会在函数开始处添加指令,压栈保存当前PSW的值,然后修改PSW,切换到指定的寄存器组,在RET指令前,添加指令弹栈恢复原来的PSW,切回到原来的寄存器组;当函数使用寄存器传递返回值时不能使用usingn,使用了usingn选项的函数之间不能互相调用;处理中断时,通常会为不同优先级的中断函数指定不同的寄存器组,而其代码使用另一个

27、寄存器组。第28页/共41页4.3 C51的函数 函数参数传递及返回值传递1.函数参数的传递C51编译器在调用函数时,只将函数的返回地址压栈,通过寄存器或固定地址的存储单元来传递参数;默认情况下,编译器最多可以通过寄存器传递3个参数,寄存器传递参数的具体情况见教材P102,表4.6。2.函数返回值的传递C51编译器始终通过寄存器传递函数的返回值,传递返回值的寄存器见表4.7。第29页/共41页4.3 C51的函数 函数的调用调用函数前需要声明函数;通常在主函数前声明函数;在主函数后定义函数;可以通过函数名直接调用函数,也可以通过函数指针间接调用函数。定义多个函数时,可在另一文件中集中定义函数,

28、将函数声明放在头文件中,主程序用#include语句包含头文件,便可调用文件中声明的函数。头文件中的条件编译,确保多个头文件相互包含时,每个头文件只被编译一次。#ifndef#endif 第30页/共41页4.3 C51的函数 函数的调用通过函数指针实现函数调用,格式((返回值类型(code*)(形参说明))函数指针)(实参说明)通过指针实现函数调用 char code*pfun;pfun=(void*)fun;/实现将函数fun的地址赋值给指针pfun第31页/共41页4.3 C51的函数 函数的调用例通过函数指针调用函数intfun_add(intvar1,intvar2);/声明函数声明

29、函数fun_addfun_addvoidmain()Charcode*pfun;/定义指向定义指向codecode存储区的指针存储区的指针intrtn=0;Begin:pfun=(void*)fun_add;/指针指针pfunpfun指向函数指向函数fun_addfun_addrtn=(int(code*)(int,int)pfun)(200,100);/通过指针通过指针pfunpfun调用函数调用函数gotoBegin;intfun_add(intvar1,intvar2)/函数定义函数定义return(var1+var2);第32页/共41页4.3 C51的函数 的库函数和宏定义库函数是编

30、译系统为用户设计的一系列标准函数,用户只需调用,而无需自己去编写这些复杂的函数,如前面所用到的头文件reg51.h、absacc.h等,有的头文件中包括一系列函数,要使用其中的函数必须先使用#include包含语句,然后才能调用。1.本征库函数#include_chkfloat_:测试并返回源点数状态_crol_,_cror_:将char型变量循环向左(右)移动指定位数后返回_iror_,_irol_:将int型变量循环向左(右)移动指定位数后返回_lrol_,_lror_:将long型变量循环向左(右)移动指定位数后返回_nop_:相当于插入NOP_testbit_:相当于JBCbitvar

31、测试该位变量并跳转同时清除第33页/共41页4.3 C51的函数 的库函数和宏定义2直接访问存储区的宏定义include”可以直接访问指定地址的存储区单元CBYTE、CWORD:直接访问程序存储区;DBYTE、DWORD:访问内部数据区;PWORD、PBYTE:访问外部数据区当前页;XBYTE、XWORD:访问外部数据区。例:rval=CBYTE0 x0002;/指向程序存贮器的0002h地址rval=XWORD0 x0002;/指向外RAM的0004h地址第34页/共41页4.3 C51的函数 的库函数和宏定义3.缓冲区处理函数include包括拷贝比较移动等函数memcmp;memcopy

32、;memmove;strcat;strchr;strcmp;strcpy;4.字符转换与字符分类includeisdigit:判断字符是否是数字islower:是否是小写isupper:是否是大写tolower:字符转换成小写字符toupper:字符转换成大写字符5.数学函数include包含常用的算术运算函数sin:sin函数cos:cos函数abs:求绝对值第35页/共41页4.4 程序设计例1 1 在下图中在下图中8XX518XX51接有五个共阴极数码管的动态显示接口电路,开关接有五个共阴极数码管的动态显示接口电路,开关打向位置打向位置“1 1”时,显示时,显示“1234512345”字

33、样,当开关打向字样,当开关打向“2 2”时,显示时,显示“HELLOHELLO”字样,试用字样,试用C51C51编程实现功能。编程实现功能。第36页/共41页#include#defineuintunsignedint#defineucharunsignedcharSbitP17=P17;main()ucharcodetab15=0 x86,0 xdb,0 xcf,0 xe6,0 xed;/*/*“1-51-5”的的字字形形码码,因因P1.7P1.7接接的的开开关关,最最高高位位送送的的“1 1”*/*/ucharcodetab25=0 xf8,0 xf9,0 xb8,0 xb8,0 xbf;

34、/*/*“HELLOHELLO”的段码的段码 “1 1”*/*/uchari;unitj;while(1)p3=0 x01;for(i=0;i5;i+)if(P17=1)P1=tab1i;elseP1=tab2i;P3=1;for(j=0;j=25000;j+);第37页/共41页4.4 程序设计例2 2 记录并显示中断次数用C语言编程。1在主程序中判断中断次数,程序如下:#includechari;codechartab16=0 x3f,0 x06,0 x5b,0 x4F,0 x66,0 x6d,0 x7d,0 x07,0 x7f,0 x6f,0 x77,0 x7c,0 x39,0 x5e,

35、0 x79,0 x71;int()interrupt2i+;/*计中断次数*/P1=tabi;/*查表,次数送显示*/main()EA=1;/*开中断总开关*/EX1=1;/*允许INT1中断*/IT1=1;/*下降沿产生中断*/ap5:P1=0 x7f/*显示“0”*/for(i=0;i16;);/*当i小于16等待中断*/gotoap5;/*当i=16重复下一轮16次中断*/第38页/共41页4.4 程序设计2在中断程序中判断中断次数:#includechari;codechartab16=0 x3f,0 x06,0 x5b,0 x4F,0 x66,0 x6d,0 x7d,0 x07,0 x7f,0 x6f,0 x77,0 x7c,0 x39,0 x5e,0 x79,0 x71;int()interrupt2i+;if(i16)P1=tabi;elsei=0;P1=0 x7f;main()EA=1;EX1=1;IT1=1;P1=0 x7f;while(1);/*等待中断*/第39页/共41页谢谢第40页/共41页感谢您的观看!第41页/共41页

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 管理文献 > 管理工具

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁