Grove-RS485 interface with arduino Mega

Does anybody know how to interface Grove RS 485 on arduino Mega

Can I use this PCB to send data to the motor driver via arduino similar as with MAX RS485

On Grove RS485 not existing DE and RE

I've not used this particular board, but some RS485 modules that don't have /RE & DE have some sort of auto switching built in that switches the RS485 line driver from Rx to Tx and back again.

I had a quick look at the schematic for this one and I can't figure out how it switches into receive mode as it looks like both /RE and DE are pulled high all the time.

Looking at the connector on the left, you supply VCC & GND and your Tx + Rx serial data lines. If the code you have references RE & DE, then you could either comment that out or assign them to unused pins.

1 Like

If I use standart example from library

/*

  RS485_HalfDuplex.pde - example using ModbusMaster library to communicate
  with EPSolar LS2024B controller using a half-duplex RS485 transceiver.

  This example is tested against an EPSolar LS2024B solar charge controller.
  See here for protocol specs:
  http://www.solar-elektro.cz/data/dokumenty/1733_modbus_protocol.pdf

  Library:: ModbusMaster
  Author:: Marius Kintel <marius at kintel dot net>

  Copyright:: 2009-2016 Doc Walker

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

#include <ModbusMaster.h>

/*!
  We're using a MAX485-compatible RS485 Transceiver.
  Rx/Tx is hooked up to the hardware serial port at 'Serial'.
  The Data Enable and Receiver Enable pins are hooked up as follows:
*/
#define MAX485_DE      3
#define MAX485_RE_NEG  2

// instantiate ModbusMaster object
ModbusMaster node;

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}

void setup()
{
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);

  // Modbus communication runs at 115200 baud
  Serial.begin(115200);

  // Modbus slave ID 1
  node.begin(1, Serial);
  // Callbacks allow us to configure the RS485 transceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

bool state = true;

void loop()
{
  uint8_t result;
  uint16_t data[6];
  
  // Toggle the coil at address 0x0002 (Manual Load Control)
  result = node.writeSingleCoil(0x0002, state);
  state = !state;

  // Read 16 registers starting at 0x3100)
  result = node.readInputRegisters(0x3100, 16);
  if (result == node.ku8MBSuccess)
  {
    Serial.print("Vbatt: ");
    Serial.println(node.getResponseBuffer(0x04)/100.0f);
    Serial.print("Vload: ");
    Serial.println(node.getResponseBuffer(0xC0)/100.0f);
    Serial.print("Pload: ");
    Serial.println((node.getResponseBuffer(0x0D) +
                    node.getResponseBuffer(0x0E) << 16)/100.0f);
  }

  delay(1000);
}

What code can I expect ? )
Thanks

I have a similar module and they switch to TX driver when serial data is detected on the Arduino side. After TX transmission, it returns back to RX.

1 Like

Great, can you share an example of code you have been used ?)

If your board is an auto switcher, then you can use any code unmodified, like you posted in #3. Just make sure that you aren't using the pins that are designated for RE & DE. If you are, then simply reassign to unused pins.

You don't need a special library for it

can you share some example ?
My existing project looks as it is

and Code

#include <ModbusMaster.h>


//RS485 //DI  TX0 //DE  pin3 //RE  pin2//R0  RX0
//ENCODER 

//RS485
#define MAX485_DE      3
#define MAX485_RE_NEG  2

// instantiate ModbusMaster object
ModbusMaster node;
void preTransmission()   {digitalWrite(MAX485_RE_NEG, 1);digitalWrite(MAX485_DE, 1);}
void postTransmission()   {digitalWrite(MAX485_RE_NEG, 0);digitalWrite(MAX485_DE, 0);}
uint8_t result,j;
uint16_t data[6];
//RS485
volatile unsigned int temp; //this variable will increase or decrease depending on the rotation of encoder
int counter = 0; // initial point of rotary encoder
int candleLenght = 1040; // Lenght -> signal  for cutting candle
int RELAY1 = 8; // relay for something else
int x; // var for operate RELAY1 on/off
boolean runMotorOneTime = false; //for running motor once

unsigned long currentMillis;

  //LED
  const int ledPin40 =  40; //cut signal millis
  const int ledPin41 =  41; //watchdog green 
  int ledState40 = HIGH; // ledState used to set the LED
  int ledState41 = LOW; // ledState used to set the LED
   long previousMillisWDOG = 0;
   long watchDogInterval = 250;
   
   long previousMillisCutLED = 250;
   long CutLedInterval = 250;
  
   
     int S1; //button status for candle L
     int S2; //button status for candle L
     int S3; //button status for candle L
  
void setup() {
  //candle lenght buttons
  pinMode(31, INPUT); //S1
  pinMode(32, INPUT); //S2
  pinMode(33, INPUT); //S3
  //Encoder
  pinMode(21, INPUT_PULLUP); // internal pullup input pin  21
  pinMode(20, INPUT_PULLUP); // internal pullup input pin  20
  //Setting up interrupt A rising pulse from encodenren activated ai0(). AttachInterrupt 2 is DigitalPin nr 20.
  attachInterrupt(2, ai0, RISING); //0 & 1 taken by RS485
  //B rising pulse from encodenren activated ai1(). AttachInterrupt 3 is DigitalPin nr 21.
  attachInterrupt(3, ai1, RISING); //0 & 1 taken by RS485
  //Encoder
 
  //RS 485
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
  //RS 485
  Serial.begin (9600);
  Serial1.begin (38400);
  Serial.println("Serail Ready");
  
  pinMode(RELAY1, OUTPUT);
  digitalWrite(RELAY1, HIGH);   //RELAY 1 is OFF

  // Modbus slave ID 1
  node.begin(1, Serial1);
  // Callbacks allow us to configure the RS485 transceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);

    writeMotorParams();
    delay(1000);
    readMotorParams();
//    delay(500);

  S1 = digitalRead(31);
  S2 = digitalRead(32);
  S3 = digitalRead(33);
}

void loop() {
 currentMillis = millis(); 
 runMotor();
    
    
  //value of counter from encoder
//  if( counter != temp ){
//   //candleLenghtButton(); 
//  temp = counter;
//
//  //Serial.println (temp); //<-- if uncomment runMotor() not run at all, serial is buisy
//  }

}




/*****************************************************************************
 ******* ANGLE ENCODER COLLECT DATA AND PASS FOR CUTTING SIGNAL *************
 *****************************************************************************/
void ai0() {
  if (digitalRead(21) == LOW) {
    
    counter++;
    
   //Serial.println(counter);
    //if (counter % candleLenght == 0 ) { //activate cutCandle for RUN motor
    if (counter % candyL(S1,S2,S3) == 0 ) { //activate cutCandle for RUN motor
      x = !x;

      cutCandle(x);//cut candle RUN motor + var y for relay to do something else
     }
  } else {
    //counter--; //we do not want count anticlockwise
  }
}

void ai1() {
  if (digitalRead(20) == LOW) { 
    //counter--; //we do not want count anticlockwise
  } else {
    
    counter++;
     
 // Serial.println(counter);
  
      //if (counter % candleLenght == 0 ) { //activate cutCandle for RUN motor
      if (counter %  candyL(S1,S2,S3) == 0 ) { //activate cutCandle for RUN motor
      x = !x;  
  
      cutCandle(x);//cut candle RUN motor + var y for relay to do something else
      

    }
  }
}

/*****************************************************************************
 *************************** CUT CANDLE **************************************
 *****************************************************************************/
int cutCandle(unsigned int x) {
  
  if (x == 1) { 
    runMotorOneTime = false;
     digitalWrite(RELAY1, HIGH);  //relay for something else OFF
     // Serial.println(currentTime);
     //Serial.println("activate cutting solenoid OFF"); //<--lagging if uncomment
  
     counter = 0;
  }
  if (x == 0) {
    runMotorOneTime = false;
    digitalWrite(RELAY1, LOW);  //relay for something else ON
  
    //Serial.println(currentTime);

    //Serial.println("activate cutting solenoid ON"); //<--lagging if uncomment
    counter = 0;   
  
  }

}

/*****************************************************************************
 *************************** MOTOR DATA **************************************
 *****************************************************************************/
void writeMotorParams() { //Setup the motor driver after hard reset
  //308 = 0x0134 fan of driver 1off
  //901 = 0x0385
  //902 = 0x0386
  //903 = 0x0387 RPM
  result = node.writeSingleRegister(0x0004, 8); delay(50);
  result = node.writeSingleRegister(0x0134, 1); delay(50);
  result = node.writeSingleRegister(0x0385, 0); delay(50);
  result = node.writeSingleRegister(0x0386, 1000); delay(50);
  result = node.writeSingleRegister(0x0387, 300); delay(50);

}

void readMotorParams() {
  result = node.readHoldingRegisters(0x0386, 1); // Control mode selection
  if (result == node.ku8MBSuccess){ 
    Serial.println("***SOME PARAMETER : ***" );
    for (j = 0; j < 1; j++) {
      data[j] = node.getResponseBuffer(j);
      Serial.print("Control Mode selection P00.04 => "); Serial.print(j); Serial.println(data[j]);
    }
  } 
}




void runMotor(){ //MOTOR ON
 if (runMotorOneTime == false){       
    ledCutSignal();
    ledWatchDog();
 
     result = node.writeSingleRegister(0x0384, 1);
   
     node.clearResponseBuffer();//if not clear can lagging
     Serial1.flush();//if not clear can lagging

    runMotorOneTime = true;//stop motor exit from method
    Serial.println("MOTOR => CUT ON"); 
    
    //Serial.println(millis()); 
    //delay(25);
    }
  }



  void ledWatchDog(){
    
    if(currentMillis - previousMillisWDOG > watchDogInterval) {
    // save the last time you blinked the LED 
    previousMillisWDOG = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState41 == LOW)
      ledState41 = HIGH;
    else
      ledState41 = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin41, ledState41);
  }
  }


  
  void ledCutSignal(){
   
   if(currentMillis - previousMillisCutLED > CutLedInterval) {
    // save the last time you blinked the LED 
    previousMillisCutLED = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState40 == LOW)
      ledState40 = HIGH;
    else
      ledState40 = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin40, ledState40);
  }
  }



/*****************************************************************************
 *************************** CANDLE LENGHT ***********************************
 *****************************************************************************/
  int candyL(int s1, int s2, int s3 ){
    long l;
    
    if(s1 == 0 && s2 == 0 &&  s3 == 0) // 0-0-0
      l = 1040;
    
    else if(s1 == 1 && s2 == 0 &&  s3 == 0) // 1-0-0
      l = 1140;
    
    else if(s1 == 1 && s2 == 0 &&  s3 == 1) // 1-0-1
      l = 1240;
    
    else if(s1 == 1 && s2 == 1 &&  s3 == 0) // 1-1-0
      l = 1340;
    
    else if(s1 == 1 && s2 == 1 &&  s3 == 1) // 1-1-1
      l = 1440;
    
    else if(s1 == 0 && s2 == 1 &&  s3 == 1) // 0-1-1
      l = 1540;
    
    else if(s1 == 0 && s2 == 0 &&  s3 == 1) // 0-0-1
      l = 1640;
    
    else if (s1 == 0 && s2 == 1 &&  s3 == 0) // 0-1-0
      l = 2000;
    
     else 
      l = 1000;
 
    return l;
  }
 /*****************************************************************************
 *************************** CANDLE LENGHT ***********************************
 *****************************************************************************/

Simple replacement Max RS485 to Grove RS485 dosent works, for some reason...

You might want to correct your hand drawn wiring diagram to get the 5V going to VCC on the RS485 module and run a GND to it as well.

As for why the Grove module doesn't work, I can't see from the schematics how it switches into receive mode. It must do but I can't see it....

Oh. sorry. wrong file (working, delete it)
This is a full diagram

I want to use Grove rs 485 in my configuration instead of Max rs485
But simple swap dosent helps......

Your RS485 wiring looks correct for a "normal" RS485 module.

Sorry to keep banging on about it but I can't see how the Grove module switches into receive mode as both /RE and DE are pulled high to +V. This is the relevant part of the schematic in case anybody else has an idea of why it's not working for you.

No problem with MAX RS 485

The problem comes up if I swap to grove-rs485, also I can see that on grove rs485 flickering only TX led, may be it is normal, I am using first time this pcb.
Have tried already 2 pcbs same issue, no any data passing to the motor driver...

Grove RS 485

That would tie in with the board being in permanent transmit mode due to /RE & DE being pulled high (according to the schematic). I must be missing something very obvious because controlling the direction of a half-duplex RS485 transceiver is such a basic thing, whether done automatically in electronics or manually through RE & DE pins.

Hopefully some other forum members like @pylon with more Modbus knowledge can shed some light on this issue and point out where we're going wrong, because it shouldn't be this hard to get RS485 working!

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.