/* MBDemo01: Convert DCON protocol of I-7000 series to Modbus/RTU protocol Compiler: BC++ 3.1 Compile mode: large Project: MBDemo01.c ..\Lib\7188XBL.Lib ..\Lib\MBR7Bnnn.Lib, with nnn being the version of Modbus/RTU library. Communication: Modbus Master <= Modbus/RTU => COM1 of 7188XB (You can change the Uplink port) <==> [Converter Kernel] <==> COM2 of 7188XB <==> I-7000 series modules This program has 3 main functions 1. 1 to N port Modbus/RTU converter One COM port is used to receive Modbus/Request from Modbus/RTU master. Other COM ports are used to link to Modbus/RTU slave devices. When gets Modbus/RTU request, the kernel can decide to send request to which COM port and return the response to the Modbus/RTU master. 2. X board supports Modbus/RTU protocol Modbus/RTU master can send request to specific NetID(station number) to access the X board that mount on io expansion bus. 3. Supports user-defined registers The internal registers are open for X board and user-defined process. You can use the internal register to store some special information. Thus, the Modbus/RTU master can access the special internal registers. Hardware: 7188XB + I-7017 + I-7024 I-7017: RS-485 address : 1 RS-485 baudrate: 115200 Checksum: disable input range: any data format: 2's complement I-7024 RS-485 address : 2 RS-485 baudrate: 115200 Checksum: disable output range: any data format: engineer Memory mapping iMemory_AI[00]~[07] <====> I-7017 Ch0~Ch7 iMemory_AO[00]~[03] <====> I-7024 Ch0~Ch3 [2004,Aug,05] by Kevin modify comment in ScanUserProcess [2006,Feb,17] by Kevin Use new I/O memory mapping method. */ #include #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; int iPort2Device; int iUserProcess=0; 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,_ModbusRTU_Slave); Set_COMEnableMode(2,_Programming); // **** 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 // Scans user-define process, // stores results to memory(internal registers). iUserProcess=ScanUserProcess(iUserProcess); } } /***************************/ /* [ScanUserProcess] */ /* for 7188E/7188EXB */ /* version 1.2.0 */ /* date: 9,Aug,2002 */ /***************************/ int ScanUserProcess(int iProcess) { // iProcess: executes which process? // return: executes which process next time? // // This function scans your special processes and stores the results // to the memory. Thus, users can use Modbus protocol to // read the memory to get the values of your special processes. // You should cut the hole scan process to many small processes. // That can reduce execution time of this function and // speed up the scan rate. // // The total internal registers spaces is limited by // constant MAX_REGISTER_COUNT in MBRTU_7B.h. You can change the number // to increase the total spaces. // // Xboard and user's process share the internal registers. // To use the internal registers, you must notice don't overlap // the registers. // // To program the COM port, you need to use the Modbus Utility to set // the COM port enable mode to programming mode. // To program the COM port, you need to use the Modbus Utility to set // the COM port enable mode to programming mode. int iPort,iRet,iValue,i; int iNextProcess; float fValue; char sInputBuf[80]; switch(iProcess) { // Analog input ==> Memory // I-7017(#1) ch0~ch7 ==> iMemory_AI[0]~iMemory_AI[7] case 0: if(mtModbusPort[2].EnableMode==_Programming) { // to read I-7017(#01) that connect to COM2 of 7188E SendCmdTo7000(2,"#01",0); // COM2, read I-7017(#01), checksum disable iRet=ReceiveResponseFrom7000_ms(2,sInputBuf,3000,0); // COM2, bufer to receive response, timeout, // checksum disable // one channel uses 4 bytes, first byet is '>'. // data format of I-7017 must be set to [2's complement] // that can make the response string shorter. // // +32767(7FFF) ==> maximum value, for example +10.0V // -32768(8000) ==> minimum value, for example -10.0V // You can use 7000 Utility to change the maximum value and minimum value. //for(i=0;i<=33;i++) // printCom(1,"%c",sInputBuf[i]); //printCom(1,"\n\r"); if(sInputBuf[0]=='>' && iRet==0) { for(i=0;i<8;i++) { iMemory_AI[i]=(int)((ascii_to_hex(sInputBuf[i*4+1])<<12) +(ascii_to_hex(sInputBuf[i*4+1+1])<<8) +(ascii_to_hex(sInputBuf[i*4+1+2])<<4) +(ascii_to_hex(sInputBuf[i*4+1+3]))); } } } iNextProcess=1; break; // Memory ==> analog out // iMemory_AO[0] ==> I-7024(#2) ch0 case 1: if(mtModbusPort[2].EnableMode==_Programming) { // to write I-7024(#02) that connect to COM2 of 7188E // pass iMemory_AO[0] to channel 0 of I-8024 // // +32767(7FFF) ==> maximum value, for example +10.0V // -32768(8000) ==> minimum value, for example -10.0V // You can use 7000 Utility to change the maximum value and minimum value. fValue=(float)iMemory_AO[0]/32768*10.0; // 10.0 means the maximum value sprintf(sInputBuf,"#020%+06.3f",fValue); // Ch0 SendCmdTo7000(2,sInputBuf,0); // COM2, write 7024, checksum disable iRet=ReceiveResponseFrom7000_ms(2,sInputBuf,3000,0); // COM2, bufer to receive response, timeout, // checksum disable } iNextProcess=2; break; // Memory ==> analog out // iMemory_AO[1] ==> I-7024(#2) ch1 case 2: if(mtModbusPort[2].EnableMode==_Programming) { // to write I-7024(#02) that connect to COM2 of 7188E // pass iMemory_AO[1] to channel 1 of I-8024 // // +32767(7FFF) ==> maximum value, for example +10.0V // -32768(8000) ==> minimum value, for example -10.0V // You can use 7000 Utility to change the maximum value and minimum value. fValue=(float)iMemory_AO[1]/32768.0*10.0; // 10.0 means the maximum value sprintf(sInputBuf,"#021%+06.3f",fValue); // Ch1 SendCmdTo7000(2,sInputBuf,0); // COM2, write 7024, checksum disable iRet=ReceiveResponseFrom7000_ms(2,sInputBuf,3000,0); // COM2, bufer to receive response, timeout, // checksum disable } iNextProcess=3; break; // Memory ==> analog out // iMemory_AO[2] ==> I-7024(#2) ch2 case 3: if(mtModbusPort[2].EnableMode==_Programming) { // to write I-7024(#02) that connect to COM2 of 7188E // pass iMemory_AO[2] to channel 2 of I-8024 // // +32767(7FFF) ==> maximum value, for example +10.0V // -32768(8000) ==> minimum value, for example -10.0V // You can use 7000 Utility to change the maximum value and minimum value. fValue=(float)iMemory_AO[2]/32768*10.0; // 10.0 means the maximum value sprintf(sInputBuf,"#022%+06.3f",fValue); // Ch2 SendCmdTo7000(2,sInputBuf,0); // COM2, write 7024, checksum disable iRet=ReceiveResponseFrom7000_ms(2,sInputBuf,3000,0); // COM2, bufer to receive response, timeout, // checksum disable } iNextProcess=4; break; // Memory ==> analog out // iMemory_AO[3] ==> I-7024(#2) ch3 case 4: if(mtModbusPort[2].EnableMode==_Programming) { // to write I-7024(#02) that connect to COM2 of 7188E // pass iMemory_AO[3] to channel 3 of I-8024 // // +32767(7FFF) ==> maximum value, for example +10.0V // -32768(8000) ==> minimum value, for example -10.0V // You can use 7000 Utility to change the maximum value and minimum value. fValue=(float)iMemory_AO[3]/32768*10.0; // 10.0 means the maximum value sprintf(sInputBuf,"#023%+06.3f",fValue); // Ch3 SendCmdTo7000(2,sInputBuf,0); // COM2, write 7024, checksum disable iRet=ReceiveResponseFrom7000_ms(2,sInputBuf,3000,0); // COM2, bufer to receive response, timeout, // checksum disable } 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; //printCom(4,"FC:%2d StartAddress:%3d IOCount:%4d\n\r",iModbusRequest_Fun, iModbusRequest_Addr,iModbusRequest_IOCount); //printCom(4,"Modbus Request\n\r In==>"); //for(i=0;i<*CommandLength;i++) // printCom(4,"[%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; //printCom(4,"\n\r Out==>"); //for(i=0;i<*ResponseLength;i++) // printCom(4,"[%02X] ",ResponseData[i]&0xFF); //printCom(4,"\n\r"); }