Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Не получили письмо с кодом активации?

Официальный форум Simple-Scada.

Просмотр сообщений

В этом разделе можно просмотреть все сообщения, сделанные этим пользователем.


Сообщения - pan2000

Страницы: 1 ... 10 11 [12] 13 14
166
...
 появляется возможность его свернуть под скаду, из-за этого через неделю около 100 запущенных процессов калькулятора.
...

...
Калькулятор в ближайшем будущем скорее всего не внедрим в скаду
...

Рабоче-крестьянский способ борьбы с 100500 экземплярами калькулятора:
- перед запуском удалить все прочие экземпляры:
Код: (delphi)
  RunApplication(GetClientName, 'TASKKILL', '/IM Calculator.exe /F /T');
- выдержать паузу для удаления всех экземпляров, иначе, с некоторой вероятностью, может уничтожится и запускаемый вновь экземпляр;
- запустить калькулятор.

При выполнении удаления на некоторое время появляется окно командной строки. Можно блокировать появление окна при помощи сценария WSH.

Пример во вложении.

167
Ваши вопросы / Re: Вопросы по кнопкам
« : 10 Июля 2019, 02:33:03 »
Есть задача : Одной кнопкой устанавливать переменную только в 1, второй только в 0 (Старт, Стоп).
Но отображать нужно два сотояния и на той и на другой кнопке, т.е. нажал "Старт" и кнопка старт подсветилась, а кнопка "Стоп" погасла и наоборот.
Не нашел простого решения , может подкажете как это сделать без скриптов?

Возможно то, что Вам нужно, но со скриптом.

Для включения-выключения используются связанные с одной переменной кнопки "Run" и "Stop", с фиксацией и двумя состояниями.
Иконка и надпись на кнопке одинаковы для обоих состояний каждой кнопки, цвет отпущенного состояния кнопок - серый, нажатого - зеленый для кнопки "Run" и красный для "Stop". Тег кнопки "Run" = 1, кнопки "Stop" = 0.
Для блокировки обратного переключения при повторном нажатии кнопки можно использовать коррекцию переменной или управление доступностью кнопки.
Скрипт по событию "Пользователь кликнул объект мышью":
Код: (delphi)
// это скрипт для коррекции переменной
  xVarForButton.Value := Sender.Tag;

// это скрипт для управления доступностью
  Button1.Enabled := Sender.Tag <> 1;  // кнопка "Run"
  Button2.Enabled := Sender.Tag = 1;   // кнопка "Stop"

Во вложении пример с обоими скриптами. Для справки показан список событий, происходящих по нажатию кнопок.

168
...
 подскажите как это понимать, почему строка 5840 не может конвертироваться в интежер
...

Ошибка StrToInt для аргумента завершающегося не цифрой:
Код: (delphi)
begin
  Text1.Text := IntToStr(StrToInt(' 5840'));    //  5840
  Text2.Text := IntToStr(StrToInt('5840 '));    // Ошибка в скрипте "Script_0" в строке 3.
end.                                          //  '5840 ' is not a valid integer value

Добавлено 13 июня 2019 года:
Посмотреть последовательность кодов символов переменной S типа String можно с помощью скрипта. Результат отображается в области Text1 четырехзначными шестнадцатиразрядными числами.

Код: (delphi)
var i: integer;
    aStr: string;
begin
  Text1.Text := '';
  aStr := S.AsStr;
  for i := 1 to Length(aStr) do
    Text1.Text := Text1.Text + IntToHex(integer(aStr[i]), 4) + ' ';
end.

169
Дело не в пробеле, а в попытке нового компилятора рассматривать строковую константу, содержащую ключевые слова Delphi, как команду.
Причем до сборки строки из отдельных констант.
Код: (delphi)
var
  aQuery: string;
begin
  aQuery :=   ',Begin';        //   следующие строки сохраняются с ошибкой:
//  aQuery :=   ', Begin';     // не все пробелы одинаково полезны
//  aQuery :=   ',' + 'Begin'; // различие между значениями суммы констант и одиночной константой
end.

170
Здравствуйте.

Пока для успешного сохранения необходимо наличие пробела между запятой и case.

Аналогичная проблема и решение от Simple-Scada:

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

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

Пример 1. (переменная TimeCnt типа int64 или integer)
Скрипт "Изменились переменные" (T2):
Код: (delphi)
begin
  TimeCnt.Value := 0;   // начало отсчета по изменению переменной - перезапуск одновибратора
end.
Скрипт "Прошла секунда"
Код: (delphi)
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):
Код: (delphi)
begin
  preTimeCnt.Value := TimeCnt.Value;   // момент отсчета по изменению переменной - перезапуск одновибратора
end.
Скрипт "Прошла секунда"
Код: (delphi)
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)
Скрипт "Прошла секунда"
Код: (delphi)
begin
    TimeCnt.Value := TimeCnt.Value + 1;
end.
Скрипт "Изменились переменные" (T2, TimeCnt):
Код: (delphi)
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 (например счетчик)
Код: (delphi)
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):
Код: (delphi)
begin
  ChangeVarTime.Value := NOW();   // начало отсчета по изменению переменной
end.
Скрипт "Прошла секунда"
Код: (delphi)
const INTERVAL = 15;
begin
  if SecondsBetween(NOW(), ChangeVarTime.Value) >= INTERVAL then  // сравнить с текущим временем события "Прошла секунда"
    OT.Value := 0
  else
    OT.Value := 1;
end.

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

Код: (delphi)
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.
 

173
нужен скрипт, который подсчитывает количество изменений состояний переменной DI_01 за интервал 10 секунд.
Здравствуйте!

Необходима одна внутренняя переменная cntDI_01 для подсчета изменений переменной DI_01, причем переменная cntDI_01 не должна переполняться за интервал 10 секунд.

Скрипт по событию "Изменились переменные":
Код: (delphi)
begin
  cntDI_01.Value := cntDI_01.Value + 1;     // счетчик изменений DI_01
end.

Второй скрипт по событию "Прошла секунда":
Код: (delphi)
// переменная статическая и сохраняется между обращением к скрипту, однако в рабочем проекте желательно использовать внутреннею переменную
var i: integer;    // i - отсчет интервала
begin
  i := (i + 1) mod 10;     // счетчик 0 - 9, отсчет временного интервала 10 сек
  if i <> 0 then exit;
// обработка данных за интервал 10 сек
   . . .
  cntDI_01.Value := 0;        // сброс счетчика изменений DI_01 для следующего интервала
end.

Пример проекта с обработкой данных, состоящей из построения таблицы изменений за последовательные интервалы, во вложении.


174

Есть переменная в контроллере, тип DWORD. В ней записаны секунды, общим количеством не более чем 86400 (полное количество секунд в сутках). Как можно отобразить на скаде в полях отдельно часы, минуты и секунды данной переменной с возможностью редактирования и без использования промежуточных внутренних переменных?


  Редактирование времени суток с использованием объект "Календарь"

Для переменной dwTimeOPC Вашего "Внешнего тега(с ОРС сервера)" нужно установить:
- тип данных "LongWord";
- шкалу с минимумом = 0, максимумом = 86399;
- виз. минимум = 0, виз. максимум = 0.99998842 (86399/86400).
Данные параметры обеспечивают масштабирование числа секунд во время суток и наоборот.

Календарь необходимо настроить на отображение только времени суток, включая секунды.
Основная переменная - dtTime, дополнительная - dwTimeOPC.

Скрипты по изменению основной и дополнительной переменных:

Код: (delphi)
begin
  dwTimeOPC.Value := Frac(dtTime.Value);  // ограничить только временем суток
end.

begin
  dtTime.value := dwTimeOPC.Value;
end.   

Максимальное использование возможностей Simple-Scada позволяет получить компактный код.

Проект из вложения проверен с сервером arОРС и эмулятором Modbus.



175
Первый вариант хранения данных

  Для Simple-Scada:
SCA_temp - индикация температуры;
SCA_set - уставка оператора.

ОРС-сервер периодически опрашивает пару этих переменных, передавая данные в Scada.
Данные записанные в SCA_set передаются в переменную PLC_set контроллера.
 
  Для контроллера:
PLC_temp - измеренная температура, в ОЗУ;
PLC_set - уставка температуры, в ОЗУ;
PLC_EE_set - уставка температуры в EEPEOM;
PLC_FACT_set - заводская уставка в EEPEOM или памяти программ.

1. При включении контроллера уставка температуры в EEPROM переписывается в уставку температуры PLC_EE_set -> PLC_set. Эта операция может выполнятся встроенным ПО контроллера (сохраняемая переменная) или программно при инициализации.

2. Далее, в цикле выполняется основная часть программы, а данные передаются в Scada, в частности PLC_set -> SCA_set.
При вводе новой уставки однократно происходит передача SCA_set -> PLC_set, а при отсутствии сохраняемых переменных ещё и  PLC_set -> PLC_EE_set.

3. При выключении контроллера и наличии сохраняемых переменных выполняется передача данных PLC_set -> PLC_EE_set.

Операция "RESET" выполняет следующие передачи данных: PLC_FACT_set -> PLC_EE_set, PLC_FACT_set -> PLC_set.

В случае если контроллер позволяет без проблем читать данные из EEPROM и частота обновления уставки небольшая (ресурс записи EEPROM), то можно выполнять сравнение с PLC_EE_set, а переменную PLC_set исключить.

Пример во вложении.


Второй вариант хранения данных

Значения заводской уставки и уставки можно хранить и в Scada: SCA_set как сохраняемую переменную, а SCA_FACT_set в файле или скрипте.
В этом случае Scada постоянно проверяет наличие связи с контроллером и при обнаружении передает данные контроллеру SCA_set  -> PLC_set, в свою очередь контроллер при включении начинает проверять переменную PLC_set на достоверность и только после состоявшейся проверки переходит к выполнению основной части программы.


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

176
Исправили событие OnClick у TM_MessageViewer в обновлении Simple-Scada 2.3.4.0.
Но событие OnClick наступает при отпускании ЛКМ, т.е. это OnMouseUp.

Проект из вложения позволяет просмотреть набор действующих событий/последовательности событий от мышки для каждого объекта, как по наличию события, так и по соответствию описания событию.
В большинстве случаев эти особенности или не значимы, или обходятся с использованием других объектов.

177
Тест во вложении.

178
При приведении строки к типу UTF8String ошибки возникают после символьных констант.
В скрипте приведена часть возможных ошибок, причем наличие/отсутствие ошибки связано с размером константы (один или более символов)
и её местом (начало и внутри строки).
Средство от ошибок - явное приведение типа константы функцией UTF8Encode().

Переменная sTest: описание - "Описание переменной", единица измерения - "Единица измерения", начальное значение - "Это строка".
Код: (delphi)
begin
// в примере строка приводится к типу UTF8String           выводимый текст
// строка начинается с односимвольной константы
  Text1.Text := 'Ё' + sTest.Description;                 // ЁРћРїРёСЃР°РЅРёРµ переменной

// строка начинается с многосимвольной константы
  Text2.Text := 'ЁЁЁ' + sTest.Description;               // ЁЁЁОписание переменной

// ЯВНОЕ ПРИВЕДЕНИЕ ТИПА
  Text3.Text := UTF8Encode('Ё') + sTest.Description;     // ЁОписание переменной

// константа завершает строку типа String
  Text4.Text := sTest.AsStr + ' Кракозябра';             // Это строка Кракозябра

// односимвольная константа внутри строки
  Text5.Text := sTest.Description + '%' + sTest.Units;   // Описание переменной%Единица измерения

// многосимвольная константа внутри строки
  Text6.Text := sTest.Description + '% ]' + sTest.Units; // Описание переменной% ]Единица измерения

// переменная как String
  Text7.Text := sTest.Description + ' = ' + sTest.AsStr;  // Описание переменной = Это строка

// переменная как UTF8string
  Text8.Text := sTest.Description + ' = ' + sTest.AsUTF8String;  // Описание переменной = Это строка
end.

       

179
Ваши вопросы / Re: Автоматизация освещения
« : 16 Февраля 2019, 13:27:44 »
Здравствуйте. Прошу помочь организовать автоматизацию управление освещением. Требуется написать скрипт на включение света, несколько штук через 3 секунды друг за другом... и блокировать кнопки включения если переключатель установлен в положение "ручное управление". Спасибо.

Пример скрипта для управления объектами по времени для проекта (во вложении):

Несколько ламп, каждая со своим выключателем, работающие в режимах:
"Ручной" - каждая лампа независимо управляется своим выключателем;
"Выключено" - все лампы выключены;
"Автомат" - лампы включаются по времени по некоторой схеме, начиная с момента включения этого режима.

Переменные:
iMode - режим работы (0 - ручное, 1 - выключено, 2 - автомат),
iButton и iLamp - векторы соответствующих выключателей и ламп,
iTimeCounter - счетчик времени в автоматическом режиме.

Код: (delphi)
const imax = 4;   // верхняя граница цикла
var i, j: integer;
begin
  i := iMode.AsInt;
  j := (iTimeCount.AsInt + 1) * (i div 2); // счет только в автомате, иначе 0
  iTimeCount.Value := j;
  case i of
  0:  iLamps.Value := iButton.AsInt;   // по ручным переключателям
  1:  iLamps.Value := 0;               // выключить все
  2:  for i := 0 to imax do            // автомат
        iLamps.Value := SetBit(iLamps.AsInt, i, j >= (i * 3 + 3)); // равномерные задержки
  end;
end.

180
Можно включить в скрипт "Прошла секунда" условный оператор, управляемой кнопкой.

Переменная iPush типа integer, 0 разряд связан с кнопкой на два состояния с фиксацией.
Переменная iCycleCounter типа integer - счетчик циклов.
Код: (delphi)
const Cycles = 20;
begin
  if GetBit(iPush.AsInt,0) then
    // кнопка нажата
    if iCycleCounter.asInt > 0 then                 // счетчик циклов:
      iCycleCounter.Value := iCycleCounter.AsInt - 1 //   ещё не 0, уменьшить
    else
      iPush.Value := SetBit(iPush.Asint, 0, false)  //    =0, отпустить кнопку
  else
    // кнопка отжата
    iCycleCounter.Value := Cycles;                   // начальное значение счетчика циклов
end.
P.S. Еще один вариант управления циклом можно посмотреть во вложении к моему предыдущему сообщению.

Страницы: 1 ... 10 11 [12] 13 14