ScriptAuthor "Beispiel" ScriptName "FBRS Modbus-RTU (Slave)" ScriptVersion "V 1.0" // Only for RS RS Hardware // This script realized the Modbus-RTU-SLAVE function on the fieldbus side // Communication - Modbus - FBRS Modbus RTU Slv Read // FBRS Modbus RTU Slv Write // Example: // The UNIGATE receive with Modbusfunctioncode 16 data and send it ti the RS side // And if the UNIGATE receive on the RS side data it store this and a Master can // read it with functioncode 3 or 4 // You can also use other functioncodes // V1.0 08.09.05 St erstellt //******************* init errorhandler **************************************** SetErrorHandler ( :Address ) ; SetSystemErrorHandler ( :SysAddress ) ; // ********************** variable declaration ********************************* // fieldbus: Var aBusInput : BUFFER[32] ; Var BusInput100 : BUFFER[100] ; Var BusInput120 : BUFFER[120] ; Var aBusOutbuf : BUFFER[32] ; Var aBusOutbuf220 : BUFFER[220] ; var wMaxByteCount : word ; Moveconst (wMaxByteCount, 244); Var wBusInputLen : Word ; Var wBusOutputLen : Word ; Var bBusInputLen : Byte ; Var bBusOutputLen : Byte ; // RS-side var aModSlvIn : Buffer[20] ; // 20 = user defined var aModSlvIn100 : buffer[100]; // Reserve buffer if aModSlvIn is to smal var aModSlvIn130 : buffer[130]; // Reserve buffer if aModSlvIn is to smal var aModSlvout : Buffer[20] ; // 20 = user defined var aModSlvOut100 : buffer[100]; // Reserve buffer if aModSlvOut is to smal var aModSlvOut130 : buffer[130]; // Reserve buffer if aModSlvOut is to smal // Modbus parameter Var wModbusRxLen : Word ; var bFunctionCode : Byte ; var wStartAddressHiLo : Word ; var wNoOfPointsHiLo : Word ; var wCoilAddressHiLo : Word ; var wForceDataHiLo : Word ; var bExceptionCode : Byte ; var wTimeOut : word ; moveconst (wTimeOut, 100); // constant Var w0 : Word ; MoveConst (w0, 0) ; Var w1 : Word ; MoveConst (w1, 1) ; Var w2 : Word ; MoveConst (w2, 2) ; Var w7 : Word ; MoveConst (w7, 7) ; Var w255 : Word ; MoveConst (w255, 255) ; var wFF00 : Word ; Moveconst (wFF00, 0xFF00); Var b0 : Byte ; MoveConst (b0, 0) ; Var b2 : Byte ; MoveConst (b2, 2) ; Var b3 : Byte ; MoveConst (b3, 3) ; Var b4 : Byte ; MoveConst (b4, 4) ; Var b6 : Byte ; MoveConst (b6, 6) ; Var b14 : Byte ; MoveConst (b14, 14) ; Var b16 : Byte ; MoveConst (b16, 16) ; // error handler Var ReturnCode : Byte ; Var NoError : Byte ; MoveConst (NoError, 0) ; // default Returncode 0 = No Error var bErrorcode : Byte ; MoveConst (bErrorcode, 0) ; var bSystemErrorcode : Byte ; // other var wOffset : Word ; var aRSInBuf : Buffer[10] ; var aRSInBufRes : Buffer[100] ; var wMAX_RS_LEN : Word ; moveconst (wMAX_RS_LEN, 100); var aUserData : Buffer[20] ; // user defined var wByteCount : Word ; var wtemp : Word ; var bStateFC5 : Byte ; var btemp : Byte ; //****************** Init serial port ****************************************** Set ( Baudrate , 9600 ) ; Set ( Databits , 8 ) ; Set ( Startbits , 1 ) ; Set ( Stopbits , 1 ) ; Set ( Parity , none ) ; // *********** Init Field Bus Modbus Slave************************************** //********** init 2. RS interface (fieldbus) *********************************** //Set ( BusBaudrate , 9600 ) ; // 9600 = default //Set ( FBRS_ANZ_DAT_BITS , 8 ) ; // 8 = default //Set ( FBRS_ANZ_STOP_BITS , 1 ) ; // 1 = default //Set ( FBRS_PARITY , No ) ; // default //Set ( FBRS_PARITY , Odd ) ; //Set ( FBRS_PARITY , Even ) ; //Set ( FBRS_PARITY , Mark ) ; // Paritybit immer 1 */ //Set ( FBRS_PARITY , Space ) ; // Paritybit immer 0 */ //Set ( FBRS_TYPE , RS232 ) ; // default //Set ( FBRS_TYPE , RS485 ) ; //Set ( FBRS_TYPE , RS422 ) ; Set ( FieldbusID , 2 ) ; // Modbus Slave ID //************************ Bus start ******************************************* // Start Bus and wait until running BusStart ; Wait ( Bus_Active ) ; //************************ main ************************************************ :WaitNewModBusData ; call :UpdateUserProgram; // Bus Buffer tauschen mit ModBusUserbuffer FBRSModRTUSlvRead ( aModSlvIn[0] , wModbusRxLen ) ;// Wait without timeout for Modbusdata // Get ( ErrorCode , bErrorcode ) ; // If bErrorcode equal b2 then :WaitNewModBusData; // or // If bErrorcode equal b0 then :NewModbusData; // or if wModbusRxLen equal w0 then :WaitNewModBusData; //:NewModbusData; Copy ( aModSlvIn[0], bFunctionCode, w1); if bFunctionCode greater b4 then :CheckForceQuery; if bFunctionCode less b3 then :CheckForceQuery; // function 3 + 4, Master Read data from Slave Copy ( aModSlvIn[1], wStartAddressHiLo, w2); // user information Copy ( aModSlvIn[3], wNoOfPointsHiLo, w2); // " " CalculateWord ( wNoOfPointsHiLo , w2 , mul , wByteCount ) ; if wByteCount greater wMaxByteCount then :ExceptionResponse03; Convert ( wByteCount , Word , aModSlvOut[1] , Byte ) ; // 2. Byte = bByteCount // TBD user : calculate your data CopyIndexed ( wByteCount , aBusOutBuf[0] , wStartAddressHiLo , aModSlvOut[2] , w0 ) ;// 3. - x Byte = user data response jump :WriteToModbus; :CheckForceQuery; if bFunctionCode greater b6 then :CheckExceptionQuery; // function 5 + 6, not supported jump :ExceptionResponse01; // function 5 + 6, Master send data to Slave Copy ( aModSlvIn[1], wCoilAddressHiLo, w2); // user information Copy ( aModSlvIn[3], wForceDataHiLo, w2); // " " if bFunctionCode equal b6 then :CheckPresetSReg; if wForceDataHiLo equal w0 then :SetStateOFF; if wForceDataHiLo equal wFF00 then :SetStateON; jump :ExceptionResponse03; :SetStateOFF; moveconst ( bStateFC5, 0 ); jump :CheckPresetSReg; :SetStateON; moveconst ( bStateFC5, 1 ); //jump :CheckPresetSReg; :CheckPresetSReg; // TBD user : calculate your data Copy ( aModSlvIn[1], aModSlvOut[1], w2); // 2. + 3. Byte Copy ( aModSlvIn[3], aModSlvOut[3], w2); // 4. + 5. Byt jump :WriteToModbus; :CheckExceptionQuery; if bFunctionCode greater b14 then :CheckForceMCoilsQuery; // function 7 - 14, not supported jump :ExceptionResponse01; :CheckForceMCoilsQuery; if bFunctionCode greater b16 then :ExceptionResponse01; // function greater 16 not supported at the moment // function 15 + 16, Master send data to slave Copy ( aModSlvIn[1], wCoilAddressHiLo, w2); // user information Copy ( aModSlvIn[3], wForceDataHiLo, w2); // " " moveconst ( wByteCount, 0); // default // Bug Copy ( aModSlvIn[5], wByteCount, w1); // " " Convert ( aModSlvIn[5] , Byte , wByteCount , Word ) ; if wByteCount greater wMaxByteCount then :ExceptionResponse03; if wCoilAddressHiLo greater wBusOutputLen then :ExceptionResponse03; // TBD user : calculate your data CopyIndexed ( wByteCount , aModSlvIn[6] , w0 , aBusInput[0] , wCoilAddressHiLo ) ; call :SendDatToRS; Copy ( aModSlvIn[1], aModSlvOut[1], w2); // 2. + 3. Byte Copy ( aModSlvIn[3], aModSlvOut[3], w2); // 4. + 5. Byte jump :WriteToModbus; //********************* Exception Response No for user ************************* :ExceptionResponse01; // Illegal Function Moveconst ( bExceptionCode, 1); jump :SetMSB; :ExceptionResponse02; // Illegal Data Address Moveconst ( bExceptionCode, 2); jump :SetMSB; :ExceptionResponse03; // Illegal data Value Moveconst ( bExceptionCode, 3); jump :SetMSB; :ExceptionResponse04; // Slave Device Failure Moveconst ( bExceptionCode, 4); jump :SetMSB; :ExceptionResponse05; // Acknowledge Moveconst ( bExceptionCode, 5); jump :SetMSB; :ExceptionResponse06; // Slave Device Busy Moveconst ( bExceptionCode, 6); jump :SetMSB; :ExceptionResponse07; // Negative Acknowledge Moveconst ( bExceptionCode, 7); jump :SetMSB; :ExceptionResponse08; // Memory Parity Error Moveconst ( bExceptionCode, 8); jump :SetMSB; //******************* calculate Modbus Error *********************************** :SetMSB; Set ( errorcode , 14 ) ; // display error on Unigate SC Convert ( bFunctionCode , Byte , wtemp , Word ) ; // only dataconverstion from byte to word CalculateByte ( wtemp , w7 , SetBit , wtemp ) ; // set MSB of FunctionCode Convert ( wtemp , Word, bFunctionCode , Byte ) ; // only dataconverstion from word to byte // Copy ( bFunctionCode, aModSlvOut[0], w1); // 1. Byte = bFunctionCode Copy ( bExceptionCode, aModSlvOut[1], w1); // 2. Byte = Exception Code jump :WriteToModbus; //***************** send Modbus Response *************************************** :WriteToModbus ; Copy ( bFunctionCode, aModSlvOut[0], w1); // 1. Byte = bFunctionCode FBRSModRTUSlvWrite ( aModSlvOut[0] ) ; // OutLen and CRC is automatic calculated by UNIGATE jump :WaitNewModBusData ; //******************* Subrotine ************************************************ :UpdateUserProgram; // TBD call :CheckRS_In; return; //******************* Error Handler subroutine ********************************* :Address; Get ( Errorcode , bErrorcode ) ; if bErrorcode equal b0 then :EndAddress; // TBD Set ( Errorcode , 14 ) ; :EndAddress; return; :SysAddress; // RS-LED static red, Yellow-LED blinking with value of "bSystemErrorCode" Get ( SystemError , bSystemErrorCode ) ; if bSystemErrorCode equal b0 then :EndSysAddress; // TBD Set ( Errorcode , 15 ) ; :EndSysAddress; return; //****************************************************************************** :CheckRS_In; ReceiveSomeCharRS( wTimeOut, aRSInBuf[0], w1 ); Get ( ErrorCode , bErrorCode ) ; if bErrorCode equal b2 then :CheckRS_InEND; // else :storeData ; //:storeData; CopyIndexed ( w1 , aRSInBuf[0] , w0 , aBusOutBuf[0] , wOffset ) ; CalculateByte ( wOffset , w1 , add , wOffset ) ; if wOffset equal wMAX_RS_LEN then :CheckRS_InEND; jump :CheckRS_In; :CheckRS_InEND; moveconst (wOffset, 0); return; //****************************************************************************** :SendDatToRS; SendRS ( aBusInput[1] , wByteCount ) ; return;