Pull to refresh

Comments 7

Саша, а ты не пробовал сравнивать вышеописанную конструкцию с банальным инкрементом в циклическом ОВ? Да, вызовов больше, но сама вызываемая процедура проще.
В циклическом OB (OB35, например) ты просто будешь знать время приращения аккумулятора времени, как константу. Но в целом задача сводится к предыдущей.
Выглядит, как проктологический подход к лечению зубов.

Я так и не понял постановки задачи, какую задачу нельзя решить с использованием стандартных встроенных в систему таймеров?

Ну и общее замечание — не надо использовать REAL без необходимости, он медленный почти на всех подобных железках.
Про подход согласен — натягивание совы на глобус, даже у таймера имя соответствующее задано. Про REAL тоже согласен.

Постановка задачи. Кратко и на пальцах. Выделяем некоторые сущности, например — DI, DO, агрегат. Каждая сущность — это массив элементов, у каждого элемента, соотвественно, есть свой индекс, т.е. уникальный номер. Обработка всех сущностей выполняется в циклах.

Для каждой сущности задается конфигурацию в реманентной памяти.
Для DI
-сигнал не в работе, подавать замещающее значение
-замещающее значение
-сигнал инвертирован
-время фильтрации дребезга контактов

Для DO
-сигнал не в работе, подавать замещающее значение
-замещающее значение
-сигнал инвертирован
-длительность управляющего импульса

Для агрегата
-индексы сигналов состояния
-индексы сигналов управления
-куча другого

У S7-300, особенно у тех, которые были поколение-два назад, все не очень хорошо с рабочей (оперативной) памятью, ее очень мало. По этой причине и заворачивали обработку в циклы. Память экономится значительно, но читаемость такого кода очень низкая.

В «тысячной» серии с рабочей памятью стало гораздо лучше, поэтому описанный в заметке пример носит больше демонстрационный и ностальгический параметр.
Я тут похоже немного неправ — забыл уже, что Сименс не позволял косвенную адресацию к C и T. Т.е. в инстанс-блок (и массив их-же) стандартные таймеры и счетчики не завернешь.
Для подобных целей сначала использовал самописную функцию
FC_On_Delay
FUNCTION "FC_On_Delay" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      input : Bool;
      current_time : Time;
      interval : Time;
   END_VAR

   VAR_IN_OUT 
      prev_input : Bool;
      output : Bool;
      start_time : Time;
   END_VAR


BEGIN
	IF #output <> #input THEN
	    IF #input THEN
	        IF #prev_input THEN
	            IF (#current_time - #start_time) > #interval THEN
	                #output := true;
	            END_IF;
	        ELSE
	            #start_time := #current_time;
	        END_IF;
	    ELSE
	        #output := false;
	    END_IF;
	END_IF;
	#prev_input := #input;
	
END_FUNCTION


Теперь использую стандартные таймеры.
Тестовый пример
TYPE "test_timer_t"
VERSION : 0.1
   STRUCT
      "timer" {InstructionName := 'IEC_TIMER'; LibVersion := '1.0'} : IEC_TIMER;
      in : Bool;
      pt : Time := T#10S;
      q : Bool;
      et : Time;
   END_STRUCT;

END_TYPE

TYPE "test_ton_timer_t"
VERSION : 0.1
   STRUCT
      "timer" {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      in : Bool;
      pt : Time := T#10S;
      q : Bool;
      et : Time;
   END_STRUCT;

END_TYPE

TYPE "test_tof_timer_t"
VERSION : 0.1
   STRUCT
      "timer" {InstructionName := 'TOF_TIME'; LibVersion := '1.0'} : TOF_TIME;
      in : Bool := true;
      pt : Time := T#10S;
      q : Bool;
      et : Time;
   END_STRUCT;

END_TYPE

DATA_BLOCK "DB_timers"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
NON_RETAIN
   VAR 
      timers : Array[1..100] of "test_timer_t";
      ton_timers : Array[1..100] of "test_ton_timer_t";
      tof_timers : Array[1..100] of "test_tof_timer_t";
   END_VAR


BEGIN

END_DATA_BLOCK

FUNCTION "FC_test_timers" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_TEMP 
      i : Int;
   END_VAR


BEGIN
	FOR #i := 1 TO 100 DO
	    "DB_timers".timers[#i].timer.TON(IN := "DB_timers".timers[#i].in,
	                                          PT := "DB_timers".timers[#i].pt,
	                                          Q => "DB_timers".timers[#i].q,
	                                          ET => "DB_timers".timers[#i].et);
	    "DB_timers".ton_timers[#i].timer(IN := "DB_timers".ton_timers[#i].in,
	                                          PT := "DB_timers".ton_timers[#i].pt,
	                                          Q => "DB_timers".ton_timers[#i].q,
	                                          ET => "DB_timers".ton_timers[#i].et);
	    "DB_timers".tof_timers[#i].timer(IN := "DB_timers".tof_timers[#i].in,
	                                          PT := "DB_timers".tof_timers[#i].pt,
	                                          Q => "DB_timers".tof_timers[#i].q,
	                                          ET => "DB_timers".tof_timers[#i].et);
	END_FOR;
	
END_FUNCTION

Отличное решение с заворачиванием в одну структуру IEC_TON и вспомогательной информации. Снимаю шляпу!

Кстати, из структуры можно, скорее всего, безболезненно, убрать Q и ET, сэкономим немного памяти.
Sign up to leave a comment.

Articles