/* MBDemo00: Modbus/RTU controller Compiler: BC++ 3.1 Compile mode: large Project: MBDemo01.c ..\Lib\7188XAL.Lib ..\Lib\MBR7Annn.Lib, with nnn being the version of Modbus/RTU library. Communication: Modbus Master <= Modbus/RTU => COM1 of 7188XA/XB (You can change the Uplink port) <==> [Converter Kernel] <==> COM2 of 7188XA/XB <==> 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: 7188XA [2006,Feb,17] by Kevin Use new I/O memory mapping method. */ #include "..\Lib\7188XA.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 XA 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); // Save COM3 setting to EEPROM ComData[3-1].baud=115200; ComData[3-1].databit=8; ComData[3-1].parity=0; ComData[3-1].stopbit=1; VcomSaveComData(3-1); // Save COM4 setting to EEPROM ComData[4-1].baud=115200; ComData[4-1].databit=8; ComData[4-1].parity=0; ComData[4-1].stopbit=1; VcomSaveComData(4-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 converter port) Set_COMEnableMode(2,_ModbusRTU_Slave); //(COM2 be a Modbus/RTU converter port) Set_COMEnableMode(3,_ModbusASCII_Slave); //(COM3 be a Modbus/ASCII converter port) Set_COMEnableMode(4,_ModbusASCII_Slave); //(COM4 be a Modbus/ASCII converter port) // **** End Modbus configuration ***** iRet=InitModbus(iMemory_DI,iMemory_DO,iMemory_AI,iMemory_AO); if(iRet) return iRet; // Put values to internal registers at initial. iMemory_AI[0]=0x7188; iMemory_AI[1]=0x4113; iMemory_AO[0]=0x1234; iMemory_AO[1]=0x5678; iMemory_DI[0]=12; // all non-zero values make DI high iMemory_DI[1]=1; // all non-zero values make DI high iMemory_DI[3]=0; // only 0 make DI low iMemory_DO[0]=1; // all non-zero values make DO hig iMemory_DO[1]=56; // all non-zero values make DO high iMemory_DO[2]=0; // only 0 make DO low 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). } } /*****************************/ /* [ScanUserProcess] */ /* for 7188E/7188XA/7188XB */ /* 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. int iPort; int iNextProcess; switch(iProcess) { case 0: // Add user's process here. // You can put some result values (integer) to AI register array. // For example, sets AI[0x19] to 0x7188. iMemory_AI[0x19]=0x7188; iNextProcess=1; break; case 1: // Add user's process here. // You can put some result values (0 or 1) to DI register array. // For example, sets DI[0x75] to 1 (high). iMemory_DI[0x75]=1; // Note: you must check if the register address // over range of the MAX_REGISTER_COUNT // constant that defined in MBTCP.h. iNextProcess=2; case 2: // Add user's process here. // For example, assume DI[0x04] is the alarm input. // If AO[0x04]>=0x7188, turn on the alarm input. if(iMemory_AO[0x04]>=0x7188) iMemory_DI[0x04]=1; else iMemory_DI[0x04]=0; iNextProcess=3; break; case 3: // Add user's process here. // you can read out DO register values to do something. // For example, if DO[0x01] is 1 (high), do something. if(iMemory_DO[0x01]==1) { // Do something } iNextProcess=0; break; // You can expand the User's Process to // suit your requirment. 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"); }