machines/projects/Printhead/test/mtestom/OmronMx2.cpp
2023-11-12 21:43:05 +01:00

1647 lines
59 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "OmronMx2.h"
#include <Controllino.h> /* Usage of CONTROLLINO library allows you to use CONTROLLINO_xx aliases in your sketch. */
#define MODBUSMASTER_DEBUG
#undef MODBUS_FREERTOS
//#include <ModbusMaster.h> // Using ModbusMaster modified for OMRON MX2 https://github.com/4-20ma/ModbusMaster
#include "ModbusMaster.h" // Using ModbusMaster modified for OMRON MX2 https://github.com/4-20ma/ModbusMaster
const char *nameOmron = {" Omron MX2 "}; // Name, brand of inverter
const char *cYes = {" Yes "};
const char *cNo = {" No "};
const char *cOne = {" 1 "};
const char *cZero = {" 0 "};
const char *cOk = {" Ok "};
const char *cError = {" error "};
const char *cInvalid = {" invalid "};
const char *cStrEnd = {" \ n "};
const char *cErrorRS485 = {" % s : Read error % s , code = % d repeat ... \ n "}; // name, function, code
const char *cErrorMutex = {" Function % s : % s , mutex is buzy \ n "}; // function, mutex
const char *cAddHeat = {" + "};
__attribute__((always_inline)) inline void _delay(int t)
{
delay(t);
}
const char *noteFC_OK = {" Modbus communication established "}; // All right
const char *noteFC_NO = {" Modbus communication lost, the inverter is locked "};
const char *noteFC_NONE = {" missing in this configuration "};
const char *fc_ON_OFF = {" ON_OFF "}; // Flag for turning on / off (frequency control)
const char *fc_INFO = {" INFO "}; // Get information from the inverter (table !!)
const char *fc_NAME = {" NAME "}; // Inverter name
const char *fc_NOTE = {" NOTE "}; // Get a description of the frequency converter. Line 80 + 1
const char *fc_PIN = {" PIN "}; // Get the pin number where analog FC is attached
const char *fc_PRESENT = {" PRESENT "}; // The presence of FC in the configuration.
const char *fc_STATE = {" STATE "}; // Status of the inverter (read)
const char *fc_FC = {" FC "}; // The target frequency of the inverter is 0.01
const char *fc_cFC = {" cFC "}; // Current inverter frequency (read)
const char *fc_cPOWER = {" cPOWER "}; // Current power (read)
const char *fc_INFO1 = {" INFO1 "}; // The first line below the inverter picture in the circuit
const char *fc_cCURRENT = {" cCURRENT "}; // Current current (read)
const char *fc_AUTO_RESET_FAULT = {" ARSTFLT "}; // Flag to automatically reset non-critical inverter error
const char *fc_LogWork = {" LOGW "}; // flag log while running
const char *fc_ANALOG = {" AN "}; // Flag of analog control
const char *fc_DAC = {" DAC "}; // Get the current DAC value
const char *fc_LEVEL0 = {" L0 "}; // Frequency level 0 in the DAC samples
const char *fc_LEVEL100 = {" L100 "}; // Frequency level 100% in the DAC samples
const char *fc_LEVELOFF = {" LOFF "}; // Minimum power at which the chastotnik turns off (minimum power limit)
const char *fc_BLOCK = {" BLOCK "}; // flag inverter global error - inverter operation is disabled; blocking can be reset by setting 0
const char *fc_ERROR = {" ERROR "}; // Get the error code
const char *fc_UPTIME = {" UPTIME "}; // Pid controller update algorithm time (ms) The main control loop
const char *fc_PID_STOP = {" PID_STOP "}; // Percentage of the level of protection (power, current, pressure, temperature) at which the frequency increase is blocked by the pid
const char *fc_PID_FREQ_STEP = {" PID_STEP "}; // The maximum step (to increase) the frequency change with PID control of 0.01 Hz It is necessary that the ERV be in time
const char *fc_START_FREQ = {" FRQ "}; // Inverter starting frequency (cm compressor) at 0.01 Hz
const char *fc_START_FREQ_BOILER = {" FRQB "}; // Starting frequency of the inverter (cm compressor) in 0.01 GHz of hot water
const char *fc_MIN_FREQ = {" MIN "}; // Minimum inverter frequency (cm compressor) in 0.01 Hz
const char *fc_MIN_FREQ_COOL = {" MINC "}; // The minimum frequency of the inverter during cooling at 0.01 Hz
const char *fc_MIN_FREQ_BOILER = {" MINB "}; // The minimum frequency of the inverter when heating the hot water in 0.01 Hz
const char *fc_MIN_FREQ_USER = {" MINU "}; // Minimum inverter frequency MANUAL MODE (cm compressor) at 0.01 Hz
const char *fc_MAX_FREQ = {" MAX "}; // Maximum inverter frequency (cm compressor) at 0.01 Hz
const char *fc_MAX_FREQ_COOL = {" MAXC "}; // Maximum inverter frequency in cooling mode at 0.01 Hz
const char *fc_MAX_FREQ_BOILER = {" MAXB "}; // The maximum frequency of the inverter in the DHW mode at 0.01 Hz the absorption of the boiler is usually less than CO
const char *fc_MAX_FREQ_USER = {" MAXU "}; // Maximum inverter frequency MANUAL MODE (cm compressor) at 0.01 Hz
const char *fc_STEP_FREQ = {" STEP "}; // Step to decrease the inverter when reaching the maximum temperature, power and current (cm compressor) at 0.01 Hz
const char *fc_STEP_FREQ_BOILER = {" STEPB "}; // Step to decrease the inverter when reaching the maximum temperature, power and dhw current of 0.01 Hz
const char *fc_DT_COMP_TEMP = {" DTC "}; // Protection by compressor temperature - how many degrees does not reach the maximum (TCOMP) and at the same time there is a decrease in frequency
const char *fc_DT_TEMP = {" DT "}; // Exceeding the temperature from the settings (feed) at which the protection is triggered (frequency decreases) in hundredths of a degree
const char *fc_DT_TEMP_BOILER = {" DTB "}; // Exceeding the temperature from the settings (supply) at which the DHW protection in hundredths of a degree is triggered
const char *fc_MB_ERR = {" MB_ERR "}; // Modbus errors
const char *fc_FC_TIME_READ = {" TR "}; // Poll time
const char *fc_fFC_RetOil = {" FRO "}; // Flag oil return
const char *fc_FC_RETOIL_FREQ = {" FRF "}; // Frequency
const char *fc_ReturnOilPeriod = {" ROP "}; // Oil return time
const char *fc_ReturnOilPerDivHz = {" ROPH "}; // The frequency at which oil returns
const char *fc_ReturnOilEEV = {" ROE "}; // Steps of the EDS at which oil is returned
const boolean DEVICEFC = false; // Наличие Частотного преобразователя в конфигурации
#define fModbus 1 // флаг наличие modbus
typedef QueueHandle_t SemaphoreHandle_t;
SemaphoreHandle_t xModbusSemaphore; // Семафор Modbus, инвертор запас на счетчик
#define MODBUS_PORT_NUM Serial3 // Аппаратный порт куда прицеплен Modbus
#define MODBUS_PORT_SPEED 19200 // Скорость порта куда прицеплен частотник и счетчик
#define MODBUS_PORT_CONFIG SERIAL_8N1 // Конфигурация порта куда прицеплен частотник и счетчик
#define MODBUS_TIME_WAIT 2000 // Время ожидания захвата мютекса для modbus мсек
inline void SemaphoreGive(QueueHandle_t xSemaphore)
{
//if(xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) xSemaphoreGive(xSemaphore);
}
unsigned int i10toa(int value, char *string, unsigned int zero_pad)
{
char *pbuffer = string;
unsigned char negative;
if (value < 0)
{
negative = 1;
value = -value;
}
else
negative = 0;
do
{
*(pbuffer++) = '0' + value % 10;
value /= 10;
} while (value > 0);
for (unsigned int i = (pbuffer - string); i < zero_pad; i++)
*(pbuffer++) = '0';
if (negative)
*(pbuffer++) = '-';
*(pbuffer) = '\0';
unsigned int len = (pbuffer - string);
for (unsigned int i = 0; i < len / 2; i++)
{
char j = string[i];
string[i] = string[len - i - 1];
string[len - i - 1] = j;
}
return len;
}
uint8_t _ftoa(char *outstr, float val, unsigned char precision)
{
while (*outstr)
outstr++;
char *instr = outstr;
// compute the rounding factor and fractional multiplier
float roundingFactor = 0.5f;
unsigned long mult = 1;
unsigned char padding = precision;
while (precision--)
{
roundingFactor /= 10.0f;
mult *= 10;
}
if (val < 0.0f)
{
*outstr++ = '-';
val = -val;
}
val += roundingFactor;
outstr += i10toa((long)val, outstr, 0);
if (padding > 0)
{
*(outstr++) = '.';
outstr += i10toa((val - (long)val) * mult, outstr, padding);
}
return outstr - instr;
}
char *_itoa(int value, char *string)
{
char *ret = string;
while (*string)
string++;
char *pbuffer = string;
unsigned char negative = 0;
if (value < 0)
{
negative = 1;
value = -value;
}
/* This builds the string back to front ... */
do
{
*(pbuffer++) = '0' + value % 10;
value /= 10;
} while (value > 0);
if (negative)
*(pbuffer++) = '-';
*(pbuffer) = '\0';
/* ... now we reverse it (could do it recursively but will
* conserve the stack space) */
uint32_t len = (pbuffer - string);
for (uint32_t i = 0; i < len / 2; i++)
{
char j = string[i];
string[i] = string[len - i - 1];
string[len - i - 1] = j;
}
return ret;
}
static void jprintf(const char *format, ...)
{
Serial.println(format);
}
int8_t set_Error(int8_t _err, char *nam)
{
Serial.println("error");
Serial.println(_err);
Serial.println(nam);
return OK;
}
// End class
static uint8_t Modbus_Entered_Critical = 0;
static inline void idle() // задержка между чтениями отдельных байт по Modbus
{
// delay(1); // Не отдает время другим задачам
_delay(1); // Отдает время другим задачам
}
static inline void preTransmission() // Функция вызываемая ПЕРЕД началом передачи
{
#ifdef PIN_MODBUS_RSE
digitalWriteDirect(PIN_MODBUS_RSE, HIGH);
#endif
_delay(10); // что бы слейв не терял первый бит
// Modbus_Entered_Critical = TaskSuspendAll(); // Запрет других задач во время передачи по Modbus
//Serial.println("critical");
}
static inline void postTransmission() // Функция вызываемая ПОСЛЕ окончания передачи
{
if (Modbus_Entered_Critical)
{
// xTaskResumeAll();
Serial.println("critical postTransmission");
Modbus_Entered_Critical = 0;
}
#ifdef PIN_MODBUS_RSE
#if MODBUS_TIME_TRANSMISION != 0
_delay(MODBUS_TIME_TRANSMISION); // Минимальная пауза между командой и ответом 3.5 символа
#endif
digitalWriteDirect(PIN_MODBUS_RSE, LOW);
#endif
}
// Инициализация Modbus без проверки связи связи
int8_t devModbus::initModbus()
{
#ifdef MODBUS_PORT_NUM
flags = 0x00;
SETBIT1(flags, fModbus); // модбас присутствует
#ifdef PIN_MODBUS_RSE
pinMode(PIN_MODBUS_RSE, OUTPUT); // Подготовка управлением полудуплексом
digitalWriteDirect(PIN_MODBUS_RSE, LOW);
#endif
// Controllino_RS485Init();
MODBUS_PORT_NUM.begin(MODBUS_PORT_SPEED, MODBUS_PORT_CONFIG); // SERIAL_8N1 - настройки по умолчанию
RS485.begin(1, MODBUS_PORT_NUM);
// Назначение функций обратного вызова
RS485.preTransmission(preTransmission);
RS485.postTransmission(postTransmission);
RS485.idle(idle);
err = OK; // Связь есть
#else
flags = 0x00;
SETBIT0(flags, fModbus); // модбас отсутвует
err = ERR_NO_MODBUS;
#endif
return err;
}
int8_t devModbus::LinkTestOmronMX2()
{
uint16_t result, ret;
err = OK;
RS485.set_slave(FC_MODBUS_ADR);
result = RS485.LinkTestOmronMX2Only(TEST_NUMBER); // Послать команду проверки связи
Serial.println("test : LinkTestOmronMX2");
Serial.println(result);
if (result == RS485.ku8MBSuccess)
ret = RS485.getResponseBuffer(0); // Получить данные с ответа
else
return err = ERR_485_INIT; // Ошибка инициализации
if (TEST_NUMBER != ret)
return err = ERR_MODBUS_MX2_0x05; // Контрольные данные не совпали
return err;
}
static devModbus Modbus;
// ------------------------------------------------ ------------------------------------------
// FREQUENCY CONVERTER ONLY ONE PIECE ALWAYS (not an array) ---------------------------
// class initialization
int8_t devOmronMX2::initFC()
{
err = OK; // ошибка частотника (работа) при ошибке останов ТН
numErr = 0; // число ошибок чтение по модбасу для статистики
number_err = 0; // Число ошибок связи при превышении FC_NUM_READ блокировка инвертора
FC = 0; // Целевая частота частотика
freqFC = 0; // текущая частота инвертора
power = 0; // Тееущая мощность частотника
current = 0; // Текуший ток частотника
startCompressor = 0; // время старта компрессора
state = ERR_LINK_FC; // Состояние - нет связи с частотником
dac = 0; // Текущее значение ЦАП
testMode = NORMAL; // Значение режима тестирования
name = (char *)nameOmron; // Имя
note = (char *)noteFC_NONE; // Описание инвертора типа нет его
// Настройки по умолчанию
_data.Uptime = DEF_FC_UPTIME; // Время обновления алгоритма пид регулятора (мсек) Основной цикл управления
_data.PidFreqStep = DEF_FC_PID_FREQ_STEP; // Максимальный шаг (на увеличение) изменения частоты при ПИД регулировании в 0.01 Гц Необходимо что бы ЭРВ успевал
_data.PidStop = DEF_FC_PID_STOP; // Проценты от уровня защит (мощность, ток, давление, темпеартура) при которой происходит блокировка роста частоты пидом
_data.dtCompTemp = DEF_FC_DT_COMP_TEMP; // Защита по температуре компрессора - сколько градусов не доходит до максимальной (TCOMP) и при этом происходит уменьшение частоты
_data.startFreq = DEF_FC_START_FREQ; // Стартовая скорость инвертора (см компрессор) в 0.01
_data.startFreqBoiler = DEF_FC_START_FREQ_BOILER; // Стартовая скорость инвертора (см компрессор) в 0.01 ГВС
_data.minFreq = DEF_FC_MIN_FREQ; // Минимальная скорость инвертора (см компрессор) в 0.01
_data.minFreqCool = DEF_FC_MIN_FREQ_COOL; // Минимальная скорость инвертора при охлаждении в 0.01
_data.minFreqBoiler = DEF_FC_MIN_FREQ_BOILER; // Минимальная скорость инвертора при нагреве ГВС в 0.01
_data.minFreqUser = DEF_FC_MIN_FREQ_USER; // Минимальная скорость инвертора РУЧНОЙ РЕЖИМ (см компрессор) в 0.01
_data.maxFreq = DEF_FC_MAX_FREQ; // Максимальная скорость инвертора (см компрессор) в 0.01
_data.maxFreqCool = DEF_FC_MAX_FREQ_COOL; // Максимальная скорость инвертора в режиме охлаждения в 0.01
_data.maxFreqBoiler = DEF_FC_MAX_FREQ_BOILER; // Максимальная скорость инвертора в режиме ГВС в 0.01 Гц поглощение бойлера обычно меньше чем СО
_data.maxFreqUser = DEF_FC_MAX_FREQ_USER; // Максимальная скорость инвертора РУЧНОЙ РЕЖИМ (см компрессор) в 0.01
_data.stepFreq = DEF_FC_STEP_FREQ; // Шаг уменьшения инвертора при достижении максимальной температуры, мощности и тока (см компрессор) в 0.01
_data.stepFreqBoiler = DEF_FC_STEP_FREQ_BOILER; // Шаг уменьшения инвертора при достижении максимальной температуры, мощности и тока ГВС в 0.01
_data.dtTemp = DEF_FC_DT_TEMP; // Привышение температуры от уставок (подача) при которой срабатыват защита (уменьшается частота) в сотых градуса
_data.dtTempBoiler = DEF_FC_DT_TEMP_BOILER; // Привышение температуры от уставок (подача) при которой срабатыват защита ГВС в сотых градуса
#ifdef FC_ANALOG_CONTROL
_data.level0 = 0; // Отсчеты ЦАП соответсвующие 0 мощности
_data.level100 = 4096; // Отсчеты ЦАП соответсвующие 100 мощности
_data.levelOff = 10; // Минимальная мощность при котором частотник отключается (ограничение минимальной мощности)
#endif
if (Modbus.initModbus() == OK)
jprintf(" modbus OK\r\n"); // выводим сообщение об установлении связи
else
{
jprintf(" modbus not present config\r\n");
}
flags = 0x00; // флаги 0 - наличие FC
_data.setup_flags = 0x00; // флаги
Serial.println("mb presetn test");
if (!Modbus.get_present()) // modbus отсутствует
{
SETBIT0(flags, fFC); // Инвертор не рабоатет
jprintf("%s, modbus not found, block.\n", name);
err = ERR_NO_MODBUS;
return err;
}
else if (DEVICEFC == true)
{
SETBIT1(flags, fFC); // наличие частотника в текушей конфигурации
}
if (get_present())
{
jprintf("Invertor %s: present config\r\n", name);
}
else
{
jprintf("Invertor %s: none config\r\n", name);
// return err;
} // выходим если нет инвертора
note = (char *)noteFC_OK; // Описание инвертора есть
err = Modbus.LinkTestOmronMX2(); // проверка связи с инвертором xModbusSemaphore не используем так как в один поток
check_blockFC();
if (err != OK)
{
Serial.println("link test:");
Serial.println(note);
Serial.println(err);
return err; // связи нет выходим
}
jprintf("Test link Modbus %s: OK\r\n", name); // Тест пройден
return;
// Если частотник работает то остановить его
get_readState(); // Получить состояние частотника
switch (state) // В зависимости от состояния
{
case 0:
case 2:
break; // ОСТАНОВКА ничего не делаем
case 3:
stop_FC(); // ВРАЩЕНИЕ Послать команду стоп и ждать остановки
while ((state != 2) || (state != 4))
{
get_readState();
// jprintf("Wait stop %s . . .\r\n", name);
_delay(3000);
}
break;
case 4: // ОСТАНОВКА С ВЫБЕГОМ ждать остановки
break;
case 5:
stop_FC(); // ТОЛЧОВЫЙ ХОД Послать команду стоп и ждать остановки
while ((state != 2) || (state != 4))
{
get_readState();
// jprintf("Wait stop %s . . .\r\n", name);
_delay(3000);
}
break;
case 6: // ТОРМОЖЕНИЕ ПОСТОЯННЫМ ТОКОМ
case 7:
err = ERR_MODBUS_STATE;
set_Error(err, name);
break; // ВЫПОЛНЕНИЕ ПОВТОРНОЙ ПОПЫТКИ Подъем ошибки на верх и останов ТН
case 8:
break; // АВАРИЙНОЕ ОТКЛЮЧЕНИЕ
case 9:
break; // ПОНИЖЕНОЕ ПИТАНИЕ
case -1:
break;
default:
err = ERR_MODBUS_STATE;
set_Error(err, name);
break; // Подъем ошибки на верх и останов ТН
}
if (err != OK)
return err;
// Установить стартовую частоту
set_target(_data.startFreq, true, _data.minFreqUser, _data.maxFreqUser); // режим н знаем по этому границы развигаем
return err;
}
#define progOK " Register% s to% d \ r \ n " // Line for displaying a message about successful register programming
#define progErr " Error setting register% s \ r \ n " // Line for displaying a message about failed register programming
#ifndef FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT
// Program a separate inverter register
// adrReg - register address
// nameReg - register name
// valReg - register value
int8_t devOmronMX2::progReg16(uint16_t adrReg, char *nameReg, uint16_t valReg)
{
_delay(50);
if ((err = write_0x06_16(adrReg, valReg)) == OK)
{
jprintf(progOK, nameReg, valReg);
}
else
{
jprintf(progErr, nameReg);
}
return err;
}
int8_t devOmronMX2 ::progReg32(uint16_t adrReg, char *nameReg, uint32_t valReg)
{
_delay(50);
if ((err = write_0x10_32(adrReg, valReg)) == OK)
{
jprintf(progOK, nameReg, valReg);
}
else
{
jprintf(progErr, nameReg);
}
return err;
}
#endif // NOT ANALOGUE MANAGEMENT
// Programming the inverter for a specific compressor
int8_t devOmronMX2 ::progFC()
{
#ifndef FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT \
// jprintf(" Programming% s.. \ r \ n ", name);
// Setting the inverter for a specific compressor Registers Hxxx Permanent magnet motor (PM motor)
progReg16(MX2_b171, (char *)"b171", 0x03); // b171 IF mode selection b171 read / write 0 (off), 1 (IM mode), 2 (high frequency mode), 3 (PM mode) = 03
progReg16(MX2_b180, (char *)"b180", 0x01); // b180 Starting the initialization process
// while (read_0x03_16 (MX2_H102) == 1) _delay (100); // Delay on initialization of the inverter - wait until the P102 register appears
//jprintf ( " Wait initialization.. \ r \ n " );
_delay(7000);
progReg16(MX2_H102, (char *)"H102", valH102); // H102 Setting the PM motor code 00 (standard Omron data) 01 (auto-tuning data) = 1
progReg16(MX2_H103, (char *)"H103", valH103); // H103 PM engine power (0.1 / 0.2 / 0.4 / 0.55 / 0.75 / 1.1 / 1.5 / 2.2 / 3.0 / 3.7 / 4, 0 / 5.5 / 7.5 / 11.0 / 15.0 / 18.5) = 7
progReg16(MX2_H104, (char *)"H104", valH104); // H104 Setting the number of poles of the PM motor = 4
progReg16(MX2_H105, (char *)"H105", valH105); // H105 Rated current of the PM motor = 1000 (this is 11A)
progReg16(MX2_H106, (char *)"H106", valH106); // H106 PM motor constant R From 0.001 to 65.535 ohms = 0.55 * 1000
progReg16(MX2_H107, (char *)"H107", valH107); // H107 Ld constant of the PM engine From 0.01 to 655.35 mH = 2.31 * 100
progReg16(MX2_H108, (char *)"H108", valH108);
progReg16(MX2_H109, (char *)"H109", valH109);
progReg32(MX2_H110, (char *)"H110", valH110); // H110 Constant J PM-engine From 0.001 to 9999,000 kg / m² = 0.01
progReg16(MX2_H119, (char *)"H119", valH119); // H119 Engine PM stabilization constant 0 to 120% s = 100
progReg16(MX2_H121, (char *)"H121", valH121); // H121 Minimum frequency of the PM motor From 0.0 to 25.5% = 10 (default)
progReg16(MX2_H122, (char *)"H122", valH122); // H122 Idling current PM of the motor From 0.00 to 100.00% = 50 (default)
progReg16(MX2_C001, (char *)"C001", valC001); // C001 Input function [1] 0 (FW: go forward) = 0
progReg16(MX2_C004, (char *)"C004", valC004); // C004 Input function [4] 18 (RS: reset) = 18
#ifndef DEMO // for the demo you do not need to configure thermal protection otherwise the eternal error E35.1
progReg16(MX2_C005, (char *)" C005 ", valC005); // C005 Input function [5] [also input “PTC”] = 19 PTC Thermistor with positive TCS for thermal protection (only C005)
#endif
progReg16(MX2_C026, (char *)" C026 ", valC026); // C026 Relay output function 5 (AL: error signal) = 05
progReg16(MX2_b091, (char *)" b091 ", valb091); // b091 Choice of stopping method 0 (braking to a complete stop), 1 (coasting stop) = 1
progReg16(MX2_b021, (char *)" b021 ", valb021); // b021 Operating mode with overload limitation = 1
progReg16(MX2_b022, (char *)" b022 ", valb022); // b022 Overload restriction level 200 ... 2000 (0.1%) =
progReg16(MX2_b023, (char *)" b023 ", valb023); // b023 Braking time with overload limitation (0.1 sec) = 10
progReg16(MX2_A001, (char *)" A001 ", valA001); // A001 Frequency reference source = 03
progReg16(MX2_A002, (char *)" A002 ", valA002); // A002 Source of the “Move” command
progReg16(MX2_A003, (char *)" A003 ", FC_BASE_FREQ / 10); // A003 fundamental frequency
progReg16(MX2_A004, (char *)" A004 ", DEF_FC_MAX_FREQ / 10); // A004 setting the maximum frequency
progReg32(MX2_F002, (char *)" F002 ", FC_ACCEL_TIME); // F002 Acceleration Time
progReg32(MX2_F002, (char *)" F003 ", FC_DEACCEL_TIME); // F003 Acceleration Braking
jprintf(" ... OK \ r \ n ");
#else
jprintf(" Analog control - no support programm Omron MX2 \ r \ n ");
#endif // NOT ANALOGUE MANAGEMENT
return err;
}
// Set Target Frequency
// parameter to show message message or not, two remaining border parameters
int8_t devOmronMX2::set_target(int16_t x, boolean show, int16_t _min, int16_t _max)
{
err = OK;
#ifdef DEMO
if ((x > = _ min) && (x <= _ max)) // Check the range of allowed frequencies
{
FC = x;
if (show)
jprintf(" Set% s:% .2f [Hz] \ r \ n ", name, FC / 100.0);
return err;
} // set the frequency OK - display a message if necessary
else
{
jprintf(" % s: Wrong frequency% .2f \ n ", name, x / 100.0);
return WARNING_VALUE;
}
#else // Battle option
uint16_t hWord, lWord;
uint8_t i;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return err; // exit if there is no inverter or it is blocked by mistake
if ((x >= _min) && (x <= _max)) // Check the range of allowed frequencies
{
#ifndef FC_ANALOG_CONTROL // Non-analog control
// Write to the inverter registers the set frequency
for (i = 0; i < FC_NUM_READ; i++) // Make FC_NUM_READ attempts
{
err = write_0x10_32(MX2_TARGET_FR, x);
if (err == OK)
break; // Command completed
_delay(100);
jprintf(" % s: repeat set frequency \ n ", name); // Display a message about the second command
}
if (err == OK)
{
FC = x;
if (show)
jprintf(" Set% s:% .2f [Hz] \ r \ n ", name, FC / 100.0);
return err;
} // set the frequency OK - display a message if necessary
else
{
err = ERR_LINK_FC;
SETBIT1(flags, fErrFC);
set_Error(err, name);
return err;
} // error generation
// Check for frequency setting and inverter adequacy
if (x != read_0x03_32(MX2_TARGET_FR))
{
err = ERR_FC_ERROR;
SETBIT1(flags, fErrFC);
set_Error(err, name);
return err;
}
#else // Analog Control
FC = x;
dac = ((level100 - level0) * FC - 0 * level100) / (100 - 0);
switch (testMode) // REAL Actions depending on the mode
{
case NORMAL:
analogWrite(pin, dac);
break; // Operation mode is not a test, we turn everything on
case SAFE_TEST:
break; // Do not include anything
case TEST:
break; // Turn on everything except the compressor
case HARD_TEST:
analogWrite(pin, dac);
break; // Turn on everything and the compressor too
}
if (show)
jprintf(" Set% s:% .2f [Hz] \ r \ n ", name, FC / 100.0); // frequency setting OK - display a message if necessary
#endif
return err;
} // if ((x> = _ min) && (x <= _ max))
else
{
jprintf(" % s: Wrong frequency% .2f \ n ", name, x / 100.0);
return WARNING_VALUE;
}
#endif // DEMO
}
// Set DAC readings corresponding to 0 power
int8_t devOmronMX2::set_level0(int16_t x)
{
if ((x >= 0) && (x <= 4096))
{
level0 = x;
return OK;
} // Only valid values
return WARNING_VALUE;
}
// Set DAC readings corresponding to 100 power
int8_t devOmronMX2::set_level100(int16_t x)
{
if ((x >= 0) && (x <= 4096))
{
level100 = x;
return OK;
} // Only valid values
return WARNING_VALUE;
}
// Set the minimum power at which the chastotnik turns off (minimum power limit)
int8_t devOmronMX2::set_levelOff(int16_t x)
{
if ((x >= 0) && (x <= 100))
{
levelOff = x;
return OK;
} // Only valid values
return WARNING_VALUE;
}
// Set the ban on the use of the inverter if the error limit is reached
void devOmronMX2::check_blockFC(){
#ifndef FC_ANALOG_CONTROL // Non-analog control
/*
if ((xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) && (err ! = OK)) // if free rtos is not running then block it the first time
{
SETBIT1(flags, fErrFC); // Set flag
note = (char *)noteFC_NO;
set_Error(err, (char *)name); // Raise the error to the top and stop the VT
return statement;
}
if (err ! = OK)
number_err++;
else
{
number_err = 0;
return;
} // Increase the error counter
if (number_err > FC_NUM_READ) // if the number of errors is increased, then the lock
{
SemaphoreGive(xModbusSemaphore); // unlock semaphore
SETBIT1(flags, fErrFC); // Set flag
note = (char *)noteFC_NO;
set_Error(err, (char *)name); // Raise the error to the top and stop the VT
}
*/
#endif
}
// Read (internal variables are updated) the state of the Inverter, returns either OK or an error
// The period FC_TIME_READ is called from the task of reading sensors
int8_t devOmronMX2::get_readState()
{
/*
uint8_t i;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return err; // exit if there is no inverter or it is blocked by mistake
err = OK;
#ifndef FC_ANALOG_CONTROL // Non-analog control
// Read the state of the inverter, if an error occurs, generate a common VT error and stop
for (i = 0; i < FC_NUM_READ; i++) // do FC_NUM_READ attempts to read
{
state = read_0x03_16(MX2_STATE); // read the state
err = Modbus.get_err(); // Copy error
if (err == OK) // Read correctly
{
if ((GETBIT(flags, fOnOff)) && (state ! = 3))
continue;
else
break; // VT turned on the compressor and the inverter does not have the correct state, we try to read one more time in the opposite case everything is ok
}
_delay(FC_DELAY_REPEAT);
// jprintf(cErrorRS485, name, __FUNCTION__, err); // Display a message about re-reading
numErr++; // number of errors reading by modbass
// jprintf_time (cErrorRS485, name, err); // Output the error code to the log
}
if (err ! = OK) // Modbass error
{
state = ERR_LINK_FC; // sign of loss of communication with the inverter
SETBIT1(flags, fErrFC); // Inverter block
set_Error(err, name); // error generation
return err; // Return
}
// else if ((testMode == NORMAL) || (testMode == HARD_TEST)) // Operation mode and hard test, analyze the state,
// if ((GETBIT (flags, fOnOff)) && (state! = 3)) // Invalid state
// {
// err = ERR_MODBUS_STATE; // Error Invalid Inverter Status
// jprintf ("% s: Compressor ON and wrong read state:% d \ n", name, state);
// set_Error (err, name);
// return err; // Return
// }
// Read the state and its correct; we read everything else
_delay(FC_DELAY_READ);
freqFC = read_0x03_32(MX2_CURRENT_FR); // read the current frequency
err = Modbus.get_err(); // Copy error
if (err ! = OK)
{
state = ERR_LINK_FC;
} // We exit the error
_delay(FC_DELAY_READ);
power = read_0x03_16(MX2_POWER); // read power
err = Modbus.get_err(); // Copy error
if (err ! = OK)
{
state = ERR_LINK_FC;
} // We exit the error
_delay(FC_DELAY_READ);
current = read_0x03_16(MX2_AMPERAGE); // read current
err = Modbus.get_err(); // Copy error
if (err ! = OK)
{
state = ERR_LINK_FC;
} // We exit the error
#else // Analog Control
freqFC = FC;
power = 0;
current = 0;
#endif
return err;
*/
}
// Run command to the inverter (target frequency DOES NOT SET)
// A command can be issued through the relay and through modbas depending on the compilation keys
int8_t devOmronMX2::start_FC()
{
/*
if (((testMode == NORMAL) || (testMode == HARD_TEST)) && (((FC < _data.minFreq) || (FC > _data.maxFreq))))
{
jprintf(" % s: Wrong frequency, ignore start \ n ", name);
return err;
} // checking the frequency is not in test mode
err = OK;
#ifndef FC_ANALOG_CONTROL // Non-analog control
#ifdef DEMO
#else // DEMO
// Warhead
if (((testMode == NORMAL) || (testMode == HARD_TEST)) && (((!get_present()) || (GETBIT(flags, fErrFC)))))
return err; // exit if there is no inverter or it is blocked by mistake
// set_target (startFreq, true); // Writing the start frequency to the inverter register is NOT always the start frequency - superboiler
err = OK;
if ((testMode == NORMAL) || (testMode == HARD_TEST)) // Operation mode and hard test, turn everything on,
{
#ifdef FC_USE_RCOMP // Use a separate wire for the run / stop command
HP dRelay[RCOMP].set_ON(); // BAD through a global variable
#else // give a run / stop command through modbas
err = write_0x05_bit(MX2_START, true); // Command Move
#endif
}
if (err == OK)
{
SETBIT1(flags, fOnOff);
startCompressor = rtcSAM3X8.unixtime();
jprintf(" % s ON \ n ", name);
}
else
{
state = ERR_LINK_FC;
SETBIT1(flags, fErrFC);
set_Error(err, name);
} // error generation
#endif
#else // FC_ANALOG_CONTROL
#ifdef DEMO
#ifdef FC_USE_RCOMP // Use a separate wire for the run / stop command
HP dRelay[RCOMP].set_ON(); // BAD through a global variable
#endif // FC_USE_RCOMP
SETBIT1(flags, fOnOff);
startCompressor = rtcSAM3X8.unixtime();
jprintf(" % s ON \ n ", name);
#else // DEMO \
// Warhead
if (((testMode == NORMAL) || (testMode == HARD_TEST)) && (((!get_present()) || (GETBIT(flags, fErrFC)))))
return err; // exit if there is no inverter or it is blocked by mistake
err = OK;
if ((testMode == NORMAL) || (testMode == HARD_TEST)) // Operation mode and hard test, turn everything on,
{
#ifdef FC_USE_RCOMP // Use a separate wire for the run / stop command
HP dRelay[RCOMP].set_ON(); // BAD through a global variable
#else
state = ERR_LINK_FC;
err = ERR_FC_CONF_ANALOG;
SETBIT1(flags, fErrFC);
set_Error(err, name); // configuration error
#endif
}
SETBIT1(flags, fOnOff);
startCompressor = rtcSAM3X8.unixtime();
jprintf(" % s ON \ n ", name);
#endif
#endif
*/
return err;
}
// Stop command to inverter Return error code
int8_t devOmronMX2::stop_FC()
{
// uint8_t i;
err = OK;
#ifndef FC_ANALOG_CONTROL // Non-analog control
#ifdef DEMO
#ifdef FC_USE_RCOMP // Use a separate wire for the run / stop command
HP dRelay[RCOMP].set_OFF(); // BAD through a global variable
#endif // FC_USE_RCOMP
if (err == OK)
{
SETBIT0(flags, fOnOff);
startCompressor = 0;
jprintf(" % s OFF \ n ", name);
}
else
{
state = ERR_LINK_FC;
SETBIT1(flags, fErrFC);
set_Error(err, name);
} // error generation
#else // not DEMO
if (!get_present())
return err; // if there is no inverter, exit
// if (((testMode == NORMAL) || (testMode == HARD_TEST)) && (((! get_present ()) || (GETBIT (flags, fErrFC))))) return err; // exit if not inverter or it is blocked by mistake
err = OK;
if ((testMode == NORMAL) || (testMode == HARD_TEST)) // Operation mode and hard test, turn everything on,
{
#ifdef FC_USE_RCOMP // Use a separate wire for the run / stop command with verification of progress
#else // give a run / stop command through modbas
err = write_0x05_bit(MX2_START, false); // Stop command
#endif
}
if (err == OK)
{
SETBIT0(flags, fOnOff);
startCompressor = 0;
jprintf(" % s OFF \ n ", name);
}
else
{
state = ERR_LINK_FC;
SETBIT1(flags, fErrFC);
set_Error(err, name);
} // error generation
#endif
#else // FC_ANALOG_CONTROL
#ifdef DEMO
#ifdef FC_USE_RCOMP // Use a separate wire for the run / stop command
HP dRelay[RCOMP].set_OFF(); // BAD through a global variable
#endif // FC_USE_RCOMP
SETBIT0(flags, fOnOff);
startCompressor = 0;
jprintf(" % s OFF \ n ", name);
#else // not DEMO
if (((testMode == NORMAL) || (testMode == HARD_TEST)) && (((!get_present()) || (GETBIT(flags, fErrFC)))))
return err; // exit if there is no inverter or it is blocked by mistake
if ((testMode == NORMAL) || (testMode == HARD_TEST)) // Operation mode and hard test, turn everything on,
{
#ifdef FC_USE_RCOMP // Use a separate wire for the run / stop command
HP dRelay[RCOMP].set_OFF(); // BAD through a global variable
#else // give a run / stop command through modbas
state = ERR_LINK_FC;
err = ERR_FC_CONF_ANALOG;
SETBIT1(flags, fErrFC);
set_Error(err, name); // configuration error
#endif
}
SETBIT0(flags, fOnOff);
startCompressor = 0;
jprintf(" % s OFF \ n ", name);
#endif
#endif // FC_ANALOG_CONTROL
return err;
}
// Get the inverter parameter as a string, the result is ADDED to ret
void devOmronMX2::get_paramFC(char *var, char *ret)
{
if (strcmp(var, fc_ON_OFF) == 0)
{
if (GETBIT(flags, fOnOff))
strcat(ret, (char *)cOne);
else
strcat(ret, (char *)cZero);
}
else if (strcmp(var, fc_INFO) == 0)
{
#ifndef FC_ANALOG_CONTROL
get_infoFC(ret);
#else
strcat(ret, " | Data not available, work through analog input |; ");
#endif
}
else if (strcmp(var, fc_NAME) == 0)
{
strcat(ret, name);
}
else if (strcmp(var, fc_NOTE) == 0)
{
strcat(ret, note);
}
else if (strcmp(var, fc_PIN) == 0)
{
_itoa(pin, ret);
}
else if (strcmp(var, fc_PRESENT) == 0)
{
if (GETBIT(flags, fFC))
strcat(ret, (char *)cOne);
else
strcat(ret, (char *)cZero);
}
else if (strcmp(var, fc_STATE) == 0)
{
_itoa(state, ret);
}
else if (strcmp(var, fc_FC) == 0)
{
_ftoa(ret, (float)FC / 100.0, 2);
}
else if (strcmp(var, fc_cFC) == 0)
{
_ftoa(ret, (float)freqFC / 100.0, 2);
}
else if (strcmp(var, fc_cPOWER) == 0)
{
_ftoa(ret, (float)power / 10.0, 1);
}
else if (strcmp(var, fc_INFO1) == 0)
{
_ftoa(ret, (float)power / 10.0, 1);
strcat(ret, " kW ");
}
else if (strcmp(var, fc_cCURRENT) == 0)
{
_ftoa(ret, (float)current / 100.0, 2);
}
else if (strcmp(var, fc_AUTO_RESET_FAULT) == 0)
{
strcat(ret, (char *)(GETBIT(_data.setup_flags, fAutoResetFault) ? cOne : cZero));
}
else if (strcmp(var, fc_LogWork) == 0)
{
strcat(ret, (char *)(GETBIT(_data.setup_flags, fLogWork) ? cOne : cZero));
}
else if (strcmp(var, fc_ANALOG) == 0)
{ // Analog control flag
#ifdef FC_ANALOG_CONTROL
strcat(ret, (char *)cOne);
#else
strcat(ret, (char *)cZero);
#endif
}
else if (strcmp(var, fc_DAC) == 0)
{
_itoa(dac, ret);
}
else
#ifdef FC_ANALOG_CONTROL
#endif
if (strcmp(var, fc_BLOCK) == 0)
{
if (GETBIT(flags, fErrFC))
strcat(ret, (char *)cOne);
else
strcat(ret, (char *)cZero);
}
else if (strcmp(var, fc_ERROR) == 0)
{
_itoa(err, ret);
}
else if (strcmp(var, fc_UPTIME) == 0)
{
_itoa(_data.Uptime, ret);
}
else // output in seconds
if (strcmp(var, fc_PID_STOP) == 0)
{
_itoa(_data.PidStop, ret);
}
else if (strcmp(var, fc_DT_COMP_TEMP) == 0)
{
_ftoa(ret, (float)_data.dtCompTemp / 100.0, 2);
}
else // degrees
if (strcmp(var, fc_PID_FREQ_STEP) == 0)
{
_ftoa(ret, (float)_data.PidFreqStep / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_START_FREQ) == 0)
{
_ftoa(ret, (float)_data.startFreq / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_START_FREQ_BOILER) == 0)
{
_ftoa(ret, (float)_data.startFreqBoiler / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_MIN_FREQ) == 0)
{
_ftoa(ret, (float)_data.minFreq / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_MIN_FREQ_COOL) == 0)
{
_ftoa(ret, (float)_data.minFreqCool / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_MIN_FREQ_BOILER) == 0)
{
_ftoa(ret, (float)_data.minFreqBoiler / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_MIN_FREQ_USER) == 0)
{
_ftoa(ret, (float)_data.minFreqUser / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_MAX_FREQ) == 0)
{
_ftoa(ret, (float)_data.maxFreq / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_MAX_FREQ_COOL) == 0)
{
_ftoa(ret, (float)_data.maxFreqCool / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_MAX_FREQ_BOILER) == 0)
{
_ftoa(ret, (float)_data.maxFreqBoiler / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_MAX_FREQ_USER) == 0)
{
_ftoa(ret, (float)_data.maxFreqUser / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_STEP_FREQ) == 0)
{
_ftoa(ret, (float)_data.stepFreq / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_STEP_FREQ_BOILER) == 0)
{
_ftoa(ret, (float)_data.stepFreqBoiler / 100.0, 2);
}
else // Hz
if (strcmp(var, fc_DT_TEMP) == 0)
{
_ftoa(ret, (float)_data.dtTemp / 100.0, 2);
}
else // degrees
if (strcmp(var, fc_DT_TEMP_BOILER) == 0)
{
_ftoa(ret, (float)_data.dtTempBoiler / 100.0, 2);
}
else // degrees
if (strcmp(var, fc_MB_ERR) == 0)
{
_itoa(numErr, ret);
}
else if (strcmp(var, fc_FC_TIME_READ) == 0)
{
_itoa(FC_TIME_READ, ret);
}
else
strcat(ret, (char *)cInvalid);
}
// Set the inverter parameter from the string
boolean devOmronMX2::set_paramFC(char *var, float x)
{
if (strcmp(var, fc_ON_OFF) == 0)
{
if (x == 0)
stop_FC();
else
start_FC();
return true;
}
else if (strcmp(var, fc_FC) == 0)
{
if ((x * 100 >= _data.minFreqUser) && (x * 100 <= _data.maxFreqUser))
{
set_target(x * 100, true, _data.minFreqUser, _data.maxFreqUser);
return true;
}
else
return false;
}
else if (strcmp(var, fc_AUTO_RESET_FAULT) == 0)
{
if (x == 0)
SETBIT0(_data.setup_flags, fAutoResetFault);
else
SETBIT1(_data.setup_flags, fAutoResetFault);
return true;
}
else if (strcmp(var, fc_LogWork) == 0)
{
_data.setup_flags = (_data.setup_flags & ~(1 << fLogWork)) | ((x != 0) << fLogWork);
return true;
}
else
#ifdef FC_ANALOG_CONTROL
#endif
if (strcmp(var, fc_BLOCK) == 0)
{
SemaphoreGive(xModbusSemaphore); // give the semaphore ALWAYS
if (x == 0)
{
SETBIT0(flags, fErrFC);
note = (char *)noteFC_OK;
}
else
{
SETBIT1(flags, fErrFC);
note = (char *)noteFC_NO;
}
return true;
}
else if (strcmp(var, fc_UPTIME) == 0)
{
if ((x >= 3) && (x < 600))
{
_data.Uptime = x;
return true;
}
else
return false;
}
else // storage in sec
if (strcmp(var, fc_PID_STOP) == 0)
{
if ((x >= 50) && (x <= 100))
{
_data.PidStop = x;
return true;
}
else
return false;
}
else // % of the target
if (strcmp(var, fc_DT_COMP_TEMP) == 0)
{
if ((x >= 1) && (x <= 25))
{
_data.dtCompTemp = x * 100;
return true;
}
else
return false;
}
else // degrees
if (strcmp(var, fc_PID_FREQ_STEP) == 0)
{
if ((x > 0) && (x <= 5))
{
_data.PidFreqStep = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_START_FREQ) == 0)
{
if ((x >= 20) && (x <= 120))
{
_data.startFreq = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_START_FREQ_BOILER) == 0)
{
if ((x >= 20) && (x <= 150))
{
_data.startFreqBoiler = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_MIN_FREQ) == 0)
{
if ((x >= 20) && (x <= 80))
{
_data.minFreq = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_MIN_FREQ_COOL) == 0)
{
if ((x >= 20) && (x <= 80))
{
_data.minFreqCool = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_MIN_FREQ_BOILER) == 0)
{
if ((x >= 20) && (x <= 80))
{
_data.minFreqBoiler = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_MIN_FREQ_USER) == 0)
{
if ((x >= 20) && (x <= 80))
{
_data.minFreqUser = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_MAX_FREQ) == 0)
{
if ((x >= 40) && (x <= 240))
{
_data.maxFreq = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_MAX_FREQ_COOL) == 0)
{
if ((x >= 40) && (x <= 240))
{
_data.maxFreqCool = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_MAX_FREQ_BOILER) == 0)
{
if ((x >= 40) && (x <= 240))
{
_data.maxFreqBoiler = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_MAX_FREQ_USER) == 0)
{
if ((x >= 40) && (x <= 240))
{
_data.maxFreqUser = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_STEP_FREQ) == 0)
{
if ((x >= 0.2) && (x <= 10))
{
_data.stepFreq = x * 100;
return true;
}
else
return false;
}
else // Hz
if (strcmp(var, fc_STEP_FREQ_BOILER) == 0)
{
if ((x >= 0.2) && (x <= 10))
{
_data.stepFreqBoiler = x * 100;
return true;
}
else
return false;
} // Hz
if (strcmp(var, fc_DT_TEMP) == 0)
{
if ((x > 0) && (x < 10))
{
_data.dtTemp = x * 100;
return true;
}
else
return false;
}
else // degrees
if (strcmp(var, fc_DT_TEMP_BOILER) == 0)
{
if ((x > 0) && (x < 10))
{
_data.dtTempBoiler = x * 100;
return true;
}
else
return false;
}
else // degrees
return false;
}
// Get information about the chastotnik, information is added to buf
char *devOmronMX2::get_infoFC(char *buf)
{
// #ifndef FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT
/*
if (!HP.dFC.get_present())
{
strcat(buf, " | Data not available (no inverter) |; ");
return buf;
} // The inverter is not in the configuration
if (HP.dFC.get_blockFC())
{
strcat(buf, " | Data not available (no Modbus communication, inverter locked) |; ");
return buf;
} // Inverter locked
int8_t i;
strcat(buf, " - | Inverter state [0: Initial state, 2: Stop 3: Turn 4: Coast stop 5: Jog 6: DC braking ");
strcat(buf, " 7: Retrying 8: Failing 9: Undervoltage -1: Blocking] | ");
_itoa(read_0x03_16(MX2_STATE), buf);
strcat(buf, " ; ");
_delay(FC_DELAY_READ);
strcat(buf, " d001 | Output frequency control (Hz) | ");
_ftoa(buf, (float)read_0x03_32(MX2_CURRENT_FR) / 100.0, 2);
strcat(buf, " ; ");
_delay(FC_DELAY_READ);
strcat(buf, " d003 | Output current control (A) | ");
_ftoa(buf, (float)read_0x03_16(MX2_AMPERAGE) / 100.0, 2);
strcat(buf, " ; ");
_delay(FC_DELAY_READ);
strcat(buf, " d014 | Power control (kW) | ");
_ftoa(buf, (float)read_0x03_16(MX2_POWER) / 10.0, 1);
strcat(buf, " ; ");
_delay(FC_DELAY_READ);
strcat(buf, " d013 | Monitoring the output voltage (V) | ");
_ftoa(buf, (float)read_0x03_16(MX2_VOLTAGE) / 10.0, 1);
strcat(buf, " ; ");
_delay(FC_DELAY_READ);
strcat(buf, " d015 | Watt-hour control (kW / h) | ");
_ftoa(buf, (float)read_0x03_32(MX2_POWER_HOUR) / 10.0, 1);
strcat(buf, " ; ");
_delay(FC_DELAY_READ);
strcat (buf, " d016 | Runtime monitoring in \" Run \ " mode (h) | " ); _itoa ( read_0x03_32 (MX2_HOUR), buf); strcat (buf, " ; " );
_delay (FC_DELAY_READ);
strcat (buf, " d017 | Runtime monitoring with power on (h) | " ); _itoa ( read_0x03_32 (MX2_HOUR1), buf); strcat (buf, " ; " );
_delay (FC_DELAY_READ);
strcat (buf, " d018 | Radiator temperature control (° C) | " ); _ftoa (buf, ( float ) read_0x03_16 (MX2_TEMP) / 10.0 , 2 ); strcat (buf, " ; " );
_delay (FC_DELAY_READ);
strcat (buf, " d102 | DC voltage control (V) | " ); _ftoa (buf, ( float ) read_0x03_16 (MX2_VOLTAGE_DC) / 10.0 , 1 ); strcat (buf, " ; " );
_delay (FC_DELAY_READ);
strcat (buf, " d080 | Counter of emergency shutdowns (pcs) | " ); _itoa ( read_0x03_16 (MX2_NUM_ERR), buf); strcat (buf, " ; " );
for (i = 0 ; i < 6 ; i ++) // Scan By Errors
{
strcat(buf, " d0 ");
_itoa(81 + i, buf);
strcat(buf, " | State at the time of the error ");
read_0x03_error(MX2_ERROR1 + i * 0x0a);
// Formation of the answer in line
strcat(buf, " [F: ");
_ftoa(buf, (float)error.MX2.fr / 100.0, 2);
strcat(buf, " I: ");
_ftoa(buf, (float)error.MX2.cur / 100.0, 2);
strcat(buf, " V: ");
_ftoa(buf, (float)error.MX2.vol / 10.0, 2);
strcat(buf, " T1: ");
_itoa(error.MX2.time1, buf);
strcat(buf, " T2: ");
_itoa(error.MX2.time2, buf);
strcat(buf, " ] Error code: | ");
if (error.MX2.code < 10)
strcat(buf, " E0 ");
else
strcat(buf, " E ");
_itoa(error.MX2.code, buf);
strcat(buf, " . ");
_itoa(error.MX2.status, buf);
strcat(buf, " ; ");
}
#endif
return buf;
*/
}
// Reset inverter errors by modbass
boolean devOmronMX2 ::reset_errorFC()
{
#ifndef FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT
write_0x06_16(MX2_INIT_DEF, 0x01); // set the initialization mode - erasing errors
_delay(FC_DELAY_READ);
if ((read_0x03_16(MX2_INIT_DEF) == 0x01) && (err = OK)) // issue an initialization command if only errors have been erased
{
write_0x06_16(MX2_INIT_RUN, 0x01);
// jprintf(" Reset error% s \ r \ n ", name);
}
else
// jprintf(" $ WARNING: bad read from MX2_INIT_DEF, no reset error \ r \ n ");
#endif
if (err == OK)
return true;
else
return false;
}
// Reset the inverter via modbas
boolean devOmronMX2::reset_FC()
{
#ifndef FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT
write_0x05_bit(MX2_RESET, true); // send a command to reset by modbas
// jprintf ("Reset% s use Modbus \ r \ n", name);
#endif
if (err == OK)
return true;
else
return false;
}
// Current state of the inverter
//
int16_t devOmronMX2::read_stateFC()
{
#ifndef FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT
state = read_0x03_16(MX2_STATE); // read the state
if (GETBIT(_data.setup_flags, fLogWork) && GETBIT(flags, fOnOff))
{
// jprintf_time(" FC:% Xh,% .2fHz,% .2fA,% .2fkW \ n ", state, (float)freqFC / 100.0, (float)current / 100.0, (float)get_power() / 1000.0);
}
return state;
#else
return 0;
#endif
}
// Radiator temperature
int16_t devOmronMX2::read_tempFC()
{
#ifndef FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT
return read_0x03_16(MX2_TEMP);
#else
return 0;
#endif
}
// Communication functions on the inverter modbas Read registers
#ifndef FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT
// Reading a single bit into the cmd register returns a code, the error is updated
// Implemented FC_NUM_READ read / write attempts to the inverter
boolean devOmronMX2 ::read_0x01_bit(uint16_t cmd)
{
uint8_t i;
boolean result;
err = OK;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return false; // exit if there is no inverter or it is blocked by mistake
for (i = 0; i < FC_NUM_READ; i++) // make FC_NUM_READ attempts to read Read the inverter status, if an error occurs, generate a common VT error and stop
{
err = Modbus.readCoil(FC_MODBUS_ADR, cmd - 1, &result); // send a request, Numbering of registers MX2 from ZERO !!!!
if (err == OK)
break; // Read successfully
_delay(FC_DELAY_REPEAT);
// jprintf(cErrorRS485, name, __ FUNCTION __, err); // Display a message about re-reading
numErr++; // number of errors reading by modbass
// jprintf_time (cErrorRS485, name, err); // Output the error code to the log
}
check_blockFC(); // check for blocking
return result;
}
// Function 0x03 read 2 bytes, returns a value, the error is updated
// Implemented FC_NUM_READ read / write attempts to the inverter
int16_t devOmronMX2::read_0x03_16(uint16_t cmd)
{
uint8_t i;
uint16_t result;
err = OK;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return 0; // exit if there is no inverter or it is blocked by mistake
for (i = 0; i < FC_NUM_READ; i++) // make FC_NUM_READ attempts to read Read the inverter status, if an error occurs, generate a common VT error and stop
{
err = Modbus.readHoldingRegisters16(FC_MODBUS_ADR, cmd - 1, &result); // Send a request, MX2 register numbering from ZERO !!!!
if (err == OK)
break; // Read successfully
_delay(FC_DELAY_REPEAT);
// jprintf(cErrorRS485, name, __FUNCTION__, err); // Display a message about re-reading
numErr++; // number of errors reading by modbass
// jprintf_time (cErrorRS485, name, err); // Output the error code to the log
}
check_blockFC(); // check for blocking
return result;
}
// Function 0x03 read 4 bytes
// Implemented FC_NUM_READ read / write attempts to the inverter
uint32_t devOmronMX2::read_0x03_32(uint16_t cmd)
{
uint8_t i;
uint32_t result;
err = OK;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return 0; // exit if there is no inverter or it is blocked by mistake
for (i = 0; i < FC_NUM_READ; i++) // make FC_NUM_READ attempts to read Read the inverter status, if an error occurs, generate a common VT error and stop
{
err = Modbus.readHoldingRegisters32(FC_MODBUS_ADR, cmd - 1, &result); // send a request, Numbering of registers MX2 from ZERO !!!!
if (err == OK)
break; // Read successfully
_delay(FC_DELAY_REPEAT);
// jprintf(cErrorRS485, name, __ FUNCTION __, err); // Display a message about re-reading
numErr++; // number of errors reading by modbass
// jprintf_time (cErrorRS485, name, err); // Output the error code to the log
}
check_blockFC(); // check for blocking
return result;
}
// Modbus function 0x03 error description num NUMBERING from 0 (total data length 10 words, 2 bytes each)
// Returns the error code and puts a description in the buffer
// Implemented FC_NUM_READ read / write attempts to the inverter
int16_t devOmronMX2::read_0x03_error(uint16_t cmd)
{
uint8_t i;
uint16_t tmp;
err = OK;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return err; // exit if there is no inverter or it is blocked by mistake
for (i = 0; i < 0x0a; i++)
error.inputBuf[i] = 0;
for (i = 0; i < FC_NUM_READ; i++) // make FC_NUM_READ attempts to read Read the inverter status, if an error occurs, generate a common VT error and stop
{
err = Modbus.readHoldingRegistersNN(FC_MODBUS_ADR, cmd - 1, 0x0a, error.inputBuf); // send a request, Numbering of registers from ZERO !!!!
if (err == OK)
break; // Read successfully
_delay(FC_DELAY_REPEAT);
// jprintf(cErrorRS485, name, __ FUNCTION __, err); // Display a message about re-reading
numErr++; // number of errors reading by modbass
// jprintf_time (cErrorRS485, name, err); // Output the error code to the log
}
if (err == OK) // For times, rearrange the words (2 bytes), i.e., the leading 2 bytes then the lower
{
tmp = error.inputBuf[6];
error.inputBuf[6] = error.inputBuf[7];
error.inputBuf[7] = tmp; // Total operating time in the "Run" mode to the time of shutdown
tmp = error.inputBuf[8];
error.inputBuf[8] = error.inputBuf[9];
error.inputBuf[9] = tmp; // The total operating time of the inverter with the power on at the time the output is turned off
}
check_blockFC(); // check for blocking
return err;
}
// Writing a single bit to the cmd register returns an error code
// Implemented FC_NUM_READ read / write attempts to the inverter
int8_t devOmronMX2::write_0x05_bit(uint16_t cmd, boolean f)
{
uint8_t i;
err = OK;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return err; // exit if there is no inverter or it is blocked by mistake
for (i = 0; i < FC_NUM_READ; i++) // make FC_NUM_READ write attempts
{
if (f)
err = Modbus.writeSingleCoil(FC_MODBUS_ADR, cmd - 1, 1); // send a request, Numbering of registers from ZERO !!!!
else
err = Modbus.writeSingleCoil(FC_MODBUS_ADR, cmd - 1, 0);
if (err == OK)
break; // Written successfully
_delay(FC_DELAY_REPEAT);
// jprintf(cErrorRS485, name, __ FUNCTION __, err); // Display a message about re-reading
numErr++; // number of errors reading by modbass
// jprintf_time (cErrorRS485, name, err); // Output the error code to the log
}
check_blockFC(); // check for blocking
return err;
}
// Writing data (2 bytes) to the cmd register returns an error code
// Implemented FC_NUM_READ read / write attempts to the inverter
int8_t devOmronMX2::write_0x06_16(uint16_t cmd, uint16_t data)
{
uint8_t i;
err = OK;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return err; // exit if there is no inverter or it is blocked by mistake
for (i = 0; i < FC_NUM_READ; i++) // make FC_NUM_READ write attempts
{
err = Modbus.writeHoldingRegisters16(FC_MODBUS_ADR, cmd - 1, data); // send a request, Numbering of registers from ZERO !!!!
if (err == OK)
break; // Written successfully
_delay(FC_DELAY_REPEAT);
// jprintf(cErrorRS485, name, __ FUNCTION __, err); // Display a message about re-reading
numErr++; // number of errors reading by modbass
// jprintf_time (cErrorRS485, name, err); // Output the error code to the log
}
check_blockFC(); // check for blocking
return err;
}
// Writing data (4 bytes) to the cmd register returns an error code
int8_t devOmronMX2 ::write_0x10_32(uint16_t cmd, uint32_t data)
{
uint8_t i;
err = OK;
if ((!get_present()) || (GETBIT(flags, fErrFC)))
return err; // exit if there is no inverter or it is blocked by mistake
for (i = 0; i < FC_NUM_READ; i++) // make FC_NUM_READ write attempts
{
err = Modbus.writeHoldingRegisters32(FC_MODBUS_ADR, cmd - 1, data); // send a request, Numbering of registers from ZERO !!!!
if (err == OK)
break; // Written successfully
_delay(FC_DELAY_REPEAT);
// jprintf(cErrorRS485, name, __ FUNCTION __, err); // Display a message about re-reading
numErr++; // number of errors reading by modbass
// jprintf_time (cErrorRS485, name, err); // Output the error code to the log
}
check_blockFC(); // check for blocking
return err;
}
#endif // FC_ANALOG_CONTROL // NOT ANALOGUE MANAGEMENT