|
|
View previous topic :: View next topic |
Author |
Message |
AnthonyRFC
Joined: 21 Jun 2015 Posts: 16 Location: Venezuela
|
MODBUS simple question |
Posted: Sun Mar 13, 2016 7:41 am |
|
|
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: 19520
|
|
Posted: Sun Mar 13, 2016 2:55 pm |
|
|
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
|
|
Posted: Sun Mar 13, 2016 3:18 pm |
|
|
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
|
|
Posted: Mon Mar 14, 2016 3:20 am |
|
|
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
|
|
Posted: Mon Mar 14, 2016 5:04 am |
|
|
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
|
|
Posted: Thu Mar 17, 2016 6:57 am |
|
|
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
|
|
Posted: Fri Mar 18, 2016 5:38 am |
|
|
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
|
|
Posted: Wed Mar 23, 2016 9:00 pm |
|
|
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. |
|
|
|
|
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
|