Measure Soil NPK values using Soil NPK Sensor with Arduino

Overview:

In this tutorial, learn how to interface soil NPK sensor with Arduino board and measure the values of main soil nutrients Nitrogen-N, Phosphorus-P, and Potassium-K present in the soil and display them on OLED display with I2C support and serial monitor.

What is NPK values? Why it is important to monitor and maintain them for plants?

The NPK value of soil indicates how much Nitrogen, Phosphorus and potassium are present in your soil or substrate. All plants need these three essential macronutrients. It is important to know the NPK values of the soil or substrates, as you can provide your plants with right amount of external NPK fertilizers according to their needs.

Let’s Analyze how these 3 macro nutrients helps your plant.

  • The N stands for nitrogen. Nitrogen is necessary for the growth of a plant with good leaf growth and color.
  • The P stands for phosphorus. Phosphorous promotes root formation and flower and fruit development.
  • The K stands for potassium. Potassium helps in transfer of water and nutrients in your plants and helps photosynthesis, it also increases the resistance against diseases and support healthy root systems.

A plant requires different amounts of these nutrients at each stage. It is important that you provide your plant with a sufficient amount of NPK and other nutrients. If you don’t, the plant may start to show deficiency symptoms as the image below.

npk defiency in plants for npk sensorFrom the above image you can notice how a corn plant turns with deficiency of nutrients such as Nitrogen, Phosphorus, and Potassium. These are vital nutrients for the plant, so providing excess or low quantities of those can lead to the damage of the plant.

Giving excess amount of NPK causes:

  • Nitrogen: Over growth with decrease in ability to fruit and flowers, attracts insects and reduces the strength of stem.
  • Phosphorus: Reduces ability to absorb Zinc and Iron and few micronutrients even though they are present in soil.
  • Potassium: Leads to inability to absorb major nutrients like nitrogen, magnesium and calcium which leads to their deficiency.

So it is important to monitor those values and provide the required amounts of NPK for healthy plant growth. So taking this in to account lets build a soil NPK monitoring device with its sensor and Arduino.

Also read: Automatic Plant watering system using Arduino

Previously testing the soil for NPK is only possible by collecting the sample and taking it to the laboratory where researchers perform tests on the soil which is time consuming, labour intensive, costly and not even possible to detect the soil NPK status on site. Later optical NPK sensors which uses spectrometer came to action which even failed to give the accurate results by stopping at 60-70% accuracy. So to overcome this few tech manufacturers such as JXCT developed a sensor which detects NPK values of the soil on the spot with nearly acceptable accuracy. Lets learn about the senor and its working specifications before getting started.

Required components:

Product NameQuantityamazon logoamazon logo india
Soil NPK sensor1https://amzn.to/35NivmLhttps://amzn.to/34roUno
Arduino Nano1https://amzn.to/36Z3TBAhttps://amzn.to/3KpUQry
MAX485 Modbus module1https://amzn.to/3hAFrbDhttps://amzn.to/3Ia8bTH
OLED display1https://amzn.to/34f0GNihttps://amzn.to/35HZK4E
Few Connecting Wireshttps://amzn.to/3H2BV4ehttps://amzn.to/3J0WVu2
You can buy the required components from the given best buy links. We choose the components according to value for money.

Soil NPK sensor(JXBS-3001 soil NPK sensor)

JXBS-3001 Soil NPK sensor is produced by a JXCTIOT company located in Weihai, China. The low cost, quick responsive, high precision & portable NPK sensor consists 3 probes made with austenitic 316 steel which works for longtime without corrosion by withstanding from rust, salt-alkali and electrolytic behaviors. The protection casing is filled with high quality epoxy resin which protects against the moisture from entering the main body of the sensor for a healthy long run of the sensor.

soil npk sensor placed in soil pot

 

The chipset which is used inside the sensor can create high sensitivity measurements with stable signal at low power consumption. The sensor is rated IP68 for water and dust proof.

Technical features:

This sensor does not require any chemical components, This sensor has Modbus communication port where we cannot connect it with microcontrollers directly but by using an intermediate Modbus module. We can connect it to most of the microcontrollers like Arduino, ESP32 and measure the Nitrogen, Phosphorus and Potassium values in Realtime, just by inserting the probes in the soil. This sensor also detects the type of the soils like Acidic soil, Alkaline soil. You need an external Modbus module such as RS485/MAX485 to connect the senor with microcontrollers.

This sensor works with voltage range of 9v-24V with maximum power consumption less than 0.15watts. which works in the temperature range of 41-113 degree Fahrenheit(5-45Celcius). Many microcontrollers such as Arduino, PIC microcontrollers, 8051 microcontrollers family, ESP etc. support this soil NPK sensor as they have baud rates of 2400,4800 and 9600. This soil NPK sensor is said to have a high precision measurements with an accuracy of ±2%, with measuring resolution of 1mg/Kg(mg/litre) and can measure the Nitrogen, phosphorus and Potassium in the range between 0 to 1999mg/kg(mg/litre).

  • Voltage: 9-24Volts
  • Power consumption: <0.15 Watts
  • Working temperature: 5-45 Celsius(41-113 F)
  • Baud rates: 2400, 4800, and 9600.
  • Measuring Resolution: 1mg/kg(kg/l)
  • Measuring range: 0-1999mg/kg
  • Accuracy: ±2%
  • Communication mode: Modbus RS485
  • Protection rated: IP68

MAX485 TTL to RS485 converter module overview:

The MAX485 TTL to RS485 converter module helps to convert the TTL signals to RS485 signal by adopting half-duplex communication. This module works at 5Volts power supply with 300 μA power consumption and gives long range communications upto 4000 feet (1.2kms) even in the electrically noisy environments. This module lets you to communicate between multiple devices 32 devices at a data speed of 2.5Mbps in the same data line through master and slave configuration (linear/multidrop) which makes it useful in the industrial applications. As the distance increases the data speed decreases proportionally.

With the help of this MAX485 module we can communicate between RS485 differential signal from NPK sensor and Microcontrollers such as Arduino.

MAX485 TTL to RS485 Converter module pinout diagram

MAX485 module has 8 pins 4 pins on each side. Check the below image of pinout diagram showing all the pins with their names.

  • max485 ttl to rs485 converter module pinout diagramReceiver output(RO): which outputs the signal, should be connected to RX
  • Receiver Enable(RE): This is active LOW by default and to enable the receiver drive HIGH through digital pin of microcontroller.
  • Driver Enable(DE): This is active HIGH by default and normally jumpered to RE pin.
  • Driver Input(DI): Should be connected to TX of microcontroller as it takes data as input.

Right pins:

  • VCC: Should be connected to 5v power supply
  • B: inverted line for Data ‘B’. Also connects to the screw pin as shown in image.
  • A: Non-inverted line for Data A. Also connects to the screw pin as shown in image.
  • GND: Ground.

Interfacing Soil NPK sensor with Arduino Nano and OLED display

Connect all the required components as shown in the below schematic diagram to interface Soil NPK sensor with Arduino Nano through MAX485 to display the Soil NPK values on the OLED display.

Circuit DiagramInterfacing Soil NPK sensor with Arduino Nano and OLED display

As you can see from the above connection diagram the Soil NPK sensor which is placed in pot with soil has 4 wires with different colors, the red one is VCC powered from 9-24 volts external power supply(9v battery or adapter), Black wire is GND, Blue wire is RS485 DATA B and yellow wire is RS485 DATA A and connected to MAX485 module respectively.

The RO and DI from the MAX485 are connected to D2 and D3 respectively as they are Rx and Tx. DE and RE pins which are to be made HIGH are connected to digital pins D7 and D8 respectively and controlled through code.

The OLED display with I2C are connected as VCC and GND are powered from the Arduino 3.3v and GND, and SCL and SDA are connected to A5 and A4 respectively. That’s it for connection now lets learn the concept of communication between the NPK sensor, Arduino and Modbus MAX485 module.

Also read: pH Meter using Arduino and pH sensor

Modbus commands for MAX485 to get data from NPK sensor

A Modbus command will send instructions to Modbus device which in our case MAX485 module.

  • Read data from discrete and coil I/O ports
  • Change the value in one of its registers, which is written to the coil and holding registers
  • Instructs the device to send back one or more values contained in its Coil and Holding register

Modbus command structure

It is important to know the structure and its function of the inquiry command, so it would be easy to code.

As we already learnt that NPK sensor is communicated through Modbus, lets take a look of its format.

Address code: It is the address of the device which is same of a device, if you use multiple devices this code changes.

In the below table find the Inquiry commands from the Modbus and response from the NPK sensor

Enquiry frame to get Nitrogen value:

{0x01,0x03, 0x00, 0x1e, 0x00, 0x01, 0xe4, 0x0c}

enquiry frame for nitrogen modbus command

As you can see from the above image an array of hex numbers are sent by host as an enquiry to get the data of nitrogen value present in the soil from the slave(sensor).

This returns a response frame from the slave with the nitrogen value along with few parameters like address, function code to send the data to particular host. As we got Nitrogen Value 0x41 converting the hexadecimal format to decimal gives 65.

Nitrogen value: -> 0x41(HEX) -> 65(DECIMAL) -> 65mg/kg.

Enquiry frame to get Phosphorus value:

{0x01,0x03, 0x00, 0x1f, 0x00, 0x01, 0xb5, 0xcc}

enquiry frame for Phosphorous modbus command

As you can see from the above image an array of hex numbers are sent by host as an enquiry to get the data of Phosphorous value present in the soil from the slave.

This returns a response frame from the slave with the Phosphorous value along with few parameters like address, function code to send the data to particular host. As we got Phosphorous Value 0x63 converting the hexadecimal format to decimal gives 99.

Phosphorous value: -> 0x63(HEX) -> 99(DECIMAL) -> 99mg/kg .

Enquiry frame to get Potassium value:

{0x01,0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xc0}

enquiry frame for Potassium modbus command

As you can see from the above image an array of hex numbers are sent by host as an enquiry to get the data of Potassium value present in the soil from the slave.

This returns a response frame from the slave with the Potassium value along with few parameters like address, function code to send the data to particular host. As we got Potassium Value 0x54 converting the hexadecimal format to decimal gives 84.

Potassium value: -> 0x54(HEX) -> 84(DECIMAL) -> 84mg/kg.

Source code for Soil NPK sensor:

After connecting everything as explained above, and learning fundamentals and principles its time to write and upload the code to Arduino to get the sensor values from the soil NPK sensor which are in Hexadecimal and convert them into decimal format and display them on the OLED display which is interfaced with Arduino.

Install the required libraries listed below before uploading the code: 

  • Adafruit SSD1306 – Adafruit_SSD1306.h – link
  • Adafruit GFX Library – Adafruit_GFX.h – link
  • AltSoftSerial Library – AltSoftSerial.h – link

After installing the libraries open Arduino IDE and check the board as Arduino Nano, port where Arduino is connected and then copy the below code and paste it in the Arduino IDE workspace and hit upload.

/*
 * https://www.circuitschools.com/
 * Interfacing Soil NPK Sensor with Arduino for measuring 
 * Nitrogen, Phosphorus, and Potassium nutrients
 */

#include <AltSoftSerial.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);

// RO to pin 8 & DI to pin 9 when using AltSoftSerial
#define RE 6
#define DE 7

const byte nitro[] = {0x01, 0x03, 0x00, 0x1e, 0x00, 0x01, 0xe4, 0x0c};
const byte phos[] = {0x01, 0x03, 0x00, 0x1f, 0x00, 0x01, 0xb5, 0xcc};
const byte pota[] = {0x01, 0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xc0};

byte values[11];
AltSoftSerial mod;

void setup() {
  Serial.begin(9600);
  mod.begin(9600);
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);

  // put RS-485 into receive mode
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  //Initializing and Configuring OLED display
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //initialize with the I2C addr 0x3C (128x64)
  delay(500);
  display.clearDisplay();
  display.setCursor(25, 15);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.println("Soil NPK Sensor");
  display.setCursor(25, 35);
  display.setTextSize(1);
  display.print("Initializing");
  display.display();
  delay(3000);
}

void loop() {
  byte val1, val2, val3;
  Serial.print("Nitrogen: ");
  val1 = nitrogen();
  Serial.print(" = ");
  Serial.print(val1);
  Serial.println(" mg/kg");
  delay(250);

  Serial.print("Phosphorous: ");
  val2 = phosphorous();
  Serial.print(" = ");
  Serial.print(val2);
  Serial.println(" mg/kg");
  delay(250);

  Serial.print("Potassium: ");
  val3 = potassium();
  Serial.print(" = ");
  Serial.print(val3);
  Serial.println(" mg/kg");
  Serial.println();
  Serial.println();
display.clearDisplay();
  
 
  display.setTextSize(2);
  display.setCursor(0, 5);
  display.print("N: ");
  display.print(val1);
  display.setTextSize(1);
  display.print(" mg/kg");
 
  display.setTextSize(2);
  display.setCursor(0, 25);
  display.print("P: ");
  display.print(val2);
  display.setTextSize(1);
  display.print(" mg/kg");
 
  display.setTextSize(2);
  display.setCursor(0, 45);
  display.print("K: ");
  display.print(val3);
  display.setTextSize(1);
  display.print(" mg/kg");
 
  display.display();
  delay(3000);
}

byte nitrogen() {
  // clear the receive buffer
  mod.flushInput();

  // switch RS-485 to transmit mode
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(1);

  // write out the message
  for (uint8_t i = 0; i < sizeof(nitro); i++ ) mod.write( nitro[i] );

  // wait for the transmission to complete
  mod.flush();
  
  // switching RS485 to receive mode
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  // delay to allow response bytes to be received!
  delay(200);

  // read in the received bytes
  for (byte i = 0; i < 7; i++) {
    values[i] = mod.read();
    Serial.print(values[i], HEX);
    Serial.print(' ');
  }
  return values[4];
}

byte phosphorous() {
  mod.flushInput();
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(1);
  for (uint8_t i = 0; i < sizeof(phos); i++ ) mod.write( phos[i] );
  mod.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
// delay to allow response bytes to be received!
  delay(200);
  for (byte i = 0; i < 7; i++) {
    values[i] = mod.read();
    Serial.print(values[i], HEX);
    Serial.print(' ');
  }
  return values[4];
}

byte potassium() {
  mod.flushInput();
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(1);
  for (uint8_t i = 0; i < sizeof(pota); i++ ) mod.write( pota[i] );
  mod.flush();
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
// delay to allow response bytes to be received!
  delay(200);
  for (byte i = 0; i < 7; i++) {
    values[i] = mod.read();
    Serial.print(values[i], HEX);
    Serial.print(' ');
  }
  return values[4];
}

Code Explanation:

Here we used the Altsoftserial library instead of original software serial as it is causing some reading issues.

At first we initialized the libraries and defined OLED display with I2C, next defined the pins for Arduino UNO where DE and RE are to be connected.

Created arrays with enquiry form data for Nitrogen, Phosphorus, and Potassium in Modbus command format.

Created loops to print the values of Nitrogen, Phosphorus and Potassium values on serial monitor and OLED display with individual functions to send the enquiry frame data from host to slave and receive the data from slave to host and convert the Hexadecimal to Decimal format and return the values towards the loop for printing the NPK values.

Please read the code where we added comments for every lines of code to understand it clearly. This code is modified version of the original code from the sensor seller as it has lots of issues with the code and inspired from Arduino forums.

Monitoring the Soil NPK values on OLED display and Serial monitor

After successful code upload place the 3 pin steel probe in soil which you want to measure the soil NPK values, and open the serial monitor to see the NPK values, also you can see the NPK values printed on OLED display as the below images.

NPK sensor with arduino values on serial monitorYou can see the NPK values, content of Nitrogen, phosphorus and potassium present in soil are printed on serial monitor.

NPK sensor with arduino npk values on oled display moduleYou can see the N: Nitrogen, P: Phosphorus, and K: Potassium values displayed on the OLED display module.

 

Errors with Solutions:

Getting 255 for all NPK values:

  • Check with connection between sensor and MAX485
  • Increase the delay to allow response bytes to be received!
  • Maybe you are not using code from the above

Getting no response from sensor data

  • Check the baud rate with the sensor manufacturer and try different baud rates
  • May be due to sensor or the Modbus module malfunctioning or not working.

Important Notes:

After analysis we found that this sensor is not completely accurate but works at an acceptable accuracy. Please try to find the sensor manufacturer datasheet to get the working enquiry frame data. Calibrating this sensor is still a dreamy hope for many users. This sensor is purely for soil only, measuring it in water gives foul results.

Applications of NPK sensor:

31 comments
  1. Hi guys, I am a massive fan of your work.

    In this precise project, my mesurement has significant changes every 5 seconds. I don’t know if this can be a baud rate problem, if there is any signal distortion, the sensor can be damaged… I’m using Arduino Uno by the way

    1. As we also mentioned at the end of the project that, this sensor is not perfect and has significant levels of inaccuracy in the Realtime. But still we can achieve some accuracy by calibrating with some effort. If it is a baud rate problem you might wont get the response or values either. Thanks.

      1. i have this sensor Soil sensor(5PIN Probe, RS485 output type) This manual works for below type:
        1:T-H-PH
        2:C-PH
        3:T-H-C-PH
        4:NPK-T-H-PH
        5:NPK-PH
        6:NPK-PH-C
        7:NPK-PH-C-T-H
        I am trying to connect it to an esp32 but I have not been successful, could you help me please

  2. In my project, I’m using 3 sensors such as soil moisture sensor, DS1820 Temperature sensor and NPK sensor with Arduino UNO board. I have received correct value for soil moisture sensor alone. Other 2 showing the garbage values like Teemperature is 129 degree celsius or 60 degree Fahrenheit and NPK values shows as 255 for each and every soil. I have tried every solutions mentioned here. I did not get any accurate answer. Can you please help me?

    1. Step 1: Check the code for the other sensors which you mentioned. If they are correct check step 2,
      Step 2: check the power supply whether its sufficient or not.
      Step 3: If you are using very long code check weither the microcontroller memory is suffiecient or not.
      Step 4: update the libraries. If nothing works
      Send the code which you created to us through the contact us page.

      1. hello i have same issue as well, i am just recieving 255, problem is how do i check if the sensor is powered sufficiently,since it doesnt have an led to show it on ? how can i troubleshoot this?

  3. Recently I have following your tutorial on the use of the soil NPK sensor and thanks to that I was able to make it work.
    But during the test I was talking it showed that different data compared to the data that I can see through the official government test I was wondering if you could offer some help.
    Thank you for your time and consideration.

    1. Hello user,
      As the government test from the certified and high pression instruments which are costly though, it gives some better results. But this sensor is not certified and as we already mentioned in our project it may give inaccurate results.
      Thanks,
      Circuitschools.

  4. Above information are very helpful .
    what is the amount of moisture content to be in the soil while using this sensor?

  5. hi i have successfully been able to get data from both the NPK sensor and PH sensor individually using the arduino mega but for some reason i tried to incorporate the both sensors on one arduino mega using the software serial communication and board rate of 9600, i had a funny experience.
    MY EXPERIENCE
    -just the ph sensor gave me accurate data and NPK sensor remained 255 throughout
    -when i eliminated the ph the NPK WORKED JUST FINE
    -When i edited and removed just one of the board declaration in the void setup the other works perfectly.

    i cant seem to figure out what i am missing. i will so much appreciate if someone can help me out.
    i can share my code if need be.

    1. Same problem is here, I am getting continuously 255 and ffff from the RS485 sensor as Ph, Salinity, Nitrate and fluoride.

      Kindly help me out.

  6. Hi,
    Thanks for this great tutorial. I am getting the following error messages despite running the code as is.

    1. Expected declaration before ‘}’ token
    AND

    2. ‘potassium’ was not declared in this scope yet I am running the code as is.

    Kindly assist on how to handle such errors. Thanks

  7. Hi everyone!
    I got this :

    Nitrogen: FF FF FF FF FF FF FF = 255 mg/kg
    Phosphorous: FF FF FF FF FF FF FF = 255 mg/kg
    Potassium: FF FF FF FF FF FF FF = 255 mg/kg

  8. Hi,

    I followed this tutorial for my NPK sensor, and it worked great. However, I also have a pH sensor, and I’m not sure how to convert the code to work with it. It’s the same make as this NPK sensor, just the pH version. THANK YOU FOR THE HELP!

  9. Same problem is here, I am getting continuously 255 and ffff from the RS485 sensor as Ph, Salinity, Nitrate and fluoride. Kindly help me out.

  10. I am getting rs485 sensor output 255 and ffff by using esp32 microcontroller, help me out to get accurate sensor data.

    I used to test many ways but not success.

  11. C:\Users\sbrra\OneDrive\Documents\Arduino\sketch_nov29b\sketch_nov29b.ino:2:10: fatal error: Adafruit_GFX.h: No such file or directory
    #include
    ^~~~~~~~~~~~~~~~
    compilation terminated.

    exit status 1

    Compilation error: Adafruit_GFX.h: No such file or directory

    I have this error message what should I do??

    1. If you go the Arduino Library Manager, you can search for the GFX Library and download it from there. Worked for me!

  12. I am using Arduino Uno with RS485 NPK sensor. I have used the above mentioned code and designed the circuit accordingly. But I am getting 255 for all NPK values not even dipping the sensor inside the soil and when i dip it into the soil same 255 mg/kg is showing. I have seen all the solutions provided for this problem like changing the baud rate, checking the connections, checking if 12V supply is being provided to the NPK sensor but did not work for me. As the code has worked for some people, I believe that there should not be any problem with the code but I am unable to figure out the problem. If anyone could come up with a solution ,it would be of great help.

  13. I am using Arduino Uno with RS485 NPK sensor. But I am getting 255 for all NPK values not even dipping the sensor inside the soil and when i dip it into the soil same 255 mg/kg is showing. I have seen all the solutions provided for this problem like changing the baud rate, checking the connections, checking if 12V supply is being provided to the NPK sensor but did not work for me. I am unable to figure out the problem. If anyone could come up with a solution ,it would be of great help.

  14. I am continuously getting these readings:
    Nitrogen: 0 FF FF FF FF FF FF = 255 mg/kg
    Phosphorous: 0 FF FF FF FF FF FF = 255 mg/kg
    Potassium: 0 FF FF FF FF FF FF = 255 mg/kg
    What does this mean and what are the solutions? I have tried the solutions you have provided, yet the problem remains. I connected the sensor to the Arduino Vin port and am drawing power from there. Is there another way I’m supposed to draw power from the 12V source, or is there another issue? I am unsure about exactly what is causing the error.

  15. With Arduino Nano, it’s working perfectly but I shifted to ESP32 and AltSoftSerial seems to not work with this library. Anyone who has the codes for ESP32?

  16. What makes the NPK sensor give constant values of 255 when I have connected just like the way you did above and I used the same code.

  17. Hello all,

    I am getting exactly the same problem as above
    Nitrogen: FF FF FF FF FF FF FF = 255 mg/kg
    Phosphorous: FF FF FF FF FF FF FF = 255 mg/kg
    Potassium: FF FF FF FF FF FF FF = 255 mg/kg

    I have verified all connections between Arduino Uno, 485 and NPK sensor, also made sure NPK sensor’s power wire is connect to 12V DC power source, the code also looks correct with the same address value as in the manual, but it still always gives 255 value for All N, P K values. Any suggestion how I could resolve it?

    Thanks a lot in advance!

Leave a Reply

Your email address will not be published. Required fields are marked *