Вот модуль для UART-RS485 адаптера и Web-интерфейс для отладки.
---
1. Библиотека ModbusMaster
Установка через Arduino IDE:
1. Скетч → Include Library → Manage Libraries
2. Поиск: "ModbusMaster" by 4-20ma
3. Установить версию 2.0.1
2. Модуль для UART-RS485
```cpp
#include <ModbusMaster.h>
#include <WiFi.h>
#include <WebServer.h>
// Настройки WiFi
const char* ssid = "CNC_Controller";
const char* password = "12345678";
WebServer server(80);
// Modbus объект
ModbusMaster inverter;
// Переменные для настройки
int modbusAddress = 10;
int baudRate = 9600;
int registerWriteAddr = 0x2000;
int registerReadAddr = 0x3000;
int frequencyRegister = 0x2001;
void setup() {
Serial.begin(115200);
// Запуск WiFi в режиме точки доступа
WiFi.softAP(ssid, password);
Serial.print("AP IP address: ");
Serial.println(WiFi.softAPIP());
// Инициализация Modbus на Serial1
Serial1.begin(baudRate, SERIAL_8N1, 16, 17); // RX=16, TX=17 ESP32
inverter.begin(modbusAddress, Serial1);
// Настройка endpoints Web-сервера
server.on("/", handleRoot);
server.on("/set", handleSet);
server.on("/read", handleRead);
server.on("/config", handleConfig);
server.begin();
Serial.println("Web server started");
}
void handleRoot() {
String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<title>CNC Inverter Controller</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial; margin: 20px; }
.card { background: #f0f0f0; padding: 15px; margin: 10px 0; border-radius: 5px; }
input, button { padding: 8px; margin: 5px; }
.status { color: green; font-weight: bold; }
.error { color: red; }
</style>
</head>
<body>
<h1>Управление инвертором YL620</h1>
<div class="card">
<h3>Быстрое управление</h3>
<button onclick="sendCommand('start')">START</button>
<button onclick="sendCommand('stop')">STOP</button>
<br>
Мощность: <input type="number" id="power" min="0" max="100" value="50">%
<button onclick="setPower()">Установить</button>
</div>
<div class="card">
<h3>Ручная отправка Modbus</h3>
Адрес: <input type="number" id="regAddr" value="2000" min="0" max="65535">
Значение: <input type="number" id="regValue" value="1">
<button onclick="writeRegister()">Write</button>
<button onclick="readRegister()">Read</button>
<br>
Результат: <span id="result">-</span>
</div>
<div class="card">
<h3>Настройки связи</h3>
Адрес устройства: <input type="number" id="mbAddr" value="10">
Скорость:
<select id="baud">
<option value="1200">1200</option>
<option value="2400">2400</option>
<option value="4800">4800</option>
<option value="9600" selected>9600</option>
<option value="19200">19200</option>
<option value="38400">38400</option>
</select>
<button onclick="saveConfig()">Сохранить</button>
</div>
<div id="status"></div>
<script>
function sendCommand(cmd) {
fetch('/set?cmd=' + cmd)
.then(r => r.text())
.then(t => document.getElementById('status').innerHTML = t);
}
function setPower() {
let power = document.getElementById('power').value;
fetch('/set?cmd=power&value=' + power)
.then(r => r.text())
.then(t => document.getElementById('status').innerHTML = t);
}
function writeRegister() {
let addr = document.getElementById('regAddr').value;
let value = document.getElementById('regValue').value;
fetch('/set?cmd=write&addr=' + addr + '&value=' + value)
.then(r => r.text())
.then(t => document.getElementById('result').innerHTML = t);
}
function readRegister() {
let addr = document.getElementById('regAddr').value;
fetch('/read?addr=' + addr)
.then(r => r.text())
.then(t => document.getElementById('result').innerHTML = t);
}
function saveConfig() {
let addr = document.getElementById('mbAddr').value;
let baud = document.getElementById('baud').value;
fetch('/config?addr=' + addr + '&baud=' + baud)
.then(r => r.text())
.then(t => document.getElementById('status').innerHTML = t);
}
</script>
</body>
</html>
)rawliteral";
server.send(200, "text/html", html);
}
void handleSet() {
String cmd = server.arg("cmd");
String response = "";
if (cmd == "start") {
response = startInverter() ? "Инвертор запущен" : "Ошибка запуска";
}
else if (cmd == "stop") {
response = stopInverter() ? "Инвертор остановлен" : "Ошибка остановки";
}
else if (cmd == "power") {
float power = server.arg("value").toFloat();
response = setPower(power) ? "Мощность установлена: " + String(power) + "%" : "Ошибка";
}
else if (cmd == "write") {
int addr = server.arg("addr").toInt();
int value = server.arg("value").toInt();
response = writeRegister(addr, value) ? "Write OK" : "Write FAIL";
}
server.send(200, "text/plain", response);
}
void handleRead() {
int addr = server.arg("addr").toInt();
uint16_t value = readRegister(addr);
server.send(200, "text/plain", String(value));
}
void handleConfig() {
modbusAddress = server.arg("addr").toInt();
baudRate = server.arg("baud").toInt();
// Переинициализация Modbus с новыми параметрами
Serial1.updateBaudRate(baudRate);
inverter.begin(modbusAddress, Serial1);
server.send(200, "text/plain", "Конфигурация сохранена");
}
bool startInverter() {
uint8_t result = inverter.writeSingleRegister(registerWriteAddr, 0x0001);
return (result == inverter.ku8MBSuccess);
}
bool stopInverter() {
uint8_t result = inverter.writeSingleRegister(registerWriteAddr, 0x0000);
return (result == inverter.ku8MBSuccess);
}
bool setPower(float percent) {
float freq = 50.0 * (percent / 100.0);
uint16_t value = freq * 100; // 0.01 Гц
uint8_t result = inverter.writeSingleRegister(frequencyRegister, value);
return (result == inverter.ku8MBSuccess);
}
bool writeRegister(int addr, int value) {
uint8_t result = inverter.writeSingleRegister(addr, value);
return (result == inverter.ku8MBSuccess);
}
uint16_t readRegister(int addr) {
uint8_t result = inverter.readHoldingRegisters(addr, 1);
if (result == inverter.ku8MBSuccess) {
return inverter.getResponseBuffer(0);
}
return 0xFFFF;
}
void loop() {
server.handleClient();
delay(10);
}
```
---
3. Схема подключения ESP32 к RS-485
```
ESP32:
GPIO16 (RX2) → RO RS-485 адаптера
GPIO17 (TX2) → DI RS-485 адаптера
GND → GND адаптера
RS-485 адаптер:
A → A инвертора (RS-485+)
B → B инвертора (RS-485-)
VCC → 3.3V или 5V ESP32
```
---
4. Функциональность Web-интерфейса
Возможности:
1. Быстрое управление: Старт/Стоп, установка мощности %
2. Ручная работа с регистрами: Любые адреса 0-65535
3. Настройка связи: Адрес устройства, скорость
4. Реальное время: Мгновенное обновление статуса
Типичные регистры для YL620:
// Запись
0x2000 - Управление (1=старт, 0=стоп)
0x2001 - Задание частоты (0-5000 = 0-50.00 Гц)
// Чтение
0x3000 - Текущая частота
0x3001 - Выходной ток
0x3002 - Выходное напряжение
0x3003 - Состояние ошибки
```
---
5. Дополнительные функции для отладки
Добавьте в handleRoot() после основного HTML:
<div class="card">
<h3>Автосканирование регистров</h3>
Начальный адрес: <input type="number" id="scanStart" value="8192">
Количество: <input type="number" id="scanCount" value="10">
<button onclick="scanRegisters()">Сканировать</button>
<pre id="scanResult"></pre>
</div>
<script>
function scanRegisters() {
let start = parseInt(document.getElementById('scanStart').value);
let count = parseInt(document.getElementById('scanCount').value);
let result = "";
for(let i = 0; i < count; i++) {
fetch('/read?addr=' + (start + i))
.then(r => r.text())
.then(t => {
result += "Регистр " + (start + i) + ": " + t + "\n";
document.getElementById('scanResult').innerText = result;
});
}
}
</script>
```
---
6. Настройка инвертора для RS-485
P00.01 = 3 // Управление через Modbus
P03.00 = 5 // 38400 бод (или 3=9600)
P03.01 = 10 // Адрес устройства
P03.02 = 2 // 8N1 (no parity)
```
Запуск:
1. Прошейте ESP32
2. Подключитесь к WiFi CNC_Controller (пароль: 12345678)
3. Откройте в браузере IP адрес (обычно 192.168.4.1)
4. Начинайте отладку!
Теперь вы можете интерактивно подбирать регистры и тестировать управление ТЭНами! 🔥
. Интересует опыт прошедших путь, от и до ... .



