{"id":210,"date":"2025-11-19T13:17:11","date_gmt":"2025-11-19T12:17:11","guid":{"rendered":"https:\/\/mrhengineering.dk\/?p=210"},"modified":"2025-11-19T13:54:21","modified_gmt":"2025-11-19T12:54:21","slug":"modbus-control-of-vfd","status":"publish","type":"post","link":"https:\/\/mrhengineering.dk\/?p=210","title":{"rendered":"MODBUS control of VFD"},"content":{"rendered":"\n<p>A long time ago I brought a variable frequency drive which I want to use for driving a spindle motor for a milling machine. The VFD is a Huanyang Inverter HY01D523B (1.5 kW, 7A, 220V 50Hz). I want to be able to control it through the MODBUS interface to be able to change speed and direction from g-code, and therefore I made the test setup <a href=\"https:\/\/fightpc.blogspot.com\/2014\/10\/vfd-control-with-arduino-using-rs485.html\" data-type=\"link\" data-id=\"https:\/\/fightpc.blogspot.com\/2014\/10\/vfd-control-with-arduino-using-rs485.html\">suggested here<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"978\" src=\"https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_arduinoUNO-1024x978.jpg\" alt=\"\" class=\"wp-image-213\" srcset=\"https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_arduinoUNO-1024x978.jpg 1024w, https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_arduinoUNO-300x287.jpg 300w, https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_arduinoUNO-768x734.jpg 768w, https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_arduinoUNO-1536x1468.jpg 1536w, https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_arduinoUNO.jpg 1662w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The MAX485 board is connected to the Arduino ports 8, 9, 10 and 11, and to 5V and ground. The screw terminal is connected to the VFD: RS+ to A and RS- to B.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"934\" height=\"1024\" src=\"https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_inverter-934x1024.jpg\" alt=\"\" class=\"wp-image-214\" srcset=\"https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_inverter-934x1024.jpg 934w, https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_inverter-274x300.jpg 274w, https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_inverter-768x842.jpg 768w, https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_inverter-1401x1536.jpg 1401w, https:\/\/mrhengineering.dk\/wp-content\/uploads\/2025\/11\/VFD_inverter-1868x2048.jpg 1868w\" sizes=\"auto, (max-width: 934px) 100vw, 934px\" \/><\/figure>\n\n\n\n<p>The inverter is wired as described in the manual. But how to use the MODBUS interface is not described in detail, so I had to search the internet and found these sources, which are helpful: <a href=\"https:\/\/www.modbustools.com\/modbus.html\" data-type=\"link\" data-id=\"https:\/\/www.modbustools.com\/modbus.html\">modbustools<\/a>, <a href=\"https:\/\/en.industryarena.com\/forum\/rs485-commands-huanyang-vfd-hy02d223b--269196.html\" data-type=\"link\" data-id=\"https:\/\/en.industryarena.com\/forum\/rs485-commands-huanyang-vfd-hy02d223b--269196.html\">industryarena<\/a> <a href=\"https:\/\/gist.github.com\/Bouni\/803492ed0aab3f944066\" data-type=\"link\" data-id=\"https:\/\/gist.github.com\/Bouni\/803492ed0aab3f944066\">Bouni<\/a> and <a href=\"https:\/\/github.com\/LacobusVentura\/MODBUS-CRC16\" data-type=\"link\" data-id=\"https:\/\/github.com\/LacobusVentura\/MODBUS-CRC16\">LacobusVentura<\/a>. The settings I use in the VFD is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PD001: 2 (Source of run commands: communication port)<\/li>\n\n\n\n<li>PD002: 2 (Source of operating frequency: communication port)<\/li>\n\n\n\n<li>PD163: 1 (Communication address: 1)<\/li>\n\n\n\n<li>PD164: 1 (Communication Baud Rate: 9600)<\/li>\n\n\n\n<li>PD165: 3 (Communication Data Method: 8N1 RTU)<\/li>\n<\/ul>\n\n\n\n<p>Here is some code for testing the setup on an Arduino UNO. The code is made so that it can be copied to larger projects. At some point I want to use it with hardware serial on an Arduino MEGA, but that is not tested yet. I cannot say that code will always work, but it works for my setup. Based on the different sources for information it seems that there are many versions of software installed on the Huanyang inverters, so I cannot promise anything.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/* Modbus rtu for Huanyang Inverter\n    PD001: 2 (Source of run commands: communication port)\n    PD002: 2 (Source of operating frequency: communication port)\n    PD163: 1 (Communication address: 1)\n    PD164: 1 (Communication Baud Rate: 9600)\n    PD165: 3 (Communication Data Method: 8N1 RTU)\n\nThe RTU demands silence for 3.5 characters time. 8*3.5\/BAUDRATE = 2.9166 ms \\approx 3 ms\n\n  2025-11-19 Morten Rydahl-Haastrup\n*\/\n#define DEBUGPRINT\n#define SOFTWARESERIAL\n#define MODBUS_BAUDRATE 9600\n#define MODBUS_SILENCE 3\n\n#ifdef SOFTWARESERIAL\n#include &lt;SoftwareSerial.h>\n#define TX_PIN 8\n#define RX_PIN 11\n#else\n#define myserial Serial2\n#endif\n\n#define DRIVE_ENABLE_PIN 9\n#define RECEIVE_ENABLE_PIN 10\n\n#define HY_RUN 1\n#define HY_FOR 2 \/\/ Forward\n#define HY_REV 17 \/\/ Backwards (it is not 3)\n#define HY_STOP 8 \n\n#define HY_READ 1\n#define HY_WRITE_FUNCTION 2\n#define HY_WRITE_CONTROL 3\n#define HY_READ_STATUS 4\n#define HY_WRITE_FREQUENCY 5\n\nstatic uint16_t MODBUS_CRC16_v2( unsigned char *buf, uint8_t len )\n{\n  \/\/https:\/\/github.com\/LacobusVentura\/MODBUS-CRC16\n\tstatic const uint16_t table&#91;2] = { 0x0000, 0xA001 };\n\tuint16_t crc = 0xFFFF;\n\tint16_t i = 0;\n\tunsigned char bit = 0;\n\tuint16_t x_or = 0;\n\n\tfor( i = 0; i &lt; len; i++ )\n\t{\n\t\tcrc ^= buf&#91;i];\n\n\t\tfor( bit = 0; bit &lt; 8; bit++ )\n\t\t{\n\t\t\tx_or = crc &amp; 0x01;\n\t\t\tcrc >>= 1;\n\t\t\tcrc ^= table&#91;x_or];\n\t\t}\n\t}\n\n  \/\/ insert the crc at the end of the buffer\n  buf&#91;len] = (unsigned char)crc;\n  buf&#91;++len] = (unsigned char)(crc>>8);\n\n\treturn crc;\n}\n\n#ifdef SOFTWARESERIAL\nSoftwareSerial myserial(RX_PIN, TX_PIN);\n#endif\n\nclass HYInverter{\n  private:\n  uint8_t pin_de; \/\/ Driver enable pin\n  uint8_t pin_re; \/\/ Receiver enable pin\n  unsigned char msg&#91;8];\n  unsigned long t = 0;\n\n  void send(unsigned char len){\n    \/\/ Is there anything in the buffer?\n    #ifdef DEBUGPRINT\n    if (myserial.available()){\n      Serial.print(\"receive: \");\n      while (myserial.available()){\n        Serial.print(myserial.read(), HEX);\n        Serial.print(\" : \");\n      }\n      Serial.println(\" \");\n    }\n    #endif\n\n    \/\/ Send the message\n    MODBUS_CRC16_v2(msg, len);\n    digitalWrite(pin_re, LOW);\n    digitalWrite(pin_de, HIGH);\n    while (millis() &lt; t); \/\/ Wait until sufficient time has passed since last message\n    myserial.write(msg, len+2);\n    t = millis() + MODBUS_SILENCE;\n    digitalWrite(pin_de, LOW);\n    digitalWrite(pin_re, HIGH);\n\n    \/\/ Print the message\n    #ifdef DEBUGPRINT\n    Serial.print(\"send: \");\n    for (uint8_t i=0; i&lt;len+2; i++){\n      Serial.print(msg&#91;i], HEX);\n      Serial.print(\" : \");\n    }\n    Serial.println(\" \");\n    #endif\n  }\n\n  public:\n\n  void init(uint8_t DE, uint8_t RE){\n    pin_de = DE;\n    pin_re = RE;\n    pinMode(DE, OUTPUT);\n    pinMode(RE, OUTPUT);\n    digitalWrite(DE, LOW);\n    myserial.begin(MODBUS_BAUDRATE);\n    msg&#91;0] = 1;\n  }\n\n  void setAddress(unsigned char adr){\n    msg&#91;0] = adr;\n  }\n\n  void start(){\n    msg&#91;1] = HY_WRITE_CONTROL;\n    msg&#91;2] = 1;\n    msg&#91;3] = HY_RUN;\n    send(4);\n  }\n\n  void setspeed(uint16_t v){\n    msg&#91;1] = HY_WRITE_FREQUENCY;\n    msg&#91;2] = 2; \/\/ Length of data\n    msg&#91;3] = (unsigned char)(v>>8);\n    msg&#91;4] = (unsigned char)(v);\n    send(5);\n  }\n\n  void stop(){\n    msg&#91;1] = HY_WRITE_CONTROL;\n    msg&#91;2] = 1;\n    msg&#91;3] = HY_STOP;\n    send(4);\n  }\n\n  void forward(){\n    msg&#91;1] = HY_WRITE_CONTROL;\n    msg&#91;2] = 1;\n    msg&#91;3] = HY_FOR;\n    send(4);\n  }\n\n  void reverse(){\n    msg&#91;1] = HY_WRITE_CONTROL;\n    msg&#91;2] = 1;\n    msg&#91;3] = HY_REV;\n    send(4);\n  }\n};\n\nHYInverter inverter;\n\nvoid setup() {\n  #ifdef DEBUGPRINT\n  Serial.begin(9600);\n  #endif\n\n  \/\/ Initialize the inverter\n  inverter.init(DRIVE_ENABLE_PIN, RECEIVE_ENABLE_PIN);\n  inverter.setAddress(1);\n  inverter.start();\n}\n\nuint8_t d = 0;\nvoid loop() {\n  if (d == 0){\n    inverter.forward();\n    d = 1;\n  }else{\n    inverter.reverse();\n    d = 0;\n  }\n\n  for (int i=0; i&lt;20; i++){\n    inverter.setspeed(i*1500);\n    delay(1000);\n  }\n\n  inverter.setspeed(0);\n  inverter.stop();\n  delay(12000);\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A long time ago I brought a variable frequency drive which I want to use for driving a spindle motor for a milling machine. The VFD is a Huanyang Inverter HY01D523B (1.5 kW, 7A, 220V 50Hz). I want to be able to control it through the MODBUS interface to be able to change speed and [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[13,16,14,17,15],"class_list":["post-210","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-arduino","tag-inverter","tag-modbus","tag-spindle-drive","tag-variable-frequency-drive"],"_links":{"self":[{"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=\/wp\/v2\/posts\/210","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=210"}],"version-history":[{"count":7,"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=\/wp\/v2\/posts\/210\/revisions"}],"predecessor-version":[{"id":220,"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=\/wp\/v2\/posts\/210\/revisions\/220"}],"wp:attachment":[{"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=210"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=210"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mrhengineering.dk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=210"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}