




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、實(shí)用文案實(shí)用文案標(biāo)準(zhǔn)文檔標(biāo)準(zhǔn)文檔最近在做一個(gè)數(shù)據(jù)采集項(xiàng)目,涉及到許多與西門子S7系列PLC的通信,由于自己的 VC水平屬于半瓶子晃蕩,所以就想利用 C#來進(jìn)行開發(fā)(個(gè)人比較喜歡 C#的代碼風(fēng)格,看著很清爽),雖然 C#這種高 級(jí)語言與底層的設(shè)備通訊效率確實(shí)不如 C+ ,但好在數(shù)據(jù)量不大,實(shí)時(shí)性要求不算太高,用 C#還是可以 應(yīng)付的。在界面開發(fā)方面,高級(jí)語言確實(shí)不如WinCC , Intouch之類的組態(tài)軟件,但在數(shù)據(jù)處理上面,卻有很大的靈活性。在這里很感謝吳向陽,在中國(guó)工控網(wǎng)上面發(fā)現(xiàn)了他的文章,因?yàn)槲沂菑?C#轉(zhuǎn)到工控方向的,以前對(duì) PLC一點(diǎn)都不懂,剛接觸這一行時(shí),學(xué)習(xí)起來很吃力,看了他的這
2、篇文章,讓我對(duì)PLC的有了更加深入的了解。我的這個(gè)DCProdave.cs 就是在他的基礎(chǔ)上修改的,加了一些自己的東西。還望各位多多提意見,多多交 流!Prodave 版本:PRODAVE6.0 - W95_S7.DLLPLC 模擬環(huán)境:PLCSIM V5.4開發(fā)環(huán)境:VS.NET 2005.從w95_s7.dll中導(dǎo)入PLC通訊函數(shù)的方法DllImport在使用 DllImport 之前,必須弓I入 InteropServices, 代碼如下:using System.Runtime.InteropServices;具體使用方法可以參考我的博客中轉(zhuǎn)載的一篇文章C#(.net)中的DllImp
3、ort用法轉(zhuǎn)寫的很不錯(cuò),千萬要注意C+數(shù)據(jù)類型到C#的對(duì)應(yīng)關(guān)系,選用合適的類型。比如 char*可以用string來轉(zhuǎn)換,指針類型 可以ref或者數(shù)組。.定義結(jié)構(gòu)體類型2.1 PLC連接參數(shù)結(jié)構(gòu)體/定義結(jié)構(gòu)體連接PLC所需參數(shù)public struct PLCConnParampublic byte Addres;/ 定義 CPU 的 MPI/DP 地址/publicbyte SegmentId;/ 保留為0publicbyte Rack;定義 CPU的機(jī)架號(hào)publicbyte Slot;定義 CPU的槽號(hào).2 PLC存儲(chǔ)區(qū)域類別編號(hào)/定義枚舉類型PLC的存儲(chǔ)區(qū)域編號(hào)public enum
4、PLCBlockType3三I = 1, /Input bytesQ =2, /Output bytesM =3, /Flag bytesT =4, /Timer wordsZ =5, /Counter wordsD =6, /Data from DB三.常用函數(shù)詳細(xì)講解3.1建立PLC連接函數(shù)首先從W95_S7.DLL中導(dǎo)入連接函數(shù),訪問權(quán)限為私有,C#將會(huì)對(duì)此函數(shù)進(jìn)行封裝,供外部調(diào)用,稍后講解./summary 與PLC建立連接,該函數(shù)必須在其他所有函數(shù)調(diào)用之前被調(diào)用/ /summary/ 連接數(shù),在DOS,WIN3.1 最多可以有 4個(gè)在 WIN95 以上最多可以有 16個(gè)/ 與 PLC
5、 通訊的設(shè)備名稱,一般為 S7ONLINE / 參數(shù)列表,4個(gè)值分別為 MPI/DP 地址保留值=0,槽號(hào) 機(jī)架號(hào)/ 0正常返回,非0為錯(cuò)誤號(hào)DllImport( w95_s7.dll)private extern static int load_tool( byte nr, string device, byte , adr_table);說明:在一個(gè)MPI/DP網(wǎng)絡(luò)中若有多個(gè)PLC時(shí),可指定多個(gè)連接列。最后一列的所有參數(shù)須置0,以標(biāo)志參數(shù)列結(jié)束。例如一個(gè)MPI/DP網(wǎng)中有兩個(gè)PLC,他們的MPI地址分別為2和3,槽號(hào)均為2,機(jī)架號(hào)均為0, 則可按如下方式調(diào)用:byte, ba=2,0,2,
6、0,3,0,2,0,0,0,0,0; int err=load_tool(1, s7online,ba); 返 回值為int型,如果返回0則表示執(zhí)行成功,非零值,則需要根據(jù)錯(cuò)誤號(hào)查找到錯(cuò)誤具體信息,具體參照本文第五部分:錯(cuò)誤代碼字典當(dāng)然如果PLC使用的是DP網(wǎng)絡(luò)時(shí),只需要將Set PG/PC Interface中接口參數(shù)分配選為PLCSIM(PROFIBUS)即可,Prodave不需要做任何修改(當(dāng)然PLC地址肯定也是 DP 口的地址哦),具體如下 圖:個(gè)人不太習(xí)慣西門子的這種函數(shù)命名,索性就按照C#的常用習(xí)慣,進(jìn)行一下簡(jiǎn)單的封裝,供外部調(diào)用/ 建立連接,同一個(gè)連接只容許調(diào)用一次/ / 連接號(hào)
7、 connNo 為 1-4/ 連接參數(shù),PLCConnParam 定義的參數(shù)結(jié)構(gòu)體 / 返回10進(jìn)制錯(cuò)誤號(hào),0表示沒有錯(cuò)誤 public static int Open( byte connNo, PLCConnParam口 connParam)7三int PLCCPUCnt = connParam.Length;if (PLCCPUCnt =0) /傳遞參數(shù)不正確10中11 return -1;12卜byte , btr = new byte PLCCPUCnt + 1, 4; 多分配1個(gè)用于存放0作為連接結(jié)束標(biāo)記/轉(zhuǎn)換連接表for (int i = 0; i connParam.Lengt
8、h; i+)16中btri,0= connParami.Addres; TOC o 1-5 h z btri,1= 0;btri,2= connParami.Slot;btri,3= connParami.Rack;btrconnParam.Length,0=0;btrconnParam.Length,1=0;btrconnParam.Length,2=0;btrconnParam.Length,3=0;/調(diào)用初始化函數(shù),打開連接int errCode = load_tool(connNo,S7ONLINE , btr);return errCode;L 29 建立于PLC的連接,只需在數(shù)采程
9、序啟動(dòng)的時(shí)候調(diào)用即可,并且只能打開一次,否則報(bào)錯(cuò).驅(qū)動(dòng)設(shè)備名稱S7ONLINE, 一般情況下是不會(huì)有變化的,所以這里就寫死了 .特別需要指出的是,這個(gè)函數(shù)的第一個(gè)參數(shù)(連 接號(hào)),是指當(dāng)前連接有多少個(gè)PLC連接(嚴(yán)格意義上來講,是CPU的個(gè)數(shù),因?yàn)橛锌赡?個(gè)PLC共用1個(gè)CPU,之間通過IM467組態(tài)),激活連接并交換數(shù)據(jù)的時(shí)候,和這個(gè)值有點(diǎn)關(guān)系.在建立連接的時(shí)候默認(rèn)激活第1個(gè)連接.2斷開與PLC的連接從W95_S7.DLL中導(dǎo)入函數(shù),依然是私有,因?yàn)槲乙獙?duì)所有的導(dǎo)入函數(shù)進(jìn)行封裝./ 斷開與PLC的連接,必須退出數(shù)采軟件之前調(diào)用,否則PLC的連接一直被占用,影響下次連接/ / 0正常返回,非0
10、為錯(cuò)誤號(hào)DllImport( w95_s7.dll)private extern static int unload_tool();關(guān)閉PLC的連接函數(shù)進(jìn)行 C#封裝,沒有改變?nèi)魏未a,只是換了個(gè)函數(shù)名.public static int Close()%return unload_tool();3.3激活連接,當(dāng)前連接列中某個(gè)時(shí)刻有且只有1個(gè)PLC是激活狀態(tài).建立連接的時(shí)候,默認(rèn)激活第1個(gè)連接./summary 激活與MPI網(wǎng)中的哪個(gè) CPU通訊,load_tool后默認(rèn)激活第一個(gè) CPU連接/summary/param name=no 連接號(hào),對(duì)應(yīng)于參數(shù) adr_table 所傳遞的連接參
11、數(shù)順序 /returns0正常返回,非0為錯(cuò)誤號(hào),若激活的連接在 MPI網(wǎng)中沒有,則返回錯(cuò)誤號(hào)517/returnsDllImport( w95_s7.dll)private extern static int new_ss( byte no);其參數(shù)與load_tool中參數(shù)adr_table所傳遞的連接參數(shù)順序?qū)?yīng)譬如byte, btr=2,0,2,0,3,020,0,0,0,0 , new_ss(1) 則激活第1個(gè)連接即與 MPI地址為2的PLC通訊,類似的new_ss(2)則激活與MPI地址為3的PLC通訊在數(shù)采系統(tǒng)中,為了讀取所有PLC的數(shù)據(jù),采用定時(shí)循環(huán)激活每個(gè)PLC的連接,然后讀
12、取其數(shù)據(jù).C#封裝如下:1 public static int ActiveConn( int connNO)2日return new_ss( byte )connNO);3.4從DB塊中讀取字節(jié)數(shù)據(jù)(返回BYTE數(shù)組)1日/ 從DB中讀取BYTE數(shù)組(字節(jié)數(shù)可以是任意長(zhǎng)度的)/ / DB 塊號(hào) / DBB 起始編號(hào),0 表示 DBB0,1 表示 DBB1,跨度為 BYTE/ 讀取的BYTE長(zhǎng)度(任意長(zhǎng)度,可以為奇數(shù))/ 返回值,BYTE 型 buffer / 0正常返回,非0為錯(cuò)誤號(hào)DllImport( w95_s7.dll)private extern static int d_field
13、_read( int blockno, int no, int amount, byte buffer);C#封裝如下:/ 讀取 DB 塊的 BYTE 數(shù)據(jù)/ / DB 塊號(hào),如:DB2 / DB數(shù)據(jù)的起始字節(jié),如DBB2則從2開始讀/ 要讀取的字節(jié)數(shù),如從 DBB2-DBB5,共 4 個(gè)字節(jié) / BYTE 型緩存區(qū),存儲(chǔ)讀取的數(shù)據(jù) / 數(shù)據(jù)緩存區(qū)的起始位置 / 返回值0:成功非0:錯(cuò)誤代碼public static int GetDBByteData( int DBBlockNO, int DBBNO, int DBByteAmount, byte buffe r, int StartInd
14、ex)10日byte bBufTemp = new byte DBByteAmount;int errCode=d_field_read(DBBlockNO, DBBNO, DBByteAmount, bBufTemp);for (int i= 0;iDBByteAmount;i+)14中15 bufferi+StartIndex = bBufTempi;16卜return errCode;這個(gè)函數(shù)是用的最多的一個(gè)函數(shù),在數(shù)采系統(tǒng)中,習(xí)慣一次性的將所有需要用到數(shù)據(jù),全部讀到字節(jié)數(shù)組 中,統(tǒng)一處理,避免不同時(shí)期凌亂讀取造成的數(shù)據(jù)不一致.需要提醒的是,必須保證數(shù)據(jù)處理函數(shù)得到的數(shù)據(jù)是PLC 一次掃
15、描周期內(nèi)的5從DB中讀取整數(shù)值(int32型)1日/ 從DB中讀取INT數(shù)據(jù)(DBW:INT16 或者DBD:INT32),最多4個(gè)字節(jié)的整數(shù)/ /DB 塊號(hào) /DBW 起始編號(hào),0 表示 DBW0,1 表示DBW2,跨度為WORD/讀取的 WORD 長(zhǎng)度(1 個(gè) WORD=2個(gè)BYTE) 2:DBW ,4:DBD/返回值,int 型整數(shù)(十進(jìn)制)/ 0正常返回,非0為錯(cuò)誤號(hào)DllImport( w95_s7.dll)private extern static int db_read( int dbno, int dwno, ref int anzahl, ref int buffer); C
16、#封裝/ 從DB塊中讀取整型數(shù)據(jù)/要讀取 DB2.DBW6,則DB塊號(hào)為2,DBB號(hào)為6,字節(jié)長(zhǎng)度為 2/要讀取DB2.DBD6,則DB塊號(hào)為2,DBB號(hào)為6,字節(jié)長(zhǎng)度為 4/ / DB 塊號(hào),如:DB2 / DBB的起始字節(jié)號(hào),如DBW2則從2開始讀,由于是 WORD(2 個(gè)BYT E),DBB號(hào)必須為偶數(shù)/ vparam name=DBByteAmount”要讀取的BYTE數(shù),必須是偶數(shù)(這里只能是 2和4,在PLC中只有DBW,DBD兩種整數(shù))/ vparam name=buffer INT32型緩存區(qū),存儲(chǔ)讀取的十進(jìn)制數(shù)據(jù) L_一 /returns返回值0:成功非0:錯(cuò)妖代碼/retu
17、rnspublic static int GetDBInt32Data( int DBBlockNO, int DBBNO, int DBByteAmount, ref int buffer)11日int DBWNO = DBBNO /2;int DBWordAmount = DBByteAmount /2;int errCode = db_read(DBBlockNO, DBWNO, ref DBWordAmount, ref buffer);byte bbuf = new byte 4;GetByteFromInt32(buffer, bbuf,true);buffer = bbuf 0
18、* 0 x1000000 + bbuf 1 * 0 x10000 + bbuf 2 * 0 x100 + bbuf 3;return errCode;這個(gè)函數(shù)讀取的是一個(gè)整數(shù),因?yàn)镈B中有DBB,DBW,DBD3 種數(shù)據(jù)類型,最大的DBD是4個(gè)字節(jié),所以設(shè)計(jì) 了這個(gè)函數(shù),讀取單個(gè)的整型值,不用再進(jìn)行BYTE口到INT的轉(zhuǎn)換了 .這里值得一提的是整數(shù)高位優(yōu)先,還是低 位優(yōu)先的問題,字節(jié)數(shù)組的順序切記要矯正,另外buffer = bbuf 0 * 0 x1000000 + bbuf 1 * 0 x10000 + bbuf 2 * 0 x100 + bbuf 3;這行代碼很有意 思,16進(jìn)制的字節(jié)進(jìn)
19、位是 0 x100.3.6 M,I,Q 3種塊的讀取函數(shù)類似(參數(shù)都是一樣的),這里放在一起進(jìn)行說明M區(qū)讀取函數(shù)/summary 讀取PLC中的M 字節(jié)數(shù)據(jù)/summary/param name=no 指定 M字節(jié)號(hào),譬如要讀取 MB10的值,則指定 no等于10/param name=anzahl”指定讀取的字節(jié)數(shù),譬如需要讀取MB10 至MB14 之間的值,則可指定為 5/ 返回獲取的值,這是一個(gè)十進(jìn)制的值,如果需要獲取某一個(gè) M位的狀態(tài), 需要把它轉(zhuǎn)換成二進(jìn)制 / 0正常返回,非0為錯(cuò)誤號(hào)DllImport( w95_s7.dll)private extern static int m_
20、field_read( int no, int anzahl, byte buffer);I區(qū)讀取函數(shù),一直不明白為什么輸入?yún)^(qū)(單詞input)簡(jiǎn)稱為I,而函數(shù)名卻為A,后來才曉得,這個(gè)A是德文的 表示方法,(Pordave是西門子公司的東東).日/ 讀取 Output 值/ / QB #/ 讀出多少個(gè) QB 字節(jié) / 返回讀出的值 ,十進(jìn)制 / 0正常返回,非0為錯(cuò)誤號(hào)DllImport( w95_s7.dll)private extern static int a_field_read( int no, int anzahl, byte buffer);Q區(qū)讀取函數(shù),參數(shù)與I 一樣.Dll
21、Import( w95_s7.dll)private extern static int e_field_read( int no, int anzahl, byte buffer);C#封裝,M,I,Q 3種塊的讀取函數(shù)類似,這里放在一個(gè)函數(shù)里,利用枚舉類型PLCBlockType進(jìn)行區(qū)分/ 從M,I,Q區(qū)中讀取字節(jié)數(shù)組/ / Block 類別,在枚舉 PLCBlockType 中定義,如要讀取 M 區(qū)的值,則 b lockType=PLCBlockType.M / 區(qū)號(hào),如 IB10,MB10 , / 要讀取的字節(jié)數(shù)量,如 IB10-IB14 共 5 個(gè)字節(jié) / byte口 類型的 buf
22、fer / byte口 存儲(chǔ)的起始位置 / 0正常返回,非0為錯(cuò)誤號(hào)public static int GetMIQByteData(PLCBlockType blockType, int BlockNO, int ByteAmount, by te bbuf, int StartIndex)10之int errCode =0;byte bBufTemp = new byte ByteAmount;局部變量,不用擔(dān)心內(nèi)存釋放的問題 .C+程序員看到new估計(jì)很謹(jǐn)慎.switch (blockType) 根據(jù)塊類別,調(diào)用相應(yīng)的塊讀取函數(shù).3 case PLCBlockType.M: errCod
23、e = m_field_read(BlockNO, ByteAmount, bBufTemp);break;case PLCBlockType.I : errCode = e_field_read(BlockNO, ByteAmount, bBufTemp);break ;case PLCBlockType.Q: errCode = a_field_read(BlockNO, ByteAmount, bBufTemp);breakfor (int i = 0; i ByteAmount; i+) 由于C#中對(duì)指針有所限制,從數(shù)組指定的起始位置,逐個(gè)賦 值.3 bbufi + Startinde
24、x = bBufTempi;四,BYTE,INT,BOOL幾種類型的數(shù)據(jù)轉(zhuǎn)換函數(shù)4.1從32位整數(shù)中提取字節(jié)數(shù)組(4個(gè)byte)/ 從INT32型數(shù)據(jù)中提取byte字節(jié)數(shù)組/ / 源數(shù)據(jù)(long 型)/ 字節(jié)數(shù)組,存放提取的 Byte 數(shù)據(jù) / 起始位置 / 提取的字節(jié)數(shù) / long型源數(shù)據(jù)是否高位優(yōu)先,如果不是,則進(jìn)行反向提取public static void GetByteFromInt32( int ibuf, byte bbuf , bool isBigEndian)9三if (isBigEndian) /高位優(yōu)先,則反向提取. TOC o 1-5 h z for (int i
25、= 0; i =8; / 右移 8 位17卜18 else 低位優(yōu)先,按順序提取.19目20 for (int i =3; i = 0; i-)21中22bbufi = ( byte )(ibuf & 0 x000000ff );23ibuf =8;24卜 4.2從字節(jié)數(shù)據(jù)中提取 bit數(shù)組(8個(gè)bit),以bool型數(shù)據(jù)代替位表示./ 從 Byte 數(shù)據(jù)中取得所有 bit 的值(1Byte=8Bit , false:0 , true:1)/ / 源數(shù)據(jù)(Byte 型),其中的 8 個(gè) bit 位,從右到左 0-7 編# / bit 數(shù)組,存放 Byte 中的 8 個(gè) bit 的值,0:fal
26、se, 1:true / 在 bit 數(shù)組中存放的起始位置 public static void GetBitFromByte( byte byteData, bool 口 bitArray, int startIndex)7三byte byteArray = new byte 1 ;byteArray 0 = byteData;System.Collections.BitArray BA = new System.Collections.BitArray(byteArray);for (int i = 0; i = 7; i+) /依次取8個(gè)位,逐個(gè)賦值12中bitArraystartInd
27、ex + i = BA.Get(i);4.3從字節(jié)數(shù)據(jù)中提取某一位的狀態(tài),以bool型返回/ 從 Byte 數(shù)據(jù)中取得某一位 bit 的值(false:0 , true:1)/ / 源數(shù)據(jù)(Byte 型),其中的 8 個(gè) bit 位,從右到左 0-7 編# / bit 位編號(hào),從右到左以 0-7 編號(hào) / bit 值,以 bool 型返回,false:0 , true:1 public static void GetBitFromByte( byte byteData, int bitNo, ref bool bitData)7Hl if (bitNo =0 & bitNo =7) / 位號(hào)必須在 07 之間byte byteArray = new byte 1 ;byteArray 0 = byteData;System.Collections.BitArrayBA = new System.Collections.BitArray(byteArray);bitData = BA.Get(bitNo);五.錯(cuò)誤代碼字典/ 根據(jù)錯(cuò)誤代碼返回錯(cuò)誤信息/ 例如 int errCode=ActiveConn(1); sring errInfo = GetErrl
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 物理-福建省莆田市2025屆高中畢業(yè)班第二次教學(xué)質(zhì)量檢測(cè)試卷(莆田二檢)試題和答案
- 歷史-陜西省安康市2025屆高三下學(xué)期第二次質(zhì)量聯(lián)考(安康二模)試題和答案
- 除草布施工方案
- 廣東省肇慶市2024-2025年高中地理 農(nóng)業(yè)和工業(yè)練習(xí)評(píng)講教學(xué)實(shí)錄 新人教版必修2
- 個(gè)人瓷磚買賣合同范例
- 供貨茶葉合同范例
- 關(guān)于定金合同范例
- 公司合作加盟合同范例
- 構(gòu)建班級(jí)共同價(jià)值觀的策略計(jì)劃
- 學(xué)生課外閱讀推廣活動(dòng)計(jì)劃
- (二調(diào))武漢市2025屆高中畢業(yè)生二月調(diào)研考試 生物試卷(含標(biāo)準(zhǔn)答案)
- (一模)臨沂市2025屆高三高考第一次模擬考試政治試卷(含答案詳解)
- 2025年安徽職業(yè)技術(shù)學(xué)院?jiǎn)握新殬I(yè)適應(yīng)性考試題庫(kù)含答案
- 2025年中考百日誓師大會(huì)校長(zhǎng)發(fā)言稿(二)
- 1.2男生女生課件(共15張)-2024-2025學(xué)年統(tǒng)編版道德與法治七年級(jí)下冊(cè)
- 2025年安徽審計(jì)職業(yè)學(xué)院?jiǎn)握新殬I(yè)技能測(cè)試題庫(kù)附答案
- 2025年共青科技職業(yè)學(xué)院?jiǎn)握新殬I(yè)技能測(cè)試題庫(kù)學(xué)生專用
- 2025年黑龍江林業(yè)職業(yè)技術(shù)學(xué)院?jiǎn)握新殬I(yè)技能測(cè)試題庫(kù)含答案
- 2025年01月吉林白山市長(zhǎng)白朝鮮族自治縣事業(yè)單位公開招聘工作人員(含專項(xiàng))和邊境村穩(wěn)邊固邊工作專干84人(1號(hào))筆試歷年典型考題(歷年真題考點(diǎn))解題思路附帶答案詳解
- Module 2 Unit 2 It will snow in Harbin.(說課稿)-2023-2024學(xué)年外研版(三起)英語六年級(jí)下冊(cè)
- 真需求-打開商業(yè)世界的萬能鑰匙
評(píng)論
0/150
提交評(píng)論