I put some code together on an Arduino MEGA to read a Modbus interface, which provides some 100 values, which are then published via MQTT
The code runs nicely for a few months now.
However, the interface is polled every 10 seconds, which results in 600 values per minute, or 850,000 per day. A bit ridiculous, in particular noting, that some of these values do not change for days, while others update every second.
My idea is to store all values in an array, its register address, and a divisor. E.g., like so:
addr, old, divisor
8000, 12345, 10
8001, 23456, -10
8018, 9876, 1
The values are both int16 and uint16, stipulating I need two arrays?!
Or store all values as unsigned and convert to signed based on boolean flag?!
E.g.
addr, old, divisor, signed
8000, 12345, 10, 1
8001, 23456, -10, 0
8018, 9876, 1, 0
The register addresses are non-consecutive, and may not be queried at each loop.
I have never worked with multi-dimensional arrays, and wondered about their performance in C, or if there is a better way of doing this,
So why store the values? So that I can compare these, and only output a value, when the value has changed.
What is also not clear how to find the register address, which is not equal to the array index, and is also not sorted. The latter is beyond control as I could read a different amount of addresses per loop.
Should I create the array with the register addresses, given that I also need a divisor value per register as well as a boolean flag for signed int16?
Any hints appreciated.
An example of reading 17 registers:
void read_inverter ()
{
static const uint16_t start_address = 0x1f4f; // 8015
static const uint8_t number_of_registers = 17; // 8031
static uint8_t result = 1;
result = modbus.readHoldingRegisters(start_address, number_of_registers);
if (result == modbus.ku8MBSuccess)
{
if (1 == OUTPUT_VALUES_VIA_MQTT)
{
// AC_Inverter_Power
g_register_value_signed = (int16_t)modbus.getResponseBuffer(0x00);
g_register_address = start_address + 0;
data_publish_int(g_register_address, g_register_value_signed, 10);
// AC_Inverter_Current
g_register_value_signed = (int16_t)modbus.getResponseBuffer(0x01);
g_register_address = start_address + 1;
data_publish_int(g_register_address, g_register_value_signed, -10);
// Inverter_Reactive
g_register_value_signed = (int16_t)modbus.getResponseBuffer(0x02);
g_register_address = start_address + 2;
data_publish_int(g_register_address, g_register_value_signed, 10);
// Output_Status
g_register_value = (uint16_t)modbus.getResponseBuffer(0x03);
g_register_address = start_address + 3;
data_publish_uint(g_register_address, g_register_value, 1);
uint8_t i;
for (i = 4; i <= 6; i++)
{ // temp
g_register_value = (uint16_t)modbus.getResponseBuffer(i);
g_register_address = start_address + i;
data_publish_uint(g_register_address, g_register_value, -10);
}
g_register_value = (uint16_t)modbus.getResponseBuffer(0x07);
g_register_address = start_address + 7;
data_publish_uint(g_register_address, g_register_value, 1);
for (i = 8; i <= 11; i++)
{ // limits
g_register_value_signed = (int16_t)modbus.getResponseBuffer(i);
g_register_address = start_address + i;
data_publish_int(g_register_address, g_register_value_signed, 10);
}
for (i = 12; i <= 14; i++)
{ // status
g_register_value = (uint16_t)modbus.getResponseBuffer(i);
g_register_address = start_address + i;
data_publish_uint(g_register_address, g_register_value, 1);
}
g_register_value_signed = (int16_t)modbus.getResponseBuffer(0x0f);
g_register_address = start_address + 15;
data_publish_int(g_register_address, g_register_value_signed, 10);
g_register_value = (uint16_t)modbus.getResponseBuffer(0x10);
g_register_address = start_address + 16;
data_publish_uint(g_register_address, g_register_value, 1);
}
}
else
{
decode_error(result, start_address);
}
return;
} /* read_inverter () */
Yes, I am aware of the code smell, but have not found a better way yet.
I imagine the multi-dimensional array may allow for a function to emerge that simplifies the code.
[edit1] added board (MEGA)