View previous topic :: View next topic |
Author |
Message |
greenbridge
Joined: 14 May 2018 Posts: 19
|
Modbus holding registers map |
Posted: Wed Aug 07, 2019 7:36 am |
|
|
Hi,
I have a Modbus RTU master unit that reads and writes holding registers indexed between 200 and 203.
Is there a simple way to adapt ex_modbus_slave.c for such purpose without need for huge holding register arrays? |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Wed Aug 07, 2019 7:47 am |
|
|
You could make it so that if the function is to read or write holding registers, you just subtract 200 from your register address.
That should be a pretty simple modification to make in the switch statement of the example file. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Wed Aug 07, 2019 8:21 am |
|
|
The supplied 'modbus_read_holding_registers function will do this
without any issues.
The syntax is simple:
read_holding_registers
Input: int8 address Slave Address
int16 start_address Address to start reading from
int16 quantity Amount of addresses to read
Output: exception 0 if no error, else the exception
So in your case you just need to call it with 'start_address' set to 200
(query, guess this is probably 0x200?), and a 'quantity' of 4. |
|
|
greenbridge
Joined: 14 May 2018 Posts: 19
|
|
Posted: Wed Aug 07, 2019 8:25 am |
|
|
Please note that I need code for the slave unit. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Wed Aug 07, 2019 9:46 am |
|
|
greenbridge wrote: | Please note that I need code for the slave unit. |
Right, I was referring to the large switch statement inside the modbus slave example c program. In there, there are cases where you deal with the read and write holding registers. In there, you can specifically add some code to translate 200 to 203 down to 0 to 3 for example, by subtracting 200 from the part of the message that tells you the start register. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Wed Aug 07, 2019 1:29 pm |
|
|
The slave is just as easy. All you need to do, is where the slave code uses:
hold_regs+modbus_rx.data[1], just subtract 200 from the value from
modbus_rx.data[1].
Then in the entry line for this section, where it tests for the same value being >=8, test for it instead being <200 || >203. So it allows values from 200 to 203.
Obviously the variable is needed in both tests. |
|
|
greenbridge
Joined: 14 May 2018 Posts: 19
|
|
Posted: Thu Aug 08, 2019 2:48 am |
|
|
From some strange reason the slave does not accept offset higher than 128:
Code: | case FUNC_READ_HOLDING_REGISTERS:
case FUNC_READ_INPUT_REGISTERS:
if(modbus_rx.data[0] || modbus_rx.data[2] /* || modbus_rx.data[1] > 203*/)
modbus_exception_rsp(input_regs[INPUT_DETECTOR_ADDR],modbus_rx.func,ILLEGAL_DATA_ADDRESS);
else
{
if(modbus_rx.func == FUNC_READ_HOLDING_REGISTERS)
modbus_read_holding_registers_rsp(input_regs[INPUT_DETECTOR_ADDR],(modbus_rx.data[3]*2),hold_regs+modbus_rx.data[1]-127);
else{
// TODO: beräkna alarm level pct
adc_read(0);
modbus_read_input_registers_rsp(input_regs[INPUT_DETECTOR_ADDR],(modbus_rx.data[3]*2),input_regs+modbus_rx.data[1]);
}
}
break; |
Traffic:
Code: | [10:44:27] <= Response: 01 03 06 10 68 00 00 08 34 44 3B
[10:44:26] => Poll: 01 03 00 7F 00 03 34 13 |
Code: | case FUNC_READ_HOLDING_REGISTERS:
case FUNC_READ_INPUT_REGISTERS:
if(modbus_rx.data[0] || modbus_rx.data[2] /* || modbus_rx.data[1] > 203*/)
modbus_exception_rsp(input_regs[INPUT_DETECTOR_ADDR],modbus_rx.func,ILLEGAL_DATA_ADDRESS);
else
{
if(modbus_rx.func == FUNC_READ_HOLDING_REGISTERS)
modbus_read_holding_registers_rsp(input_regs[INPUT_DETECTOR_ADDR],(modbus_rx.data[3]*2),hold_regs+modbus_rx.data[1]-128);
else{
// TODO: beräkna alarm level pct
adc_read(0);
modbus_read_input_registers_rsp(input_regs[INPUT_DETECTOR_ADDR],(modbus_rx.data[3]*2),input_regs+modbus_rx.data[1]);
}
}
break; |
Traffic:
Code: | [10:46:32] <= Response: 01 03 06 00 00 00 00 00 00 21 75
[10:46:32] => Poll: 01 03 00 80 00 03 04 23 |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Thu Aug 08, 2019 2:53 am |
|
|
What chip are you compiling for?.
If this is a PIC24/30, the default for all integers is signed. So an int8, will
only support -127 to 128. You'd need to change the declarations of the buffer
arrays used for the data to unsigned int8, or BYTE (which default to unsigned
int8), instead of 'char'.
Have run into this repeatedly with char arrays on these chips... :( |
|
|
greenbridge
Joined: 14 May 2018 Posts: 19
|
|
Posted: Thu Aug 08, 2019 3:00 am |
|
|
I am compiling for PIC16F1518.
Last edited by greenbridge on Thu Aug 08, 2019 7:03 am; edited 1 time in total |
|
|
greenbridge
Joined: 14 May 2018 Posts: 19
|
|
Posted: Thu Aug 08, 2019 3:55 am |
|
|
From the supplied modbus_phy_layer.h:
Code: | struct
{
unsigned int8 address;
unsigned int8 len; //number of bytes in the message received
function func; //the function of the message received
exception error; //error recieved, if any
unsigned int8 data[MODBUS_SERIAL_RX_BUFFER_SIZE]; //data of the message received
} modbus_rx; |
All the integers are unsigned. It seems that the problem is caused somewhere else, or did I look in the right place? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Thu Aug 08, 2019 5:06 am |
|
|
Try bracketting:
hold_regs+(modbus_rx.data[1]-127));
hold_regs, is a pointer into RAM. Now if you add first, it is probable that it is
taken beyond the available end of the RAM 'area' by the addition, before the
subtraction is then done.
The internal knowledge of how large a pointer is allowed to be may be
interfering.
You have got #device *=16?.
Needed otherwise you are limiting memory address range to 8bits. |
|
|
greenbridge
Joined: 14 May 2018 Posts: 19
|
|
Posted: Thu Aug 08, 2019 5:45 am |
|
|
Thanks. Works fine for holding registers with offset 200.
Now I have a new problem (surprise!):
The input registers have offset 300.
Code: | 300 = 0b000100101100 |
is read by slave as
Do you have any suggestions which hardware would be suitable for this application? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Thu Aug 08, 2019 6:57 am |
|
|
Have you got the register array declared as int16 (it needs to be).
How old is your compiler?.
Critical question. Historically CCS had a fault, that pointers would increment
by one, whatever 'size' the variable being pointed to 'was'. This has been
fixed for a long while, but if your compiler predates this fix, then the
arithmetic to find the actual variable address would need to multiply
the index by two to be pointing to the right location.
Honestly, the PIC16 makes things very hard, any PIC18 would be a lot
better. Except for tiny applications, I'd use a PIC18 every time.... |
|
|
greenbridge
Joined: 14 May 2018 Posts: 19
|
|
Posted: Thu Aug 08, 2019 7:01 am |
|
|
I have quite new PC running Win10.
I tried to alter the data array definition in modbus_rx structure to unsigned int16 but it messes up the CRC. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Thu Aug 08, 2019 7:19 am |
|
|
Again how old is your compiler?.
Where have you sourced the code you are using?.
The standard slave example, with the current compilers has the array
declared as int16, for PCD, PCH & PCM based chips. I've looked back over
ten years at the examples, and they are all using 16bit arrays for the
registers.
They read the data from the receiving (byte) array using the
modbus_read_holding_registers function. They don't attempt to directly
use the receive array. |
|
|
|