/* MBDemo03: Communicate with a Modbus/RTU (or Modbus/ASCII) slave device (PLC) Compiler: BC++ 3.1 Compile mode: large Project: MBDemo01.c ..\Lib\7188XBL.Lib ..\Lib\MBR7Bnnn.Lib, with nnn being the version of Modbus library. Communication: 7188/8000 <== COM port ==> Modbus/RTU (or ASCII) slave device (PLC) Hardware: 7188/8000 + Modbus/RTU (or ASCII) slave device (PLC) Memory mapping iMemory_DI[00]~[49] <====> PLC DI register [100]~[149] iMemory_DO[00]~[49] <====> PLC DO register [100]~[149] iMemory_AI[00]~[07] <====> PLC AI register [100]~[107] iMemory_AO[00]~[07] <====> PLC AO register [100]~[107] [2004,Aug,05] by Kevin Re-write the demo. [2005,Sep,29] by Kevin Re-write the demo. [2006,Feb,17] by Kevin Use new I/O memory mapping method. */ #include "..\Lib\7188XB.h" #include "..\Lib\MBRTU.h" int iScanUserProcess=0; int ScanUserProcess(int iProcess); //The I/O memory mapping unsigned char far iMemory_DI[100]; unsigned char far iMemory_DO[100]; int far iMemory_AI[100]; int far iMemory_AO[100]; int main(void) { int iScanCOMPort=1; int iRet; InitLib(); //To use XB library version 2.0 (after 2004/Mar/08). // ***** Begin changing COM port setting ****** // Call following codes once when you change the COM port setting. // After saving the setting to the EEPROM, you should remove the codes. // Save COM1 setting to EEPROM ComData[1-1].baud=115200; ComData[1-1].databit=8; ComData[1-1].parity=0; ComData[1-1].stopbit=1; VcomSaveComData(1-1); // Save COM2 setting to EEPROM ComData[2-1].baud=115200; ComData[2-1].databit=8; ComData[2-1].parity=0; ComData[2-1].stopbit=1; VcomSaveComData(2-1); // ***** End changing COM port setting ****** // ***** Begin Modbus configuration ***** // Before the Modbus Utility can support the 7188XB -MRTU, // You can add following functions to configure the Modbus settings. Set_NetID(1); Set_StationCountPerCOMPort(10); /* COM1: UpLink mode be a Modbus/RTU slave port link to other Modbus/RTU master device, such as HMI or PC. COM2: Programming mode The Modbus kernel doesn't control the COM port. Users can program the COM port to control other RS-232/485 devices. */ Set_COMEnableMode(1,_Programming); //To print some debug information. Set_COMEnableMode(2,_Programming); //To link to Modbus/ASCII slave device. // **** End Modbus configuration ***** iRet=InitModbus(iMemory_DI,iMemory_DO,iMemory_AI,iMemory_AO); if(iRet) return iRet; for(;;) { // Begin of the Modbus Kernel if(mtModbusPort[iScanCOMPort].EnableMode==_ModbusRTU_Slave) CheckModbusRTURequest(iScanCOMPort); // Is any request from Modbus/RTU Master ? if(mtModbusPort[iScanCOMPort].EnableMode==_ModbusASCII_Slave) CheckModbusASCIIRequest(iScanCOMPort); // Is any request from Modbus/ASCII Master ? iScanCOMPort++; if(iScanCOMPort>iTotalCOMPort) iScanCOMPort=1; // End of the Modbus Kernel /****************************/ /*** User's control logic ***/ /****************************/ iScanUserProcess=ScanUserProcess(iScanUserProcess); } } /*******************************/ /* [ScanUserProcess] */ /* for 7188E/7188XA/7188XB */ /* 8000 */ /* version 1.3.0 */ /* date: 29,Sep,2005 */ /*******************************/ int ScanUserProcess(int iProcess) { /* iProcess: executes which process? return: executes which process next time? In MBDemo03, following code can map DO, DI, AO, AI registers of the Modbus/RTU (or Modbus/ASCII) slave device (PLC) to iMemory_DO, iMemory_DI,iMemory_AO, iMemory_AI continuously. If the register on the PLC is changed, 7188/8000 can get latest status after 4 scan processes. */ int iPort,iRet,i; int iNextProcess; switch(iProcess) { case 0: // Add user's process here // For example, sends modbus request to modbus/slave device // to read DI iPort=2; if(mtModbusPort[iPort].EnableMode==_Programming) { // Read PLC DI[100]~[149] iRet=ModbusASCII_Master(iPort,1,2,0,100,50,500,1); // COM port, NetID, FC=2 to read DI, iMemory_DI base address, // device memory base address, I/O count. // Timeout = 500 ms //Print the DI data (only first 10 data) if(iRet==NoError) { for(i=0;i<10;i++) printCom1("DI[%02d]=%d ",i,iMemory_DI[i]); printCom1("\n\r"); } else printCom1("Read DI error! Error code=%d\n\r",iRet); } iNextProcess=1; break; case 1: // Add user's process here // For example, sends modbus request to modbus/slave device // to write DO iPort=2; if(mtModbusPort[iPort].EnableMode==_Programming) { iMemory_DO[0]=0; iMemory_DO[1]=1; iMemory_DO[2]=0; iMemory_DO[3]=1; iMemory_DO[4]=0; // Write to PLC DO[100]~[149] iRet=ModbusASCII_Master(iPort,1,15,0,100,50,500,1); // COM port, NetID, FC=15 to write DO, iMemory_DO base address, // device memory base address, I/O count. // Timeout = 500 ms if(iRet==NoError) printCom1("Write DO ok.\n\r"); else printCom1("Write DO error! Error code=%d\n\r",iRet); } iNextProcess=2; break; case 2: // Add user's process here // For example, sends modbus request to modbus/slave device // to read AI iPort=2; if(mtModbusPort[iPort].EnableMode==_Programming) { // Read PLC AI[100]~[107] iRet=ModbusASCII_Master(iPort,1,4,0,100,8,500,1); // COM port, NetID, FC=4 to read AI, iMemory_AI base address, // device memory base address, I/O count. // Timeout = 500 ms //Print the DI data if(iRet==NoError) { for(i=0;i<8;i++) printCom1("AI[%02d]=%04X ",i,iMemory_AI[i]); printCom1("\n\r"); } else printCom1("Read AI error! Error code=%d\n\r",iRet); } iNextProcess=3; break; case 3: // Add user's process here // For example, sends modbus request to modbus/slave device // to read AO iPort=2; if(mtModbusPort[iPort].EnableMode==_Programming) { iMemory_AO[0]=0x0000; iMemory_AO[1]=0x1111; iMemory_AO[2]=0x2222; iMemory_AO[3]=0x3333; iMemory_AO[4]=0x4444; iMemory_AO[5]=0x5555; iMemory_AO[6]=0x6666; iMemory_AO[7]=0x7777; //Write PLC AO[100]~[107] iRet=ModbusASCII_Master(iPort,1,16,0,100,8,500,1); // // COM port, NetID, FC=16 to write AO, iMemory_AO base address, // device memory base address, I/O count. // Timeout = 500 ms if(iRet==NoError) printCom1("Write AO ok.\n\r"); else printCom1("Write AO error! Error code=%d\n\r",iRet); } iNextProcess=0; break; default: iNextProcess=0; break; } return iNextProcess; } void Modbus_Request_Event(char* CommandData,int* CommandLength) { /* Modbus_Request_Event is supported since version 1.6.8 [2007,03,13]. char* CommandData: For Modbus/TCP, it includes 6 leading bytes. (needful) For Modbus/RTU, it includes 6 leading bytes. (needless) int* CommandLength: For Modbus/TCP, it includes 6 leading bytes. For Modbus/RTU, it includes 6 leading bytes. */ /* Example code */ //int i; //printCom1("FC:%2d StartAddress:%3d IOCount:%4d\n\r",iModbusRequest_Fun, iModbusRequest_Addr,iModbusRequest_IOCount); //printCom1("Modbus Request\n\r In==>"); //for(i=0;i<*CommandLength;i++) // printCom1("[%02X] ",CommandData[i]&0xFF); } void Modbus_Response_Event(char* ResponseData,int* ResponseLength) { /* char* ResponseData: For Modbus/TCP, it includes 6 leading bytes. For Modbus/RTU, it doesn't include 6 leading bytes int* CommandLength: For Modbus/TCP, it includes 6 leading bytes. For Modbus/RTU, it doesn't include 6 leading bytes */ //If you want to change the content of the ResponseData, //you have to do 2 steps for Modbus/TCP or Modbus/RTU. //Step1: Change content (Note:you must know the modbus protocol well) //ResponseData[6]=0x19; //ResponseData[7]=0x75; //ResponseData[8]=0x04; //ResponseData[9]=0x01; //Step2: Update data length //*ResponseLength=10; //int i; //printCom1("\n\r Out==>"); //for(i=0;i<*ResponseLength;i++) // printCom1("[%02X] ",ResponseData[i]&0xFF); //printCom1("\n\r"); }