Need help configuring soil ph sensor with rs485 output

I have a soil pH sensor with rs485 output that is connected to MAX485 and ESP32. I'm having a bit of a problem as the serial monitor doesn't show the correct value (Just random characters that is not supposed to be showing)

This is the Datasheet for the sensor

and this is my code:

#include <ModbusMaster.h>

#define RE 5   // GPIO 5
#define DE 6   // GPIO 6

const byte ph[] = {0x01, 0x03, 0x00, 0x0D, 0x00, 0x01, 0x15, 0xC9};
byte values[2];  // Assuming the response is 2 bytes
ModbusMaster node;

void setup() {
  Serial.begin(4800);  // Adjust the baud rate to 4800
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  digitalWrite(RE, LOW);   // Set RE low for receiving data
  digitalWrite(DE, LOW);   // Set DE low for receiving data
  node.begin(1, Serial);    // Node ID 1, use hardware serial for communication

  // Wait for the serial connection to be established
  while (!Serial) {
    delay(10);
  }

  Serial.println("Serial communication established.");
}

void loop() {
  // Send inquiry frame to the soil pH sensor
  sendInquiryFrame();

  // Wait for a response from the soil pH sensor
  delay(500);  // Adjust the delay as needed

  // Read and process the response
  if (readResponse()) {
    // Calculate pH value from the received data
    uint16_t pHRaw = (values[0] << 8) | values[1];
    float pHValue = pHRaw / 100.0;  // Assuming the pH value is represented as a two-decimal fixed-point number

    Serial.print("Soil pH: ");
    Serial.println(pHValue, 2);  // Print pH value with 2 decimal places
  } else {
    Serial.println("Failed to read from the soil pH sensor.");
  }

  delay(3000);
}

void sendInquiryFrame() {
  // Enable DE to send data
  digitalWrite(DE, HIGH);

  // Send inquiry frame to the soil pH sensor
  if (Serial.write(ph, sizeof(ph)) != sizeof(ph)) {
    Serial.println("Failed to send inquiry frame.");
  }

  delay(2);  // Allow time for transmission to complete
  digitalWrite(DE, LOW);  // Disable DE to receive data
}

bool readResponse() {
  digitalWrite(DE, LOW);
  digitalWrite(RE, HIGH);
  delay(10);
  
  // Read the response from the soil pH sensor
  for (byte i = 0; i < 2; i++) {
    if (Serial.available()) {
      values[i] = Serial.read();
      Serial.print(values[i], HEX);
    } else {
      Serial.println("Timeout waiting for response byte.");
      return false;
    }
  }
  Serial.println();

  digitalWrite(RE, LOW);

  // Check if the expected number of bytes are received
  return (Serial.available() == 0);
}

The following are the pinouts for the max485 for more reference: DI - GPIO19 DE - GPIO6 RE - GPIO5 RO - GPIO21

i tried using the other inquiry frame from the datasheet and also connecting and disconnecting the pins but it still persists. Any form of criticisms is much appreciated

Did inquiry frame send successfully? Or you see this message:

Did you code print the response bytes or it experienced the timeout?
By the way, your "timeout" code is incorrect, it didn't wait for any timeout and exits just if serial do not receive a byte immeditially.

this is the one that shows in my serial monitor

This is the wiring my soil pH sensor to MAX485


the brown and black wire which is positive and negative respectively are connected to a 12v power supply and the Yellow and Blue which is the A and B is connected into the A and B port of the Max485 (The wires are coated in metal jacket if that helps)

Indeed!
You can't use the same Serial for RS485 and for output messages to the Monitor.
As a result, neither one nor the other will work for you.

The Serial is busy for outputting messages to the computer, to work with RS485 you need to select a different serial port - for example a Serial2 on pins 16 and 17

1 Like

hi, can you elaborate more on this solution? thank you

replace your setup() function to this code:

Connect your RS485 to pins 16 and 17
Do not forget to setup correct baudrate in Arduino Serial Monitor - 115200

Some observations that may help you:

As already mentioned, you need 2 separate serial ports - 1 to handle your Serial.print output and another to communicate with your RS485 sensor.

The datasheet indicates that the default baud rate is 9600 baud (see section 3.1).

You need to be careful in your handling of the RE & DE signals. Generally RE & DE operate as a pair - either both LOW (receive) or both HIGH (transmit). If you only drive DE HIGH (and keep RE LOW) when transmitting, then your receiver will hear its own transmission which you will need to ignore. This doesn't happen if you also drive RE HIGH when transmitting.

You are on the right track here. However, using a delay like this can lead to the transmission being cut short or the transceiver still being in transmit mode when the remote device tries to respond. Have a look at Serial.flush() rather than using delay().

The response from the sensor consists of a Modbus reply message. See the response frame in section 3.4 where you will see a 7 byte response and the location of the pH value in that response.

2 Likes

Thank you! Ill look into this further and reply a output

Hi, i've tried this solution and this is the output that comes out of the serial monitor:
image

This is the wiring diagram of the Max485 to ESP32 that i did:

DI - GPIO 16
DE - GPIO 6
RE - GPIO 5
RO - GPIO 17

This output is from ESP32 booting process, it has nothing to do with your code.
The messages from your program should start from

"Serial communication established."

line.

If you don't see this text - it means your program doesn't start correctly.

That's exactly what is happening.....The booting process just keeps repeating endlessly

According to this info using GPIO6-GPIO11 is strictly not recommended

1 Like

I changed the pinout for my max485:

DI - GPIO22
RE - GPIO5
DE - GPIO23
RO - GPIO13

Now this is the output that i am getting:

image

This is the full code:

#include <ModbusMaster.h>
#include <WiFi.h>

#define RE 5   // GPIO 5
#define DE 23   // GPIO 23

ModbusMaster node;

#define RXD2 22
#define TXD2 13

void setup() {
  Serial.begin(115200);  
  Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);   // Set baud rate to 115200
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  digitalWrite(RE, LOW);   // Set RE low for receiving data
  digitalWrite(DE, LOW);   // Set DE low for receiving data
  node.begin(1, Serial2);    // Node ID 1, use hardware serial for communication

  // Wait for the serial connection to be established
  while (!Serial) {
    delay(10);
  }

  Serial.println("Serial communication established.");
}

void loop() {
  // Send inquiry frame to the soil pH sensor
  if (sendInquiryFrame()) {
    // Wait for a response from the soil pH sensor
    delay(10);  // Adjust delay as needed
    if (node.available()) {
      node.receive();
      uint16_t pHValue = node.getResponseBuffer(0x00);  // Assuming response starts at register 0x00
      Serial.print("Soil pH: ");
      Serial.println(pHValue / 100.0, 2);  // Convert to float and print with 2 decimal places
    } else {
      Serial.println("Failed to read from the soil pH sensor.");
    }
  } else {
    Serial.println("Failed to send inquiry frame.");
  }

  delay(3000);
}

bool sendInquiryFrame() {
  // Enable DE to send data
  digitalWrite(DE, HIGH);

  // Send inquiry frame to the soil pH sensor
  if (node.writeMultipleRegisters(0x00, 1) != node.ku8MBSuccess) {
    Serial.println("Failed to send inquiry frame.");
    return false;
  }

  delay(2);  // Allow time for transmission to complete
  digitalWrite(DE, LOW);  // Disable DE to receive data
  return true;
}

Did you finally find the solution?

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