Modbus ASCII achieve multi-master applications

1, update the design
on the original protocol stack limitations when used in the presence of the master Modbus ASCII and Modbus RTU is the same, so we do not analyze its shortcomings, only discuss the updated design. We will define the master station and the access to the common object, when we use in a particular application, then a special case into a specific master and slave objects.

First, we consider the main station, the main station every object in principle we plan corresponds to a port on our equipment, here refers to the serial port. So in the same port, which is under a particular master, we can define a plurality of different addresses from the station. But on a different port may have an address from the same station. As shown below:

 

We can see from the figure above, our aim is to make the protocol stack support, multi-master and multi-slave, and in different master, the slave address is repeated unaffected. See depending on the object from a master station can manage 254 in FIG slave objects, but also by the fact that the load capacity.

Next we also need to consider the slave object. Master two types of operation is nothing more than slaves: read and write information from the station information from the station. For reading the information from the station, the master station needs to send a request command, waits for the response information returned from the station, the master station then analyzes the received information and updates the corresponding parameter values. There are two things we consider, the first response message is not returned to the corresponding register address, so in order to resolve the location register when the command transmitted must be known, in order to facilitate resolution will be stored in order from the object station. Second when parsing the response, if the response is similar to the two commands can not distinguish, so we also need to remember what the previous command Yes. It is also stored in the object from the station.

As for the write operation from the station, whether written request from where, the protocol stack is certainly other data processing process sent me, after the receipt of the request is what we need to record a master control station from which a What parameters. We do not distinguish between the main station, the main station because each process is independent of the process, but for the slaves and the parameters we need to distinguish. Each master station addresses can take is 0 to 255, but the 0 and 255 have been defined, it is actually 1-254. So we use a 256-bit variables, each corresponding to the station number to mark its request if there is need to write. Recording the master station, as follows:

 

In fact, we are not likely to use the 256 flags as Modbus ASCII itself is a simple application set. We use 256 flags, mainly on account of the range of the station address to facilitate the operation of the software-dependent. There each request flag write slave parameters, we will be stored in each slave objects, as different from the station may have very different, more flexible storage to each slave convenient.

2. Coding
We have designed our update, then we have to implement it according to this design. We operate mainly from the following aspects: First, the master station to achieve the object type and the object type from the station; and instantiation object instantiated from the second station, the master object; third, read out from the master station during operation; fourth, during the write operation from the master station. Next we will examine each describe it.

2.1, the definition of the object type
and at the same Modbus RTU, Modbus ASCII protocol stack in a package, we need to define the master station and the slave target objects, naturally, will inevitably have to define both types.

First we define the local master type, whose members include: a write uint32_t slave flag array; field number of slaves; slave sequence field; Patron slave station through the list management; 4 data update function pointer. Defined as follows:

/ * Define a local master object type ASCII * /

typedef struct LocalASCIIMasterType{

  uint32_t flagWriteSlave [8]; // write station controls a flag, up to 256 stations, corresponds to the station address.

  uint16_t slaveNumber; // number of slave stations from the list

  uint16_t readOrder; // current from a standing position from the station list

  ASCIIAccessedSlaveType * pSlave; // slave list

  UpdateCoilStatusType pUpdateCoilStatus; // update the amount of coil functions

  UpdateInputStatusType pUpdateInputStatus; // update state quantity input function

  UpdateHoldingRegisterType pUpdateHoldingRegister; // update function of the amount of holding register

  UpdateInputResgisterType pUpdateInputResgister; // update the input register vector function

}ASCIILocalMasterType;

About Master object type, in the previous update the design has been said very clearly, only two fields need to explain. First, the slave station from the list of objects is used to record Patron station managed. Second, readOrder field indicates the current position in the list of access from the stand, while the length of the number of stations slaveNumber object from that list. Specifically as shown below:

 

Also you need to define the object from the station, which indicates really Slaves object simply for convenience and the master station. From the station list is the master of this object. Specific structure is as follows:

/ * ASCII definitions are accessed from the station object type * /

typedef struct AccessedASCIISlaveType{

  uint8_t stationAddress; // station address

  uint8_t cmdOrder; // current command in the command list

  The total number of list command // command; uint16_t commandNumber

  uint8_t (* pReadCommand) [17]; // Read command list

  uint8_t * pLastCommand; // command once sent

  uint32_t flagPresetCoil; // flag preset control coil

  uint32_t flagPresetReg; // flag preset control register

}ASCIIAccessedSlaveType;

About three fields need to explain the slave object. First, we take a look at "read the list of commands (uint8_t (* pReadCommand) [17])" field, and Modbus RTU different, it is 17 bytes, which is determined by the Modbus ASCII message format. as follows:

 

There is flagPresetCoil and flagPresetReg field. These two fields are used to represent the coil and the holding register write request.

2.2, instantiate an object
we define a master slave type of object that is, we need to instantiate these objects during use. In general a hardware port we will be instantiated as a master object.

ASCIILocalMasterType hgraMaster;

/ * Initialize ASCII Master Object * /

InitializeASCIIMasterObject(&hgraMaster,2,hgraSlave,NULL,NULL,NULL,NULL);

And a master management objects 1-254 slave objects, we may be composed of an array of a plurality of slave stations from the target object instance and assigns it to the master station management.

ASCIIAccessedSlaveType hgraSlave[]={{1,0,2,slave1ReadCommand,NULL,0x00,0x00},{2,0,2,slave2ReadCommand,NULL,0x00,0x00}};

Therefore, according to the master and slave instantiated conditions, we need to instantiate a complete instantiation of the master station objects from the object to. Initializing the master station, here the data processing function pointer 4 is initialized to NULL, there is a default handler will be copied to it, the function is a continuation of the previous version, while simplifying the operation simple applications. A pointer to the command transmitted from the station is also assigned NULL, because the initial command, had not sent.

2.3, read operation from the station
read from the station and principle of operation is the same as the previous version. Transmitting a command to the slave and then the received message is parsed in a certain order. We were on the master and slave managed by definition, it will send a command to save objects from the station, from the station list stored in the master object, so we need to be modified analytic functions.

/ * Server analyzes the received corresponding information * /

void ParsingAsciiSlaveRespondMessage(AsciiLocalMasterType *master,uint8_t *recievedMessage, uint8_t *command,uint16_t rxLength)

{

    int i=0;

    int j=0;

    uint8_t *cmd=NULL;

   

    / * Determines whether Modbus ASCII message * /

    if (0x3A != recievedMessage[0])

    {

        return ;

    }

 

    / * * Is determined whether the message is complete receiver /

    if ((rxLength < 17) || (recievedMessage[rxLength - 2] != 0x0D) || (recievedMessage[rxLength - 1] != 0x0A))

    {

        return ;

    }

 

    uint16_t length = rxLength - 3;

    uint8_t hexMessage[256];

 

    if (!CovertAsciiMessageToHex(recievedMessage + 1, hexMessage, length))

    {

        return ;

    }

   

    / * Check the received data is correct * /

    if (!CheckASCIIMessageIntegrity(hexMessage, length/2))

    {

        return ;

    }

   

    / * Code is wrong determining function * /

    FunctionCode fuctionCode = (FunctionCode)hexMessage[1];

    if (CheckFunctionCode(fuctionCode) != MB_OK)

    {

        return;

    }

 

    if ((command == NULL)||(!CheckMessageAgreeWithCommand(recievedMessage, command)))

    {

        while(i<master->slaveNumber)

        {

            if(master->pSlave[i].stationAddress==hexMessage[0])

            {

                break;

            }

            i++;

        }

       

        if(i>=master->slaveNumber)

        {

            return;

        }

   

        if((master->pSlave[i].pLastCommand==NULL)||(!CheckMessageAgreeWithCommand(recievedMessage,master->pSlave[i].pLastCommand)))

        {

            j=FindAsciiCommandForRecievedMessage(recievedMessage,master->pSlave[i].pReadCommand,master->pSlave[i].commandNumber);

     

            if(j<0)

            {

                return;

            }

     

            cmd=master->pSlave[i].pReadCommand[j];

        }

        else

        {

            cmd=master->pSlave[i].pLastCommand;

        }

    }

    else

    {

        cmd=command;

    }

 

    uint8_t hexCommand[256];

    CovertAsciiMessageToHex(cmd + 1, hexCommand, 14);

 

    uint16_t startAddress = (uint16_t)hexCommand[2];

    startAddress = (startAddress << 8) + (uint16_t)hexCommand[3];

    uint16_t quantity = (uint16_t)hexCommand[4];

    quantity = (quantity << 8) + (uint16_t)hexCommand[5];

 

    if ((fuctionCode >= ReadCoilStatus) && (fuctionCode <= ReadInputRegister))

    {

        HandleAsciiSlaveRespond[fuctionCode - 1](master,hexMessage,startAddress,quantity);

    }

}

The main part of the analytic function is to check whether the received message is legitimate Modbus ASCII message. No problem checking station is called protocol parsing. The data handler is the last call that we need to write in specific applications. When the front of the main station initialization, we initialize the callback function is NULL, the weakening of the actual function definitions are accounted for in the protocol, it is necessary to achieve the specific operation of address registers and variables. Particular note is that when parsing Modbus ASCII messages, after removal of the characters at the beginning and end of the character, ASCII code needs to be converted into a binary number to complete resolution.

2.4, write slave operation
written after the other is in the process of requesting, we need to identify the object and then write the unitary slave operation. Specific identification of the slave to which the write is stored in the master instance. And the need to write a variable which is recorded in the slave station from the examples.

Therefore, the process detects the need to write a bit set corresponding to the slaves, i.e. corresponding to the change in position flagWriteSlave. Which variables need to write the bit corresponding to the station and flagPresetReg flagPresetCoil is labeled. These modifications are implemented in other processes to identify changes in the request, and specific write operation is in the process of this Master station, a change is detected flag uniformly implemented.

This part of the protocol stack without modifying code, since each station are variable and each object associated DETAILED As so modified the particular application.

3, return validation
view of the similarities Modbus ASCII and Modbus RTU, we designed the same network structure. But considering the general Modbus ASCII communications for the small amount of data, so we designed a relatively simple slaves. Therefore, we designed the network: establishing stack two hosts, each from two management stations, each of the coils from station 8 and two holding registers. FIG specific configuration:

 

We know from the figure, the gateway needs to implement Modbus Modbus slave for communications and a upper level; need to implement two Modbus master for communication and the lower bits.

In this experiment, we read nothing needs to be said, only need to send a return message to parse command. Therefore, we describe the midpoint for ease of operation, the need to write consecutive segments, we only found after the first write request to a location, it will write data continuously subsequent write-once. Write the modified flag code is as follows:

/ * Modify the control station to enable an amount of from coil * /

static void PresetSlaveCoilControll(uint16_t startAddress,uint16_t endAddress)

{

  if((8<=startAddress)&&(startAddress<=15)&&(8<=endAddress)&&(endAddress<=15))

  {

    ModifyWriteRTUSlaveEnableFlag(&hgraMaster,hgraMaster.pSlave[0].stationAddress,true);

   

    if((startAddress<=8)&&(8<=endAddress))

    {

      hgraMaster.pSlave[0].flagPresetCoil|=0x01;

    }

    if((startAddress<=9)&&(9<=endAddress))

    {

      hgraMaster.pSlave[0].flagPresetCoil|=0x02;

    }

    if((startAddress<=10)&&(10<=endAddress))

    {

      hgraMaster.pSlave[0].flagPresetCoil|=0x04;

    }

    if((startAddress<=11)&&(11<=endAddress))

    {

      hgraMaster.pSlave[0].flagPresetCoil|=0x08;

    }

    if((startAddress<=12)&&(12<=endAddress))

    {

      hgraMaster.pSlave[0].flagPresetCoil|=0x10;

    }

    if((startAddress<=13)&&(13<=endAddress))

    {

      hgraMaster.pSlave[0].flagPresetCoil|=0x20;

    }

    if((startAddress<=14)&&(14<=endAddress))

    {

      hgraMaster.pSlave[0].flagPresetCoil|=0x40;

    }

    if((startAddress<=15)&&(15<=endAddress))

    {

      hgraMaster.pSlave[0].flagPresetCoil|=0x80;

    }

  }

 

  if((16<=startAddress)&&(startAddress<=23)&&(16<=endAddress)&&(endAddress<=23))

  {

    ModifyWriteRTUSlaveEnableFlag(&hgraMaster,hgraMaster.pSlave[1].stationAddress,true);

    if((startAddress<=16)&&(16<=endAddress))

    {

      hgraMaster.pSlave[1].flagPresetCoil|=0x01;

    }

    if((startAddress<=17)&&(17<=endAddress))

    {

      hgraMaster.pSlave[1].flagPresetCoil|=0x02;

    }

    if((startAddress<=18)&&(18<=endAddress))

    {

      hgraMaster.pSlave[1].flagPresetCoil|=0x04;

    }

    if((startAddress<=19)&&(19<=endAddress))

    {

      hgraMaster.pSlave[1].flagPresetCoil|=0x08;

    }

    if((startAddress<=20)&&(20<=endAddress))

    {

      hgraMaster.pSlave[1].flagPresetCoil|=0x10;

    }

    if((startAddress<=21)&&(21<=endAddress))

    {

      hgraMaster.pSlave[1].flagPresetCoil|=0x20;

    }

    if((startAddress<=22)&&(22<=endAddress))

    {

      hgraMaster.pSlave[1].flagPresetCoil|=0x40;

    }

    if((startAddress<=23)&&(23<=endAddress))

    {

      hgraMaster.pSlave[1].flagPresetCoil|=0x80;

    }

  }

 

  if((24<=startAddress)&&(startAddress<=31)&&(24<=endAddress)&&(endAddress<=31))

  {

    ModifyWriteRTUSlaveEnableFlag(&hgpjMaster,hgpjMaster.pSlave[0].stationAddress,true);

    if((startAddress<=24)&&(24<=endAddress))

    {

      hgpjMaster.pSlave[0].flagPresetCoil|=0x01;

    }

    if((startAddress<=25)&&(25<=endAddress))

    {

      hgpjMaster.pSlave[0].flagPresetCoil|=0x02;

    }

    if((startAddress<=26)&&(26<=endAddress))

    {

      hgpjMaster.pSlave[0].flagPresetCoil|=0x04;

    }

    if((startAddress<=27)&&(27<=endAddress))

    {

      hgpjMaster.pSlave[0].flagPresetCoil|=0x08;

    }

    if((startAddress<=28)&&(28<=endAddress))

    {

      hgpjMaster.pSlave[0].flagPresetCoil|=0x10;

    }

    if((startAddress<=29)&&(29<=endAddress))

    {

      hgpjMaster.pSlave[0].flagPresetCoil|=0x20;

    }

    if((startAddress<=30)&&(30<=endAddress))

    {

      hgpjMaster.pSlave[0].flagPresetCoil|=0x40;

    }

    if((startAddress<=31)&&(31<=endAddress))

    {

      hgpjMaster.pSlave[0].flagPresetCoil|=0x80;

    }

  }

 

  if((32<=startAddress)&&(startAddress<=39)&&(32<=endAddress)&&(endAddress<=39))

  {

    ModifyWriteRTUSlaveEnableFlag(&hgpjMaster,hgpjMaster.pSlave[1].stationAddress,true);

    if((startAddress<=32)&&(32<=endAddress))

    {

      hgpjMaster.pSlave[1].flagPresetCoil|=0x01;

    }

    if((startAddress<=33)&&(33<=endAddress))

    {

      hgpjMaster.pSlave[1].flagPresetCoil|=0x02;

    }

    if((startAddress<=34)&&(34<=endAddress))

    {

      hgpjMaster.pSlave[1].flagPresetCoil|=0x04;

    }

    if((startAddress<=35)&&(35<=endAddress))

    {

      hgpjMaster.pSlave[1].flagPresetCoil|=0x08;

    }

    if((startAddress<=36)&&(36<=endAddress))

    {

      hgpjMaster.pSlave[1].flagPresetCoil|=0x10;

    }

    if((startAddress<=37)&&(37<=endAddress))

    {

      hgpjMaster.pSlave[1].flagPresetCoil|=0x20;

    }

    if((startAddress<=38)&&(38<=endAddress))

    {

      hgpjMaster.pSlave[1].flagPresetCoil|=0x40;

    }

    if((startAddress<=39)&&(39<=endAddress))

    {

      hgpjMaster.pSlave[1].flagPresetCoil|=0x80;

    }

  }

 

}

As with the Modbus RTU is a write request in a write request flag and the corresponding parameter set modification process request from the write request flag station. Detection flag bit is then in the process of the master object, is achieved according to the operating state of the flag.
--------------------- 

Guess you like

Origin www.cnblogs.com/ly570/p/10961093.html