Your plants, like you, require food. In order to be healthier and more productive, plants need the “big three” essential nutrients nitrogen, phosphorus, and potassium, also known as NPKs.

If the soil in your garden doesn’t have enough of these nutrients, plants won’t grow to their full potential. Therefore, it is essential to measure the soil’s current N, P, and K levels to determine how much additional nutrient content must be added to increase crop fertility.

Using an NPK Soil Sensor and an Arduino, you can quickly determine the levels of these nutrients in the soil.

What Is NPK? and Why It’s So Important?

The letters NPK stand for the three major nutrients that plants require to grow and thrive: nitrogen, phosphorus, and potassium.

Nitrogen is responsible for the growth and greenness of plant leaves.

Phosphorus helps the plant grow strong roots, fruit, and flowers.

Potassium improves the overall health and hardiness of a plant.

JXCT Soil NPK sensor

The JXCT Soil NPK sensor is a low-cost, quick-responding, reasonably accurate, and portable sensor. It aids in the real-time monitoring of NPK nutrient content in soil for smart agriculture.

The soil NPK sensor can detect the levels of nitrogen, phosphorus, and potassium in the soil (not in water). It helps determine soil fertility, allowing for a more systematic assessment of soil condition.

soil npk sensor

The sensor operates on 5-30V and consumes very little power. According to the datasheet, it is capable of measuring nitrogen, phosphorus, and potassium with a resolution of up to 1 mg/kg (mg/l).

The sensor includes a stainless steel probe that is rust-proof, electrolytic resistant, and salt-alkali resistant. It can therefore be used with any type of soil, including alkaline soil, acid soil, substrate soil, seedling bed soil, and coconut bran soil.

The probe is sealed to the body with high-density epoxy resin to prevent moisture from entering the body.

The best part is that the sensor has an IP68 rating, which means it is protected against dust and moisture, allowing it to operate normally for a very long time.

To be used effectively over long distances, the sensor features the RS485 communication interface and supports the standard Modbus-RTU communication protocol.

It should be noted that the sensor cannot be used with an Arduino directly. To communicate with Arduino, you’ll need an RS-485 transceiver module that converts a UART serial stream to RS-485.

Technical Specifications

Here are the specifications:

Power5V-30V
Measuring Range0-1999 mg/kg (ml/l)
Operating Temperature5-45 °C
Resolution1mg/kg (ml/l)
Precision±2% F.S.
Output SignalRS485
Protection ClassIP68

Heads-up

The JXCT soil NPK sensor is an electrical conductivity sensor (EC sensor). It does not directly measure the soil’s NPK content, but rather estimates it based on the electrical conductivity of the soil.

Be aware that this method is tricky and prone to producing inaccurate results.

For your information, there are inexpensive sensors out there that work on the same principle.

Soil NPK sensor Pinout

The sensor comes with a 2m cable with tinned copper wires. The pinout is shown in the figure below.

soil npk sensor pinout

VCC is the VCC pin. Connects to 5V – 30V.

A is a differential signal that is connected to the A pin of the MAX485 Modbus Module.

B is another differential signal that is connected to the B pin of the MAX485 Modbus Module.

GND is the Ground pin.

Wiring a Soil NPK Sensor to an Arduino

As previously stated, the NPK sensor cannot be used directly with an Arduino. To communicate with Arduino, you’ll need an RS-485 transceiver module that converts a UART serial stream to RS-485, such as the one shown below.

rs485 transceiver module

Okay, so let’s get to the wiring.

The soil NPK Sensor has four wires. The power wire is brown and should be connected to the 5V-30V power supply. The ground wire is black and should be connected to a common ground.

The yellow wire of the NPK sensor should be connected to the RS485 module’s A pin, and the blue wire should be connected to the RS485 module’s B pin.

Connect the RS485 module’s R0 and DI pins to the Arduino’s digital pins 2 and 3, respectively. These digital pins will be used as virtual RX and TX serial lines.

Note that if you are using a Mega or Mega 2560, you should use digital pins 10 and 11, as digital pins 2 and 3 do not support change interrupts, which is a known limitation of the softwareSerial library.

The RS485 module’s VCC pin should be connected to the Arduino’s 5V output, and the DE and RE pins should be connected to digital pins 7 and 8, respectively.

Finally, make sure your circuit and Arduino share a common ground.

The wiring is shown in the image below.

arduino wiring soil npk sensor

Usage Instructions

Choose an appropriate measuring location, avoid stones, make sure the steel probe does not come into contact with any hard objects, and insert the sensor vertically into the soil.

soil npk sensor vertical insertion

Optionally, the sensor can be inserted horizontally into the pit, in which case the pit is excavated vertically with a diameter greater than 20 cm before being tightly backfilled.

soil npk sensor horizontal insertion

What is Modbus?

Just in case you don’t know what Modbus is, it’s probably a good idea to brush up on it before we move on.

Modbus is a de-facto standard for industrial communication protocols because it is open source and royalty-free. For data transfer, it uses RS-485, RS-422, and RS-232 interfaces, as well as Ethernet TCP/IP networks (the Modbus TCP protocol).

There are various implementation types of Modbus. The following are the most popular protocol types:

  • Modbus RTU (The one we are going to configure)
  • Modbus ASCII
  • Modbus TCP

Modbus RTU Protocol

Modbus RTU is a master-slave protocol. In this protocol, only the master device (in our case, an Arduino) is allowed to initiate communication. The other devices on the network are known as slaves (in our case, NPK sensors), and they can only respond to requests. Modbus RTU can support up to 247 devices on the same physical network. 

Modbus RTU Data Frame

Over the Modbus bus, messages are exchanged between the master and slave in the form of data frames. There are Request and Response frames. A request is a message sent by the master to one of the slaves. A response is a message sent by the slave to the master. 

The request also includes a checksum which is used to make sure the messaged is not corrupted on the way to the slave.

A typical Modbus RTU message contains the address of the SlaveID device, the function code, the data based on the function code, and the CRC of the checksum.

typical modbus rtu data frame

The following is an example of a Modbus RTU Request frame instructing slave #1 to return the value of a single register beginning at address 2.

sample modbus rtu request frame

All slaves except slave #1 ignore this message. Slave #1 then sends a response message that looks like this:

sample modbus rtu response frame

Modbus RTU requests for reading NPK Sensor

The following are three distinct Modbus RTU requests for reading the Nitrogen (N), Phosphorous (P), and Potassium (K) values from the NPK Sensor. If the request is successful, the sensor sends a Response message containing the reading.

For Reading Nitrogen

The Modbus RTU request for reading the Nitrogen level is:

modbus rtu request for reading nitrogen

You will receive a similar response:

modbus rtu response with nitrogen reading

From the Response, you can obtain the nitrogen level. For instance, if the response contains the value 0x0020 in the data field, the nitrogen level can be calculated as follows:

Nitrogen = 0x0020HEX = 32DEC => 32 mg/kg

For Reading Phosphorous

Similarly, the Modbus RTU request for reading the phosphorus level is:

modbus rtu request for reading phosphorous

You will receive a similar response:

modbus rtu response with phosphorous reading

From the Response, you can obtain the phosphorus level. For instance, if the response contains the value 0x0025 in the data field, the phosphorus level can be calculated as follows:

Phosphorous = 0x0025HEX = 37DEC => 37 mg/kg

For Reading Potassium

Similar to the previous two requests, the Modbus RTU request for reading the Potassium level is:

modbus rtu request for reading potassium

You will receive a similar response:

modbus rtu response with potassium reading

From the Response, you can obtain the potassium level. For instance, if the response contains the value 0x0030 in the data field, the potassium level can be calculated as follows:

Potassium = 0x0030HEX = 48DEC => 48 mg/kg

Arduino Example Code

The following test sketch reads the nitrogen, phosphorus, and potassium values from the soil NPK sensor and prints them to the serial monitor.

#include <SoftwareSerial.h>
#include <Wire.h>

// RE and DE Pins set the RS485 module
// to Receiver or Transmitter mode
#define RE 8
#define DE 7

// Modbus RTU requests for reading NPK values
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};

// A variable used to store NPK values
byte values[11];

// Sets up a new SoftwareSerial object
// Digital pins 10 and 11 should be used with a Mega or Mega 2560
SoftwareSerial mod(2, 3);
//SoftwareSerial mod(10, 11);
 
void setup() {
  // Set the baud rate for the Serial port
  Serial.begin(9600);

  // Set the baud rate for the SerialSoftware object
  mod.begin(9600);

  // Define pin modes for RE and DE
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  
  delay(500);
}
 
void loop() {
  // Read values
  byte val1,val2,val3;
  val1 = nitrogen();
  delay(250);
  val2 = phosphorous();
  delay(250);
  val3 = potassium();
  delay(250);

  // Print values to the serial monitor
  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");
  
  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++){
    //Serial.print(mod.read(),HEX);
    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++){
    //Serial.print(mod.read(),HEX);
    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++){
    //Serial.print(mod.read(),HEX);
    values[i] = mod.read();
    Serial.print(values[i],HEX);
    }
    Serial.println();
  }
  return values[4];
}

You will see something like this.

soil npk sensor output

Login
ADS CODE