 的PLC-HMI工程實(shí)戰(zhàn)記錄(一)創(chuàng)建PLC工程模板項(xiàng)目)
一個(gè)PLC-HMI實(shí)戰(zhàn)工程的過程記錄。一、新建TIA工程組態(tài)PLC時(shí)可以直接指定PLC型號(hào)也可以不指定CPU使用unspecified CPU這樣做的好處是保持模板的通用性并且在硬件確定之后不用手動(dòng)逐個(gè)輸入組態(tài)硬件連接到已通電的CPU使用“在線”、“硬件檢測(cè)”就可以直接把實(shí)際的硬件讀取到項(xiàng)目中。使用這種讀取在線PLC的方式組態(tài)有一個(gè)坑點(diǎn)是必須給在線硬件分配PROFINET 設(shè)備名稱并與程序中的名稱一致否則會(huì)組態(tài)失敗。二、新建程序分組命名為“系統(tǒng)OB”添加OB30、OB82、OB100、OB86、OB122等必要和有可能用到的OB系統(tǒng)塊。三、新建PLC數(shù)據(jù)類型這個(gè)命名為“AreaVar”的數(shù)據(jù)類型包含了數(shù)據(jù)分區(qū)I/QM/DB)、DB編號(hào)、數(shù)據(jù)起點(diǎn)、數(shù)據(jù)字節(jié)長(zhǎng)度等信息可用來(lái)進(jìn)行各種以字節(jié)為單位的塊間操作。這個(gè)數(shù)據(jù)類型是本工程與上位機(jī)通信的基礎(chǔ)類型它指定了數(shù)據(jù)報(bào)文的位置和長(zhǎng)度。四、導(dǎo)入之前導(dǎo)出保存的CRC校驗(yàn)表DB文件“添加新的外部文件”、“從源生成塊”這樣就把外部的db文件轉(zhuǎn)換為項(xiàng)目中的DB塊。新建分組“背景類DB”并將生成的DB塊拖入五、創(chuàng)建TCP連接并組態(tài)和編程連接創(chuàng)建連接之前需要將CPU指定為具有網(wǎng)絡(luò)通信能力的型號(hào)這里指定為1513-1PN。1、新建程序塊分組功能塊2、在分組中新建FB命名為“上位通信”此功能塊負(fù)責(zé)與上位機(jī)通信。3、打開上位通信FB開始編程。4、從指令庫(kù)中將TCON拖入FB的網(wǎng)絡(luò)會(huì)自動(dòng)創(chuàng)建一個(gè)DB塊TCON_DB。5、點(diǎn)擊“開始組態(tài)”按鈕對(duì)連接進(jìn)行組態(tài)在打開的組態(tài)窗口中伙伴未指定伙伴主動(dòng)建立連接連接數(shù)據(jù)新建作為一個(gè)模板無(wú)需為PLC特意指定IP地址當(dāng)在實(shí)際的項(xiàng)目中改變了CPU的IP地址后連接參數(shù)中的地址會(huì)自動(dòng)隨之改變?yōu)樾碌摹_@樣就將PLC創(chuàng)建為TCP主站。可以看到在系統(tǒng)塊的程序資源中自動(dòng)生成了2個(gè)數(shù)據(jù)塊PLC_1_Connection_DB用于存儲(chǔ)連接參數(shù)。TCON_DB則是TCON指令的背景數(shù)據(jù)塊這些都是自動(dòng)生成和分配的無(wú)需人工參與只要知道其用途即可。6、編譯一下確認(rèn)生成無(wú)誤7、為上位通信FB塊創(chuàng)建一個(gè)數(shù)據(jù)塊上位通信_(tái)工作DB并在DB中定義一個(gè)Struct作為TCON指令的參數(shù)容器8、在上位通信FB中為TCON指令分配參數(shù)9、在OB1中調(diào)用上位通信FB調(diào)用時(shí)會(huì)自動(dòng)創(chuàng)建一個(gè)背景DB將其命名為上位通信_(tái)背景DB并拖入“背景類DB”分組中。這個(gè)分組中的DB全部為背景類的DB無(wú)需人工干預(yù)和編輯。10、在上位通信_(tái)工作DB中補(bǔ)充發(fā)送和接收的參數(shù)容器11、在上位通信FB中繼續(xù)編程拖入發(fā)送和接收指令增加接收和發(fā)送功能12、在創(chuàng)建兩個(gè)相同的DB塊用來(lái)存放上行和下行報(bào)文13、繼續(xù)完善上位通信FB把發(fā)送和接收指令的DATA端口指向新建的兩個(gè)報(bào)文DB14、創(chuàng)建FC塊命名為“_build_AreaVal”功能是由Area、DBnum、offset、byteCount這幾個(gè)參數(shù)來(lái)生成一個(gè)自定義的區(qū)域變量AreaVal接口Input 數(shù)據(jù)類型Area ByteDBNum UIntOffset UIntbyteCount UIntInOutdestAreaVar AreaVarscl:#destAreaVar.Area : #Area; #destAreaVar.DBNum : #DBNum; #destAreaVar.Offset : #Offset; #destAreaVar.byteCount : #byteCount;15、創(chuàng)建FC塊命名為“組態(tài)上行報(bào)文”用來(lái)組態(tài)上行報(bào)文接口InputframeHeader1 Byte 幀頭字節(jié)1frameHeader2 Byte 幀頭字節(jié)2frameEnd1 Byte 幀尾字節(jié)1frameEnd2 Byte 幀尾字節(jié)2srcAreaVars Array[*] of AreaVar 源數(shù)據(jù)區(qū)域支持多區(qū)域輸入DB_CRC_TABLE Array[0..255] of Word CRC查表運(yùn)算的表格OutputInOutdestArea AreaVar 目標(biāo)區(qū)域存放上行報(bào)文的字節(jié)TempTemp_1 AreaVarwCRC Wordi DIntpos DInt 字節(jié)臨時(shí)指針bTemp BytewTemp WordnIndex DIntvarTemp AreaVartmp_DI1 DInttmp_DI2 DIntConstantReturn組態(tài)上行報(bào)文 Voidscl////////////////////////////組態(tài)幀頭/////////////////////////// POKE(area : #destArea.Area, dbNumber : #destArea.DBNum, byteOffset : 0, value : #frameHeader1); //幀頭1 POKE(area : #destArea.Area, dbNumber : #destArea.DBNum, byteOffset : 1, value : #frameHeader2); //幀頭2 #pos : 2; //#tmp_DI1 : LOWER_BOUND(ARR : #srcAreaVars, DIM : 1); //#tmp_DI2 : UPPER_BOUND(ARR : #srcAreaVars, DIM : 1); FOR #i : LOWER_BOUND(ARR : #srcAreaVars, DIM : 1) TO UPPER_BOUND(ARR : #srcAreaVars, DIM : 1) DO #varTemp : #srcAreaVars[#i]; ////////組態(tài)區(qū)域變量的信息本幀數(shù)據(jù)的區(qū)域和起點(diǎn)、長(zhǎng)度////// POKE(area : #destArea.Area, //本幀數(shù)據(jù)的區(qū)域 dbNumber : #destArea.DBNum, byteOffset : #pos, value : #varTemp.Area); #pos : #pos 1; POKE(area : #destArea.Area, //字節(jié)占位 dbNumber : #destArea.DBNum, byteOffset : #pos, value : #varTemp.Area); #pos : #pos 1; POKE(area : #destArea.Area, //本幀數(shù)據(jù)的DB號(hào) dbNumber : #destArea.DBNum, byteOffset : #pos, value : #varTemp.DBNum); //value : DINT_TO_BYTE(IN:#varTemp.DBNum)); #pos : #pos 4; POKE(area : #destArea.Area, //本幀數(shù)據(jù)的起始字節(jié)偏移 dbNumber : #destArea.DBNum, byteOffset : #pos, value : #varTemp.Offset); #pos : #pos 4; POKE(area : #destArea.Area, //本幀數(shù)據(jù)的字節(jié)數(shù) dbNumber : #destArea.DBNum, byteOffset : #pos, value : #varTemp.byteCount); #pos : #pos 4; ///////////////////////////////組態(tài)幀數(shù)據(jù)內(nèi)容///////////////////////// POKE_BLK(area_src : #varTemp.Area, dbNumber_src : #varTemp.DBNum, byteOffset_src : #varTemp.Offset, area_dest : #destArea.Area, dbNumber_dest : #destArea.DBNum, byteOffset_dest : #pos, count : #varTemp.byteCount); #pos : #pos #varTemp.byteCount; END_FOR; ///////////////////////////////組態(tài)幀尾//////////////////////////// POKE(area : #destArea.Area, //幀尾1 dbNumber : #destArea.DBNum, byteOffset : #pos, value : #frameEnd1); #pos : #pos 1; POKE(area : #destArea.Area, //幀尾2 dbNumber : #destArea.DBNum, byteOffset : #pos, value : #frameEnd2); #pos : #pos 1; /////////////////////////////////CRC16校驗(yàn)和////////////////////////////// #destArea.byteCount : #pos; #wCRC : 16#FFFF; FOR #i : 0 TO #destArea.byteCount - 1 DO #bTemp : PEEK(area : #destArea.Area, byteOffset : #i, dbNumber : #destArea.DBNum); #wTemp : #wCRC XOR BYTE_TO_WORD(IN : #bTemp); #wTemp : #wTemp AND 16#00FF; #nIndex : WORD_TO_INT(IN : #wTemp); #wCRC : SHR(IN : #wCRC, N : 8) XOR #DB_CRC_TABLE[#nIndex]; END_FOR; //寫入CRC字 POKE(area : #destArea.Area, dbNumber : #destArea.DBNum, byteOffset : #pos, value : #wCRC); #pos : #pos 2; #destArea.byteCount : #pos;16、在“上位通信_(tái)工作DB”中增加幀頭和幀尾的定義17、在“上位通信”FB中編程組態(tài)上行報(bào)文上行報(bào)文的區(qū)域暫時(shí)不填具體到實(shí)際的PLC再填。18、創(chuàng)建FC塊命名為“解析下行數(shù)據(jù)”接口InputframeHeader1 Byte 幀頭字節(jié)1frameHeader2 Byte 幀頭字節(jié)2frameEnd1 Byte 幀尾字節(jié)1frameEnd2 Byte 幀尾字節(jié)2rsv_area_var AreaVar 接收下行報(bào)文的DB塊DB_CRC_TABLE Array[0..255] of WordOutputDONE BoolInOutTempi DInt 0.0pos DInt 4.0 字節(jié)臨時(shí)指針tmp_head Byte 8.0tmp_end Byte 9.0tmp_areaVar AreaVar 10.0bTemp Byte 28.0wTemp Word 30.0wCRC Word 32.0nIndex Int 34.0ConstantReturn解析下行數(shù)據(jù) Voidscl:#DONE : FALSE; ////////////////////////////解析幀頭/////////////////////////// #pos : 0; // 字節(jié)指針 #tmp_head : PEEK(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos); //幀頭1 IF #frameHeader1 #tmp_head THEN #DONE : FALSE; RETURN; END_IF; #pos : #pos 1; #tmp_head : PEEK(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos); //幀頭2 IF #frameHeader1 #tmp_head THEN #DONE : FALSE; RETURN; END_IF; #pos : #pos 1; IF PEEK(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos) #frameEnd1 THEN IF PEEK(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos 1) #frameEnd2 THEN #DONE : TRUE; RETURN; END_IF; END_IF; /////////////////////////解析區(qū)域變量的參數(shù)//////////////////// #tmp_areaVar.Area : PEEK(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos); //幀區(qū)域 #pos : #pos 2; #tmp_areaVar.DBNum : DWORD_TO_DINT(IN : PEEK_DWORD(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos)); //幀DB號(hào) #pos : #pos 4; #tmp_areaVar.Offset : DWORD_TO_DINT(PEEK_DWORD(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos)); //幀字節(jié)偏移 #pos : #pos 4; #tmp_areaVar.byteCount : DWORD_TO_DINT(PEEK_DWORD(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos)); //幀字節(jié)長(zhǎng)度 #pos : #pos 4; #tmp_areaVar.bit : DWORD_TO_DINT(PEEK_DWORD(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos)); //幀位bit #pos : #pos 4; //pos目前位于數(shù)據(jù)區(qū)之前 ////////////////////////////解析數(shù)據(jù)內(nèi)容和CRC////////////////////////// //解析CRC #wCRC : 16#FFFF; FOR #i : 0 TO #pos #tmp_areaVar.byteCount 1 DO //讀取接收DB從0到數(shù)據(jù)長(zhǎng)度再多讀4位幀尾 #bTemp : PEEK(area : #rsv_area_var.Area, byteOffset : #i, dbNumber : #rsv_area_var.DBNum); #wTemp : #wCRC XOR BYTE_TO_WORD(IN : #bTemp); #wTemp : #wTemp AND 16#00FF; #nIndex : WORD_TO_INT(IN : #wTemp); #wCRC : SHR(IN : #wCRC, N : 8) XOR #DB_CRC_TABLE[#nIndex]; END_FOR; #wCRC : #wCRC; #pos : #pos #tmp_areaVar.byteCount; //pos目前位于數(shù)據(jù)區(qū)之后幀尾之前 IF #wCRC PEEK_WORD(area : #rsv_area_var.Area, byteOffset : #pos 2, dbNumber : #rsv_area_var.DBNum) THEN //CRC失敗 #DONE : FALSE; RETURN; END_IF; ////////////////////////////解析幀尾/////////////////////////////////// #tmp_end : PEEK(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos); //幀尾1 IF #frameEnd1 #tmp_end THEN #DONE : FALSE; RETURN; END_IF; #pos : #pos 1; #tmp_end : PEEK(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos); //幀尾2 IF #frameEnd2 #tmp_end THEN #DONE : FALSE; RETURN; END_IF; #pos : #pos 1; //此時(shí)的pos位于幀尾后CRC前 #pos : #pos - #tmp_areaVar.byteCount - 2; //把pos移回到數(shù)據(jù)區(qū)的起始 /////////////////////////////////如果是bool////////////////////////////// IF #tmp_areaVar.bit 16#FFFFFFFF THEN POKE_BOOL(area : #tmp_areaVar.Area, ////寫一個(gè)bool位 dbNumber : #tmp_areaVar.DBNum, byteOffset : #tmp_areaVar.Offset, bitOffset : DINT_TO_INT(IN : #tmp_areaVar.bit), value : PEEK_BOOL(area : #rsv_area_var.Area, dbNumber : #rsv_area_var.DBNum, byteOffset : #pos, bitOffset : #tmp_areaVar.bit)); /////////////////////////////////如果不是bool////////////////////////////// ELSE //寫塊數(shù)據(jù) POKE_BLK(area_src : #rsv_area_var.Area, dbNumber_src : #rsv_area_var.DBNum, byteOffset_src : #pos, area_dest : #tmp_areaVar.Area, dbNumber_dest : #tmp_areaVar.DBNum, byteOffset_dest : #tmp_areaVar.Offset, count : #tmp_areaVar.byteCount); END_IF; #DONE : TRUE;