das ist vermutlich ein anderes Problem. Du hältst die Zeitabstände nicht ein und liest zu schnell das nächste Register.
dirty:
mach ein delay(1000) vor dem zweiten readHoldingRegister.
hier hab ich ein Beispiel wie ich es meist mache.
Das postTransmission setzt eine Zeitmarke wann die Client->Server Kommunikation geendet hat
Das preTransmission prüft, ob genug zeit vergangen ist (und blockiert falls nicht erreicht).
Ist zwar auch blockierend, aber nur wenn es notwendig ist.
P.S.: Die "Wartezeit" soll abhängig von der Schnittstellengeschwindigkeit sein. Da gibts Vorgaben in der Modbus Spezifikation
Summary
*******************************************************
Modbus Client Example 0x50 (Modbus Master)
Using several Modbus Function Codes
This Modbus Client
- reads from Modbus Servers periodically and switches a local pin accordingly
- sends a new value to Modbus Servers when a button is pressed
hardware
- a LED
- 4 push buttons
- a MAX485-TTL adapter
by noiasca
2022-01-02
*******************************************************/
#include <ModbusMaster.h> // Modbus Master 2.0.0 by Doc Walker - install with Library Manager
// client and servers must know the same registers
enum
{
// just add or remove registers and your good to go
// The first register starts at address 0 which is for Function 3 Register 40001
regButton, // read a button
regADC0, // analog port 0
regLED, // set a LED
regServo, // set a Servo
HOLDING_REGS_SIZE // leave this one
};
// client specific
constexpr byte ledPinA = 13;
constexpr byte ledPinB = 16;
constexpr byte buttonPinA = A0;
constexpr byte buttonPinB = A1;
constexpr byte buttonServoPinA = A2;
constexpr byte buttonServoPinB = A3;
constexpr byte modbus_enable_pin = 5; // The GPIO used to control the MAX485 TX pin. Set to 255 if you are not using RS485 or a selfsensing adapter
constexpr uint32_t modbus_baud = 19200; // use slow speeds with SoftSerial
//constexpr byte rxPin = 2; // for Softserial
//constexpr byte txPin = 3;
uint32_t previousTx = 0;
uint16_t restTx = 15000; // rest time between transmissions - microseconds
ModbusMaster serverA; // instantiate ModbusMaster object - slave - node
void preTransmission()
{
while (micros() - previousTx < restTx)
{
yield(); // wait some time and do background tasks.
}
Serial.println();
digitalWrite(modbus_enable_pin, HIGH);
}
void postTransmission()
{
previousTx = micros(); // remember last timestamp
digitalWrite(modbus_enable_pin, LOW);
}
struct Input {
const byte buttonPin;
uint32_t previousMillis;
byte lastButtonState; // stores the true readed state
};
Input input[] {
{buttonPinA, 0, HIGH},
{buttonPinB, 0, HIGH},
{buttonServoPinA, 0, HIGH},
{buttonServoPinB, 0, HIGH},
};
/* *******************************************************
Serial Interface
* **************************************************** */
// if you don't have enough HW Serial (i.e. on an UNO)
// you are forced to use SoftwareSerial or AltSoftSerial
//include <SoftwareSerial.h>
//SoftwareSerial mySerial(rxPin, txPin);
byte stateChangeDetection(byte i) // returns true if change was changed
{
byte buttonState = digitalRead(input[i].buttonPin);
byte result = false;
// compare the buttonState to its previous state
if (buttonState != input[i].lastButtonState) {
result = true;
Serial.print(input[i].buttonPin); Serial.print(F(" is "));
if (buttonState == LOW) {
Serial.println(F("on"));
} else {
Serial.println(F("off"));
}
delay(50);// Delay a little bit to avoid bouncing
}
input[i].lastButtonState = buttonState; // save the current state as the last state, for next time through the loop
return result;
}
void handleButton()
{
int result = 0;
// if the button has changed, we send the (inversed) last state to the server
if (stateChangeDetection(0)) {
result = serverA.writeSingleCoil(regLED, !input[0].lastButtonState);
if (result != serverA.ku8MBSuccess)
{
Serial.print(F("E: ServerA no success register ")); Serial.println(regLED);
}
}
// send a random value to the servo register
if (stateChangeDetection(2) && input[2].lastButtonState == LOW) {
result = serverA.writeSingleRegister(regServo, random(256));
if (result != serverA.ku8MBSuccess)
{
Serial.print(F("E: ServerA no success register ")); Serial.println(regServo);
}
}
}
void requestData()
{
static uint32_t previousMillis = 0;
uint32_t currentMillis = millis();
if (currentMillis - previousMillis > 5000) // set the interval in ms
{
previousMillis = currentMillis;
uint16_t reg = regButton;
int result;
// slave: read (6) 16-bit registers starting at register 2 to RX buffer
//result = serverA.readHoldingRegisters(regButton, 2);
result = serverA.readHoldingRegisters(0, 1);
if (result == serverA.ku8MBSuccess) // do something if read is successfull
{
uint16_t value = serverA.getResponseBuffer(0);
Serial.println(value);
if (value) digitalWrite(ledPinA, HIGH); else digitalWrite(ledPinA, LOW);
value = serverA.getResponseBuffer(1); // we requested two registers, so we can print the ADC0 value also:
Serial.print(F("ADC0=")); Serial.println(value);
}
else
{
Serial.print(F(" ServerA no success register ")); Serial.print(regButton); Serial.print(F(" result=")); Serial.println(result, HEX);
}
reg = 1002;
result = serverA.readHoldingRegisters(reg, 2);
if (result == serverA.ku8MBSuccess) // do something with data if read is successful
{
uint16_t value = serverA.getResponseBuffer(0);
Serial.println(value);
}
else
{
Serial.print(F("E ServerA no success add register ")); Serial.print(reg); Serial.print(F(" result=")); Serial.println(result, HEX);
}
reg = 1002;
result = serverA.writeSingleRegister(reg, random(256));
if (result == serverA.ku8MBSuccess) // do something with data if read is successful
{
;
}
else
{
Serial.print(F("E ServerA no success add register ")); Serial.print(reg); Serial.print(F(" result=")); Serial.println(result, HEX);
}
reg = 2000;
byte noOfValues = 4;
result = serverA.readInputRegisters(reg, noOfValues); //FC4
if (result == serverA.ku8MBSuccess) // do something with data if read is successful
{
for (byte i = 0; i < noOfValues; i++)
{
Serial.print(serverA.getResponseBuffer(i));
Serial.print("\t");
}
Serial.println();
}
else
{
Serial.print(F("E ServerA no input register ")); Serial.print(reg); Serial.print(F(" result=")); Serial.println(result, HEX);
}
}
}
void setup()
{
Serial.begin(115200);
Serial.println(F("Modbus Client Example 0x50"));
for (auto & i : input) pinMode(i.buttonPin, INPUT_PULLUP);
// use Serial (port 0); initialize Modbus communication baud rate
Serial3.begin(modbus_baud);
serverA.begin(2, Serial3); // communicate with Modbus server ID 2 over the given Serial interface
// Init enable pins for modbus master library
pinMode(modbus_enable_pin, OUTPUT);
digitalWrite(modbus_enable_pin, LOW);
// Callbacks allow us to configure the RS485 transceiver correctly
serverA.preTransmission(preTransmission);
serverA.postTransmission(postTransmission);
// init local hardware
pinMode(ledPinA, OUTPUT);
pinMode(ledPinB, OUTPUT);
}
void loop()
{
handleButton();
requestData();
}