CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

MODBUS simple question

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
AnthonyRFC



Joined: 21 Jun 2015
Posts: 16
Location: Venezuela

View user's profile Send private message

MODBUS simple question
PostPosted: Sun Mar 13, 2016 7:41 am     Reply with quote

Hi all:

I have a simple question regarding the modbus library and its use.

**How I can read more than 8 inputs or coils status? Just making the int8 input to a bigger variable?

**How i do it when I have more that 32 inputs (using a long)?


My current CCS is ver 4.104


Best regards and thanks for your time!
_________________
From Cumaná, Venezuela.
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sun Mar 13, 2016 2:55 pm     Reply with quote

You need to use an array. Modbus itself only handles data as int16 values, and coils as int8. The write_multiple coils code, is happy to accept an array of up to 250bytes. Coil numbers are allowed to be up to 2000. The example is only an example. Look at how the register access code is done (which uses an array), but be aware that registers are accessed as 16bit objects, while coils are always organised as 8bit.
AnthonyRFC



Joined: 21 Jun 2015
Posts: 16
Location: Venezuela

View user's profile Send private message

PostPosted: Sun Mar 13, 2016 3:18 pm     Reply with quote

So I must group inputs into a byte? Later into an array?


Something like this?

Code:

int8 inputs[]={}
//...

...//
inputs[1]=(port_b);
inputs[2]=(port_c);

//(and so on..)




I'm a little confused around this.

Thanks for your help!
_________________
From Cumaná, Venezuela.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Mar 14, 2016 3:20 am     Reply with quote

The example code uses eight of each type of MODBUS endpoint, eight coils, eight discrete input with input registers, eight holding registers, etc.

A coil is a single bit output, on or off. The example organises eight of them into a single int8. A coil is a bit, not a byte. They may be written individually.

A discrete input is a single bit. A discrete input is a bit, not a byte. They may be read individually. The example organises eight of them into a single int8.

A input register is up to sixteen bits. It is intended for "live" data. The example organises eight of them in an array. They may be read or written.

A holding register is up to sixteen bits. They are intended for processed data. They may be read or written.

These are the main data types. Coils are not used as much now as they were when MODBUS was first developed. They perhaps are most useful for global on/off controls, interlocks and similar functions.

Input registers are also comparitively rarely used in modern MODBUS systems. They were are intended for live, changing data.

Holding registers are the most commonly used these days. They are simply sixteen (or less - you don't have to implement all bits of a register) bit data of any type. They are general purpose and were orginally intended for processed data that changed less often than live data. They can be used for calibration parameters, control and other stuff.

There can be many more of each than the example provides. The example, for simplicity, does just eight of each. They can be accessed individually or in arbitrarily large groups. The example code can be expanded to more than eight, but it takes a little thinking about.

There are various limits as to how many of each can be read and written at a time to do with message size limits and so on. The code may place its own limits, just as the example code does. The code should give sensible MODBUS error messages when an attempt is made to access an unimplemented coil, input or register.

You do not have to have actual arrays to contain all the data. I use virtualisation to implement many registers and coils, etc. and don't have arrays of coils, or bytes of coils, and arrays of int16s for holding registers. Instead I redirect the request for data to an appropriate routine. Its a bit like an object orientated approach, instead of accessing data that's necessarily a copy of something, I use access routines (get/set routines) to provide the latest data.

Here is a part of my example code derived code. This is for reading holding registers. I'm using an array of sixteen "scratch" registers to temporarily hold the data from my virtualised registers, read by Read_Register():


Code:

            case FUNC_READ_HOLDING_REGISTERS:
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
                  modbus_rx.data[1] >=  MAX_REGISTERS || modbus_rx.data[3]+modbus_rx.data[1] >  MAX_REGISTERS)
                  modbus_exception_rsp(Modbus_address, modbus_rx.func, ILLEGAL_DATA_ADDRESS);
               else
               {
                  // Read the registers into our holding area. Note we can only cope with up to 16.
                  for (Register_Address = 0; Register_Address < modbus_rx.data[3]; Register_Address++)
                  {
                     Scratch_Registers[Register_Address] = Read_Register(modbus_rx.data[1] + Register_Address);
                  }
               
                  // Send back the scratch copy of the registers.
                  modbus_read_holding_registers_rsp(Modbus_address,(modbus_rx.data[3]*2), Scratch_Registers);

                  event_count++;
               }
               break;
AnthonyRFC



Joined: 21 Jun 2015
Posts: 16
Location: Venezuela

View user's profile Send private message

PostPosted: Mon Mar 14, 2016 5:04 am     Reply with quote

Let me explain what I got and correct me if I'm wrong:

1.- Use the length of the request (modbus_rx.data[3]) in a for cycle to evaluate the actual data of inputs (coming from the ports of the PIC).

2.-Save the data into and array.

3.-Response to the master using that array.

Correct?

Thanks for your help!
_________________
From Cumaná, Venezuela.
AnthonyRFC



Joined: 21 Jun 2015
Posts: 16
Location: Venezuela

View user's profile Send private message

PostPosted: Thu Mar 17, 2016 6:57 am     Reply with quote

Hi.. I tried to modify the software and I'm getting the **TIME OUT error** using ModScan32.

First: I change the limit of the lenght to accept more than 8 addresses
Code:

      if((modbus_rx.address == MODBUS_ADDRESS) || modbus_rx.address == 0)
      {
      int16 start_adr=(modbus_rx.data[0]*256)+modbus_rx.data[1];
         switch(modbus_rx.func)
         {
         
         case FUNC_READ_COILS:    //read coils
            case FUNC_READ_DISCRETE_INPUT:    //read inputs
               if (start_adr>=512|| modbus_rx.data[2]||modbus_rx.data[3]+start_adr>512)





Second: I group all individual inputs into 4 bytes (I've 28 inputs) and put them into an array
.
Code:

 int8 data_puerto_[4];
                  data_a=(PORTA&0b00111110)>>1;
                  data_b=PORTE<<5;
                  data_puerto_[0]=~(data_b|data_a);//Inputs 1-8
                  data_a=((PORTC)&0b00011111);
                  data_b=(PORTD&0b00000111)<<5;
                  data_puerto_[1]=~(data_b|data_a);//Inputs 9-16
                  data_a=((PORTB&0b00000100)<<5)|((PORTD&0b11110000)>>1);
                  data_b=((PORTC&0b11100000)>>5);
                  data_puerto_[2]=~(data_a|data_b);//Inputs 17-24
                  data_a=(PORTB&0b01111000)>>3;
                  data_b=~(data_a);
                  data_puerto_[3]=(data_b&0b00001111); //Inputs 25-28

Third: Response to the master with the array.

Code:


 if(modbus_rx.func == FUNC_READ_COILS){
                     data = coils>>(modbus_rx.data[1]);      //move to the starting coil
                     data = data & (0xFF>>(8-modbus_rx.data[3]));  //0 out values after quantity
                     modbus_read_discrete_input_rsp(MODBUS_ADDRESS, 0x01, &data);
                  }
                  else{
                 
                  modbus_read_discrete_input_rsp(MODBUS_ADDRESS, 0x01, data_puerto_);             
                 
                  }


PD: I test the comunication using:

Code:

  data_a=(PORTA&0b00111110)>>1; //Take data and aply a mask
   data_b=PORTE<<5;                         
   inputs=data_b;


And it works perfect, no time out error, nothing!

PD2: I'm using CCS 4.104 and USB-RS485 cable.

My hardware: 16F877+MAX485


_________________
From Cumaná, Venezuela.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Fri Mar 18, 2016 5:38 am     Reply with quote

A few issues that need to be addressed:

Coils are single logic OUTPUTS: they can be written individually with FUNC_WRITE_SINGLE_COIL and in groups of arbitary size with FUNC_WRITE_MULTIPLE_COILS. The state of them can also be read back with FUNC_READ_COILS in groups or individually.

Discrete inputs are single logic INPUTS: They are NOT the same as coils, which are OUTPUTS. They may be read with FUNC_READ_DISCRETE_INPUT individually or as a group.

You have to implement all of these MODBUS standard functions even if it is something as simple as:

Code:

            case FUNC_READ_DISCRETE_INPUT:    //read inputs
               // There are no modbus inputs, therefore we always return an error.
               modbus_exception_rsp(Modbus_address,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               break;


as it is in some of my code.


Your code, as posted, mixes up discrete inputs with coils - they are very different things - and only deals with a set number of coils, not as individuals and groups of any (within reason) length. It also does not check that the request sets the required number of coils, and does not give correct error returns (MODBUS calls them "exceptions") for out of bounds commands. All these must be handled correctly before the code can be claimed to be "working".
AnthonyRFC



Joined: 21 Jun 2015
Posts: 16
Location: Venezuela

View user's profile Send private message

PostPosted: Wed Mar 23, 2016 9:00 pm     Reply with quote

RF_Developer wrote:
A few issues that need to be addressed:

Your code, as posted, mixes up discrete inputs with coils - they are very different things - and only deals with a set number of coils, not as individuals and groups of any (within reason) length. It also does not check that the request sets the required number of coils, and does not give correct error returns (MODBUS calls them "exceptions") for out of bounds commands. All these must be handled correctly before the code can be claimed to be "working".



Yes, you're right, but the first step was to communicate with the master (ModScan32).

Indeed, I have problems with the addressing of inputs, I don't know exactly how do it.

At the moment, I limit the slave software to respond only to the master from address 001 to the 32, and also check the length or amount of inputs requested (to modify how many bytes are sent).
Code:

   
                  if (modbus_rx.data[3]<=8){ //Here I check the length of the request
                  tx_len=1;                  //..and define how many bytes are sended.
                  }
                  if ((modbus_rx.data[3]>8)&&(modbus_rx.data[3]<=16)){
                  tx_len=2;
                  }
                  if ((modbus_rx.data[3]>16)&&(modbus_rx.data[3]<=24)){
                  tx_len=3;
                  }
                  if ((modbus_rx.data[3]>24)&&(modbus_rx.data[3]<=32)){
                  tx_len=4;
                  }
           
                 
                  if(modbus_rx.func == FUNC_READ_COILS){
                     data = coils>>(modbus_rx.data[1]);     
                   
                     modbus_read_discrete_input_rsp(MODBUS_ADDRESS, tx_len, &data);
                  }
                  else{
                  //data = inputs>>(modbus_rx.data[1]);
                  modbus_read_discrete_input_rsp(MODBUS_ADDRESS,tx_len, data_puerto_);             
                 
                  }





Thanks for your time and help!
_________________
From Cumaná, Venezuela.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group