/* MB_X304: Modbus/RTU controller + X304 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 <==> Modbus/RTU slave device 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 + X304 Memory mapping iMemory_DI[00]~[03] <====> X304 DI Ch0~Ch3 iMemory_DO[00]~[03] <====> X304 DO Ch0~Ch3 iMemory_AI[00]~[02] <====> X304 DI Ch0~Ch2 iMemory_AO[00]~[00] <====> X304 DO Ch0~Ch0 [22,Apr,2003] 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" #include "..\Lib\Xboard\X304.h" int iScanUserProcess=0; int iScanXboardProcess=0; int ScanUserProcess(int iProcess); int ScanXboard(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); Set_COMEnableMode(1,_ModbusRTU_Slave); //(COM1 be a Modbus/RTU slave port) Set_COMEnableMode(2,_ModbusRTU_Slave); //(COM2 be a Modbus/RTU slave port) // **** End Modbus configuration ***** iRet=InitModbus(iMemory_DI,iMemory_DO,iMemory_AI,iMemory_AO); if(iRet) return iRet; X304_Init(); 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 iUserProcess=ScanUserProcess(iUserProcess); // Scans user-define process, // stores results to memory(internal registers). iScanXboardProcess=ScanXboard(iScanXboardProcess); // Change this if you don't // plug a X board on expansion bus. } } /***************************/ /* [ScanUserProcess] */ /* for 7188E/7188XB */ /* version 1.0.1 */ /* 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 MBTCP_7E.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. int iPort,iRet,i; int iNextProcess; switch(iProcess) { case 0: // Add user's process here. // For example, add CRC error number to AI register. iMemory_AI[0x10]=0x7188; //Address 0x10 is an example, //you can change it to suit your application. iNextProcess=1; break; case 1: // Add user's process here // For example, add Timeout error number to AI register. iMemory_DI[0x11]=1; //Address 0x11 is an example,=1 to set DI[0x11]=high. //you can change it to suit your application. iNextProcess=0; break; default: iNextProcess=0; break; } return iNextProcess; } /***************************/ /* [ScanXboard] */ /* for 7188E/7188XB */ /* version 1.0.1 */ /* date: 9,Aug,2002 */ /***************************/ int ScanXboard(int iProcess) { /* iProcess: executes which process? return: executes which process next time? This function scans the X board and stores the results to the memory. Thus, users can use Modbus protocol to read the memory to get the values of the Xboard. 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 MBTCP_7E.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. For X304 Memory mapping iMemory_DI[00]~[03] <====> X304 DI Ch0~Ch3 iMemory_DO[00]~[03] <====> X304 DO Ch0~Ch3 iMemory_AI[00]~[02] <====> X304 DI Ch0~Ch2 iMemory_AO[00]~[00] <====> X304 DO Ch0~Ch0 */ int i,iNextProcess; float fValue; int iValue; switch(iProcess) { case 0: // Analog input ==> memory (Ch0) fValue=X304_AnalogIn(0); iMemory_AI[0]=(int)(fValue/5.0*32767.0); // +/-5 ==> +/-32767 iNextProcess=1; break; case 1: // Analog input ==> memory (Ch1) fValue=X304_AnalogIn(1); iMemory_AI[1]=(int)(fValue/5.0*32767.0); // +/-5 ==> +/-32767 iNextProcess=2; break; case 2: // Analog input ==> memory (Ch2) fValue=X304_AnalogIn(2); iMemory_AI[2]=(int)(fValue/5.0*32767.0); // +/-5 ==> +/-32767 iNextProcess=3; break; case 3: // Memory ==> analog output (Ch0) fValue=(float)iMemory_AO[0]/32767.0*5.0; // +/-5 ==> +/-32767 X304_AnalogOut(0,fValue); iNextProcess=4; break; case 4: // Digital input ==> memory iValue=X304_DigitalIn(); for(i=0;i<4;i++) // X304 has 4 DI channels { if((iValue&0x01)!=0) iMemory_DI[i]=1; else iMemory_DI[i]=0; iValue>>=1; } iNextProcess=5; break; case 5: //Memory ==> digital output iValue=0; for(i=0;i<4;i++) // X304 has 4 DO channels if(iMemory_DO[i]!=0) iValue+=(1<"); //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"); }