 的PLC-HMI工程實戰(zhàn)記錄(一)創(chuàng)建PLC工程模板項目)
一個PLC-HMI實戰(zhàn)工程的過程記錄。一、新建TIA工程組態(tài)PLC時可以直接指定PLC型號也可以不指定CPU使用unspecified CPU這樣做的好處是保持模板的通用性并且在硬件確定之后不用手動逐個輸入組態(tài)硬件連接到已通電的CPU使用“在線”、“硬件檢測”就可以直接把實際的硬件讀取到項目中。使用這種讀取在線PLC的方式組態(tài)有一個坑點是必須給在線硬件分配PROFINET 設(shè)備名稱并與程序中的名稱一致否則會組態(tài)失敗。二、新建程序分組命名為“系統(tǒng)OB”添加OB30、OB82、OB100、OB86、OB122等必要和有可能用到的OB系統(tǒng)塊。三、新建PLC數(shù)據(jù)類型這個命名為“AreaVar”的數(shù)據(jù)類型包含了數(shù)據(jù)分區(qū)I/QM/DB)、DB編號、數(shù)據(jù)起點、數(shù)據(jù)字節(jié)長度等信息可用來進行各種以字節(jié)為單位的塊間操作。這個數(shù)據(jù)類型是本工程與上位機通信的基礎(chǔ)類型它指定了數(shù)據(jù)報文的位置和長度。四、導(dǎo)入之前導(dǎo)出保存的CRC校驗表DB文件“添加新的外部文件”、“從源生成塊”這樣就把外部的db文件轉(zhuǎn)換為項目中的DB塊。新建分組“背景類DB”并將生成的DB塊拖入五、創(chuàng)建TCP連接并組態(tài)和編程連接創(chuàng)建連接之前需要將CPU指定為具有網(wǎng)絡(luò)通信能力的型號這里指定為1513-1PN。1、新建程序塊分組功能塊2、在分組中新建FB命名為“上位通信”此功能塊負責與上位機通信。3、打開上位通信FB開始編程。4、從指令庫中將TCON拖入FB的網(wǎng)絡(luò)會自動創(chuàng)建一個DB塊TCON_DB。5、點擊“開始組態(tài)”按鈕對連接進行組態(tài)在打開的組態(tài)窗口中伙伴未指定伙伴主動建立連接連接數(shù)據(jù)新建作為一個模板無需為PLC特意指定IP地址當在實際的項目中改變了CPU的IP地址后連接參數(shù)中的地址會自動隨之改變?yōu)樾碌摹_@樣就將PLC創(chuàng)建為TCP主站。可以看到在系統(tǒng)塊的程序資源中自動生成了2個數(shù)據(jù)塊PLC_1_Connection_DB用于存儲連接參數(shù)。TCON_DB則是TCON指令的背景數(shù)據(jù)塊這些都是自動生成和分配的無需人工參與只要知道其用途即可。6、編譯一下確認生成無誤7、為上位通信FB塊創(chuàng)建一個數(shù)據(jù)塊上位通信_工作DB并在DB中定義一個Struct作為TCON指令的參數(shù)容器8、在上位通信FB中為TCON指令分配參數(shù)9、在OB1中調(diào)用上位通信FB調(diào)用時會自動創(chuàng)建一個背景DB將其命名為上位通信_背景DB并拖入“背景類DB”分組中。這個分組中的DB全部為背景類的DB無需人工干預(yù)和編輯。10、在上位通信_工作DB中補充發(fā)送和接收的參數(shù)容器11、在上位通信FB中繼續(xù)編程拖入發(fā)送和接收指令增加接收和發(fā)送功能12、在創(chuàng)建兩個相同的DB塊用來存放上行和下行報文13、繼續(xù)完善上位通信FB把發(fā)送和接收指令的DATA端口指向新建的兩個報文DB14、創(chuàng)建FC塊命名為“_build_AreaVal”功能是由Area、DBnum、offset、byteCount這幾個參數(shù)來生成一個自定義的區(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)上行報文”用來組態(tài)上行報文接口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查表運算的表格OutputInOutdestArea AreaVar 目標區(qū)域存放上行報文的字節(jié)TempTemp_1 AreaVarwCRC Wordi DIntpos DInt 字節(jié)臨時指針bTemp BytewTemp WordnIndex DIntvarTemp AreaVartmp_DI1 DInttmp_DI2 DIntConstantReturn組態(tài)上行報文 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ū)域和起點、長度////// 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號 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校驗和////////////////////////////// #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、在“上位通信_工作DB”中增加幀頭和幀尾的定義17、在“上位通信”FB中編程組態(tài)上行報文上行報文的區(qū)域暫時不填具體到實際的PLC再填。18、創(chuàng)建FC塊命名為“解析下行數(shù)據(jù)”接口InputframeHeader1 Byte 幀頭字節(jié)1frameHeader2 Byte 幀頭字節(jié)2frameEnd1 Byte 幀尾字節(jié)1frameEnd2 Byte 幀尾字節(jié)2rsv_area_var AreaVar 接收下行報文的DB塊DB_CRC_TABLE Array[0..255] of WordOutputDONE BoolInOutTempi DInt 0.0pos DInt 4.0 字節(jié)臨時指針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號 #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é)長度 #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ù)長度再多讀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; //此時的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, ////寫一個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;