Hardware-agnostic VFD (Variable Frequency Drive) controller via Modbus RTU.
- Read monitoring data (frequency, current, voltage, bus voltage)
- Set running frequency (0-100%)
- Status and fault detection with human-readable strings
- Bring your own Modbus implementation
git clone https://github.com/bahrom1dd1n/vfd-controller.git
# Copy src/ and include/ to your project- Modbus Library: master-modbus
- Hardware: RS485 interface
Edit include/vfd_config.h for your VFD model (default: Delixi):
#define VFD_MONITORING_ADDRESS 0x9000 // Adjust for your VFD
#define VFD_SET_FREQ_ADDRESS 0xA001
#define VFD_STATUS_ADDRESS 0xB000
#define VFD_ISSUE_ADDRESS 0xB001#include "vfd_controller.h"
#include "mmodbus.h" // Your Modbus library
vfd_issue my_write_reg(uint16_t slave, uint16_t addr, uint16_t val) {
int result = mmodbus_writeHoldingRegister16i(slave, addr, val);
return (result == 0) ? VFD_SUCCESS : VFD_ERROR_MODBUS_FAIL;
}
vfd_issue my_read_multi_reg(uint16_t slave, uint16_t addr,
uint16_t count, uint16_t *buf) {
int result = mmodbus_readHoldingRegisters16i(slave, addr, count, buf);
return (result == 0) ? VFD_SUCCESS : VFD_ERROR_MODBUS_FAIL;
}vfd_context_t vfd = {
.slave_address = 16,
.mb_write_single_reg = my_write_reg,
.mb_read_single_reg = my_read_reg,
.mb_read_multi_reg = my_read_multi_reg
};
vfd_init(&vfd);
// Set frequency to 50%
vfd_set_running_freq(&vfd, 50.0);
// Main loop
while (1) {
vfd_update(&vfd); // Read all registers
float freq = vfd_get_running_freq(&vfd);
float current = vfd_get_output_current(&vfd);
if (vfd_get_issue(&vfd) != VFD_NO_FAULT) {
printf("Fault: %s\n", vfd_get_issue_string(&vfd));
}
delay(100);
}void vfd_init(vfd_context_t *ctx)- Initialize VFD context
int vfd_set_running_freq(vfd_context_t *ctx, float speed)- Set frequency (0.00-100.00%)int vfd_update(vfd_context_t *ctx)- Read all VFD registers (call periodically)
float vfd_get_running_freq(vfd_context_t *ctx)- Current frequency (Hz × 0.01)float vfd_get_reference_freq(vfd_context_t *ctx)- Target frequencyfloat vfd_get_output_current(vfd_context_t *ctx)- Output current (A × 0.01)uint16_t vfd_get_output_voltage(vfd_context_t *ctx)- Output voltage (V)float vfd_get_bus_line_voltage(vfd_context_t *ctx)- Bus voltage (V × 0.1)vfd_status vfd_get_status(vfd_context_t *ctx)- Status enumvfd_issue vfd_get_issue(vfd_context_t *ctx)- Fault code enumconst char* vfd_get_status_string(vfd_context_t *ctx)- Status as stringconst char* vfd_get_issue_string(vfd_context_t *ctx)- Fault as string
Typical Settings (adjust for your VFD):
- Baud rate: 9600
- Parity: None
- Stop bits: 2
- Data bits: 8
Register Map (Delixi default):
| Address | Access | Description | Resolution |
|---|---|---|---|
| 0x9000 | Read | Running frequency | 0.01 Hz |
| 0x9001 | Read | Reference frequency | 0.01 Hz |
| 0x9002 | Read | Output current | 0.01 A |
| 0x9003 | Read | Output voltage | 1 V |
| 0x9004 | Read | Bus voltage | 0.1 V |
| 0xA001 | Write | Set frequency | 0.01% (0-10000) |
| 0xB000 | Read | Status | Enum |
| 0xB001 | Read | Fault code | Enum |
| Code | Description |
|---|---|
VFD_SUCCESS |
Operation successful |
VFD_ERROR_INVALID_PARAM |
Invalid parameter |
VFD_ERROR_MODBUS_FAIL |
Modbus communication failed |
VFD_ERROR_OUT_OF_RANGE |
Value out of range |
VFD_NONE- No statusVFD_FORWARD_RUN- Running forwardVFD_REVERSE_RUN- Running reverseVFD_STOP- Stopped
39 predefined fault codes including:
- Over-current/voltage conditions
- Motor overload/overheat
- Communication errors
- Hardware faults
- See
vfd_config.hfor complete list
// Initialize Modbus with 2.5ms timeout
mmodbus_init(2500);
// Setup VFD context with callbacks
vfd_context_t ctx = {
.slave_address = 16,
.mb_write_single_reg = my_mb_write_single_reg,
.mb_read_multi_reg = my_mb_read_multi_reg
};
vfd_init(&ctx);
// Control loop: ramp frequency 0-99% every 500ms
while (1) {
vfd_update(&ctx); // Read VFD data
if (HAL_GetTick() - last_time > 500) {
vfd_set_running_freq(&ctx, freq);
freq += step;
if (freq >= 99) step = -1;
if (freq < 5) step = 1;
last_time = HAL_GetTick();
}
}- Check your VFD's Modbus register map documentation
- Update addresses in
vfd_config.h - Adjust scaling factors in
vfd_controller.cif needed - Update fault/status enums if different
MCU (UART TX/RX) <---> RS485 Transceiver <---> VFD (A/B terminals)
(e.g., MAX485)
Wiring:
- RS485 A/B → VFD Modbus A/B terminals
- Ground → Ground
MIT License - Use freely in commercial/personal projects.
- Fork the repository
- Create feature branch (
git checkout -b feature/new-vfd-support) - Commit changes (
git commit -m 'Add support for XYZ VFD') - Push to branch (
git push origin feature/new-vfd-support) - Open Pull Request
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Modbus library: master-modbus by nimaltd