Вопросы по скриптам в Simple-Scada 2

Автор Simple-Scada, 29 января 2016, 15:19:20

Олег Печёнов

Отлично!
Оперативно!
Спасибо!
Все работает!

Simple-Scada

#826
Олег Печёнов, обязательно замените во втором скрипте по событию "Прошла секунда" локальную переменную "i" на глобальную внутреннюю переменную, иначе при переходе на новые версии скады скрипт будет работать непредсказуемо, т.к. локальные переменные могут получить произвольное значение при каждом выполнении скрипта. Напишите, если есть вопросы.
Код: pascal
begin
  vrTime.Value := vrTime.Value + 1;     // счетчик 0 - 9, отсчет временного интервала 10 сек
  if vrTime.Value < 10 - 1 then exit;
  // обработка данных за интервал 10 сек
   . . .
  vrTime.Value := 0;          // сброс таймера
  cntDI_01.Value := 0;        // сброс счетчика изменений DI_01 для следующего интервала
end. 
, где vrTime - внутренняя переменная типа Integer.

Олег Печёнов


Олег Печёнов

Добрый день!
еще заявочка на скрипт.
переменная DO_06 должна семь секунд иметь значение 0, затем девять секунд значение 1,
и так циклично.
Благодарю.

Simple-Scada

#829
Здравствуйте.
Нужно создать внутреннюю переменную: vrTimer, тип данных Integer. И секундный скрипт:
Код: pascal
const
  INTERVAL_1 = 7;
  INTERVAL_2 = 9;
begin
  if DO_06.AsInt = 0 then 
  begin
    if vrTimer.AsInt < INTERVAL_1 then
      vrTimer.Value := vrTimer.Value + 1;
  
    if vrTimer.AsInt = INTERVAL_1 then
    begin
      DO_06.Value := 1;
      vrTimer.Value := 0;
    end;
  end else
    begin
      if vrTimer.AsInt < INTERVAL_2 then 
        vrTimer.Value := vrTimer.Value + 1;
  
      if vrTimer.AsInt = INTERVAL_2 then
      begin
        DO_06.Value := 0;
        vrTimer.Value := 0;
      end;
    end;
end.

pan2000

Алгоритм использующий область данных (а не команд) для задания временных последовательностей:

Код: pascal
const
  INTERVAL = 16;
  arDO_06: array [0..(INTERVAL - 1)] of integer =
            (0, 0, 0, 0, 0, 0, 0,        // образ выхода DO_06, в частности и не бинарный
            1, 1, 1, 1, 1, 1, 1, 1, 1);  //   или для нескольких выходов
begin
{  if vrTimer.AsInt < 0 then <обработка ошибки индекса массива> }

  if vrTimer.AsInt >= INTERVAL then vrTimer.Value := 0;
  DO_06.Value := arDO_06[vrTimer.AsInt];
  vrTimer.Value := vrTimer.Value + 1;
end. 
 

Олег Печёнов

Огромное спасибо за решения. Очень интересно!

Олег Печёнов

Добрый день!
еще запрос на сложный скрипт.

если за 15 секунд переменная T2.Value не изменила значение, то переменной OT.Value :=0.

Благодарю.

pan2000

#833
Цитата: Олег Печёнов от 11 апреля 2019, 11:28:24если за 15 секунд переменная T2.Value не изменила значение, то переменной OT.Value :=0.

Это одновибратор с перезапуском. Ниже приведены примеры для одновибратора с перезапуском и повторным пуском.

Пример 1. (переменная TimeCnt типа int64 или integer)
Скрипт "Изменились переменные" (T2):
Код: pascal
begin
  TimeCnt.Value := 0;   // начало отсчета по изменению переменной - перезапуск одновибратора
end.
Скрипт "Прошла секунда"
Код: pascal
const INTERVAL = 15;
begin
  if TimeCnt.Value >= INTERVAL then  
    OT.Value := 0                      // таймер сработал
  else
    begin
      OT.Value := 1; // если удалить эту команду, то одновибратор будет работать в режиме однократного запуска по OT=1
      TimeCnt.Value := TimeCnt.Value + 1;
    end;
end.

Пример предполагает последовательное выполнение скриптов из-за переменной TimeCnt, изменяемой в обоих скриптах.
Вполне возможно, что в последующих реализациях Simple-Scada скрипты станут обрабатываться паралллельно.

Пример 2. Аналог примера 1, но с изменениями переменной только в одном скрипте. (переменные TimeCnt и preTimeCnt типа int64 или integer)
Скрипт "Изменились переменные" (T2):
Код: pascal
begin
  preTimeCnt.Value := TimeCnt.Value;   // момент отсчета по изменению переменной - перезапуск одновибратора
end.
Скрипт "Прошла секунда"
Код: pascal
const INTERVAL = 15;
begin
  if (TimeCnt.Value - preTimeCnt.Value) >= INTERVAL then  
    OT.Value := 0                      // таймер сработал
  else
    begin
      OT.Value := 1; // если удалить эту команду, то одновибратор будет работать в режиме однократного запуска по OT=1
      TimeCnt.Value := TimeCnt.Value + 1;
    end;
end.

Пример 3. Основная обработка в скрипте по изменению переменных. (переменные TimeCnt и preTimeCnt типа int64 или integer)
Скрипт "Прошла секунда"
Код: pascal
begin
    TimeCnt.Value := TimeCnt.Value + 1;
end.
Скрипт "Изменились переменные" (T2, TimeCnt):
Код: pascal
const INTERVAL = 15;
begin
  if Variable.Name = 'T2' then preTimeCnt.Value := TimeCnt.Value;
  if Variable.Name = 'TimeCnt' then
    if (TimeCnt.Value - preTimeCnt.Value) > INTERVAL then
      OT.Value := 0
    else
      OT.Value := 1;
end.

Пример 4. Один скрипт, необходимое условие - уникальность изменения переменной T2 (например счетчик)
Код: pascal
const INTERVAL = 15;
var i: integer;
begin
  i := T2.Value;
  if i <> preT2.Value then TimeCnt.Value := 0;
  preT2.Value := i;
  if TimeCnt.Value >= INTERVAL then
    OT.Value := 0
  else
    begin
      OT.Value := 1;
      TimeCnt.Value := TimeCnt.Value + 1;
    end;
end.      

Пример 5. С использованием текущего времени. (Переменная  ChangeVarTime - типа DateTime)
Скрипт "Изменились переменные" (T2):
Код: pascal
begin
  ChangeVarTime.Value := NOW();   // начало отсчета по изменению переменной 
end.
Скрипт "Прошла секунда"
Код: pascal
const INTERVAL = 15;
begin
  if SecondsBetween(NOW(), ChangeVarTime.Value) >= INTERVAL then  // сравнить с текущим временем события "Прошла секунда"
    OT.Value := 0
  else
    OT.Value := 1;
end.

deldemo

#834
Здравствуйте.
В новой версии S-S не компилируется скрипт
Код: pascal
begin
  if not (Sender is TM_Button) then Exit;

  with Sender as TM_Button do
    if Assigned(VariableEx) then
        if GetBit(VariableEx.AsInt,7) then
          begin
            VariableEx.Value := SetBit(VariableEx.Value,7,False);
            VariableEx.Value := SetBit(VariableEx.Value,6,False);
          end else
            begin
              VariableEx.Value := SetBit(VariableEx.Value,6,False);
            end;
    end.
end.
     
Точнее он в редакторе скриптов компилируется, но когда сохраняем проект скрипт отмечается как скрипт с ошибками                         

Simple-Scada

#835
Здравствуйте.
У Вас в коде лишний "end." не принадлежащий ни одной конструкции.
Код: pascal
begin
  if not (Sender is TM_Button) then Exit;
 
  with Sender as TM_Button do
    if Assigned(VariableEx) then
      if GetBit(VariableEx.AsInt,7) then
      begin
        VariableEx.Value := SetBit(VariableEx.Value,7,False);
        VariableEx.Value := SetBit(VariableEx.Value,6,False);
      end else
        VariableEx.Value := SetBit(VariableEx.Value,6,False);
end.

deldemo

#836
Интересно что пред идущая версия проглатывала данный скрипт.

И опять же, повторюсь. Он компилируется в редакторе скриптов без ошибок.

Simple-Scada

#837
Верно. Раньше каждый скрипт был отдельной программой и его компиляция заканчивалась на "end.", поэтому компиляция проходила. Сейчас все скрипты компилируются в единую программу и каждый скрипт обязательно должен содержать один "end.".

ЦитироватьИ опять же, повторюсь. Он компилируется в редакторе скриптов без ошибок.
И это верно, пока Вы компилируете скрипт отдельно - ошибок не будет, он закончится на первом "end.". Но при сохранении проекта код скрипта будет помещён в общую программу вместе со всеми остальными скриптами и ошибка с двумя "end." выявится, что и происходит.

По сути, предыдущая версия компилятора разрешала реальную ошибку, игнорируя её. Теперь эта ошибка не игнорируется и должна быть исправлена, как и любая другая ошибка в коде.

deldemo

#838
Тогда сразу же хочется кнопку "Компилировать все"

deldemo

#839
Еще одна непонятка.

Есть скрипт с запросом к БД
при компиляции выдает ошибку [Update_tblPremix]"begin" not found
Если закоментировать блок с CASE в запросе - то компиляция проходит без ошибок.
Код: pascal
{Заполняем таблицу tblPremix}
procedure Update_tblPremix;
var
  aQuery:string;
begin
  aQuery :=    'SELECT '+
               'DP_PRODUCT_ID '+
               ',AR_NAME '+
               ',AR_ARTICLECODE '+
//               ',CASE DP_PREMIX_STATUS1 WHEN 1 THEN ''X'' ELSE '''' END AS PREMIX_STATUS1 '+
//               ',CASE DP_PREMIX_STATUS2 WHEN 1 THEN ''X'' ELSE '''' END AS PREMIX_STATUS2 '+
//               ',CASE DP_PREMIX_STATUS3 WHEN 1 THEN ''X'' ELSE '''' END AS PREMIX_STATUS3 '+
//               ',CASE DP_PREMIX_STATUS4 WHEN 1 THEN ''X'' ELSE '''' END AS PREMIX_STATUS4 '+     
               'FROM CFG_DAYPROGRAM '+
               'INNER JOIN CFG_ARTICLE ON DP_PRODUCT_ID = AR_ARTICLE_ID '+
               'WHERE (DP_BATCHESDONE < DP_BATCHESSET AND DP_LOTNUMBER > 0 AND DP_PRODUCE = 1 AND DP_MODIFYTYPE <> ''D'') '+
                                    'OR DP_LOTNUMBER IN (SELECT DP_LOTNUMBER '+
                                    'FROM CFG_DAYPROGRAM '+
                                    'INNER JOIN CFG_BATCHES ON DP_LOTNUMBER = BD_LOTNUMBER '+
                                    'INNER JOIN CFG_UNITS ON UN_BATCHNUMBER = BD_BATCHNUMBER '+
                                    'WHERE BD_BATCHNUMBER > 1 '+
                                    'AND UN_MODIFYTYPE <> ''D'') '+
               'ORDER BY DP_PRODUCTIONNUMBER;';

  tblPremix.RunSQL(aQuery, tsSaveFixRow);
end;

begin
  if vUpdate_tblPremix.Value = true then    // если тру - то выполняем процедуру
    begin
      Update_tblPremix;
      vUpdate_tblPremix.Value := false;
    end;
end.