简介

该传感器适用于检测土壤肥沃情况,5-30V宽电压供电,RS485输出,可检测氮、磷、钾,响应快,输出稳定,可搭配Arduino UNO R3与TTL转485扩展板,快速搭建测试。

土壤传感器防护等级为IP68,采用黑色阻燃环氧树脂真空灌装密封,探针材质选用316型不锈钢,具有防锈防水防腐蚀、耐盐碱腐蚀、耐长期电解,受土壤含盐量影响较小,可长期埋入土壤中,适用各种土质。

土壤传感器广泛适用于稻田、大棚种植、水稻、蔬菜种植、果园苗圃、花卉以及土壤研究等。

注:氮磷钾传感器数据只能作为参考,无法像专业仪器精准。

特点

技术规格

引脚示意图

标号 名称 功能描述
棕线 VCC 电源输入正极,DC5-30V供电
黑线 GND 电源接地线
黄线 485-A RS485数据A线
蓝线 485-B RS485数据B线

尺寸图

尺寸图

通信协议

1、通讯基本参数

接口 编码 数据位 奇偶校验位 停止位 错误校验 波特率
RS485 8位二进制 8 1 CRC 2400bit/s、4800bit/s、9600 bit/s 可设,默认9600bit/s

2、数据帧格式定义

采用 ModBus-RTU 通讯规约,格式如下:

主机问询帧结构:

地址码 功能码 寄存器起始地址 寄存器长度 校验码低位 校验码高位
1byte 1byte 2byte 2byte 1byte 1byte

从机应答帧结构:

地址码 功能码 有效字节数 数据一区 第二数据区 第N数据区 校验码
1byte 1byte 1byte 2byte 2byte 2byte 2byte

3、通讯协议示例及解释

3.1、举例:读取设备地址 0x01 的氮含量暂存值

问询帧(16 进制):

地址码 功能码 寄存器起始地址 寄存器长度 校验码低位 校验码高位
0x01 0x03 0x00 0x1E 0x00 0x01 0xE4 0x0C

应答帧(16 进制):

地址码 功能码 返回有效字节数 氮暂存值 校验码低位 校验码高位
0x01 0x03 0x02 0x00 0x20 0xB9 0x9C

氮含量暂存值计算:

3.2、举例:读取设备地址 0x01 的磷含量暂存值

问询帧(16 进制):

地址码 功能码 寄存器起始地址 寄存器长度 校验码低位 校验码高位
0x01 0x03 0x00 0x1F 0x00 0x01 0xB5 0xCC

应答帧(16 进制):

地址码 功能码 返回有效字节数 磷暂存值 校验码低位 校验码高位
0x01 0x03 0x02 0x00 0x25 0x79 0x9F

磷含量暂存值计算:

3.3、举例:读取设备地址 0x01 的钾含量暂存值

问询帧(16 进制):

地址码 功能码 寄存器起始地址 寄存器长度 校验码低位 校验码高位
0x01 0x03 0x00 0x20 0x00 0x01 0x85 0xC0

应答帧(16 进制):

地址码 功能码 返回有效字节数 钾暂存值 校验码低位 校验码高位
0x01 0x03 0x02 0x00 0x30 0xB8 0x50

钾含量暂存值计算:

4、寄存器地址

寄存器地址 PLC或组态地址 内容 操作 定义说明
001EH 40031(十进制) 氮含量暂存值 读写 被写入的氮含量值或测试值
001FH 40032(十进制) 磷含量暂存值 读写 被写入的磷含量值或测试值
0020H 40033(十进制) 钾含量暂存值 读写 被写入的钾含量值或测试值
03E8H 41001(十进制) 氮含量暂存值 系数高十六位 读写 浮点数
03E9H 41002(十进制) 氮含量暂存值系数低十六位 读写 浮点数
03EAH 41003(十进制) 氮含量暂存值的偏差值 读写 整数
03F2H 41011(十进制) 磷含量暂存值 系数高十六位 读写 浮点数
03F3H 41012(十进制) 磷含量暂存值系数低十六位 读写 浮点数
03F4H 41013(十进制) 磷含量暂存值的偏差值 读写 整数
03FCH 41021(十进制) 钾含量暂存值 系数高十六位 读写 浮点数
03FDH 41022(十进制) 钾含量暂存值系数低十六位 读写 浮点数
03FEH 41023(十进制) 钾含量暂存值的偏差值 读写 整数
07D0H 42001(十进制) 设备地址 读写 1-254(出厂默认1)
07D1H 42002(十进制) 设备波特率 读写 0代表2400 1代表4800 2代表9600

使用教程

准备

接线图

烧录代码前,请将扩展板的收发模式开关切换到AUTO,运行/编译开关切换到OFF,烧录代码后,运行/编译开关切换到ON,串口波特率选择9600

Arduino连接图

示例代码

uint8_t Com[8] = { 0x01, 0x03, 0x00, 0x1E, 0x00, 0x01, 0xE4, 0x0C };   //氮
uint8_t Com1[8] = { 0x01, 0x03, 0x00, 0x1F, 0x00, 0x01, 0xB5, 0xCC };  //磷
uint8_t Com2[8] = { 0x01, 0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xC0 };  //钾
int N, P, K;
void setup() {
  Serial.begin(9600);  //初始化串口
}
void loop() {
  int N = readN();
  Serial.print("N = ");
  Serial.print(N);
  Serial.print(" mg/kg  ");
  int P = readP();
  Serial.print("P = ");
  Serial.print(P);
  Serial.print(" mg/kg  ");
  int k = readK();
  Serial.print("K = ");
  Serial.print(K);
  Serial.println(" mg/kg  ");
  delay(1000);
}

int readN(void) {
  uint8_t Data[10] = { 0 };
  uint8_t ch = 0;
  bool flag = 1;
  while (flag) {
    delay(100);
    Serial.write(Com, 8);
    delay(10);
    if (readN(&ch, 1) == 1) {
      if (ch == 0x01) {
        Data[0] = ch;
        if (readN(&ch, 1) == 1) {
          if (ch == 0x03) {
            Data[1] = ch;
            if (readN(&ch, 1) == 1) {
              if (ch == 0x02) {
                Data[2] = ch;
                if (readN(&Data[3], 4) == 4) {
                  if (CRC16_2(Data, 5) == (Data[5] * 256 + Data[6])) {
                    N = Data[3] * 256 + Data[4];
                    flag = 0;
                  }
                }
              }
            }
          }
        }
      }
    }
    Serial.flush();
  }
  return N;
}

int readP(void) {
  uint8_t Data1[10] = { 0 };
  uint8_t ch1 = 0;
  bool flag1 = 1;
  while (flag1) {
    delay(100);
    Serial.write(Com1, 8);
    delay(10);
    if (readN(&ch1, 1) == 1) {
      if (ch1 == 0x01) {
        Data1[0] = ch1;
        if (readN(&ch1, 1) == 1) {
          if (ch1 == 0x03) {
            Data1[1] = ch1;
            if (readN(&ch1, 1) == 1) {
              if (ch1 == 0x02) {
                Data1[2] = ch1;
                if (readN(&Data1[3], 4) == 4) {
                  if (CRC16_2(Data1, 5) == (Data1[5] * 256 + Data1[6])) {
                    P = Data1[3] * 256 + Data1[4];
                    flag1 = 0;
                  }
                }
              }
            }
          }
        }
      }
    }
    Serial.flush();
  }
  return P;
}

int readK(void) {
  uint8_t Data2[10] = { 0 };
  uint8_t ch2 = 0;
  bool flag2 = 1;
  while (flag2) {
    delay(100);
    Serial.write(Com2, 8);
    delay(10);
    if (readN(&ch2, 1) == 1) {
      if (ch2 == 0x01) {
        Data2[0] = ch2;
        if (readN(&ch2, 1) == 1) {
          if (ch2 == 0x03) {
            Data2[1] = ch2;
            if (readN(&ch2, 1) == 1) {
              if (ch2 == 0x02) {
                Data2[2] = ch2;
                if (readN(&Data2[3], 4) == 4) {
                  if (CRC16_2(Data2, 5) == (Data2[5] * 256 + Data2[6])) {
                    K = Data2[3] * 256 + Data2[4];
                    flag2 = 0;
                  }
                }
              }
            }
          }
        }
      }
    }
    Serial.flush();
  }
  return K;
}


uint8_t readN(uint8_t *buf, size_t len) {
  size_t offset = 0, left = len;
  int16_t Tineout = 500;
  uint8_t *buffer = buf;
  long curr = millis();
  while (left) {
    if (Serial.available()) {
      buffer[offset] = Serial.read();
      offset++;
      left--;
    }
    if (millis() - curr > Tineout) {
      break;
    }
  }
  return offset;
}

unsigned int CRC16_2(unsigned char *buf, int len) {
  unsigned int crc = 0xFFFF;
  for (int pos = 0; pos < len; pos++) {
    crc ^= (unsigned int)buf[pos];
    for (int i = 8; i != 0; i--) {
      if ((crc & 0x0001) != 0) {
        crc >>= 1;
        crc ^= 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }

  crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
  return crc;
}

结果:将土壤传感器插入土里,则串口打印出传感器检测到的氮、磷、钾值。

注:氮磷钾传感器数据只能作为参考,无法像专业仪器精准。

Arduino串口打印数据图

安装使用方法

1、速测法

选定合适的测量地点,避开石块,确保钢针不会碰到坚硬的物体,按照所需测量深度抛开表层土,保持下面土壤原有的松紧程度,紧握传感器垂直插入土壤,插入时不可左右晃动,一个测点的小范围内建议多次测量求平均值。

速测法

2、埋地测量法

垂直挖直径>20cm 的坑,在既定的深度将传感器钢针水平插入坑壁,将坑填埋严实,稳定一段时间后,即可进行连续数天,数月乃至更长时间的测量和记录。 速测法

3、注意事项

常见问题

无输出或输出错误存在可能的原因:

还有客户对此产品有任何问题,欢迎通过 qq 或者论坛联系我们! 更多问题及有趣的应用,可以访问论坛进行查阅或发帖

更多

DFRobot 商城购买链接