Wemos d1 mini pro / max485 / danfoss vlt 6000

Hello, please take a look at this code. I want to read from danfoss vlt 6000 parameter 511. according to the manual, the address should look like 511 * 10 - 1, that is 5109 decimal.
when I try to read the parameter I get error 226. I try twist A and B, use other pins on wemos, use another modbus libraries. I want only know, that this code is fine. then i can buy another one max485 and try again.

i have connected DI to D6 and RO to D5, RE and DE to D3. A - 68 (danfoss) B- 69 (danfoss)

other things like webserial and arduino ota are there because the converter is already mounted and working.

i use this max485

danfoss vlt 6000 manual
Modbus RTU danfoss manual

full code here, shortest code is in third post

#include <ModbusMaster.h>
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <map>
#include <ESPAsyncWebServer.h>
#include <WebSerial.h>
#include <ArduinoOTA.h>

#define SLAVE_ID 1
#define FIRST_REG 0
#define REG_COUNT 2

#define MAX485_DE D3 // D5
#define MAX485_RE D3 // D6

// Nastavenie Wi-Fi
const char* ssid = "WiFi";      // Zmeň na svoje SSID
const char* password = "pass";  // Zmeň na svoje heslo

uint16_t holdingRegisterAddress = 511; // Predvolená hodnota
uint16_t data = 0;

// Inicializácia SoftwareSerial
SoftwareSerial S(D5, D6); // RX, TX
AsyncWebServer server(80);
ModbusMaster mb;

// IP adresa a subnet pre ESP8266
IPAddress localIP(192, 168, 1, 11);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

// Mapa pre faktory konverzie
std::map<int, float> faktor_konverzie = {
    {500, 1.0}, {501, 1.0}, {502, 1.0}, {503, 1.0},
    {504, 1.0}, {505, 1.0}, {506, 1.0}, {507, 1.0},
    {508, 1.0}, {509, 0.1}, {510, 0.001}, {511, 0.001},
    {512, 0.1}, {513, 0.01}, {514, 0.01}, {515, 1.0},
    {516, 0.01}, {517, 0.1}, {518, 1.0}, {519, 1.0},
    {520, 1.0}, {521, 1.0}, {522, 0.1}, {523, 0.1},
    {524, 0.0001}, {525, 0.1}, {526, 0.1}
};

// Funkcia pre vykreslenie stránky
void handleRoot(AsyncWebServerRequest *request) {
    String html = "<!DOCTYPE html><html><head><title>Modbus Hodnota</title>";
    html += "<script src='https://code.jquery.com/jquery-3.6.0.min.js'></script>";
    html += "<script src='https://cdn.jsdelivr.net/npm/chart.js'></script>";
    html += "<style>canvas { width: 100% !important; height: 300px !important; }</style>";
    html += "</head><body>";
    html += "<h1>Hodnota z registra:</h1>";
    
    // Formulár na zadávanie adresy holding registra
    html += "<form id='registerForm'>";
    html += "Zadaj adresu holding registra: <input type='number' id='registerAddress' value='" + String(holdingRegisterAddress) + "' min='0'>";
    html += "<input type='submit' value='Načítať'>";
    html += "</form>";
    
    // Canvas pre graf
    html += "<canvas id='myChart'></canvas>";
    html += "<script>";
    html += "var ctx = document.getElementById('myChart').getContext('2d');";
    html += "var myChart = new Chart(ctx, {";
    html += "type: 'line',";
    html += "data: { labels: [], datasets: [{ label: 'Hodnota registra', data: [], borderColor: 'rgba(75, 192, 192, 1)', borderWidth: 1 }] },";
    html += "options: { scales: { y: { beginAtZero: true } } }";
    html += "});";

    // AJAX na aktualizáciu grafu
    html += "function fetchValue(address) {";
    html += "$.ajax({";
    html += "url: '/getValue?address=' + address,";
    html += "success: function(data) {";
    html += "data = parseInt(data);"; // Prevod na celé číslo
    html += "if (myChart.data.labels.length >= 10) {";
    html += "myChart.data.labels.shift();"; // Odstránenie najstaršej hodnoty
    html += "myChart.data.datasets[0].data.shift();"; // Odstránenie najstaršej hodnoty
    html += "}";
    html += "myChart.data.labels.push(new Date().toLocaleTimeString());"; // Pridanie časovej značky
    html += "myChart.data.datasets[0].data.push(data);"; // Pridanie novej hodnoty
    html += "myChart.update();"; // Aktualizácia grafu
    html += "}";
    html += "});";
    html += "}";

    // Obsluha formulára
    html += "$('#registerForm').submit(function(event) {";
    html += "event.preventDefault();"; // Zastavenie predvoleného správania formulára
    html += "var address = $('#registerAddress').val();";
    html += "fetchValue(address);"; // Volanie funkcie fetchValue s zadanou adresou
    html += "});";
    
    html += "</script>";
    html += "</body></html>";
    
    request->send(200, "text/html", html);
    WebSerial.println("request send");
}

// Funkcia pre získanie hodnoty registra
void handleGetValue(AsyncWebServerRequest *request) {
    uint8_t result;
    WebSerial.println("handleGetValue");
  
    // Získanie adresy z požiadavky
    if (request->hasParam("address")) {
        holdingRegisterAddress = request->getParam("address")->value().toInt();
    }

    // Prepočet adresy na hexadecimálnu formu pre Danfoss
    int modbusAddress = holdingRegisterAddress * 10 - 1;
    WebSerial.println(modbusAddress);

    digitalWrite(MAX485_DE, HIGH);
    digitalWrite(MAX485_RE, HIGH);

    // Inicializácia výsledku
    result = mb.readHoldingRegisters(modbusAddress, 2); // Pokus o čítanie

    digitalWrite(MAX485_DE, LOW);
    digitalWrite(MAX485_RE, LOW);

    // Spracovanie výsledku
    if (result == mb.ku8MBSuccess) {
        float faktor = faktor_konverzie[holdingRegisterAddress];
        float processedValue = mb.getResponseBuffer(0) * faktor;
        request->send(200, "text/plain", String(processedValue));
        WebSerial.println(processedValue);
    } else {
        request->send(500, "text/plain", "Chyba: " + String(result));
        WebSerial.println("result chyba " + String(result));
    }
}

void setup() {
    S.begin(9600); // Spustenie SoftwareSerial
    mb.begin(SLAVE_ID, S); // Inicializácia Modbus s ID a prenosom

    // Nastavenie Wi-Fi
    WiFi.config(localIP, gateway, subnet);
    WiFi.begin(ssid, password);

    // Čakanie na pripojenie k Wi-Fi
    while (WiFi.status() != WL_CONNECTED) {
        delay(2000);
    }
    
    // Nastavenie WebSerial pre výstup logov
    WebSerial.begin(&server);

    // Nastavenie rout pre server
    server.on("/", HTTP_GET, handleRoot);
    server.on("/getValue", HTTP_GET, handleGetValue);

    // Spustenie webového servera
    server.begin();

    // Inicializácia OTA
    ArduinoOTA.onStart([]() {
        String type;
        if (ArduinoOTA.getCommand() == U_FLASH) {
            type = "sketch"; // je to nahratie sketchu
        } else { // U_SPIFFS
            type = "filesystem"; // je to nahratie SPIFFS
        }
        // Uložení názvu pre použitie pri debugovaní
        WebSerial.print("Start updating " + type);
    });
    ArduinoOTA.onEnd([]() {
        WebSerial.println("\nEnd");
    });
    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
        WebSerial.printf("Progress: %u%%\r", (progress / total) * 100); // Opravená chyba tu
    });
    ArduinoOTA.onError([](ota_error_t error) {
        WebSerial.printf("Error[%u]: ", error);
        if (error == OTA_AUTH_ERROR) {
            WebSerial.println("Auth Failed");
        } else if (error == OTA_BEGIN_ERROR) {
            WebSerial.println("Begin Failed");
        } else if (error == OTA_CONNECT_ERROR) {
            WebSerial.println("Connect Failed");
        } else if (error == OTA_RECEIVE_ERROR) {
            WebSerial.println("Receive Failed");
        } else if (error == OTA_END_ERROR) {
            WebSerial.println("End Failed");
        }
    });
    ArduinoOTA.begin();

    pinMode(MAX485_DE, OUTPUT);
    pinMode(MAX485_RE, OUTPUT);
    digitalWrite(MAX485_RE, LOW);
    digitalWrite(MAX485_DE, LOW);
}

void loop() {
    WebSerial.loop();     // Spracovanie WebSerial
    ArduinoOTA.handle();  // Spracovanie OTA
    delay(10);            // Krátka oneskorenie pre stabilitu
}

I would recommend making a minimum length code that demonstrates the problem. Remove any other code not related or needed to demonstrate the problem. For example remove all the code related to serving web pages. Just have the minimum code read the required register and print the result to serial monitor.

Making this minimum code may help you solve the problem yourself. If not, post it here and forum members will be much more likely to have the time to read through it and check it for you.

1 Like

thanks for answer, here is the simplest code what i try, but a become error 226

include <ModbusMaster.h>
#include <SoftwareSerial.h>

// Pripoj TX a RX piny k Wemos D1 mini pro
SoftwareSerial mySerial(D5, D6); // RX, TX
ModbusMaster mb;

void setup() {
    Serial.begin(115200);      // Inicializácia sériovej komunikácie pre debugovanie
    mySerial.begin(9600);      // Inicializácia sériovej komunikácie pre MAX485
    mb.begin(1, mySerial);     // Nastav adresu Modbus master na 1
}

void loop() {
    uint8_t result;

    // Vypočítaj začiatkovú adresu pre parameter 514
    uint16_t startAddress = (514 * 10) - 1; // 5139

    // Pošli príkaz na čítanie holding registrov
    result = mb.readHoldingRegisters(startAddress, 2); // Adresa 1, začiatok 5139, čítaj 2 registrové hodnoty

    if (result == mb.ku8MBSuccess) { // Kontrola výsledku
        uint32_t motorCurrent = (mb.getResponseBuffer(0) << 16) | mb.getResponseBuffer(1); // Kombinuj 2 registre na UINT32
        motorCurrent *= -2; // Aplikuj konverzný faktor (v tomto prípade -2)

        Serial.print("Motor Current: ");
        Serial.print(motorCurrent);
        Serial.println(" Amps");
    } else {
        Serial.print("Chyba: ");
        Serial.println(result); // Vypíš chybu
    }

    delay(1000); // Krátka pauza pred ďalším čítaním
}

Much better.

Unfortunately I don't have experience using modbus, and I cannot see any problem with that code.

Hopefully a forum member with modbus knowledge will answer soon.

I suggest editing your original post and adding a note at the top that a shorter code has been added in post #3. Don't make any other change to the original post.

1 Like

@sapler is this the ModbusMaster library you are using?

Unless I missed it, I can't see where your code controls the RE and DE signals. The library makes calls to the functions preTransmission and post transmission that are usually part of your code.

However, your RS485 module may be an auto switching one that doesn't have RE and DE.
EDIT: it's a standard RS485 module so you need to control RE and DE.

In addition and possibly unrelated to your issue, I think the Wemos D1 is a 3.3v device, but the MAX485 is a 5v device. You would need to implement some level shifting in order to protect the Wemos from the 5v output of the MAX485.

Here's the code from one of the library examples:

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}

And the code at the end of setup() to tell the library about them:

  // Modbus slave ID 1
  node.begin(1, Serial);
  // Callbacks allow us to configure the RS485 transceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
1 Like

so which address is correct one?

1 Like

it doesn't matter, i only tried different addresses.

include <ModbusMaster.h>
#include <SoftwareSerial.h>

// Pripoj TX a RX piny k Wemos D1 mini pro
SoftwareSerial mySerial(D5, D6); // RX, TX
ModbusMaster mb;

void setup() {
    Serial.begin(115200);      // Inicializácia sériovej komunikácie pre debugovanie
    mySerial.begin(9600);      // Inicializácia sériovej komunikácie pre MAX485
    mb.begin(1, mySerial);     // Nastav adresu Modbus master na 1
}

void loop() {
    // Vypočítaj začiatkovú adresu pre parameter 511
   const uint16_t startAddress = 5109; 

    // Pošli príkaz na čítanie holding registrov
    uint8_t errNum = mb.readHoldingRegisters(startAddress, 2); // Adresa 1, začiatok 5139, čítaj 2 registrové hodnoty

    if (errNum == mb.ku8MBSuccess) { // Kontrola výsledku
        uint32_t motorCurrent = mb.getResponseBuffer(0); // Kombinuj 2 registre na UINT32
        motorCurrent = (motorCurrent << 16) | mb.getResponseBuffer(1); // Kombinuj 2 registre na UINT32
        motorCurrent *= -2; // Aplikuj konverzný faktor (v tomto prípade -2)

        Serial.print("Motor Current: ");
        Serial.print(motorCurrent);
        Serial.println(" Amps");
    } else {
        Serial.print("Chyba: ");
        Serial.println(errNum); // Vypíš chybu
    }

    delay(1000); // Krátka pauza pred ďalším čítaním
}

and not forget to show the serial monitor output messages

1 Like

yes i use this library, yes, this mas485 really needs DE and RE controls, I have them in the long code, I forgot to write it in a hurry in this short code. but thanks for the warning, about the voltage differences between the wemos and the max485, I think there will probably be a problem, I'll try using the Uno and report back with the result.

edit : now i try this code with another one max485 module (new) and same result, error 226, on danfoss i set baud 9600, no parity / 1 stop bit.

#include <ModbusMaster.h>
#include <SoftwareSerial.h>

#define MAX485_DE 3
#define MAX485_RE 4
// Pripoj TX a RX piny k Wemos D1 mini pro
SoftwareSerial mySerial(2, 5); // RX, TX
ModbusMaster mb;

void preTransmission()
{
  digitalWrite(MAX485_RE, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE, 0);
  digitalWrite(MAX485_DE, 0);
}

void setup() {
    Serial.begin(115200);      // Inicializácia sériovej komunikácie pre debugovanie
    mySerial.begin(9600);      // Inicializácia sériovej komunikácie pre MAX485
    mb.begin(1, mySerial);     // Nastav adresu Modbus master na 1
    pinMode(MAX485_RE, OUTPUT); 
    pinMode(MAX485_DE, OUTPUT);
    digitalWrite(MAX485_RE, 1);
  digitalWrite(MAX485_DE, 1);
}

void loop() {
   // Vypočítaj začiatkovú adresu pre parameter 511
   const uint16_t startAddress = 5109; 
     preTransmission(); 
     delay(20); 
    // Pošli príkaz na čítanie holding registrov
    uint8_t errNum = mb.readHoldingRegisters(startAddress, 2); // Adresa 1, začiatok 5139, čítaj 2 registrové hodnoty
    delay(20);
    postTransmission();
    if (errNum == mb.ku8MBSuccess) { // Kontrola výsledku
        uint32_t motorCurrent = mb.getResponseBuffer(0); // Kombinuj 2 registre na UINT32
        motorCurrent = (motorCurrent << 16) | mb.getResponseBuffer(1); // Kombinuj 2 registre na UINT32
        motorCurrent *= -2; // Aplikuj konverzný faktor (v tomto prípade -2)

        Serial.print("Motor Current: ");
        Serial.print(motorCurrent);
        Serial.println(" Amps");
    } else {
        Serial.print("Chyba: ");
        Serial.println(errNum); // Vypíš chybu
    }

    delay(5000); // Krátka pauza pred ďalším čítaním
    
  }

another idea what can i try ?

thanks very very much

error-code 226 means timeout - no response

  • did you try to the most basic modbus-request and get an answer for this request?

  • does this VLT6000-device send any kind of messages by itself?

  • do you have an oscilloscope ?

  • do you have a logic analyser? (there are these 10 to 20 $ cheap 24 MHz 8 channel logic analysers

This page from the danfoss modbus RTU-manual describes the factory settings


Did you check if your device is still adjusted to factory settings?

1 Like

Not sure it will make a difference, but you don't call preTransmission and postTransmission yourself. Those routines are called by the library and you simply tell the library about them in your setup code.

See my post #5 above - end of post detailing callbacks.

1 Like

i dont have osciloscope,
danfoss i have on factory setting, only i change rs485 protocol to modbus RTU and a try baud 9600 then 4800.

i try now this code

#include <ModbusMaster.h>
#include <SoftwareSerial.h>

#define MAX485_DE 3
#define MAX485_RE 4
// Pripoj TX a RX piny k Wemos D1 mini pro
SoftwareSerial mySerial(2, 5); // RX, TX
ModbusMaster mb;

void preTransmission()
{
  digitalWrite(MAX485_RE, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE, 0);
  digitalWrite(MAX485_DE, 0);
}

void setup() {
    Serial.begin(9600);      // Inicializácia sériovej komunikácie pre debugovanie
    mySerial.begin(4800);      // Inicializácia sériovej komunikácie pre MAX485
    mb.begin(1, mySerial);     // Nastav adresu Modbus master na 1
    
  mb.preTransmission(preTransmission);
  mb.postTransmission(postTransmission);
}

void loop() {
   // Vypočítaj začiatkovú adresu pre parameter 511
   const uint16_t startAddress = 5129; 
     
    // Pošli príkaz na čítanie holding registrov
    uint8_t errNum = mb.readHoldingRegisters(startAddress, 2); // Adresa 1, začiatok 5139, čítaj 2 registrové hodnoty
    
    if (errNum == mb.ku8MBSuccess) { // Kontrola výsledku
        uint32_t motorCurrent = mb.getResponseBuffer(0); // Kombinuj 2 registre na UINT32
        motorCurrent = (motorCurrent << 16) | mb.getResponseBuffer(1); // Kombinuj 2 registre na UINT32
        motorCurrent *= -2; // Aplikuj konverzný faktor (v tomto prípade -2)

        Serial.print("Motor Current: ");
        Serial.print(motorCurrent);
        Serial.println(" Amps");
    } else {
        Serial.print("Chyba: ");
        Serial.println(errNum); // Vypíš chybu
    }

    delay(5000); // Krátka pauza pred ďalším čítaním
    
  }

i buy logic analyser.
i will check what come from my arduino nano. then i send respond.

thank you guys

I would suggest a simple USB-RS485 dongle so that your PC can listen in to the comms on the RS485 bus.

Parameter 511 should be address 5109 according to the user manual you provided.

1 Like

As soon as you put together multiple components.
The number of possible bugs is rising.

Did you do some basic testing with two microcontrollers each having such a RS485-modul and to send/receive messages between these two microcontrollers each µC connected to one RS485-module?

1 Like

also guys, i think problem was here

when i define RE/DE like this all works

#define MAX485_DE      3
#define MAX485_RE_NEG  4 

this works

#include <ModbusMaster.h>

#define MAX485_DE      3
#define MAX485_RE_NEG  4 

// instantiate ModbusMaster object
ModbusMaster node;

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}

void setup()
{
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);

  // Modbus communication runs at 115200 baud
  Serial.begin(9600);

  // Modbus slave ID 1
  node.begin(1, Serial);
  // Callbacks allow us to configure the RS485 transceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

bool state = true;

void loop()
{
  uint8_t result;
  uint16_t data[6];
  
  // Toggle the coil at address 0x0002 (Manual Load Control)
 //  result = node.writeSingleCoil(0x0002, state);
  //state = !state;

  // Read 16 registers starting at 0x3100)
  result = node.readHoldingRegisters(0x1477, 2);
  if (result == node.ku8MBSuccess)
  {
    uint32_t motorCurrent = node.getResponseBuffer(0); // Kombinuj 2 registre na UINT32
        motorCurrent = (motorCurrent << 16) | node.getResponseBuffer(1); // Kombinuj 2 registre na UINT32
        motorCurrent *= 0.0001; // Aplikuj konverzný faktor (v tomto prípade -2)
    Serial.print("Motor Current: ");
        Serial.print(motorCurrent);
        Serial.println(" Amps");
    } else {
        Serial.print("Chyba: ");
        Serial.println(result); // Vypíš chybu
    }
  

  delay(5000);
}

i try too wemos d1 mini pro with max485 and with softwareserial works fine. but i supply max485 with 3,3V.

thanks very very much guys you helped me

It doesn't make any difference how you define them.

#define DONALD_DUCK      3
#define DONALD_TRUMP  4 

would work equally, as far as it corresponds with your function.

@kmin Look at the 1st post, D3 and D4 were there...

oh yes, u have true, then i have maybe broken wire or something,

EDIT :
i connected first time DE/RE two pins togheter and a control this pins with one digital output, i thing that cant be problem.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.