📡 Протокол Modbus RTU для JXCT 7-в-1¶
Дата: Июль 2025 Версия: 3.10.0
Автор: JXCT Development Team
📋 Содержание¶
- Содержание
- Обзор
- Технические характеристики
- Настройки порта (UART2)
- Параметры MODBUS
- Карта регистров
- Основные измерения
- Системные регистры
- Примеры протокола
- 1. Чтение pH почвы (регистр 0x0006)
- 2. Чтение температуры почвы (регистр 0x0013)
- 3. Чтение нескольких регистров (NPK)
- Схема подключения ESP32
- Физическое подключение
- Подключение к датчику JXCT
- Питание датчика (отдельное!)
- Реализация в коде ESP32
- Инициализация UART и SP3485E
- Чтение данных
- Диагностика и отладка
- Коды ошибок ModbusMaster
- Проверка связи
- Расчет CRC16
- Типичные проблемы и решения
- 1. Таймаут ответа (ku8MBResponseTimedOut)
- 2. Ошибка CRC (ku8MBInvalidCRC)
- 3. Недопустимый адрес данных (ku8MBIllegalDataAddress)
- Валидация данных
- Допустимые диапазоны
- Справочная информация
- Документация производителя
- Связанные файлы проекта
- Поддержка
- Связь с разработчиками
- Дополнительные ресурсы
- Полезные ссылки
📖 Содержание¶
- 📋 Обзор
- 🔧 Технические характеристики
- 📊 Карта регистров
- 🔍 Примеры протокола
- 🔧 Схема подключения ESP32
- ⚡ Оптимизация производительности
- 🐛 Отладка и диагностика
- 🔒 Безопасность
- 📋 Связанная документация
📋 Обзор¶
Датчик JXCT 7-в-1 использует протокол Modbus RTU через интерфейс RS485 для передачи данных измерений почвы. Этот документ содержит полную техническую спецификацию протокола.
🔧 Технические характеристики¶
Настройки порта (UART2)¶
Параметр │ Значение
────────────────────┼─────────────
Скорость передачи │ 9600 baud
Биты данных │ 8 bits
Четность │ None (N)
Стоп биты │ 1 bit
Управление потоком │ None
Формат │ 8N1
Интерфейс │ RS485 полудуплекс
Параметры MODBUS¶
Параметр │ Значение
────────────────────────┼─────────────
Протокол │ Modbus RTU
Адрес устройства │ 1 (по умолчанию, настраивается)
Функция чтения │ 0x03 (Read Holding Registers)
Функция записи │ 0x06 (Write Single Register)
Таймаут ответа │ 1000 мс
Максимум попыток │ 3
Интерфейс │ RS485 полудуплекс
📊 Карта регистров¶
Основные измерения¶
Регистр │ Адрес │ Параметр │ Формула │ Единицы │ Диапазон
────────┼───────┼────────────────────┼────────────────┼─────────┼──────────────
0x0006 │ 6 │ pH почвы │ значение ÷ 100 │ pH │ 0.00-14.00
0x0012 │ 18 │ Влажность почвы │ значение ÷ 10 │ % │ 0.0-100.0
0x0013 │ 19 │ Температура почвы │ значение ÷ 10 │ °C │ -10.0-50.0
0x0015 │ 21 │ Электропроводность │ как есть │ µS/cm │ 0-20000
0x001E │ 30 │ Азот (N) │ как есть │ мг/кг │ 0-2000
0x001F │ 31 │ Фосфор (P) │ как есть │ мг/кг │ 0-2000
0x0020 │ 32 │ Калий (K) │ как есть │ мг/кг │ 0-2000
Системные регистры¶
Регистр │ Адрес │ Параметр │ Формула │ Единицы │ Доступ
────────┼───────┼────────────────────┼────────────────┼─────────┼────────────
0x0007 │ 7 │ Версия прошивки │ как есть │ версия │ Только чтение
0x0008 │ 8 │ Калибровка │ как есть │ флаги │ Чтение/запись
0x000B │ 11 │ Статус ошибок │ как есть │ флаги │ Только чтение
0x000C │ 12 │ Адрес устройства │ как есть │ адрес │ Чтение/запись
🔍 Примеры протокола¶
1. Чтение pH почвы (регистр 0x0006)¶
Запрос:
Байт │ Hex │ Описание
─────┼─────┼─────────────────────────────
0 │ 01 │ Адрес устройства (1)
1 │ 03 │ Функция (Read Holding Registers)
2 │ 00 │ Адрес регистра (High byte)
3 │ 06 │ Адрес регистра (Low byte) - 0x0006
4 │ 00 │ Количество регистров (High byte)
5 │ 01 │ Количество регистров (Low byte) - 1
6 │ 64 │ CRC16 (High byte)
7 │ 0B │ CRC16 (Low byte)
Ответ:
Байт │ Hex │ Описание
─────┼─────┼─────────────────────────────
0 │ 01 │ Адрес устройства (1)
1 │ 03 │ Функция (Read Holding Registers)
2 │ 02 │ Количество байт данных (2)
3 │ 02 │ Значение pH (High byte)
4 │ BC │ Значение pH (Low byte)
5 │ 38 │ CRC16 (High byte)
6 │ 05 │ CRC16 (Low byte)
Расчет значения:
2. Чтение температуры почвы (регистр 0x0013)¶
Запрос:
Ответ:
Расчет значения:
3. Чтение нескольких регистров (NPK)¶
Запрос (регистры 0x001E-0x0020):
Ответ:
Расчет значений:
🔧 Схема подключения ESP32¶
Физическое подключение¶
RS-485 интерфейс¶
- Используется трансивер SP3485E
- Скорость передачи: до 10 Mbps
- Защита от ESD: ±15kV HBM
- Питание: 3.3V (оптимально для ESP32)
Подключение SP3485E¶
ESP32 GPIO │ SP3485E Pin │ Функция
─────────────┼────────────┼──────────────────────────────────
GPIO16 │ RO │ Receive Output (к UART RX)
GPIO17 │ DI │ Data Input (от UART TX)
GPIO4 │ DE │ Driver Enable (управление передатчиком)
GPIO5 │ RE │ Receiver Enable (управление приемником)
GND │ GND │ Общий провод
3.3V │ VCC │ Питание модуля
Важность раздельного управления DE и RE¶
- DE (Driver Enable) - управляет передатчиком:
- HIGH: передатчик активен (для отправки данных)
- LOW: передатчик в высокоимпедансном состоянии
- RE (Receiver Enable) - управляет приемником:
- HIGH: приемник отключен (во время передачи)
- LOW: приемник активен (для приема данных)
Раздельное управление этими пинами обеспечивает: 1. Более точный контроль над временем переключения 2. Возможность тонкой настройки задержек 3. Предотвращение коллизий на шине RS-485 4. Улучшенную помехозащищенность
Временные диаграммы переключения¶
DE ──┐ ┌────────┐ ┌────────
│ │ │ │
└──────────┘ └──────────┘
RE ──┐ ┌────────┐ ┌────────
│ │ │ │
└──────────┘ └──────────┘
├─ прием ──┤├─ передача ─┤├─ прием ──┤
│◄─ 50µs ─►│ │◄─ 50µs ─►│
Задержки переключения: - 50 микросекунд перед передачей (preTransmission) - 50 микросекунд после передачи (postTransmission)
Подключение к датчику JXCT¶
Transceiver │ JXCT Sensor │ Цвет провода │ Функция
─────────────┼─────────────┼──────────────┼─────────────────
A+ Terminal │ A+ │ Желтый │ RS485 Data+
B- Terminal │ B- │ Синий │ RS485 Data-
Питание датчика (отдельное!)¶
Источник │ JXCT Sensor │ Цвет провода │ Функция
─────────────┼─────────────┼──────────────┼─────────────────
12-24V DC+ │ VCC │ Красный │ Питание датчика
GND │ GND │ Черный │ Общий минус
⚙️ Реализация в коде ESP32¶
Инициализация UART и SP3485E¶
void setupModbus() {
// Настройка UART2 для Modbus
Serial2.begin(9600, SERIAL_8N1, MODBUS_RX_PIN, MODBUS_TX_PIN);
// Настройка пинов SP3485E
pinMode(MODBUS_DE_PIN, OUTPUT); // GPIO4
pinMode(MODBUS_RE_PIN, OUTPUT); // GPIO5
digitalWrite(MODBUS_DE_PIN, LOW); // Передатчик выключен
digitalWrite(MODBUS_RE_PIN, LOW); // Приемник включен
// Инициализация Modbus
node.begin(SENSOR_ID, Serial2);
// Настройка обработчиков переключения режима
node.preTransmission(preTransmission); // Перед передачей
node.postTransmission(postTransmission); // После передачи
}
// Управление направлением передачи SP3485E
void preTransmission() {
digitalWrite(MODBUS_DE_PIN, HIGH); // Режим передачи
delayMicroseconds(50);
}
void postTransmission() {
delayMicroseconds(50);
digitalWrite(MODBUS_RE_PIN, LOW); // Режим приема
}
Чтение данных¶
void readSensorData() {
// Чтение pH
uint8_t result = modbus.readHoldingRegisters(0x0006, 1);
if (result == modbus.ku8MBSuccess) {
uint16_t ph_raw = modbus.getResponseBuffer(0);
float ph = ph_raw / 100.0;
}
// Чтение температуры
result = modbus.readHoldingRegisters(0x0013, 1);
if (result == modbus.ku8MBSuccess) {
uint16_t temp_raw = modbus.getResponseBuffer(0);
float temperature = temp_raw / 10.0;
}
// Чтение NPK (3 регистра за один запрос)
result = modbus.readHoldingRegisters(0x001E, 3);
if (result == modbus.ku8MBSuccess) {
uint16_t nitrogen = modbus.getResponseBuffer(0);
uint16_t phosphorus = modbus.getResponseBuffer(1);
uint16_t potassium = modbus.getResponseBuffer(2);
}
}
🛠️ Диагностика и отладка¶
Коды ошибок ModbusMaster¶
Код │ Константа │ Описание
────┼────────────────────────┼─────────────────────────────
0 │ ku8MBSuccess │ Успешное выполнение
1 │ ku8MBIllegalFunction │ Недопустимая функция
2 │ ku8MBIllegalDataAddress│ Недопустимый адрес данных
3 │ ku8MBIllegalDataValue │ Недопустимое значение данных
4 │ ku8MBSlaveDeviceFailure│ Ошибка ведомого устройства
224 │ ku8MBInvalidSlaveID │ Недопустимый ID устройства
225 │ ku8MBInvalidFunction │ Недопустимая функция
226 │ ku8MBResponseTimedOut │ Таймаут ответа
227 │ ku8MBInvalidCRC │ Ошибка CRC
Проверка связи¶
bool testModbusConnection() {
logSystem("Тест связи с датчиком JXCT...");
// Попытка чтения версии прошивки
uint8_t result = modbus.readHoldingRegisters(0x0007, 1);
if (result == modbus.ku8MBSuccess) {
uint16_t version = modbus.getResponseBuffer(0);
logSuccess("Датчик найден! Версия прошивки: %d.%d",
(version >> 8) & 0xFF, version & 0xFF);
return true;
} else {
logError("Ошибка связи с датчиком: %d", result);
return false;
}
}
🔍 Расчет CRC16¶
MODBUS RTU использует CRC16 с полиномом 0xA001:
uint16_t calculateCRC16(uint8_t* data, size_t length) {
uint16_t crc = 0xFFFF;
for (size_t i = 0; i < length; i++) {
crc ^= (uint16_t)data[i];
for (int j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = crc >> 1;
}
}
}
return crc;
}
🚨 Типичные проблемы и решения¶
1. Таймаут ответа (ku8MBResponseTimedOut)¶
Причины: - Неправильное подключение A+/B- - Неисправность кабеля RS485 - Неправильный адрес устройства - Проблемы с питанием датчика
Решение:
// Проверка подключения
if (!testModbusConnection()) {
logError("Проверьте подключение RS485 и питание датчика");
}
2. Ошибка CRC (ku8MBInvalidCRC)¶
Причины: - Помехи в линии RS485 - Плохое качество кабеля - Неправильная скорость передачи
Решение: - Использовать экранированный кабель - Проверить заземление - Добавить терминальные резисторы (120 Ом)
3. Недопустимый адрес данных (ku8MBIllegalDataAddress)¶
Причины: - Запрос несуществующего регистра - Различия в версиях прошивки датчика
Решение:
// Проверка поддерживаемых регистров
const uint16_t test_registers[] = {0x0006, 0x0012, 0x0013, 0x0015};
for (int i = 0; i < 4; i++) {
uint8_t result = modbus.readHoldingRegisters(test_registers[i], 1);
if (result != modbus.ku8MBSuccess) {
logWarn("Регистр 0x%04X недоступен: %d", test_registers[i], result);
}
}
📐 Валидация данных¶
Допустимые диапазоны¶
bool validateSensorData(SensorData& data) {
// Температура: -45°C до +115°C (диапазон датчика JXCT 7-in-1)
if (data.temperature < SENSOR_TEMP_MIN || data.temperature > SENSOR_TEMP_MAX) return false;
// Влажность: 0% до 100%
if (data.humidity < SENSOR_HUMIDITY_MIN || data.humidity > SENSOR_HUMIDITY_MAX) return false;
// pH: 3.0 до 9.0 (рабочий диапазон датчика JXCT 7-in-1)
if (data.ph < SENSOR_PH_MIN || data.ph > SENSOR_PH_MAX) return false;
// EC: 0 до 10000 µS/cm (рабочий диапазон датчика JXCT 7-in-1)
if (data.ec < SENSOR_EC_MIN || data.ec > SENSOR_EC_MAX) return false;
// NPK: 0 до 1999 мг/кг (рабочий диапазон датчика JXCT 7-in-1)
if (data.nitrogen < SENSOR_NPK_MIN || data.nitrogen > SENSOR_NPK_MAX) return false;
if (data.phosphorus < SENSOR_NPK_MIN || data.phosphorus > SENSOR_NPK_MAX) return false;
if (data.potassium < SENSOR_NPK_MIN || data.potassium > SENSOR_NPK_MAX) return false;
return true;
}
📋 Справочная информация¶
Документация производителя¶
- Производитель: JXCT (Jingxun Changtong)
- Модель: JXBS-3001 7-in-1 Soil Sensor
- Интерфейс: RS485 Modbus RTU
- Питание: 12-24V DC
- Протокол: Modbus RTU
Связанные файлы проекта¶
src/modbus_sensor.h
- Определения констант и структурsrc/modbus_sensor.cpp
- Реализация функцийinclude/jxct_config_vars.h
- Настройки пиновdocs/API.md
- REST API документация
Документ обновлен для версии JXCT v3.10.0
📞 Поддержка¶
💬 Связь с разработчиками¶
- Telegram: @Gfermoto
- GitHub Issues: Сообщить о проблеме
- Документация: GitHub Pages
📚 Дополнительные ресурсы¶
- Руководство пользователя
- Техническая документация
- Агрономические рекомендации
- Руководство по компенсации
- API документация
- Управление конфигурацией
- Схема подключения
- Управление версиями
🔗 Полезные ссылки¶
- 🌱 GitHub репозиторий - Исходный код проекта
- 📋 План рефакторинга - Планы развития
- 📊 Отчет о техническом долге - Анализ технических проблем
- 🏗️ Архитектура системы - Общая архитектура проекта