Просмотр полной версии : ПЛК160 + ПЧ Eaton DC1 по modbus
Столкнулся с необходимостью управлять преобразователем частоты Eaton DC1. Застрял на прочтении слова состояния и неисправности (они объединены в одно слово).
20576
То есть неисправность шифруется шестнадцатеричным кодом во втором байте слова состояния и неисправности.
20577
Соответственно, как я понимаю мне нужно вырезать нужный кусок информации из WORDа и его анализировать. Но с операторами сдвига у меня мягко говоря пока туго (то есть вообще ещё не сталкивался).
Если я правильно понял, то последовательность действий примерно такая:
VAR
pt :POINTER TO WORD;
avar_pch :BYTE;
stat_pch :WORD;
code_err :WORD;
END_VAR
pt:=ADR(stat_pch);
avar_pch:=WORD_TO_BYTE(SHR(pt^,??)); (*Смещаемся на 8 бит (или не 8??) вправо и остальное заполняем нулями*)
(*Анализируем коды ошибок*)
CASE avar_pch OF
16#00: code_err:=1;
16#01: code_err:=2;
...
...
END_CASE
Но почти уверен, что код не совсем верен. Так как на руках преобразователя ещё нет, хотел бы проконсультироваться по коду у профессионалов :rolleyes:
Столкнулся с необходимостью управлять преобразователем частоты Eaton DC1. Застрял на прочтении слова состояния и неисправности (они объединены в одно слово).
20576
То есть неисправность шифруется шестнадцатеричным кодом во втором байте слова состояния и неисправности.
20577
Соответственно, как я понимаю мне нужно вырезать нужный кусок информации из WORDа и его анализировать. Но с операторами сдвига у меня мягко говоря пока туго (то есть вообще ещё не сталкивался).
Если я правильно понял, то последовательность действий примерно такая:
VAR
pt :POINTER TO WORD;
avar_pch :BYTE;
stat_pch :WORD;
code_err :WORD;
END_VAR
pt:=ADR(stat_pch);
avar_pch:=WORD_TO_BYTE(SHR(pt^,??)); (*Смещаемся на 8 бит (или не 8??) вправо и остальное заполняем нулями*)
(*Анализируем коды ошибок*)
CASE avar_pch OF
16#00: code_err:=1;
16#01: code_err:=2;
...
...
END_CASE
Но почти уверен, что код не совсем верен. Так как на руках преобразователя ещё нет, хотел бы проконсультироваться по коду у профессионалов :rolleyes:
1. Операцию сдвига SHR можно было использовать без всяких указателей срезу к stat_pch
2. А если уж использовать указатель, то так
VAR
stat_pch: WORD;
pt: POINTER TO BYTE;
avar_pch: BYTE;
END_VAR
pt:=ADR(stat_pch)+1;
avar_pch:=pt^;
Ага, понятно. Попробую сейчас.
А зачем +1 к pt?
В итоге написал такой ФБ:
FUNCTION_BLOCK avar_pch_dc1
VAR_INPUT
alarm_pch :BOOL; (*Вход аварийного состояния*)
stat_pch :WORD; (*Слово состояния с преобрзователя*)
END_VAR
VAR_OUTPUT
ovr_cur, ovr_dr, err_phase, ovr_heat :BOOL; (*Выходы аварий*)
END_VAR
VAR
(*pt :POINTER TO WORD; (*Адрес входной переменной*)*)
avar_pch :BYTE; (*Переменная в байтах*)
code_err :WORD; (*Код аварии*)
err :BOOL; (*Наличие аварии*)
END_VAR
(*
Коды аварий (hex)
00 Остановлен, готов к работе
01 Избыточный ток тормозного прерывателя
02 Перегрузка тормозного резистора
03 • Перегрузка по току на выходе преобразователя частоты
• Перегрузка двигателя
• Перегрев радиатора преобразователя частоты
04 Перегрев двигателя
05 Внутренняя неисправность (силовая схема)
06 Перенапряжение в звене постоянного тока
07 Недостаточное напряжение в звене постоянного тока
08 Перегрев радиатора охлаждения
09 Перегрев радиатора охлаждения
0A Настройки по умолчанию (параметры загружены)
C0 сообщение о внешней ошибке
0C Ошибка магистральной шины
0D Зарезервирован
0E Неисправность фазы (со стороны электрической сети)
0F Неисправность функции управления приемистостью двигателя (для подхвата вращающегося двигателя)
10 Неисправность встроенного термистора (радиатор)
11 Неисправность контрольной суммы EEPROM
12 Аналоговый вход:
• значение вне диапазона
• разрыв провода (контроль 4 мА)
*)
IF alarm_pch THEN
err:=TRUE; (*Установить признак аварии*)
(*pt:=ADR(stat_pch);*)
(*avar_pch:=WORD_TO_BYTE(SHR(pt^,8)); (*Смещаемся на 8 бит (или не 8??) вправо и остальное заполняем нулями*)*)
avar_pch:=WORD_TO_BYTE(SHR(stat_pch,8)); (*Смещаемся на 8 бит (или не 8??) вправо и остальное заполняем нулями*)
(*Коды ошибок, полученные с датчика*)
CASE avar_pch OF
16#00: code_err:=1; (*Остановлен, готов к работе*)
16#01: code_err:=2; (*Избыточный ток тормозного прерывателя*)
16#02: code_err:=3; (*Перегрузка тормозного резистора*)
16#03: code_err:=4; (*Перегрузка по току ПЧ, ЭД или перегрев радиатора преобразователя частоты*)
16#04: code_err:=5; (*Перегрев двигателя*)
16#05: code_err:=6; (*Внутренняя неисправность (силовая схема)*)
16#06: code_err:=7; (*Перенапряжение в звене постоянного тока*)
16#07: code_err:=8; (*Недостаточное напряжение в звене постоянного тока*)
16#08: code_err:=9; (*Перегрев радиатора охлаждения*)
16#09: code_err:=10; (*Перегрев радиатора охлаждения*)
16#C0: code_err:=11; (*сообщение о внешней ошибке*)
16#0C: code_err:=12; (*Ошибка магистральной шины*)
16#0E: code_err:=13; (*Неисправность фазы (со стороны электрической сети)*)
16#0F: code_err:=14; (*Неисправность функции управления приемистостью двигателя (для подхвата вращающегося двигателя)*)
16#10: code_err:=15; (*Неисправность встроенного термистора (радиатор)*)
16#11: code_err:=16; (*Неисправность контрольной суммы EEPROM*)
16#12: code_err:=17; (*Неисправность аналогового входа (вне диапазона или разрыв провода)*)
ELSE
err:=FALSE;
code_err:=0; (*Нет аварии ПЧ*)
END_CASE
IF code_err=4 THEN
ovr_cur:=TRUE;
ELSE ovr_cur:=FALSE; END_IF;
IF code_err=5 THEN
ovr_dr:=TRUE;
ELSE ovr_dr:=FALSE; END_IF;
IF code_err=13 THEN
err_phase:=TRUE;
ELSE err_phase:=FALSE; END_IF;
IF (code_err=9 OR code_err=10) THEN
ovr_heat:=TRUE;
ELSE ovr_heat:=FALSE; END_IF;
END_IF;
Надеюсь будет работать...
По идее в avar_pch уже и есть код ошибки. Можно и без CASE обойтись и не использовать переменную code_err.
Но если хочется иметь коды ошибок по порядку, то и CASE можно уменьшить
VAR
stat_pch: WORD;
pt: POINTER TO BYTE;
avar_pch: WORD;
code_err: WORD;
END_VAR
pt:=ADR(stat_pch)+1;
avar_pch:=pt^;
(*Анализируем коды ошибок*)
CASE avar_pch OF
16#C0: code_err:=11;
16#0C: code_err:=12;
16#0D: code_err:=13;
16#0E: code_err:=14;
16#0F: code_err:=15;
16#10: code_err:=16;
16#11: code_err:=17;
16#12: code_err:=18;
ELSE
IF avar_pch <= 10 THEN
code_err:=avar_pch;
ELSE
code_err:=0;
END_IF
END_CASE
Ага, понятно. Попробую сейчас.
А зачем +1 к pt?
Для того чтобы указатель указывал на старший BYTE в stat_pch
ЗЫ. А я смотрю Вы все равно и указатель и сдвиг используете, а зачем?
По идее в avar_pch уже и есть код ошибки. Можно и без CASE обойтись и не использовать переменную code_err.
Но если хочется иметь коды ошибок по порядку, то и CASE можно уменьшить
VAR
stat_pch: WORD;
pt: POINTER TO BYTE;
avar_pch: WORD;
code_err: WORD;
END_VAR
pt:=ADR(stat_pch)+1;
avar_pch:=pt^;
(*Анализируем коды ошибок*)
CASE avar_pch OF
16#C0: code_err:=11;
16#0C: code_err:=12;
16#0D: code_err:=13;
16#0E: code_err:=14;
16#0F: code_err:=15;
16#10: code_err:=16;
16#11: code_err:=17;
16#12: code_err:=18;
ELSE
IF avar_pch <= 10 THEN
code_err:=avar_pch;
ELSE
code_err:=0;
END_IF
END_CASE
Понятно, огромное спасибо за разъяснения
Для того чтобы указатель указывал на старший BYTE в stat_pch
И ещё раз спасибо
ЗЫ. А я смотрю Вы все равно и указатель и сдвиг используете, а зачем?
Я указатель закоментировал
Powered by vBulletin® Version 4.2.3 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot