Half duplex Modbus RS485 Continually send the string

Hi,

I am trying to control led over Modbus RS485 (Half duplex). My sender is Arduino nano and receiver is UNO. I used softserial for communication. With attached example everything working fine.

Now I want to on/off the led on receiver. My challenge are:

  1. Handle the continually send the string due to for loop on sender board.

  2. Instead of continually I want to send one string when button is press and wait for next push.

  3. Receiver side hold the status of led OR toggle the led based on received string.

Mainly issue is below string

static String teststring = "RS485"; // Serial Communication is easy!";

                                                  // Continually send the test string with a pause at the end
  for (unsigned int cnt = 0; cnt < teststring.length(); cnt++) {

                                                  // Get the next character to send
    txValue = teststring[cnt];
    Serial.print("Sending:");Serial.println(char(txValue));

I want to send specific string with push toggle button.

Thanks,

Receiver slave.txt (2.37 KB)

Sender Master.txt (2.91 KB)

loop() is just what the name indicates: it executes in an endless loop.

If you want something to happen only once, set a flag when it should be done, test the flag and do it once and reset the flag afterwards. Also see the StateChangeDetection example.

#define baudRate    115200
SoftwareSerial RS485(RS485rx, RS485Tx);
RS485.begin(baudRate);

If you need a baud rate higher than 9600, use a hardware serial interface.

I am trying to control led over Modbus RS485 (Half duplex).

What you're doing in these sketches has nothing to do with ModBus it's a simple serial transmission. Your setup with SoftwareSerial will horribly fail if ModBus is used. SoftwareSerial blocks the complete processor during complete byte transfers, so the timing for true ModBus cannot be established. If you just use two Arduinos and do simple RS-485 traffic it might work this way but don't count on it.

Thanks Pylon for your comment. I am trying to control simple ON / OFF led on receiver board which also send feedback to transmitter. These led on off with push button which hold the status of button also. My sketches are attached below and working fine as expected.

But my way of dealing with code is difficult So I want to fix these button and status in array (transmitter side) as 3rd attachment but receiver side I didn't receive anything.

How i can shorter the sender code. Suggest me because I am not good in coding.

Thanks,

rece.ino (3.05 KB)

sender_debounce.ino (14.2 KB)

Master_full_controll.ino (5.9 KB)

In your new code the routines ActA() and ActB() are never called. As they are the only code that sends anything to the RS485 interface, nothing is ever sent.

As these two routines are identical with the exception of the character to be sent you can combine them into one routine which accepts the txValue as a parameter.

They send only letter "A" and "B" and receiver act based on received letter. If you can help me to modify the below section of code where I am facing problem. I try to make array of textstring but did not succeed. My target to send the string from array when push the related button in array.

 static String teststring = "B"; // Serial Communication is easy!";

  // Continually send the test string with a pause at the end
  for ( int i = 0; i < 1; i++) {

    // Get the next character to send
    txValue = teststring[i];
    Serial.print("Sending:"); Serial.println(char(txValue));

DrDiettrich:
loop() is just what the name indicates: it executes in an endless loop.

If you want something to happen only once, set a flag when it should be done, test the flag and do it once and reset the flag afterwards. Also see the StateChangeDetection example.

I add the flag status change in array format it work fine on transmitter side ( like A0/A1 and B0/B1 OFF/ON) but did not receive anything on receiver side. I think due to " Serial.print(txValue*); " here lost the byte and data should be send in byte which I try to do but something is wrong if you can correct me.*
My transmitter code is Below:
```
*#include "Arduino.h"

// Library to allow a Serial port on arbitrary pins
#include <SoftwareSerial.h>

// These are the pins we'll be talking to the RS485 device on
#define RS485rx    3 // RS485 Receive pin
#define RS485Tx   4 // RS485 Transmit pin
#define RS485inout  2 // RS485 Transmit or Receive status

#define RS485Transmit HIGH
#define RS485Receive  LOW
#define ledPin      13
#define baudRate    115200

//////////////Btn***//////////////////

boolean LED_state[4] = {0}; // stores the states of the LEDs
boolean PState[4] = {0}; // stores the states of the LEDs

// Define the RS485 object
SoftwareSerial RS485(RS485rx, RS485Tx);

// The data bytes we're sending or receiving
byte rxValue;
byte txValue;

// -----------------------------------------------------------------
// SETUP         SETUP         SETUP         SETUP         SETUP
// -----------------------------------------------------------------
void setup() /****** SETUP: RUNS ONCE ******/
{
 // Debugging window
 Serial.begin(9600);

// switches

pinMode(5, INPUT_PULLUP);
 pinMode(6, INPUT_PULLUP);
 pinMode(7, INPUT_PULLUP);
 pinMode(8, INPUT_PULLUP);

// LEDs
 pinMode(9, OUTPUT);
 pinMode(10, OUTPUT);
 pinMode(11, OUTPUT);
 pinMode(12, OUTPUT);

// Set modes for pins
 pinMode(ledPin, OUTPUT);
 pinMode(RS485inout, OUTPUT);

// Ensure the on-board LED is off
 digitalWrite(ledPin, HIGH);

// Set RS485 device to read initially
 digitalWrite(RS485inout, RS485Receive);

// Set the baud rate. The longer the wire the slower you should
 // set the transmission rate. Anything here:
 // 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250,
 // 38400, 57600, and 115200
 // MUST BE THE SAME AS THE SENDER UNIT!
 RS485.begin(baudRate);
}

// -----------------------------------------------------------------
// LOOP     LOOP     LOOP     LOOP     LOOP     LOOP     LOOP
// -----------------------------------------------------------------
void loop()
{
 ButtonDebounce();
}

void ButtonDebounce(void)
{
 static byte buttonState[4]     = {LOW, LOW, LOW, LOW, };   // the current reading from the input pin
 static byte lastButtonState[4] = {LOW, LOW, LOW, LOW, };   // the previous reading from the input pin

char txValue[4] = {'A', 'B', 'C', 'D'};

// the following variables are long's because the time, measured in miliseconds,
 // will quickly become a bigger number than can be stored in an int.
 static long lastDebounceTime[8] = {0};  // the last time the output pin was toggled
 long debounceDelay = 50;         // the debounce time; increase if the output flickers

byte reading[4];

reading[0] = digitalRead(5);
 reading[1] = digitalRead(6);
 reading[2] = digitalRead(7);
 reading[3] = digitalRead(8);

for (int i = 0; i < 4; i++) {
   if (reading[i] != lastButtonState[i]) {
     // reset the debouncing timer
     lastDebounceTime[i] = millis();
   }

if ((millis() - lastDebounceTime[i]) > debounceDelay) {
     // whatever the reading is at, it's been there for longer
     // than the debounce delay, so take it as the actual current state:

// if the button state has changed:
     if (reading[i] != buttonState[i]) {
       buttonState[i] = reading[i];

// only toggle the LED if the new button state is HIGH
       if (buttonState[i] == HIGH) {
         LED_state[i] = !LED_state[i];
         PState[i] = !PState[i];
         Serial.print(txValue[i]);
         Serial.println(PState[i]);

}
     }
   }
 }

// set the LEDs
 digitalWrite(9, LED_state[0]);
 digitalWrite(10, LED_state[1]);
 digitalWrite(11, LED_state[2]);
 digitalWrite(12, LED_state[3]);

// save the reading.  Next time through the loop,
 // it'll be the lastButtonState:
 lastButtonState[0] = reading[0];
 lastButtonState[1] = reading[1];
 lastButtonState[2] = reading[2];
 lastButtonState[3] = reading[3];
}

void ActA()
{

char teststring[] = "R"; // Serial Communication is easy!";
 txValue = teststring[0];
 Serial.print("Sending:"); Serial.println(char(txValue));

// Set the RS485 to transmit mode and send the value
 digitalWrite(RS485inout, RS485Transmit);
 RS485.write(txValue);

// small delay to allow transmission to complete
 delay(1);

// Switch RS485 to receive mode
 digitalWrite(RS485inout, RS485Receive);
 while (!RS485.available());
 // After each character is sent look for a received answer
 if (RS485.available())
 {
   // LED flicker
   digitalWrite(ledPin, HIGH);

// Read the incoming byte
   rxValue = RS485.read();

// Display it on the Serial Monitor as a char (not an integer value)
   Serial.print("Got back:"); Serial.println(char(rxValue));

// Turn off LED
   digitalWrite(ledPin, LOW);  // Show activity

// Debugging delay so we can follow activity
   delay(100);
 }
}

void ActB()
{
 char teststring[] = "S"; // Serial Communication is easy!";
 txValue = teststring[0];
 Serial.print("Sending:"); Serial.println(char(txValue));

// Set the RS485 to transmit mode and send the value
 digitalWrite(RS485inout, RS485Transmit);
 RS485.write(txValue);

// small delay to allow transmission to complete
 delay(1);

// Switch RS485 to receive mode
 digitalWrite(RS485inout, RS485Receive);
 while (!RS485.available());
 // After each character is sent look for a received answer
 if (RS485.available())
 {
   // LED flicker
   digitalWrite(ledPin, HIGH);

// Read the incoming byte
   rxValue = RS485.read();

// Display it on the Serial Monitor as a char (not an integer value)
   Serial.print("Got back:"); Serial.println(char(rxValue));

// Turn off LED
   digitalWrite(ledPin, LOW);  // Show activity

// Debugging delay so we can follow activity
   delay(100);
 }
}*
```

static String teststring = "B"; // Serial Communication is easy!";

Don't use the String class on Arduinos, it will fragment your memory and sooner or later your sketch fails.

Use C-type strings:

char *teststring = "B";
for (i = 0; i < strlen(teststring); i++) {
  Serial.print(teststring[i]);
}

Although using a string for one character doesn't make much sense.

It's not a good idea to use strlen() in the loop condition, because it computes the length with every invocation. It's simpler to wait for the trailing \0 byte in the string.

pylon:

static String teststring = "B"; // Serial Communication is easy!";

Don't use the String class on Arduinos, it will fragment your memory and sooner or later your sketch fails.

Use C-type strings:

char *teststring = "B";

for (i = 0; i < strlen(teststring); i++) {
 Serial.print(teststring[i]);
}




Although using a string for one character doesn't make much sense.

Yes I can change String with < RS485.write('B'); > when button is pressed send ' B ' its working fine. But I am looking to send the flag with this letter like B0 / B1 as I attached the sketch #6 . with this code receiver receive 02 message A and 1 I want to get these in one message.

In simple I can say how we can send more than one string in one message.