陈桂友单片机程序设计 PPT课件_第1页
陈桂友单片机程序设计 PPT课件_第2页
陈桂友单片机程序设计 PPT课件_第3页
陈桂友单片机程序设计 PPT课件_第4页
陈桂友单片机程序设计 PPT课件_第5页
已阅读5页,还剩83页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1 88 第五章单片机的C语言程序设计及仿真调试本章学习目标掌握单片机C语言程序中的常用功能掌握KeilC的程序设计掌握STC15F2K60S2单片机C语言程序调试过程 2 88 汇编语言和C语言的选择问题设计规模较小的嵌入式应用系统时 可以使用汇编语言 因为代码一般不长 且较简单 当程序比较复杂 且没有很好的注释时 使用汇编编程的可读性和可维护性会很差 代码的可重性也比较低 使用C语言编程 编写简单 直观易读 便于维护 通用性好 在控制任务比较复杂或者具有大量运算的系统中 C语言优势明显 由于模块化 用C语言编写的程序具有很好的可移植性 3 88 5 1单片机C语言程序中的常用功能 一 逻辑运算和位运算1 逻辑运算符按逻辑运算符用于逻辑运算 包括与 或 非 三种 对于使用逻辑运算符的表达式 返回0表示 假 返回1表示 真 4 88 与运算符 5 88 或运算符 功能 检查两个条件中是否有一个为真的运算符 只要有一个条件为真 运算结果就为真 上例改为 如果任一语句为真 程序需执行某些操作 则条件代码如下 a 10 b 7 6 88 逻辑非运算符 功能 表示对表达式的真值取反 例如 如果变量s小于10 程序需执行某些操作 则条件代码如下 s 10 s不大于等于10 7 88 2 位运算符很多系统程序常要求进行位 bit 运算或处理 语言提供了六种位运算符 按位与 按位或 按位异或 取反 左移 8 88 1 按位 与 运算按位与运算符 是双目运算符 功能是参与运算的两数各对应的二进制位相与 只有对应的两个位均为1时 结果位才为1 否则为0 例如 9 500001001 00000101 00000001按位与运算通常用来对某些位清0或保留某些位 例如把a的高八位清0 保留低八位可用a 255 255的二进制数为0000000011111111 9 88 2 按位 或 运算按位或运算符 是双目运算符 功能是参与运算的两数各对应的二进制位相或 只要对应的两个位有一个为1时 结果位就为1 例如 9 500001001 00000101 00001101 十进制为13 或运算通常用来对某些位置1 10 88 3 按位 异或 运算按位异或运算符 是双目运算符 功能是参与运算的两数各对应的二进制位相异或 当两个对应的位相异时 结果为1 例如 9 500001001 00000101 00001100 十进制为12 异或运算通常用来对某些位取反 11 88 4 求反运算求反运算符 为单目运算符 具有右结合性 功能是对参与运算的数的各二进制位按位求反 例如 9 0000000000001001 结果为 1111111111110110 12 88 5 左移运算左移运算符 是双目运算符 功能是把 左边的运算数的各二进制位全部左移若干位 由 右边的数指定移动的位数 高位丢弃 低位补0 例如 a 4指把a的各二进位向左移动4位 如a 00000011 十进制3 左移4位后为00110000 十进制48 13 88 6 右移运算右移运算符 是双目运算符 功能是把 左边的运算数的各二进制位全部右移若干位 右边的数指定移动的位数 例如 设a 15 a 2000001111右移为00000011 十进制3 对于有符号数 在右移时 符号位将随同移动 当为正数时 最高位补0 而为负数时 符号位为1 最高位是补0或是补1取决于编译系统的规定 14 88 二 预处理以 号开头的命令是预处理命令 语言提供了多种预处理功能 如宏定义 define 文件包含 include 条件编译等 合理地使用预处理功能 可以使得编写的程序便于阅读 修改 移植和调试 也利于模块化程序设计 下面介绍常用的预处理功能 15 88 1 宏定义 define 在 语言源程序中允许用一个标识符来表示一个字符串 称为宏 被定义为宏的标识符称为宏名 在编译预处理时 对程序中所有出现的宏名 都用宏定义中的字符串去代换 这称为宏代换或宏展开 宏代换是由预处理程序自动完成的 在 语言中 宏分为有参数和无参数两种 16 88 1 无参宏定义无参宏的宏名后不带参数 其定义的一般形式为 define标识符字符串其中 标识符为所定义的宏名 字符串可以是常数 表达式 格式串等 符号常量的定义就是一种无参宏定义 此外 常对程序中反复使用的表达式进行宏定义 如要终止宏定义 可使用 undef命令 17 88 2 带参宏定义在宏定义中的参数称为形式参数 在宏调用中的参数称为实际参数 对带参数的宏 在调用中 不仅要宏展开 而且要用实参去代换形参 带参宏定义的一般形式为 define宏名 形参表 字符串 18 88 在字符串中含有各个形参 带参宏调用的一般形式为 宏名 实参表 例如 defineMAX a b a b a b 取a和b的最大数 19 88 2 文件包含 include 文件包含的一般形式为 include 文件名 功能是把指定的文件插入该命令行位置取代该命令行 从而把指定的文件和当前的源程序文件连成一个源文件 20 88 说明以下几点 包含命令中的文件名可以用双引号括起来 也可以用尖括号括起来 例如 include stdio h include二者的区别 使用尖括号表示在包含文件目录中去查找 包含目录由用户在开发环境中设置 而不在源文件目录去查找 使用双引号则表示首先在当前的源文件目录中查找 若未找到才到包含目录中去查找 21 88 3 条件编译条件编译就是按不同的条件去编译不同的程序部分 从而产生不同的目标代码文件 条件编译对于程序的移植和调试 可以分段调试 非常有用 特别是在操作系统的裁减中 经常使用条件编译 22 88 1 第一种形式 ifdef标识符程序段1 else程序段2 endif功能是 如果标识符已被 define命令定义过 则对程序段1进行编译 否则对程序段2进行编译 如果没有程序段2 它为空 本格式中的 else可以没有 23 88 2 第二种形式 ifndef标识符程序段1 else程序段2 endif功能是 如果标识符未被 define命令定义过则对程序段1进行编译 否则对程序段2进行编译 这与第一种形式的功能正相反 24 88 3 第三种形式 if常量表达式程序段1 else程序段2 endif功能是 如果常量表达式的值为真 非0 则对程序段1进行编译 否则对程序段2进行编译 因此可以使程序在不同条件下 完成不同的功能 25 88 5 2KeilC和ANSIC 一 KeilC51扩展关键字C51有以下扩展关键字 共19个 at sbit sfr bit sfr16 idata bdata xdata pdata data code alien small compact large using reentrant interrupt task 26 88 1 内存区域 MemoryAreas 1 程序存储器 code 程序存储区 可以使用code定义表格常数 2 内部RAM 用以下关键字说明 data 直接寻址区 内部RAM的低128字节 地址范围为00H 7FH idata 间接寻址区 包括整个内部RAM区 256字节 地址范围为00H 0FFH bdata 可位寻址区 地址范围为20H 2FH 27 88 3 外部数据存储器 外部RAM视使用情况可由以下关键字标识 xdata 可指定多达64KB的外部直接寻址区 地址范围0000H 0FFFFH pdata 能访问1页 256Bytes 的外部RAM 很少用 28 88 存储类型的指定 变量或参数的存储类型可由存储模式指定缺省类型 也可由关键字code data idata xdata pdata直接声明指定 例如 unsignedchardatabuffer charcodearray hello unsignedcharxdataarr 10 4 4 29 88 4 特殊功能寄存器 SFR STC15F2K60S2单片机的特殊功能寄存器 SFR 寻址区 用来控制定时器 计数器 串口 I O及其他部件 为了支持SFR及其可寻址位的声明 引入了sfr sbit等关键词 30 88 sfr 字节寻址 语法如下 sfrsfr name int constant 如sfrP0 0 x80 0 x80为P0口的地址 后为常数 并且这个常数必须在特殊功能寄存器的地址范围内 位于0 x80到0 xFF之间 31 88 sfr16 字寻址如sfr16DPTR 0 x82 指定DPTR的地址DPL 0 x82 DPH 0 x83 sbit 位寻址用于声明可位寻址的特殊功能寄存器的位变量 32 88 sbit可以有下面声明方法 方法1 sbitbitname sfr name bit number 其中 sfr name必须是已定义的SFR的名字 bit number是位号 0 7 如 sbitCY PSW 7 定义CY为PSW的第7位 方法2 sbitbitname sfr address bit number 其中 sfr address是SFR所在的地址 0 x80 0 xff bit number是位号 0 7 如 sbitOV 0 xD0 2 定义PSW中的OV位方法3 sbitbitname bit address 其中 bit address是位地址 如 sbitEA 0 xAF 第0 xAF位为EA 33 88 对于大多数8051内核单片机 Keil提供了一个包含所有特殊功能寄存器和它们的位的定义的头文件reg51 h 通过包含头文件可以很容易的进行新的扩展 附录C提供了STC15F2K60S2单片机的头文件stc15 h的内容 其中包含了标准8051单片机寄存器的定义 编程时只需包含这一个文件即可 该文件可以从中下载 34 88 2 at 关键字若要实现变量的绝对定位 称为绝对变量 可以直接在数据定义后加上 at 常数地址 即可 注意 1 绝对变量不能被初始化 2 bit型函数及变量不能用 at 指定 35 88 例如 unsignedcharidataADCdata at 0 x40 指定ADCdata变量在40H处unsignedcharxdatabuffer 20 at 0 x0010 指定buffer数组从XRAM的0010H单元开始 36 88 3 存储模式存储模式决定了没有明确指定存储类型的变量时 函数参数等的缺省存储区域 有Small Compact和Large三种模式 指定存储模式 图5 1指定存储模式 37 88 1 Small模式在该模式中所有变量都默认位于单片机内部数据存储器 这和使用data指定存储器类型的方式一样 此模式访问变量的效率很高 但所有的数据对象和堆栈必须适合内部RAM堆栈的大小 如果将变量都配置在内部数据存储器内 Small模式是最佳选择 该模式的优点是访问速度快 缺点是空间有限 只适用于小程序 38 88 2 Compact模式所有缺省变量均位于外部RAM区的一页内 256字节 这和使用pdata指定存储器类型一样 在STARTUP A51文件中说明 也可用pdata指定 该模式空间比Small宽裕 速度比Small慢 比Large快 是一种中间状态 39 88 3 Large模式所有缺省变量可放在多达64KB的外部RAM区 这和使用xdata指定存储器类型一样 使用数据指针DPTR进行寻址 通过数据指针访问外部数据存储器的效率较低 特别是当变量为2个字节或更多字节时 该模式的数据访问比Small和Compact产生更多的代码 优点是空间大 可存变量多 缺点是速度较慢 40 88 4 变量或数据类型 表5 1C51数据类型 41 88 C51提供以下几种扩展数据类型 bit 位变量值为0或1 sbit 从字节中定义的位变量 0或1 sfr sfr字节地址 0 x80 0 xff sfr16 sfr字地址 0 x80 0 xff 其实是占用两个连续的地址 其余数据类型如 char enum short int long float等与ANSIC相同 下面着重介绍位变量及其声明 42 88 1 bit型变量bit型变量可用于变量类型和函数声明 函数返回值等 存储于内部RAM的20H 2FH单元中 注意 1 使用禁止中断 pragmadisable 或包含明确的寄存器组切换 usingn 的函数不能返回位值 否则 编译器会识别出来并产生一个错误信息 2 位不能声明为一个指针 如bit bit poiter 是错误的 3 不能有bit数组如 bitarr 5 是错误的 43 88 2 可位寻址区说明使用sbit声明可独立访问可位寻址对象的位 sbit声明要求基址对象的存贮器类型为 bdata 否则只有绝对的位声明方法是合法的 位的位置 操作符号后的数字 的最大值依赖于指定的基类型对于char uchar而言是0 7 对于int uint short ushort而言是0 15 对于long ulong而言是0 31 44 88 下面举例说明位寻址的声明方法 例如 intbdatabittest at 0 x20 也可以省略 at 0 x20 sbitbit0 bittest 0 0 x20单元的第0位sbitbit15 bittest 15 0 x21单元的第7位注意 可位寻址对象的位的声明只能放到main函数的外部 作为全局变量使用 否则 编译会出错 45 88 二 扩展I O口的使用STC15F2K60S2单片机除了芯片上的I O口外 还可在片外扩展I O端口 由于使用C语言访问外部I O时用到指针的功能 因此 首先介绍KeilC51的指针 46 88 1 KeilC51指针KeilC51支持一般指针 GenericPointer 和存储器指针 MemorySpecificPointer 一般指针的声明和使用均与标准C相同 同时还可以说明指针的存储类型 47 88 例如 下面的语句都声明pt为指向保存在外部RAM中unsignedchar数据的指针 但pt本身的保存位置却不同 unsignedcharxdata pt pt本身依存储模式存放unsignedcharxdata datapt pt被保存在内部RAM中unsignedcharxdata xdatapt pt被保存在外部RAM中 48 88 一般指针本身用3个字节存放 分别为存储器类型 高位偏移量和低位偏移量 基于存储器的指针 说明时即指定了存储类型 例如 chardata str str指向data区中char型数据intxdata pow pow指向外部RAM的int型整数这种指针存放时 只需一个字节或2个字节就够了 因为只需存放偏移量 49 88 关于堆栈指针SP的设定一般情况下 用户不需要在C语言程序中修改堆栈指针SP 但要关心一下SP的位置 C51为变量分配好内部RAM后 将SP放在第一个空闲的内部RAM处 可以在编译后生成的 m51文件中观察到栈顶的位置 一般程序编译连接成功后要习惯性地看一下 m51文件 看一下是不是有足够的栈空间可用 另外 C51是在startup A51中设置SP指针的 用CODE选项生成的汇编代码中是找不到这段代码的 startup A51是C51的初始化代码 单片机复位后先执行这段代码 完成初始化后由它调用main 函数 特殊需要时 可以修改这段代码 然后连接到用户的程序中去 50 88 2 外部扩展I O口的访问在C51中有两种方法访问外部I O端口 方法1 使用自定义指针 由于片外I O端口与片外存储器统一编址 所以可以定义xdata类型的指针访问外部I O端口 51 88 例如 某单片机应用系统中 使用8255扩展I O端口 采用线选法对8255进行地址译码 单片机的P2 7 A15 接8255的片选引脚 8255的命令字地址为7FF3H PA口地址为7FF0H PB口地址为7FF1H PC口地址为7FF2H 访问8255的C程序如下 52 88 写端口程序 charxdata com8255 定义指向外部存储区的指针com8255 0 x7ff3 使指针指向8255的控制口地址7FF3H com8255 0 x81 输出81H到端口以上C程序相当于下面的汇编语言程序 MOVDPTR 7FF3HMOVA 81HMOVX DPTR A 53 88 读端口程序 charxdata com8255 定义指针com8255 0 x7ff0 使指针指向8255的PA口地址7FF0Hchari i com8255 读PA端口到变量i 54 88 方法2 使用C51预定义指针 为了方便地访问外部存储器及I O端口 在C51中的absacc h头文件做了如下定义 利用这些定义可以方便地访问外部I O端口 defineCBYTE unsignedcharvolatilecode 0 defineDBYTE unsignedcharvolatiledata 0 definePBYTE unsignedcharvolatilepdata 0 defineXBYTE unsignedcharvolatilexdata 0 55 88 例如 include definePORTAXBYTE 0 x7ff0 其中 PORTA为程序定义的I O端口名称 内的内容 7ff0H为PORTA的地址voidmain void chara PORTA 0 x81 输出81H到端口7ff0Ha PORTA 读端口7ff0H到变量a 56 88 三 KeilC51函数C51的函数声明对ANSIC作了扩展 具体包括 1 中断函数声明中断函数通过使用interrupt关键字和中断号 0 31 来声明 中断号告诉编译器中断服务程序的入口地址 57 88 STC15F2K60S2单片机的中断号及中断服务程序入口地址如表所示 表5 2中断号及中断服务程序入口地址 58 88 例如 串行口1的中断函数可以声明如下 voidUART1 ISR void interrupt4 using1 中断服务程序的代码 上述代码声明了串行口1中断服务函数 其中 interrupt4说明是串行口1的中断 using1指明采用工作寄存器区1区 using1在中括号中 说明该段可以省略 其他中断函数的定义与此类似 中断函数具体是哪个中断的函数 与中断号有关 而与函数名无关 59 88 2 指定工作寄存器区当需要指定函数中使用的工作寄存器区时 使用关键字using后跟一个0到3的数 对应着工作寄存器0到3区 例如 在下面的函数中使用了工作寄存器1区 相当于PSW 4 0 PSW 3 1 unsignedcharGetKey void using1 用户程序代码 60 88 3 指定存储模式用户可以使用small compact及large说明存储模式 例如 voidfun1 void small 提示 small说明的函数内部变量全部使用内部RAM 关键的 经常性的 耗时的地方可以这样声明 以提高运行速度 61 88 4 函数的参数传递规则最多只能有3个参数通过寄存器传递 规律如表5 3所示 表5 3函数的参数传递规则 62 88 5 函数返回值的规定函数返回值一律放于寄存器中 规则如表5 4所示 表5 4函数返回值的规定 63 88 6 函数的重入可以在函数前声明函数的可重入性 只对一个函数有效 如果声明为不可重入的 说明该函数调用过程中将不可被中断 递归或可重入函数指定在主程序和中断中都可调用的函数 容易产生问题 因为单片机和PC不同 PC使用堆栈传递参数 且静态变量以外的内部变量都在堆栈中 而单片机一般使用寄存器传递参数 内部变量一般在RAM中 函数重入时会破坏上次调用的数据 64 88 可以用以下两种方法解决函数的重入问题 第一种方法 在相应的函数前使用 pragmadisable 声明 即只允许主程序或中断之一调用该函数 第二种方法 将该函数说明为可重入的 如下 voidfunc param reentrant 65 88 KeilC51编译后将生成一个可重入变量堆栈 然后就可以模拟通过堆栈传递变量的方法 因为单片机内部堆栈空间的限制 C51没有像大系统那样使用调用堆栈 一般在C语言中调用过程时 会把过程的参数和过程中使用的局部变量入栈 66 88 为了提高效率 C51没有提供这种堆栈 而是提供一种压缩栈 每个过程被给定一个空间 用于存放局部变量 过程中的每个变量都存放在这个空间的固定位置 当递归调用这个过程时 会导致变量被覆盖 在某些实时应用中 非重入函数是不可取的 因为 函数调用时可能会被中断程序中断 而在中断程序中可能再次调用这个函数 所以C51允许将函数定义成重入函数 重入函数可被递归调用和多重调用 而不用担心变量被覆盖 因为每次函数调用时的局部变量都会被单独保存 因为这些堆栈是模拟的 重入函数一般都比较大 运行起来也比较慢 67 88 由于一般可重入函数由主程序和中断调用 所以通常中断程序使用与主程序不同的工作寄存器组 另外 对可重入函数 在相应的函数前面加上开关 pragmanoaregs 以禁止编译器使用绝对寄存器寻址 可生成不依赖于寄存器组的代码 68 88 四 STC15F2K60S2单片机C51程序框架 include stc15 h stc15 h为单片机寄存器定义头文件 具体内容参见附录C voiddelay longdelaytime 声明子函数 子函数可以有返回值voidmain void 此处可存放应用系统的初始化代码while 1 主程序循环 根据需要填入适当的内容delay 100 可以调用用户自定义的子函数 69 88 各个子函数的声明 voiddelay longdelaytime while delaytime 0 delaytime 子函数的实现代码 各个中断函数的实现 voidINT0 ISR void interrupt0 外部中断0服务子函数 根据需要填入程序代码 voidT0 ISR void interrupt1 定时器0中断服务子函数 根据需要填入程序代码 voidINT1 ISR void interrupt2 外部中断1服务子函数 根据需要填入程序代码 voidT1 ISR void interrupt3 定时器1中断服务子函数 根据需要填入程序代码 70 88 voidUART1 ISR void interrupt4 串口1中断服务子函数 根据需要填入程序代码 注意中断请求标志的清零 voidADC ISR void interrupt5 ADC中断服务子函数 根据需要填入程序代码 注意中断请求标志的清零 voidLVD ISR void interrupt6 低电压检测中断子函数 根据需要填入程序代码 注意中断请求标志的清零 voidPCA ISR void interrupt7 PCA中断子函数 根据需要填入程序代码 注意中断请求标志的清零 voidUART2 ISR void interrupt8 串口2中断子函数 根据需要填入程序代码 注意中断请求标志的清零 voidSPI ISR void interrupt9 SPI中断子函数 根据需要填入程序代码 注意中断请求标志的清零 71 88 voidINT2 ISR void interrupt10 外部中断2服务子函数 根据需要填入程序代码 voidINT3 ISR void interrupt11 外部中断3服务子函数 根据需要填入程序代码 voidT2 ISR void interrupt12 定时器2中断服务子函数 根据需要填入程序代码 voidINT4 ISR void interrupt16 外部中断4服务子函数 根据需要填入程序代码 72 88 例5 1 编程实现通过延时函数 P1 0输出方波信号 并通过示波器观察程序输出波形的周期 include stc15 h STC15F2K60S2单片机寄存器定义头文件sbitP10 P1 0 定义P1 0引脚voiddelay unsignedlongcnt 延时函数声明voidmain void P10 1 while 1 主程序循环 delay 60000 P10 P10 voiddelay unsignedlongcnt 延时函数 while cnt 0 cnt 73 88 可以使用集成开发环境 IDE 对单片机程序进行软件模拟调试 由于此时无需任何硬件与开发 可以降低程序开发的成本 并且程序开发可以在系统硬件完成之前开始 5 3单片机C语言程序调试 74 88 模拟仿真调试的方法和过程与汇编语言模拟仿真调试的过程相同 但是 软件模拟调试无法仿真精确的硬件信号 难以仿真过程控制中的通信网络时序及实时转换 因此当软件开发过程进入必须有最终硬件参与共同完成的阶段时 就需要进行在系统调试 传统的仿真方法是使用仿真器进行仿真和调试 下面介绍如何使用仿真器进行程序的仿真和调试 75 88 一 使用仿真器进行程序的仿真调试使用宏晶单片机仿真器适用于STC单片机应用技术的学习和实验程序的调试 使用过程如下 1 硬件设置目前的仿真方式为双CPU仿真 监控CPU和仿真CPU 仿真CPU目标芯片必须是宏晶的IAP系列 目前只支持IAP15F2K60S2 仿真完成后 可以直接将程序下载STC15F2K60S2单片机中 76 88 计算机 仿真器和学习板连接示意图如图所示 图5 2计算机 仿真器和学习板连接示意图 77 88 2 软件设置用户程序中需要在0 x73的地址处保留6个字节 C语言程序 需在代码中添加如下语句 charcodereserved 6 at 0 x73 在程序中进行声明汇编语言程序 需在代码中添加如下语句 CSEGAT73H 在代码段33H定址RESERVED DS6 保留6字节或者ORG73H 在代码段33H定址RESERVED DB0FFH 0FFH 0FFH 0FFH 0FFH 0FFH 保留6字节 78 88 对于汇编语言程序 复位入口的程序必须为跳转指令 建议使用长跳转 如 ORG0 复位入口地址LJMPRESET 使用LJMP指令 其它中断向量ORG73H 保留字节地址RESERVED DB0FFH 0FFH 0FFH 0FFH 0FFH 0FFH 保留6字节 ORG0100H 用户代码地址RESET 复位入口 用户代码 79 88 按照上述要求 将例5 1中的程序进行改写 改写后的程序如下 include stc15 h STC15F2K60S2单片机寄存器定义头文件charcodereserved 6 at 0 x73 在程序中进行声明sbitP10 P1 0 定义P1 0引脚voiddelay unsign

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论