Зачистил все лишнее.
Обычно таймерами не пользуюсь, просто пишу текущее время в переменную, и потом сравниваю, это уже от безысходности, но, попробую, спасибо!
Вид для печати
С таймером - не прокатило.. Изначально, управление сложнее, с бОльшим кол-вом переменных, через TIME(). Чтобы не отнимать время на кучу кода - втыкнул таймер.
Про Adjust - да, прошу прощения: это пытался вывести CASE за условие IF (Если нужна калибровка, то Adjust =1, иначе 0, энд иф. И уже далее - просто кейс. Так тоже не сработало). Вернул счет с единички - тоже самое: при калибровке - система стоит. Уже попробовал ОТКР/ЗАКР вынести в отдельную функцию, а фб оставить чисто на такие модули с таймерами. Результат тот же..
Думал ошибка инициации ФБ, уже намертво прибил Ven[1], но, с другой стороны, все 9 заслонок открываются/закрываются, значит все ок.. воткнуть RETURN после каждого шага, чтобы, условно, "не ждать сейчас таймер, заглянем потом" - так же не дают результата..Код:IF Ven[num].Flap.xAdjust THEN (* Выносим Case за IF *)
Ven[num].Flap.sAdjust:=1;
ELSE
Ven[num].Flap.sAdjust:=0;
END_IF;
CASE Ven[num].Flap.sAdjust OF (*то же, без цикла IF*)
1: Ven[num].Flap.Close:=FALSE; (*Шаг 1*)
VEN[num].Flap.Open:=TRUE;
t1(IN:=TRUE, PT:=T#40s);
IF t1.q THEN
Ven[num].Flap.sAdjust:=Ven[num].Flap.sAdjust+1;
t1(IN:=FALSE, PT:=t1.PT);
END_IF;
2: VEN[num].Flap.Close:=TRUE; (* Шаг 2*)
VEN[num].Flap.Open:=FALSE;
t1(IN:=TRUE, PT:=T#40s);
IF t1.q THEN
Ven[num].Flap.sAdjust:=Ven[num].Flap.sAdjust+1;
t1(IN:=FALSE, PT:=t1.PT);
END_IF;
3: VEN[num].Flap.Close:=FALSE; (* Шаг 3*)
VEN[num].Flap.Open:=FALSE;
Ven[num].Flap.sAdjust:=0; (* Сбрасыываем все *)
Ven[num].Flap.xAdjust:=FALSE;
END_CASE
Тоже самое, но без CASE. Не катит..Код:IF Ven[num].Flap.sAdjust = 1 THEN
Ven[num].Flap.Close:=FALSE;
VEN[num].Flap.Open:=TRUE;
t1(IN:=TRUE, PT:=T#40s);
IF t1.q THEN
Ven[num].Flap.sAdjust:=Ven[num].Flap.sAdjust+1;
t1(IN:=FALSE, PT:=t1.PT);
END_IF;
END_IF;
IF Ven[num].Flap.sAdjust = 2 THEN
VEN[num].Flap.Close:=TRUE;
VEN[num].Flap.Open:=FALSE;
t1(IN:=TRUE, PT:=T#40s);
IF t1.q THEN
Ven[num].Flap.sAdjust:=Ven[num].Flap.sAdjust+1;
t1(IN:=FALSE, PT:=t1.PT);
END_IF;
END_IF;
IF Ven[num].Flap.sAdjust = 3 THEN
VEN[num].Flap.Close:=FALSE;
VEN[num].Flap.Open:=FALSE;
Ven[num].Flap.sAdjust:=0;
Ven[num].Flap.xAdjust:=FALSE;
END_IF;
У вас переменная bool, а вы её в кейс засунули как переменную инт, и она в первом иф всегда 1...
Пардон, там x... и s...
Выносите таймеры из кейса.
Если честно, кровь из глаз чуть не пошла от этого кода. Ничего там не понял... Вернее впал в спупор.
Вы же в кодесисе... Таймеры запускаются? В кейсах или ифах сделайте переменную равную тру, у уже ей запускайте таймер вне условий. Сброс таймеров можете таким же оставить, но только с командой фальш без задания времени.И ещё одно замечание:Код:
t1(IN:=парарам, PT:=T#40s);
IF Ven[num].Flap.sAdjust = 1 THEN
Ven[num].Flap.Close:=FALSE;
VEN[num].Flap.Open:=TRUE;
Парарам :=тру;
IF t1.q THEN
Ven[num].Flap.sAdjust:=Ven[num].Flap.sAdjust+1;
t1(IN:=FALSE);
END_IF;
END_IF;
И т.д.
IF Ven[num].Flap.sAdjust = 2 THEN
VEN[num].Flap.Close:=TRUE;
VEN[num].Flap.Open:=FALSE;
t1(IN:=TRUE, PT:=T#40s);
IF t1.q THEN
Ven[num].Flap.sAdjust:=Ven[num].Flap.sAdjust+1;
t1(IN:=FALSE, PT:=t1.PT);
END_IF;
END_IF;
IF Ven[num].Flap.sAdjust = 3 THEN
VEN[num].Flap.Close:=FALSE;
VEN[num].Flap.Open:=FALSE;
Ven[num].Flap.sAdjust:=0;
Ven[num].Flap.xAdjust:=FALSE;
END_IF;
T1[I](IN:=парарам[I], PT:=T#40s);
Наверно такое хотели получить:
А какая вообще функция у данного механизма и зачем нужна калибровка?Код:IF Ven[num].Flap.xAdjust THEN (* Выносим Case за IF *)
IF Ven[num].Flap.sAdjust=0 THEN Ven[num].Flap.sAdjust:=1; END_IF;
ELSE
Ven[num].Flap.sAdjust:=0;
END_IF;
CASE Ven[num].Flap.sAdjust OF (*то же, без цикла IF*)
1: Ven[num].Flap.Close:=FALSE; (*Шаг 1*)
VEN[num].Flap.Open:=TRUE;
t1(IN:=TRUE, PT:=T#10s);
IF t1.q THEN
Ven[num].Flap.sAdjust:=2;
t1(IN:=FALSE);
END_IF;
2: VEN[num].Flap.Close:=TRUE; (* Шаг 2*)
VEN[num].Flap.Open:=FALSE;
t1(IN:=TRUE, PT:=T#10s);
IF t1.q THEN
Ven[num].Flap.sAdjust:=3;
t1(IN:=FALSE);
END_IF;
3: VEN[num].Flap.Close:=FALSE; (* Шаг 3*)
VEN[num].Flap.Open:=FALSE;
Ven[num].Flap.sAdjust:=0; (* Сбрасыываем все *)
Ven[num].Flap.xAdjust:=FALSE;
END_CASE
(*Функция открытия заслонки*)
IF Ven[num].Flap.Open THEN
IF Ven[num].Flap.Open AND NOT Ven[num].Flap.xOpen THEN
Ven[num].Flap.xOpen:=TRUE;
Ven[num].Flap.Close:=Ven[num].Flap.xClose:=FALSE;
Ven[num].Flap.t_Pos:=TIME();
ELSIF Ven[num].Flap.Open AND Ven[num].Flap.xOpen THEN
Ven[num].Flap.Pos:= Ven[num].Flap.Pos + 0.00258 * (TIME_TO_REAL(TIME() - Ven[num].Flap.t_Pos));
Ven[num].Flap.t_Pos:=TIME();
IF Ven[num].Flap.Pos > 90 THEN Ven[num].Flap.Pos:=90;
END_IF;
ELSE
Ven[num].Flap.xOpen:=FALSE;
END_IF;
END_IF;
(* Функция закрытия заслонки *)
IF Ven[num].Flap.Close THEN
IF Ven[num].Flap.Close AND NOT Ven[num].Flap.xClose THEN
Ven[num].Flap.xClose:=TRUE;
Ven[num].Flap.xOpen:= FALSE;
Ven[num].Flap.t_Pos:=TIME();
ELSIF Ven[num].Flap.Close AND Ven[num].Flap.xClose THEN
Ven[num].Flap.Pos:= Ven[num].Flap.Pos - 0.00258 * (TIME_TO_REAL(TIME() - Ven[num].Flap.t_Pos));
Ven[num].Flap.t_Pos:=TIME();
IF Ven[num].Flap.Pos < 0 THEN Ven[num].Flap.Pos:=0;
END_IF;
ELSE
Ven[num].Flap.xClose:=FALSE;
END_IF;
END_IF;
Таймеры и внутри и за CASE - работают. Работает и счетчик шагов, но не присваивались значения на выходы ПЛК..
Опыт путем выяснил следующее: если в цикл запихнуть переменную, привязанную, непосредственно к выходу ПЛК - все работает. Если (как в моем случае) - это именно функция управления - не хочет ее обработать, что достаточно печально.. Будем разбираться, как это обходить..
Не знаю, насколько правильно, но вместо таймеров провожу сравнения. Как минимум - все необходимые периоды, как правило, в одном месте, в какой-нибудь структуре..
Код:...
Ven[num].Flap.tMove:=TIME(); (*Присваиваем текущую временную метку*)
...
IF (TIME() - Ven[num].Flap.tMove) >= Ven[num].Flap.lMove THEN (*Если текущее время плк минус временная метка больше-равно нужной, то..*)
Ven[num].Flap.sAdjust:=3;
Ven[num].Flap.tMove:=TIME(); (*Обновляем метку, если нужно*)
END_IF;
Это заслонки воздуховодов одновременно, приточки, кондеев и парогенератора. То есть, помимо регулировки воздушного потока "по восстребованию", они играют роль предохранителя от затопления воздуховодов увлажнителем, если авария у УК и отвалится подача, упадет качество воздуха (докинуть свежего), факторов уйма. А калибровка - банально нет датчиков положения, есть только концевики внутри самого привода. Все равно позиционирование будет копить ошибки и раз в месяц-пару нужно синхронить положение. Плюс "не залипнут", если в одном положении давно, что уже бывало..
а накой уходить в 3й шаг? заради выключить выходы?
зачем мутилово с IF перед case? шаг 0 в case может быть из ";"
чего флапу не сделать свой action где он это все без ven[num].flap.
Порядок такой - запоминаем текущее положение -> открываемся -> закрываемся -> возвращаемся туда, "где вроде было ок" -> отстаиваемся чуть -> передаем управление обратно ПИДу. Это уже упрощенный варик, чтоб хоть как-то заставить сиё работать..
просто тест, мало ли.. с учетом перепробаванных вариантов - почему нет..
Заслонок 9 (помещений), по 2 выхода на штуку (18). Помимо них - еще куча мишуры, пресущей данным помещениям. И не хотелось бы возиться с каждым такой штукой отдельно, собственно, было написано маппирование, а управление - через циклы и аттрибуты через точки
А вот и проблема.. есть выход, который управляет сигналом на открытие. В "конфигурации ПЛК" назвал его Flap1Open (пробовал там же переносить в глобальные и прибивать гвоздями через AT - тоже самое). В функции карты присвоил его в массив Ven[1].Flap.Open:=Flap1Open (почему-то не наоборот). Так нормально работает функция управления на открытие, но в режиме калибровки значение на сам выход не записывается. Но, если поменять местами Flap1Open:=Ven[1].Flap.Open, то режим открытия работать перестает, а вот в калибровке - выход включается, но не выключается по таймеру (функция - одна и та же). Чертовщина..
Помимо небольшой оптимизации и пары интересностей с CASE - проблема не особо решилась. То есть, я так понимаю, из вышестоящих (управляющих систем) - обращение к переменным примерно то же, что моя "кровь из глаз", но, как минимум ясна структура (система, номер, девайс, атрибут). При обработке 20+ разных систем - становится понятнее. Мне не в падлу расписать. Как минимум, Вы за 10 минут поняли "что-куда" и поправили. По быстродействию: утверждать не могу, пока доделки не будут доделаны - нельзя запустить тест на скорость цикла ПЛК. Кодесис 2.3 - банально, старый. К овену претензий нет, кроме, немного усложненной документации.
Возможно, не КДС, а Вы такой старый что поленились дочитать до конца документацию https://owen.ru/uploads/373/plc1xx_p...ation_v2.0.pdf раздел 3.8
скорее всего это родилось из этого и неуемного желания использовать метод тыка: "а вдруг заработает"
Код:IF Close AND NOT xClose THEN
xClose:=TRUE;
xOpen:= FALSE;
t_Pos:=TIME();
ELSIF Close THEN
Pos:= Pos - 0.00258 * (TIME_TO_REAL(TIME() - t_Pos));
t_Pos:=TIME();
IF Pos < 0 THEN Pos:=0;
END_IF;
END_IF;
xClose := Close;
Именно так..
Предпочитаю просто ставить временные метки по интересующим местам, со времен микроконтроллеров, но - да, не читал. Эт я к тому, что, пока все не будет дописано - нет особого смысла.
Пробовал, уже потом подумал про ошибку маппирования. Визуализация не мешалась, если ничего не трогать)Цитата:
Сообщение от 1exan
Вообще, выяснил следующее: функции работают (шаги шагают, таймеры таймерят) и, если указывать имена самих выходов - все отлично работает. То есть, если заглянуть в функцию map, то видно, что и переменная, которая должна передавать значение на выход так же переключается ( Ven[1].....open). Фактически, все свелось к тому, что нельзя запихать выход в массив. То есть, можно это обойти, если это простые дискретные выходы через ADR, но, видимо не канает с быстрыми..
С простыми дискретными - работает. Там можно сделать так: " Ven[3].Flap:= ADR(%QB3.0); " , а потом присвоить управление номеру бита нужного выхода, то есть у нас управление по прямому адресу, только что проверил. А вот с фастами, из-за того, что это чистый BOOL в CdS 2* - нельзя, ADR хочет BYTE +. Сейчас просто найду, с чем можно поменять местами эти заслонки. В целом - вопрос решен. Хотелось бы, все-таки разобраться, как можно быстрые дискретники удобно обрабатывать, но уже потом.. Спасибо всем за помощь, безусловно, появилась пища для размышления.
Можно сказать - намеренно: время - да, съедает, но, в основном - "учение через боль" лучше усваивается, иначе обленюсь)
Вероятность того, что структуры ваших внутренних объектов совпадут с типами и расположением физических входов и выходов в контроллере - приближается к нулю. Поэтому я например делаю так:
Объявляю глобальные переменные физических входов и выходов типа такого:
(можно конечно забить имена прямо в конфигурацию, но мне так удобнее, и нет проблем при смене конфигурации).Код:DI_1 AT %IX0.0 : BOOL; (* Дискретный вход 1 *)
DI_2 AT %IX0.1 : BOOL; (* Дискретный вход 2 *)
DI_3 AT %IX1.0.0 : BOOL; (* Дискретный вход 5 *)
DI_4 AT %IX1.0.1 : BOOL; (* Дискретный вход 6 *)
DI_5 AT %IX1.0.2 : BOOL; (* Дискретный вход 7 *)
DI_6 AT %IX1.0.3 : BOOL; (* Дискретный вход 8 *)
...
DO_1 AT %QX2.0 : BOOL; (* Дискретный выход 1 *)
DO_2 AT %QX2.1 : BOOL; (* Дискретный выход 2 *)
DO_3 AT %QX2.2 : BOOL; (* Дискретный выход 3 *)
DO_4 AT %QX2.3 : BOOL; (* Дискретный выход 4 *)
DO_5 AT %QX3.0.0 : BOOL; (* Дискретный выход 5 *)
DO_6 AT %QX3.0.1 : BOOL; (* Дискретный выход 6 *)
...
В отдельной программе, которая выполняется в отдельной задаче со свободным циклом выполнения делаю их присваивание/чтение:
Уж не знаю, насколько это "медленней" по сравнению с работой со входами/выходами через байты - но подозреваю, что несущественно.Код:arBlock[1]. xInStart := DI_5 ; (* *)
arBlock[1]. xInStop := DI_6 ; (* *)
...
DO_5 := arBlock[1]. xOutStart ; (* *)
DO_6 := arBlock[1]. xOutAlarm ; (* *)
...
Но при этом вы не привязаны к расположению входов/выходов в структурах и можно в любой момент "отключить" физические входы/выходы для, например, 'эмуляции процесса
АБСОЛЮТНО соглаасен! Я так делаю прям вот всегда! У меня этому даже кусок статьи посвящён (рекомендую прочитать, без шуток): https://cs-cs.net/technologii-testir...a-plk#4_____io
Только я НЕ использую прямую адресацию, а разбираю в таких переменных битовые маски и именую переменные понятным текстом. Вот так:
Мои методы и технологии описаны в статье. Берите все на вооружение!Код:hwBtnLgt1EPrihojMain : BOOL; (* W2.I1: Кнопки LT-41: 1 Этаж Прихожая Общий *)
hwBtnLgt1EPrihojTrackShkaf : BOOL; (* W2.I2: Кнопки LT-42: 1 Этаж Прихожая Трек у Шкафа *)
hwBtnLgt1EPrihojZerkalo : BOOL; (* W2.I3: Кнопки LT-43: 1 Этаж Прихожая Зеркало *)
hwBtnLgt1EPrihojSpotDver : BOOL; (* W2.I4: Кнопки LT-44: 1 Этаж Прихожая Споты Дверь *)
hwBtnLgt1EPrihojFuncShkaf : BOOL; (* W2.I5: Кнопки LT-45: 1 Этаж Прихожая Функциональный у Шкафа *)
hwBtnLgt1EPrihojIgrDecor : BOOL; (* W2.I6: Кнопки LT-46: 1 Этаж Прихожая/Игровая Декор *)
hwBtnLgt1EZakutok : BOOL; (* W2.I7: Кнопки LT-47: 1 Этаж Закуток *)
hwBtnLgt1EMicroKabinet : BOOL; (* W2.I8: Кнопки LT-48: 1 Этаж Микрокабинет *)
hwBtnLgt1EIgrMain : BOOL; (* W2.I9: Кнопки LT-49: 1 Этаж Игровая Общий *)
hwBtnLgt1EIgrTrack : BOOL; (* W2.I10: Кнопки LT-50: 1 Этаж Игровая Трек Окно *)
hwBtnLgt1EPrihojMain := W2_DI32.0; (* W2.I1: Кнопки LT-41: 1 Этаж Прихожая Общий *)
hwBtnLgt1EPrihojTrackShkaf := W2_DI32.1; (* W2.I2: Кнопки LT-42: 1 Этаж Прихожая Трек у Шкафа *)
hwBtnLgt1EPrihojZerkalo := W2_DI32.2; (* W2.I3: Кнопки LT-43: 1 Этаж Прихожая Зеркало *)
hwBtnLgt1EPrihojSpotDver := W2_DI32.3; (* W2.I4: Кнопки LT-44: 1 Этаж Прихожая Споты Дверь *)
hwBtnLgt1EPrihojFuncShkaf := W2_DI32.4; (* W2.I5: Кнопки LT-45: 1 Этаж Прихожая Функциональный у Шкафа *)
hwBtnLgt1EPrihojIgrDecor := W2_DI32.5; (* W2.I6: Кнопки LT-46: 1 Этаж Прихожая/Игровая Декор *)
hwBtnLgt1EZakutok := W2_DI32.6; (* W2.I7: Кнопки LT-47: 1 Этаж Закуток *)
hwBtnLgt1EMicroKabinet := W2_DI32.7; (* W2.I8: Кнопки LT-48: 1 Этаж Микрокабинет *)
hwBtnLgt1EIgrMain := W2_DI32.8; (* W2.I9: Кнопки LT-49: 1 Этаж Игровая Общий *)
hwBtnLgt1EIgrTrack := W2_DI32.9; (* W2.I10: Кнопки LT-50: 1 Этаж Игровая Трек Окно *)
Там ещё и технология теестирования IO и обработки ошибок IO есть!
Не, не именованные константы. Если не сложно - лучше почитать мою статью. Я там подробно всё расписал как раз для вставки на форум.
Шаги моей задумки такие:
1. Много переменных в программах ПЛК - булевые: Дискретные датчики, статусы сигналов, выходы на реле, контакторы.
2. Привязка переменных в ПЛК делается по разному. Встроенные входы-выходы можно привязать в конфигурации (причём одни сразу булевые, а другие - байтами по 8 входов или выходов), а IO модулей ввода-вывода вообще читается по 16 бит или по 32 бита (смотря какие модули используем0.
Всё это приводит к чёртовому зоопарку: что-то объявлено в конфигурации ПЛК, что-то используется сразу в коде типа "DIModbus.4" без понятных имён, что-то формируется ещё где-то.
3. Меня выбесило то, что нет системности, где привязываются ВСЕ каналы ввода-вывода, и я сделал так:
а) Объявляю в Глобальных переменных все нужные названия переменных ввода-вывода ПОНЯТНЫМИ именами.
б) В конфигурации ПЛК объявляю групповые переменные для каналов опроса - битовые маски.
в) В задаче (в одном месте) TaskIO разбираю битовые маски и привязываю их там к моим переменным.
г) В остальных задачах обращаюсь к своим понятным и красивым переменным.
Благодаря этому привязка IO происходит ТОЛЬКО в одном месте программы, она наглядная, и там можно что-то легко поменять.
А в программе я оперирую понятными переменными типа hwStatusUPS, hwStatusL1 и так далее, что делает код читаемым и избавляет от магических чисел (с которыми я на форуме ОВЕНа сталкиваюсь больше, чем за весь стаж программирования).
В общем, настоятельно рекомендую почитать мою статью! Заодно новых методов разработки и отладки можно там набраться!
Не знаю о чем спор, но программа должна быть универсальный, даже иметь возможность переноса на железо другого производителя. А для этого программа пишется не опираясь на вид описания входов выходов. Для этого организуют прокладки, которые тэги контроллера копируют в тэги программы и наоборот.
DI_5 не более непонятное имя, чем W1_DIA.0:
DI_5 - это дискретный вход №5, что по-моему, очевидно следует из его имени, и W1_DIA.0 - это тоже дискретный вход №5, что уже не совсем очевидно, и поэтому наверное дополнительно указывается в комментарии
Я лично не вижу ничего плохого в прямой адресации при работе с физическими входами/выходами
Прошу прощения, не правильно написал изначально, и народ запутал, уже голова не варила: заслонки трехпроводные, двухфазные, без отслеживания положения. Собственно, описанное с использованием REAL - были функции отслеживания текущего положения заслонки по времени ее работы. Еще раз - пардон
Поясните, пожалуста, не вкурил.. Я создаю некую систему, пусть ту же вентиляху. Одно из свойств системы - те же заслонки. В функции карты (соответствие входов/выходов и переменных в массиве для обработки 1 блоком) собственно все раскидываю. При каких условиях может начаться апокалипсис?
Обзываю входы в конфигураторе на первых порах, для тестов, чтоб не запутаться.
Вот тут как раз и случился затык, от чего и полез на форум народ пытать. Есть выход (пусть QX1.0, запихал его в переменную (Пусть DO1). Далее, для того, чтобы можно было обработать в цикле, присваиваем этот выход в переменную массива, пусть Sys[1]._Do1. Соответственно, для всей системы была написана функция карты (Sys[1]._Do1:=DO1) (делаю так для всех систем, а потом объявляю один раз при инициализиции). При управлении "без лишнего" - работает. Включается-выключается и через массив и через прямую. При управлении, как было, через CASE работает только, если мы пишем непосредственно в переменную выхода (прямую, DO1). Может я чего не понимаю, конечно.. А то и многое) В обработке через условия (CASE/IF), если запишем в переменную массива (Sys[1]._Do1), видно, что значение ее меняется, но не присваивается в D01. Поэтому и разродилась идея уйти в обычные дискретные выходы, так как нет "прослойки", в виде "DO...", а можно сразу, через адресацию сунуть все в эррей. Ну, как бэ - да, во-первых, ADR на %QX сделать не удастся, во-вторых - нужны 2 переменные (указатель на байт и указатель на бит), но, и черт с ним, не самая большая проблема.
Статью почитаю, спасибо)
Прочитал два раза, ничего не понял
Посмотрел ещё раз ваш проект:
Вы объявляете выходы в конфигурации:
Вложение 73596
а потом здесь зачем то читаете их состояние
Код:Ven[1].Flap.Open:=Flap1Open;
Ven[1].Flap.Close:=Flap1Close;
Вы ничего не путаете?
И сейчас неправильно!
Могу лишь догадываться, но скорее всего разговор про привод КЗР (клапан запорно-регулирующий) без датчика положения.
И раз привод трёхпроводный, то никак не "двухфазный" (это вообще в нашем бренном мире существует???).
а люфт заслонки и привода, время выбега, инерционный выбег и т.д. учитывали?
если нет, то уже через день весь ваш расчёт (функции отслеживания текущего положения заслонки) будет показывать это положение в попугаях.
Как сказал capzap - неуемный метод тыка.. Предполагалось, что, таким образом их можно засунуть (выходы) в массив. Эт уже пробовал менять местами (а вдруг..). "Вдруг" не случилось. Теперь все работает. Может не очень красиво, но работает:
Соответственно - Ven[3].Flap.Num : Pointer to ByteКод:Ven[3].Flap.Num := ADR(%QB3.0);
Ven[3].Flap.Num^.0 := Ven[3].Flap.Close; (* Бит 0, Заслонка 3, закрыть *)
Ven[3].Flap.Num^.1 := Ven[3].Flap.Open; (* Бит 1, Заслонка 3, открыть *)
Правильно. Изначально озвучили "по фазе на каждую сторону"
Уже по факту наблюдений. Сейчас основное - запустить. Подстройка - как получится, не успеваю (да и не хочу) заниматься всем, но не попишешь.. Самой регулировкой будет заниматься пид, а ему, как водится, плевать на погрешность в пару градусов, есть обратная связь в виде скорости воздушного потока. Увидим позже
С этого и началась вся тема - так не работает в режиме калибровки, который состоит из нескольких шагов CASE. Вся история заканчивается тем, что видно, что происходит на каждом шаге и даже присваиваются значения в Ven[1].Flap.Open, но не в Flap1Open.
Условно
Так не работает. Ven[1].Flap.Open / Close - меняют значения, но не пишут их в выходы.Код:CASE step Of
1: ....
Ven[1].Flap.Open:=true;
...
...
2: ...
Ven[1].Flap.Close:=true;
...
...
END_CASE
Так работает, но это уже не массивКод:CASE step Of
1: ....
Flap1Open:=true;
...
...
2: ...
Flap1Close:=true;
...
...
END_CASE
Поэтому вчера перешел на побитовую адресацию
С положением-то проблем не было, как раз..Цитата:
Сообщение от 1exan
Ну да. Все отлично работает. Только не записывает. И надо дойти до чего нибудь. Чтоб записывало. А так - все хорошо. Даже 500 вариантов
Думаю надо с нуля переработать код. Обычно это помогает.
Я год прорабатывал программу для управления механизмом с 32мя датчиками, всеми авариями от не сошёл с концевого до одновременно нажатых кнопок. 3 раза переделывал. Теперь только в проекты его вставляю и не задумываюсь как там что работает.