7 in one multiparameter soil sensor with esp32

hey values are showing mixed and sometimes it shows 255 for all parameters, can you please help me with it?

and the code i used is :

type or paste code here
`````#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/////
#define SCREEN_WIDTH 128    // OLED display width, in pixels
#define SCREEN_HEIGHT 64    // OLED display height, in pixels
#define OLED_RESET -1       // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
   

  
#define RE 13
#define DE 12
  
const byte nitro[] = {0x01, 0x03, 0x00, 0x87, 0x0E, 0x0E, 0x34, 0x37};
const byte phos[] = {0x01, 0x03, 0x00, 0x8A, 0x0E, 0x0E, 0x34, 0x37};
const byte pota[] = {0x01, 0x03, 0x00, 0x8E, 0x0E, 0x0E, 0x34, 0x37};
const byte soil_ph[] = {0x01, 0x03, 0x02, 0xAE, 0x0E, 0x0E, 0x34, 0x37};
const byte soil_moist[] = {0x01, 0x03, 0x01, 0x64, 0x0E, 0x0E, 0x34, 0x37};
const byte temp[] = {0x01, 0x03, 0xFF, 0xDD, 0x0E, 0x0E, 0x34, 0x37};
const byte ec[] = {0x01, 0x03, 0x04, 0xD2, 0x0E, 0x0E, 0x34, 0x37};

byte values[11];
HardwareSerial mod(2);  // Use Serial2 for RS485 communication
  
void setup() {
  Serial.begin(9600);
  mod.begin(9600, SERIAL_8N1, 16, 17); // Set the baud rate and pins for Serial2
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialize OLED display
  delay(500);
  display.clearDisplay();
  display.setCursor(25, 25);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.println(" Soil  Sensor");
  display.setCursor(25, 40);
  display.setTextSize(1);
  display.print("Initializing");

  display.display();
  delay(1000);
}

void loop() {
  byte val1, val2, val3, val4, val5, val6, val7;
  val1 = nitrogen();
  delay(250);
  val2 = phosphorous();
  delay(250);
  val3 = potassium();
  delay(250);
  val4 = ph();
  delay(250);
  val5 = moist();
  delay(250);
  val6 = stemp();
  delay(250);
  val7 = econd();
  delay(250);
   
  Serial.print("Nitrogen: ");
  Serial.print(val1);
  Serial.println(" mg/kg");
  Serial.print("Phosphorous: ");
  Serial.print(val2);
  Serial.println(" mg/kg");
  Serial.print("Potassium: ");
  Serial.print(val3);
  Serial.println(" mg/kg");
  Serial.print("Soil pH: ");
  Serial.print(val4);
  Serial.println(" pH");
  Serial.print("Soil Moisture: ");
  Serial.print(val5);
  Serial.println(" %");
  Serial.print("Temperature: ");
  Serial.print(val6);
  Serial.println(" C");
  Serial.print("Electrical Conductivity: ");
  Serial.print(val7);
  Serial.println(" mS/m");
  delay(5000);

  display.clearDisplay();
  
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("N: ");
  display.print(val1);
  display.setTextSize(1);
  display.print(" mg/kg");
 
  display.setTextSize(1);
  display.setCursor(0, 15);
  display.print("P: ");
  display.print(val2);
  display.setTextSize(1);
  display.print(" mg/kg");
 
  display.setTextSize(1);
  display.setCursor(0, 30);
  display.print("K: ");
  display.print(val3);
  display.setTextSize(1);
  display.print(" mg/kg");

  display.setTextSize(1);
  display.setCursor(0, 43);
  display.print("PH: ");
  display.print(val4);
  display.setTextSize(1);
  display.print(" ph");
     
  display.setTextSize(1);
  display.setCursor(0, 57);
  display.print("SM: ");
  display.print(val5);
  display.print(" %");

  display.display(); 

  delay(2000);
}
  
byte nitrogen() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(nitro, sizeof(nitro)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte phosphorous() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(phos, sizeof(phos)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte potassium() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(pota, sizeof(pota)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte ph() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(soil_ph, sizeof(soil_ph)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte moist() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(soil_moist, sizeof(soil_moist)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte stemp() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(temp, sizeof(temp)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte econd() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(ec, sizeof(ec)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

and the circuit diagram is ( but here im not uisng OLED):

I moved your topic to an appropriate forum category @prakashpoojary.

In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

This is an important part of responsible forum usage, as explained in the "How to get the best out of this forum" guide. The guide contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

1 Like

@prakashpoojary if you search this forum for NPK sensor, then you will find many discussions with the same issue you are having - some are using an UNO / Nano and some are using an ESP32.

Your code would indicate that you are using an OLED to display results.

That usually indicates that the sensor isn't responding.

You need a GND between the sensor and the RS485 module too.

EDIT: Also note that the basic code you have found to communicate with the soil sensor has a major flaw in it that will result in the code mixing up the returned values.

hi mark, thank you for replying. I'm just done with what you have said, but the error still remains. I have removed all the OLED functions and I have connected GND between the sensor and the rs485 module. here is the updated code.

#include <Wire.h>
#define RE 13
#define DE 12

const byte nitro[] = {0x01, 0x03, 0x00, 0x87, 0x0E, 0x0E, 0x34, 0x37};
const byte phos[] = {0x01, 0x03, 0x00, 0x8A, 0x0E, 0x0E, 0x34, 0x37};
const byte pota[] = {0x01, 0x03, 0x00, 0x8E, 0x0E, 0x0E, 0x34, 0x37};
const byte soil_ph[] = {0x01, 0x03, 0x02, 0xAE, 0x0E, 0x0E, 0x34, 0x37};
const byte soil_moist[] = {0x01, 0x03, 0x01, 0x64, 0x0E, 0x0E, 0x34, 0x37};
const byte temp[] = {0x01, 0x03, 0xFF, 0xDD, 0x0E, 0x0E, 0x34, 0x37};
const byte ec[] = {0x01, 0x03, 0x04, 0xD2, 0x0E, 0x0E, 0x34, 0x37};

byte values[11];
HardwareSerial mod(2);  // Use Serial2 for RS485 communication

void setup() {
  Serial.begin(9600);
  mod.begin(9600, SERIAL_8N1, 16, 17); // Set the baud rate and pins for Serial2
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);

  // Initialize any necessary components or libraries here

  delay(1000);
}

void loop() {
  byte val1, val2, val3, val4, val5, val6, val7;
  val1 = nitrogen();
  delay(250);
  val2 = phosphorous();
  delay(250);
  val3 = potassium();
  delay(250);
  val4 = ph();
  delay(250);
  val5 = moist();
  delay(250);
  val6 = stemp();
  delay(250);
  val7 = econd();
  delay(250);

  Serial.print("Nitrogen: ");
  Serial.print(val1);
  Serial.println(" mg/kg");
  Serial.print("Phosphorous: ");
  Serial.print(val2);
  Serial.println(" mg/kg");
  Serial.print("Potassium: ");
  Serial.print(val3);
  Serial.println(" mg/kg");
  Serial.print("Soil pH: ");
  Serial.print(val4);
  Serial.println(" pH");
  Serial.print("Soil Moisture: ");
  Serial.print(val5);
  Serial.println(" %");
  Serial.print("Temperature: ");
  Serial.print(val6);
  Serial.println(" C");
  Serial.print("Electrical Conductivity: ");
  Serial.print(val7);
  Serial.println(" mS/m");
  delay(5000);

  delay(2000);
}

byte nitrogen() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(nitro, sizeof(nitro)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte phosphorous() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(phos, sizeof(phos)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte potassium() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(pota, sizeof(pota)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte ph() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(soil_ph, sizeof(soil_ph)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte moist() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(soil_moist, sizeof(soil_moist)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte stemp() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(temp, sizeof(temp)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

byte econd() {
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(10);
  if (mod.write(ec, sizeof(ec)) == 8) {
    digitalWrite(DE, LOW);
    digitalWrite(RE, LOW);
    for (byte i = 0; i < 7; i++) {
      values[i] = mod.read();
      Serial.print(values[i], HEX);
    }
    Serial.println();
  }
  return values[4];
}

and I will provide you the manual as well, please once check if I might have made any errors in the code by placing the wrong address of the sensor. since I'm new to this field, I have limited knowledge of this field. please help me to get the proper output.

here is the manual



remaining pictures I will post in this reply.



remaining 2 picture of manual i ll post in the reply


image

Which Arduino are you using - the image in the wiring diagram looks like it might be a Nano?

If I try and compile that code in the Arduino IDE for a Nano, then it does not compile without errors....

Let's try something really simple to see if we can get a response.

I think your wiring from the diagram you posted is:

DI  -> 11
RO  -> 10
RE  -> 9
DE  -> 8
VCC -> 5V
GND -> GND

Try this code:

// This attempt uses the SoftwareSerial & raw Modbus packets.
//
// RS485 module wired up as:
// RS485 DI signal to pin 11
// RS485 RO signal to pin 10
// RS485 RE signal to pin 9
// RS485 DE signal to pin 8
// RS485 VCC to 5V
// RS485 GND to GND
//
#include <SoftwareSerial.h>

#define RE 9
#define DE 8

const uint32_t TIMEOUT = 500UL;

// canned message to your RS485 device
// change this for any other canned modbus message you like
// remember to make sure that the checksum is correct!
uint8_t msg[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A};

SoftwareSerial swSerial(10, 11); // Receive (data in) pin, Transmit (data out) pin

void setup() {
  Serial.begin(9600);
  swSerial.begin(9600);
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
  delay(1000);
}

void loop() {
  uint32_t startTime = 0;

  Serial.print("TX: ");
  printHexMessage( msg, sizeof(msg) );

  // send the command
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay( 10 );
  swSerial.write( msg, sizeof(msg) );
  swSerial.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  Serial.print("RX: ");
  
  // read any data received and print it out
  startTime = millis();
  while ( millis() - startTime <= TIMEOUT ) {
    if (swSerial.available()) {
      printHexByte(swSerial.read());
    }
  }
  Serial.println();
  delay(2000);
}

void printHexMessage( uint8_t values[], uint8_t sz ) {
  for (uint8_t i = 0; i < sz; i++) {
    printHexByte( values[i] );
  }
  Serial.println();
}

void printHexByte(byte b)
{
  Serial.print((b >> 4) & 0xF, HEX);
  Serial.print(b & 0xF, HEX);
  Serial.print(' ');
}

If it works, then it should print out any data received from your sensor - in this case the temperature parameter.

hello sir, here is complete detail about my sensors and components

  • ESP32 DEVKIT1 with 30 pins. pins are named VIN,GND, D13, D12, D14, D27, D26, D25, D33, D32, D35, D34, VN, VP, EN, 3V3, GND, D15, D2, D4, RX2, TX2, D5, D18, D19, D21, RX0, TX0, D22, D23, along with 1 EN button and 1 Boot button.

  • Rs485 module with 8 pins, pins are named VCC, B, A, GND, R0, RE, DE, DI, it operating at 5V.

  • 7 in one soil sensor, with parameter temp, moisture, EC, salt, pH, N, P, K and it has 4 wires with 4 different colors black, red, green, and yellow. and it's operating at 7-24V dc.

I'm following this circuit diagram

I tried your code in my esp32 board, the output is getting like this, I don't understand what it is!

Ok. You are using an ESP32. I believe that on the ESP32, the TXD & RXD pins are used for uploading code and debugging.

There is a second hardware serial port labelled TX2 (GPIO17) & RX2 (GPIO16). I would suggest you use that one to talk to your sensor.

I believe that the test code should be something like this, but I don't have the hardware to test it:

// RS485 module wired up as:
// RS485 DI signal to pin TX2
// RS485 RO signal to pin RX2
// RS485 RE signal to pin D13
// RS485 DE signal to pin D12
// RS485 VCC to 5V
// RS485 GND to GND
//

#define RE 13
#define DE 12

const uint32_t TIMEOUT = 500UL;

// canned message to your RS485 device
// change this for any other canned modbus message you like
// remember to make sure that the checksum is correct!
uint8_t msg[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A};

void setup() {
  Serial.begin(9600);
  Serial2.begin(9600);
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
  delay(1000);
}

void loop() {
  uint32_t startTime = 0;

  Serial.print("TX: ");
  printHexMessage( msg, sizeof(msg) );

  // send the command
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay( 10 );
  Serial2.write( msg, sizeof(msg) );
  Serial2.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  Serial.print("RX: ");
  
  // read any data received and print it out
  startTime = millis();
  while ( millis() - startTime <= TIMEOUT ) {
    if (Serial2.available()) {
      printHexByte(Serial2.read());
    }
  }
  Serial.println();
  delay(2000);
}

void printHexMessage( uint8_t values[], uint8_t sz ) {
  for (uint8_t i = 0; i < sz; i++) {
    printHexByte( values[i] );
  }
  Serial.println();
}

void printHexByte(byte b)
{
  Serial.print((b >> 4) & 0xF, HEX);
  Serial.print(b & 0xF, HEX);
  Serial.print(' ');
}

You should also check to see if the ESP32 has 5V tolerant inputs. The RS485 module you are using will drive the RO pin to 5V which may damage your ESP32.

hi mark, the output of your code looks like this. it does not show RX

Did you switch to the TX2 and RX2 pins?

I will see if I can put some hardware together similar to yours and check that what I am saying is correct.

I have an ESP32-WROOM-32 here. I connected it up as described in the comments in the code I gave you in post #9.

The ESP32 successfully sends the canned modbus message and can receive a response - assuming your sensor sends one back.

The message:

0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A

should query your sensor and ask it for the temperature.

Perhaps your sensor doesn't like being asked for temperature on its own. If that is the case, then you can change the message so that it is the one in the example from the manual like this:

uint8_t msg[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x04, 0x08};

This all assumes that your sensor is still at the default address of 01 and using 9600 baud.

RX still shows 00 as the output after updating the code. yes, 01 is the default address as mentioned in the manual, and using 9600 baud.

And when i remove the RX connection, this appears

And sometimes I used to get this! especially when I try to remove and put the wires back. (for example, I tried to remove D12 and put it back, at that time this output appeared and again it turned into 00 again in no time)

image

esp32 is not 5v tolerant..
need a level shifter..
or a 3.3v 485 board..
sorry.. ~q

where did these come from??
don't look correct..
from the doc you posted..
looks like..

//01 address, 03 function code,next 2 bytes starting address 0, next 2 bytes qty, then check sum
{0x01,0x03,0x00,0x00,0x00,0x07,0x04,0x08}

will get all sensors vals..
did some modbus..
Modbus tester..
you can use the test app, don't even have to connect..
fill in the vals and click send it will display byte sequence with checksum that it would send..
oh, sorry for butting in.. :slight_smile:
good luck.. ~q

if the checksum is wrong, then the packet is suppose to be ignored..
you won't get any replies..
~q

post 9 looks correct, should have a response..
could be the 5v??

~q

@qubits-us thanks for the clarification re the 5V tolerance.
@prakashpoojary this is something I hinted at back in post #9.

There's one test you can try, assuming your ESP32 hasn't been damaged by the 5V logic.
Change the following code:

// send the command
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay( 10 );
  Serial2.write( msg, sizeof(msg) );
  Serial2.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

to this:

// send the command
  digitalWrite(DE, HIGH);
  digitalWrite(RE, LOW);   // <- this line chsnges
  delay( 10 );
  Serial2.write( msg, sizeof(msg) );
  Serial2.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

Disconnect your sensor from A & B and run the code. You should get back what you are sending.

1 Like