crc计算 delphi

合集下载

Delphi与仪表之间的MODBUS通讯

Delphi与仪表之间的MODBUS通讯

Delphi与仪表之间的MODBUS通讯【摘要】在工控领域,经常会遇到各式各样的现场仪表,这些仪表分散在现场的各个位置,这样的话对管理人员和现场操作人员来说都非常不方便,那如何解决这个问题呢?此时就会用到一种方案,那就是配置上位机,用来集中控制这些仪表,这就是所谓的集散系统。

那么如何通过上位机与现场仪表通讯来获取仪表的数据,同时又能对仪表进行远程操作呢?这也就是今天要论述的课题。

在进行通信程序编写之前,我们首先得对现场仪表有一定的了解,最起码地是应该知道现场仪表支持什么通讯协议,需要设置哪些参数,然后才能展开下一步的工作。

【关键词】Delphi;ModBus;集散系统;多线程一、MODBUS通讯协议MODBUS是由莫迪康(现为施耐德公司的一个品牌)在1979年发明的,是全球第一个真正用于工业现场的总线协议。

MODBUS协议是应用于电子控制器上的一种通用语言,通过它,控制器之间或其他设备之间可以通信,它已经成为一通用工业标准。

有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。

它定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。

它描述了一控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。

它制定了消息域格局和内容的公共格式。

当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。

如果需要回应,控制器将生成反馈信息并用Modbus协议发出。

在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。

这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。

二、VSD-6仪表简介VSD-6仪表是某厂家自己制作的一款仪表,它具有一个标准的MODBUS端口(二线制的RS485接囗),在一条RS485总线上可接入接出1至16台VSD-6控制仪表,可方便地同各种组态软件(如:组态王、WINCC、昆仑通态)直接连接通讯,也可以按照标准MODBUS(RTU)通讯协议自编程。

delphi 获取MAC地址

delphi 获取MAC地址
If (Res = TIME_ZONE_ID_STANDARD) Then Begin
DT := DT-((TZ.Bias+TZ.StandardBias) / (24*60));
Result := DateTimeToStr(DT)+' '+WideCharToString(TZ.StandardName);
mymaclength:=length(mymac);
r:=sendarp(myip,0,@mymac,@mymaclength);
label1.caption:='errorcode:'+inttostr(r);
label2.caption:=format('%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x',[mymac[0],mymac[1],mymac[2],mymac[3],mymac[4],mymac[5]]);
Var
AI,Work : PIPAdapterInfo;
Size : Integer;
Res : Integer;
I : Integer;
Function MACToStr(ByteArr : PByte; Len : Integer) : String;
Begin
Result := '';
End;
Function GetAddrString(Addr : PIPAddrString) : String;
Begin
Result := '';
While (Addr <> nil) do Begin

DELPHI获取硬盘、CPU、网卡序列号

DELPHI获取硬盘、CPU、网卡序列号

DELPHI获取硬盘、CPU、⽹卡序列号 //引⽤及TYPE变量申明usesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls,nb30; {重要引⽤}typePASTAT = ^TASTAT;TASTAT = recordadapter : TAdapterStatus;name_buf : TNameBuffer;end;TForm1 = class(TForm)Button1: TButton;Edit1: TEdit;Label1: TLabel;Label2: TLabel;Label3: TLabel;Edit2: TEdit;Edit3: TEdit;Button2: TButton;Edit4: TEdit;Label4: TLabel;procedure Button1Click(Sender: TObject);procedure Button2Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;implementation{$R *.dfm}typeTCPUID = array[1..4] of Longint;//取硬盘系列号:function GetIdeSerialNumber: pchar; //获取硬盘的出⼚系列号;const IDENTIFY_BUFFER_SIZE = 512;typeTIDERegs = packed recordbFeaturesReg: BYTE;bSectorCountReg: BYTE;bSectorNumberReg: BYTE;bCylLowReg: BYTE;bCylHighReg: BYTE;bDriveHeadReg: BYTE;bCommandReg: BYTE;bReserved: BYTE;end;TSendCmdInParams = packed recordcBufferSize: DWORD;irDriveRegs: TIDERegs;bDriveNumber: BYTE;bReserved: array[0..2] of Byte;dwReserved: array[0..3] of DWORD;bBuffer: array[0..0] of Byte;end;TIdSector = packed recordwGenConfig: Word;wNumCyls: Word;wReserved: Word;wNumHeads: Word;wBytesPerTrack: Word;wBytesPerSector: Word;wSectorsPerTrack: Word;wVendorUnique: array[0..2] of Word;sSerialNumber: array[0..19] of CHAR;wBufferType: Word;wBufferSize: Word;wECCSize: Word;sFirmwareRev: array[0..7] of Char;sModelNumber: array[0..39] of Char;wMoreVendorUnique: Word;wDoubleWordIO: Word;wCapabilities: Word;wReserved1: Word;wPIOTiming: Word;wDMATiming: Word;wBS: Word;wNumCurrentCyls: Word;wNumCurrentHeads: Word;wNumCurrentSectorsPerTrack: Word;ulCurrentSectorCapacity: DWORD;wMultSectorStuff: Word;ulTotalAddressableSectors: DWORD;wSingleWordDMA: Word;wMultiWordDMA: Word;bReserved: array[0..127] of BYTE;end;PIdSector = ^TIdSector;TDriverStatus = packed recordbDriverError: Byte;bIDEStatus: Byte;bReserved: array[0..1] of Byte;dwReserved: array[0..1] of DWORD;end;TSendCmdOutParams = packed recordcBufferSize: DWORD;DriverStatus: TDriverStatus;bBuffer: array[0..0] of BYTE;end;varhDevice: Thandle;cbBytesReturned: DWORD;SCIP: TSendCmdInParams;aIdOutCmd: array[0..(SizeOf(TSendCmdOutParams) + IDENTIFY_BUFFER_SIZE-1)-1] of Byte; IdOutCmd: TSendCmdOutParams absolute aIdOutCmd;procedure ChangeByteOrder(var Data; Size: Integer);//函数中的过程varptr: Pchar;i: Integer;c: Char;beginptr := @Data;for I := 0 to (Size shr 1) - 1 do beginc := ptr^;ptr^ := (ptr + 1)^;(ptr + 1)^ := c;Inc(ptr, 2);end;end;begin //函数主体Result := '';if SysUtils.Win32Platform = VER_PLATFORM_WIN32_NT thenbegin // Windows NT, Windows 2000hDevice := CreateFile('\\.\PhysicalDrive0', GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);endelse // Version Windows 95 OSR2, Windows 98hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0);if hDevice = INVALID_HANDLE_VALUE then Exit;tryFillChar(SCIP, SizeOf(TSendCmdInParams) - 1, #0);FillChar(aIdOutCmd, SizeOf(aIdOutCmd), #0);cbBytesReturned := 0;with SCIP dobegincBufferSize := IDENTIFY_BUFFER_SIZE;with irDriveRegs dobeginbSectorCountReg := 1;bSectorNumberReg := 1;bDriveHeadReg := $A0;bCommandReg := $EC;end;end;if not DeviceIoControl(hDevice, $0007C088, @SCIP, SizeOf(TSendCmdInParams) - 1,@aIdOutCmd, SizeOf(aIdOutCmd), cbBytesReturned, nil) then Exit;finallyCloseHandle(hDevice);end;with PIdSector(@IdOutCmd.bBuffer)^ dobeginChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber));(Pchar(@sSerialNumber) + SizeOf(sSerialNumber))^:= #0;Result := Pchar(@sSerialNumber);end;end;//=================================================================//CPU系列号:FUNCTION GetCPUID : TCPUID; assembler; register;asmPUSH EBX {Save affected register}PUSH EDIMOV EDI,EAX {@Resukt}MOV EAX,1DW $A20F {CPUID Command}STOSD {CPUID[1]}MOV EAX,EBXSTOSD {CPUID[2]}MOV EAX,ECXSTOSD {CPUID[3]}MOV EAX,EDXSTOSD {CPUID[4]}POP EDI {Restore registers}POP EBXEND;function GetCPUIDStr:String;varCPUID:TCPUID;beginCPUID:=GetCPUID;Result:=IntToHex(CPUID[1],8)+IntToHex(CPUID[2],8)+IntToHex(CPUID[3],8)+IntToHex(CPUID[4],8); end;///================================================================================== ///取MAC(⾮集成⽹卡):function NBGetAdapterAddress(a: Integer): string;varNCB: TNCB; // Netbios control block //NetBios控制块ADAPTER: TADAPTERSTATUS; // Netbios adapter status//取⽹卡状态LANAENUM: TLANAENUM; // Netbios lanaintIdx: Integer; // Temporary work value//临时变量cRC: Char; // Netbios return code//NetBios返回值strTemp: string; // Temporary string//临时变量begin// InitializeResult := '';try// Zero control bloclZeroMemory(@NCB, SizeOf(NCB));// Issue enum commandNCB.ncb_command := Chr(NCBENUM);cRC := NetBios(@NCB);// Reissue enum commandNCB.ncb_buffer := @LANAENUM;NCB.ncb_length := SizeOf(LANAENUM);cRC := NetBios(@NCB);if Ord(cRC) <> 0 thenexit;// Reset adapterZeroMemory(@NCB, SizeOf(NCB));NCB.ncb_command := Chr(NCBRESET);NCB.ncb_lana_num := na[a];cRC := NetBios(@NCB);if Ord(cRC) <> 0 thenexit;// Get adapter addressZeroMemory(@NCB, SizeOf(NCB));NCB.ncb_command := Chr(NCBASTAT);NCB.ncb_lana_num := na[a];StrPCopy(NCB.ncb_callname, '*');NCB.ncb_buffer := @ADAPTER;NCB.ncb_length := SizeOf(ADAPTER);cRC := NetBios(@NCB);// Convert it to stringstrTemp := '';for intIdx := 0 to 5 dostrTemp := strTemp + InttoHex(Integer(ADAPTER.adapter_address[intIdx]), 2);Result := strTemp;finallyend;end;//========================================================================== //取MAC地址(集成⽹卡和⾮集成⽹卡):function Getmac:string;varncb : TNCB;s:string;adapt : TASTAT;lanaEnum : TLanaEnum;i, j, m : integer;strPart, strMac : string;beginFillChar(ncb, SizeOf(TNCB), 0);ncb.ncb_command := Char(NCBEnum);ncb.ncb_buffer := PChar(@lanaEnum);ncb.ncb_length := SizeOf(TLanaEnum);s:=Netbios(@ncb);for i := 0 to integer(lanaEnum.length)-1 dobeginFillChar(ncb, SizeOf(TNCB), 0);ncb.ncb_command := Char(NCBReset);ncb.ncb_lana_num := na[i];Netbios(@ncb);Netbios(@ncb);FillChar(ncb, SizeOf(TNCB), 0);ncb.ncb_command := Chr(NCBAstat);ncb.ncb_lana_num := na[i];ncb.ncb_callname := '* ';ncb.ncb_buffer := PChar(@adapt);ncb.ncb_length := SizeOf(TASTAT);m:=0;if (Win32Platform = VER_PLATFORM_WIN32_NT) thenm:=1;if m=1 thenbeginif Netbios(@ncb) = Chr(0) thenstrMac := '';for j := 0 to 5 dobeginstrPart := IntToHex(integer(adapt.adapter.adapter_address[j]), 2);strMac := strMac + strPart + '-';end;SetLength(strMac, Length(strMac)-1);end;if m=0 thenif Netbios(@ncb) <> Chr(0) thenbeginstrMac := '';for j := 0 to 5 dobeginstrPart := IntToHex(integer(adapt.adapter.adapter_address[j]), 2);strMac := strMac + strPart + '-';end;SetLength(strMac, Length(strMac)-1);end;end;result:=strmac;end;function PartitionString(StrV,PrtSymbol: string): TStringList;variTemp: integer;beginresult := TStringList.Create;iTemp := pos(PrtSymbol,StrV);while iTemp>0 do beginif iTemp>1 then result.Append(copy(StrV,1,iTemp-1));delete(StrV,1,iTemp+length(PrtSymbol)-1);iTemp := pos(PrtSymbol,StrV);end;if Strv<>'' then result.Append(StrV);end;function MacStr():String;varStr:TStrings;i:Integer;MacStr:String;beginMacStr:='';Str:=TStringList.Create;Str:=PartitionString(Getmac,'-');for i:=0 to Str.Count-1 doMacStr:=MacStr+Str[i];Result:=MacStr;end;//============================================== //调⽤⽰例procedure TForm1.Button1Click(Sender: TObject);beginEdit3.Text:=strpas(GetIdeSerialNumber);//取硬盘号Edit2.text:=GetCPUIDStr;//CPU系列号edit4.Text:=NBGetAdapterAddress(12);//⾮集成⽹卡Edit1.text:=MacStr;//集成和⾮集成⽹卡end;。

Delphi运算符

Delphi运算符

delphi、c++与vb中的运算符2008-11-21 15:10Delphi_C++_VB 基本运算符号2007-02-25 11:55运算符赋值运算符Pascal :=C/C++ =BASIC =比较运算符运算符等于不等于小于(等于) 大于(等于)Pascal = <> <(=) >(=)C/C++ == != <(=) >(=)BASIC =或者Is <> <(=) >(=)逻辑运算符运算符逻辑与逻辑或逻辑非Pascal and or notC/C++ && || !BASIC And Or Not算术运算符运算符加减乘除(浮点数)除(整数)取模指数Pascal + - * / div mod 无C/C++ + - * / / % 无BASIC + - * / / Mod ^运算符与取反或异或左移右移Pascal and not or xor shl shrC/C++ & ~ | ^ << >>BASIC And Not Or Xor 无无Delphi运算符(2)2007-12-01 12:072.1.4 算术运算符算术运算符是执行算术运算如加、减、乘、除等的符号。

和其他大多数语言不同,在Pascal 中,进行乘、除时,整数和浮点数使用的符号不同。

例如:I := J div C;整数J和C作除法运算,并将结果赋值给I。

几种语言的算术运算符比较见表2-4。

表2-4 算术运算符2.1.5 按位运算符我们知道,变量在内存中是使用一些位(Bit)存储0或者1来保存的。

按位运算符就是对位进行运算的符号。

例如:varI: Byte; {Byte类型的取值范围在0~255,用8比特保存}beginI := 0; {此时I在内存中状态:00000000}I := not I; {对各位取反,因此变为"11111111",即255}end;几种语言的按位运算符比较见表2-5。

各种位运算经验(源码用delphi示例)

各种位运算经验(源码用delphi示例)

二进制中的1有奇数个还是偶数个我们可以用下面的代码来计算一个32位整数的二进制中1的个数的奇偶性,当输入数据的二进制表示里有偶数个数字1时程序输出0,有奇数个则输出1。

例如,1314520的二进制101000000111011011000中有9个1,则x=1314520时程序输出1。

vari,x,c:longint;beginreadln(x);c:=0;for i:=1 to 32 dobeginc:=c + x and 1;x:=x shr 1;end;writeln( c and 1 );end.但这样的效率并不高,位运算的神奇之处还没有体现出来。

同样是判断二进制中1的个数的奇偶性,下面这段代码就强了。

你能看出这个代码的原理吗?varx:longint;beginreadln(x);x:=x xor (x shr 1);x:=x xor (x shr 2);x:=x xor (x shr 4);x:=x xor (x shr 8);x:=x xor (x shr 16);writeln(x and 1);end.为了说明上面这段代码的原理,我们还是拿1314520出来说事。

1314520的二进制为101000000111011011000,第一次异或操作的结果如下:00000000000101000000111011011000XOR 0000000000010100000011101101100---------------------------------------00000000000111100000100110110100得到的结果是一个新的二进制数,其中右起第i位上的数表示原数中第i和i+1位上有奇数个1还是偶数个1。

比如,最右边那个0表示原数末两位有偶数个1,右起第3位上的1就表示原数的这个位置和前一个位置中有奇数个1。

对这个数进行第二次异或的结果如下:00000000000111100000100110110100XOR 000000000001111000001001101101---------------------------------------00000000000110011000101111011001结果里的每个1表示原数的该位置及其前面三个位置中共有奇数个1,每个0就表示原数对应的四个位置上共偶数个1。

Delphi下用SPCOMM对Modbus编程

Delphi下用SPCOMM对Modbus编程

Delphi下用SPCOMM对Modbus编程一、流程主体流程与普通的串口编程一样。

二、ModbusModbus普通串口不致的地方就是发送与返回的数据除遵循串口本身要求外,还有格式要求。

这里以读多位bit为例,其它的读者可查询Modbu功能码文档。

01功能码,读取多个线圈(位,bit),命令为16进制发送命令:01 01 48 00 00 10 2A 66返回命令: 01 01 02 FF 03 B8 0D三、例程例:串口SPCOMM控件名为:SPCOMM1;发送时钟名为:TimerCom;(1)控件属性设置mName := 'COM1'; //串中号表示 COM1、COM2等串口的名字SPCOMM1.BaudRate := 9600; //波特率根据实际需要设定的波特率,在串口打开后也可更改此值,实际波特率随之更改SPCOMM1.ParityCheck := False;//表示是否需要奇偶校验;SPCOMM1.Parity := None; //没有奇偶校验位; 奇偶校验位;SPCOMM1.ReadIntervalTimeOut:= 40; //信息发送后,40毫秒内返回的数据都算作一次返回。

注意要比发送间隔小。

TimerCom.Interval := 50 //时钟刷新间隔 TimerCom.Interval >SPCOMM1.ReadIntervalTimeOut(2)打开串口SPCOMM1.StopComm; //先关闭串口SPCOMM1.StartComm; //打开串口(3)形成发送命令CRCParityCheck16为对发送命令进行CRC校验,这里就不写了。

varbufByte:array[0..50000] of Byte;bufComReadChar :array[0..50000] of chari,nComReadLength:Integer;nCRC:Word;strSend:string;FnCRCFunt,FnCRCStart:Cardinal;//校验多项式,校验初始值 ]begin//先将数据形成16进制字符组成的字符串,然后再来校验发送strSend := '';strSend := IntToHex(1,2); //第1字节机组号strSend := strSend + '01'; //modbus 功能码01 读多个位操作strSend := strSend + IntToHex(StrToInt('$4800',4); //起始地址3、4字节strSend := strSend + IntToHex(16,4); //位总数, 5、6字节for i := 0 to 5 dobeginbufByte[i] := StrToInt('$' + copy(strSend,i*2+1,2));end;nCRC:=CRCParityCheck16(FnCRCStart ,FnCRCFunt,bufByte,6);strSend := strSend + IntToHex(nCRC,4);for i:=0 to 7 dobufComReadChar:=char(strtoint('$'+copy(strSend,i*2+1,2)));nComReadLength := 8;SPCOMM1.WriteCommData(bufComReadChar,nComReadLe ngth); //发送命令,参数:命令,命令长度end;(4)接受返回命令并解析SPCOMM1ReceiveData(Sender: TObject;Buffer: Pointer; BufferLength: Word);vari:integer;rbuf:array [1..1000] of byte ;begin//接收到数据,进行解析move(Buffer^,(pchar(@rbuf))^,BufferLength);for i := 1 to BufferLength dobeginstrTemp := strTemp + IntToHex(rbuf[i],2) + ' ';end;end;。

delphi 位运算简介及实用技巧

delphi 位运算简介及实用技巧

位运算简介及实用技巧去年年底写的关于位运算的日志是这个Blog里少数大受欢迎的文章之一,很多人都希望我能不断完善那篇文章。

后来我看到了不少其它的资料,学习到了更多关于位运算的知识,有了重新整理位运算技巧的想法。

从今天起我就开始写这一系列位运算讲解文章,与其说是原来那篇文章的follow-up,不如说是一个remake。

当然首先我还是从最基础的东西说起。

什么是位运算?程序中的所有数在计算机内存中都是以二进制的形式储存的。

位运算说穿了,就是直接对整数在内存中的二进制位进行操作。

比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算。

举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理):110AND 1011----------0010 --> 2由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。

当然有人会说,这个快了有什么用,计算6 and 11没有什么实际意义啊。

这一系列的文章就将告诉你,位运算到底可以干什么,有些什么经典应用,以及如何用位运算优化你的程序。

Pascal和C中的位运算符号,下面的a和b都是整数类型,则:C语言 Pascal语言按位与 a & b a and b按位或 a | b a or b异或 a ^ b a xor ba取反 ~a not左移位 a << b a shl b右移位 a >> b a shr b注意C中的逻辑运算和位运算符号是不同的。

520|1314=1834,但520||1314=1,因为逻辑运算时520和1314都相当于True。

同样的,!a和~a也是有区别的。

各种位运算的使用:=== 1. and运算 ===and运算通常用于二进制取位操作,例如一个数 and 1的结果就是取二进制的最末位。

DELPHIXE11.1的几个数学取整

DELPHIXE11.1的几个数学取整

DELPHIXE11.1的几个数学取整Delphi下的四舍五入和取整,除了截取整数Trunc()之外,都是四舍六入五留双,即银行家算法。

但是好像又不全是这么回事儿。

要以实测为准。

例如3.15和3.25,修约时应分别得到3.2和3.2,而不是3.2和3.3。

这个算法在大学物理实验里也是这样。

但是也偶有争议,说是不同的Delphi版本编译器怎样怎样。

我比较了Delphi7和Delphi XE11.1,结果是一样的。

Round()在四舍六入,而SimpleRoundTo()仍然在四舍五入。

unit Unit1;interfaceusesWinapi.Windows, Winapi.Messages, System.SysUtils, System .Variants, System.Classes, Vcl.Graphics,Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;typeTForm1 = class(TForm)Button1: TButton;procedure Button1Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;implementationuses math;{$R *.dfm}function RoundClassic(R: Real): Int64;beginResult:= Trunc(R);if Frac(R) >= 0.5 thenResult:= Result + 1;end;function RoundThief(R: Real): Int64;beginR:=R+0.0000000000001;Result:= Trunc(R);if Frac(R) >= 0.5 thenResult:= Result + 1;end;procedure TForm1.Button1Click(Sender: TObject); vara: integer;b: real;begina := Trunc(0.35 * 10);showmessage('3.5取整数部分' + inttostr(a));a := round(2.5);showmessage('Round(2.5)四舍六入五留双,得到2而不是3:' + inttostr(a));b := simpleroundto(2.5, 0);showmessage('2.5取整,SimpleRounTo又开始传统四舍五入3:' + floattostr(b));b := simpleroundto(2.55, -1);showmessage('2.55留1位小数,SimpleRounT o又开始传统四舍五入2.6:' + floattostr(b));b := simpleroundto(2.45, -1);showmessage('2.45留1位小数,SimpleRounT o又开始传统四舍五入2.5:' + floattostr(b));a := ceil(123.4);showmessage('123.4向上取整:' + inttostr(a));a := ceil(-123.4);showmessage('-123.4向上取整:' + inttostr(a));a := floor(123.4);showmessage('123.4向下取整:' + inttostr(a));a := floor(-123.4);showmessage('-123.4向下取整:' + inttostr(a));a := RoundClassic(124.5);showmessage('124.5经典四舍五入:' + inttostr(a));a := RoundThief(124.5);showmessage('124.5取巧四舍五入:' + inttostr(a));//showmessage('33.025四舍五入:' + floattostr(RoundTo(33.025,-2)));end;end.。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档