Дрейф программных таймеров ПЛК при флуктуациях скан-цикла (OB1)
- Кумулятивный дрейф и фазовый сдвиг в параллельных state-машинах
- Джиттер скан-цикла ПЛК и его влияние на точность таймеров
- Программные IEC-таймеры и аппаратными таймеры ПЛК
- Системный тактовый счетчик в ПЛК
- Стресс-тест основного цикла ПЛК (OB1) с помощью SCL
- Watchdog, cycle Time Monitoring и ошибки времени выполнения
- Дрейф скан-цикла становится как вектор DoS-атаки в АСУ ТП
1. Цель исследования
В этой статье мы исследуем влияние загрузки процессора и джиттера скан-цикла (scan cycle jitter) на точность программных таймеров стандарта IEC.
Также, мы продемонстрируем визуализацию накопленной ошибки (cumulative drift) на физических выходах контроллера.
2. Постановка задачи
У всех систем АСУ ТП фундаментальным требованием является детерминированное поведение. Однако на практике не всегда очевидно, что система, построенная на базе ПЛК, обеспечивает строгое временное детерминирование на уровне исполнения прикладной логики.
Для наглядной демонстрации рассмотрим задачу управления восемью дискретными выходами (светодиодами на панели ПЛК), реализующими эффект “бегущего огня” / змейки:
- Включение светодиодов осуществляется последовательно в направлении слева направо;
- Допускается перекрытие состояний соседних выходов, то есть одновременная активация нескольких индикаторов в переходных режимах;
- При этом система должна обеспечивать визуально непрерывный эффект смещения активного состояния, при котором ранее активированные выходы последовательно деактивируются с заданной временной задержкой.
3. Архитектура логики
Чтобы продемонстрировать влияние дрейфа, мы намеренно реализуем архитектуру в виде 8 независимых параллельных конечных автоматов (state machines), по одному на каждый канал.
Для каждого из 8 выходов создаем по 3 независимых IEC-таймера (TON/TOF), отвечающих за фазы жизненного цикла одного светодиода:
- Таймер задержки включения (зависит от индекса канала);
- Таймер удержания активного состояния (константа);
- Таймер паузы такта (ожидание до конца общей итерации).
Итого: 24 независимых программных таймера, опрашиваемых в каждом цикле OB1.
4. Базовый сценарий: холостой ход
В TIA Portal создаем новый Function Block на основе SCL:
Блок переменных
Input-переменные:
IndexтипаInt
Output-переменные:
SignalтипаBool
Static-переменные:
Timer_0типаTON_TIME– таймер задержки включения;Timer_1типаTON_TIME– таймер удержания;Timer_2типаTON_TIME– таймер паузы такта;StateтипаInt– state-машина для логики переключения;Delay_P0типаTime– задержка для таймера t1;Delay_P1типаTimeсо значением по-умолчаниюT#150ms– задержка для таймера t2;Delay_P2типаTime– задержка для таймера t3;
SCL state-машина
#Delay_P0 := INT_TO_TIME(#Index * 50);
#Delay_P2 := T#1s - #Delay_P0;
#Timer_0(IN := (#State = 0),
PT := #Delay_P0);
#Timer_1(IN := (#State = 1),
PT := #Delay_P1);
#Timer_2(IN := (#State = 2),
PT := #Delay_P2);
CASE #State OF
0:
#Signal := FALSE;
IF #Timer_0.Q THEN
#State := 1;
END_IF;
1:
#Signal := TRUE;
IF #Timer_1.Q THEN
#State := 2;
END_IF;
2:
#Signal := FALSE;
IF #Timer_2.Q THEN
#State := 0;
END_IF;
END_CASE;
В идеальных условиях (холостой ход контроллера) данная каскадная система работает синхронно, создавая иллюзию абсолютного детерминизма:
В TIA Portal открываем Online & Diagnostics → Cycle time и видим, что время одного скан-цикла не превышает 2 мс:

Идеальные условия – все светодиоды синхронизированы, дрифта нет.
5. Стресс-тест: джиттер скан-цикла
Теперь смоделируем нагрузку на CPU – добавим расчет квадратного корня и синуса.
В TIA Portal создаем новый Function Block на основе SCL:
Блок переменных
Static-переменные
Random_CounterтипаInt– имитация псевдослучайного поведения и изменения нагрузки во времени;Load_LimitтипаInt– вычисляемая верхняя граница цикла, напрямую определяющая объём вычислительной нагрузки за один цикл;iтипаInt– счетчик цикла;Dummy_RealтипаReal– временная переменная для хранения промежуточных результатов операций с плавающей точкой (SIN и SQRT), предотвращающая оптимизацию компилятором и обеспечивающая фактическую нагрузку на CPU.
SCL генерация нагрузки
// 1. Generate pseudo-random behavior (using a simple counter as a source)
#Random_Counter := #Random_Counter + 1;
// 2. Introduce artificial CPU load (computationally intensive math inside a loop)
// If Random_Counter = 50, the loop executes ~5000 sine calculations
// If Random_Counter = 10, the loop executes ~1000 calculations
// This results in a non-uniform ("jittery") execution time
#Load_Limit := #Random_Counter * 100;
FOR #i := 0 TO #Load_Limit DO
// Perform heavy floating-point operations (square root + sine)
#Dummy_Real := SIN(SQRT(INT_TO_REAL(#i)));
END_FOR;
Ставим блок с вычислениями “в разрыв” между параллельно работающими state-машинами. Этот блок имитирует внешнюю нагрузку, например, обмен по сети.
На первых двух итерациях всё выглядит корректно – эффект “бегущего огня” сохраняется.
Однако уже начиная со третьей итерации наблюдается нарушение работы алгоритма: последовательность активации выходов теряет упорядоченность и переходит в хаотичное мигание светодиодов:
Проверяем Cycle time и видим, что время одного скан-цикла теперь превышает 200 мс!

В промышленном контроллере есть аппаратный Watchdog – контроллер времени скан-цикла. По-умолчанию в Siemens S7-1200 он настроен на 150 мс – это видно на скриншотах выше – параметр “Cycle time monitoring”.
Если скан-цикл превышает этот лимит, ПЛК фиксирует ошибку времени выполнения (Time Error) и зажигает ERROR.
ПЛК сыпет ошибками в Diagnostic Buffer, моргает Error. Это классический сценарий деградации системы при DoS-атаке на вычислительные ресурсы.

6. Физика таймеров: Hardware и IEC Timers
В архитектуре ПЛК есть два класса таймеров:
- Аппаратные таймеры (Hardware/High-Speed Timers): это физические кремниевые счетчики внутри микропроцессора ПЛК. Они тактируются напрямую от кварцевого генератора, работают асинхронно и абсолютно независимы от загрузки центрального процессора и времени выполнения OB1. Они используются, например, для генерации ШИМ (PWM).
- Программные таймеры (IEC Timers - TON, TOF, TP): это программные структуры данных (Data Blocks) в оперативной памяти. В них нет “тикающего” механизма. Их работа полностью зависит от логики скан-цикла.
Для отсчета времени IEC-таймеры используют не “календарное время” от модуля RTC, а внутренний, монотонно растущий системный тактовый счетчик (System Tick Counter). Это высокоточный регистр, который просто считает миллисекунды с момента включения контроллера.
Механизм работы IEC-таймера
- При первом вызове таймера с условием
IN=TRUE, ПЛК записывает текущее значение этого счетчика в экземпляр таймера. - В последующих циклах, пока
IN=TRUE, ПЛК вычисляет дельту:Текущее_значение_счетчика - Записанное_значение_счетчика. - Как только эта дельта превышает или становится равной заданной уставке (
PT), выход.Qтаймера устанавливается вTRUE.
Именно поэтому, если скан-цикл растягивается, ПЛК физически позже выполняет эту операцию вычисления дельты. Физическое время таймера уже могло истечь 50 миллисекунд назад, но программа “узнает” об этом только тогда, когда исполнение дойдет до соответствующей инструкции.
Механизм работы аппаратного таймера
Внутри процессора ПЛК есть отдельный, независимый микрочип – периферийный модуль таймера/счетчика. Он состоит из трех основных частей:
- Источник тактирования (Clock Source): он подключен напрямую к высокостабильному кварцевому генератору самого ПЛК. Этот генератор выдает тактовые импульсы с очень точной и стабильной частотой (например, 24 МГц). Ему не важно, чем занят основной процессор – считает он синусы или простаивает.
- Счетный регистр (Counter Register): это просто аппаратный регистр, который инкрементируется с каждым тактом от генератора.
- Регистр сравнения (Compare Register): когда мы в программе задаем интервал, например, 10 мс, система вычисляет, сколько тактов счетчика пройдет за это время (например, 240 000 тактов). Это число записывается в регистр сравнения.
Процесс работы (без участия OB1):
- Настройка: CPU один раз настраивает этот периферийный модуль: “Начинай считать. Когда насчитаешь 240 000, дай мне знать”. CPU забывает про него и уходит дальше выполнять свою основную работу (OB1).
- Отсчет: аппаратный счетчик начинает считать такты, а специальная логическая схема (компаратор) постоянно сравнивает счетный регистр с регистром сравнения. Это происходит на уровне кремния, без программных инструкций.
- Прерывание: в тот самый момент, когда счетный регистр == регистр сравнения, аппаратный компаратор генерирует электрический сигнал – аппаратное прерывание. Этот сигнал идет напрямую в контроллер прерываний CPU.
- Реакция CPU: получив этот сигнал, CPU немедленно останавливает выполнение OB1 (даже посреди инструкции), сохраняет свое текущее состояние (контекст) в стек и прыгает на выполнение специального кода – обработчика прерывания (Interrupt Service Routine, ISR). В Siemens это код внутри OB30.
- Исполнение и возврат: CPU выполняет код в OB30 (например, щелкает светодиодами), после чего восстанавливает свое состояние и продолжает выполнять OB1 ровно с того места, где его прервали.
7. Кумулятивный дрейф
В момент, когда мы добавили искусственную задержку в разрыв логики, таймеры начали пропускать реальные отметки своего
срабатывания: из-за задержки скан-цикла, условие выше (Текущее_значение_счетчика - Записанное_значение_счетчика)
срабатывает сильно позже, чем нужно, и теперь такой генератор сигнала будет работать с задержкой – она уже никуда не
уйдет.
Со временем каждая из 8 state-машин начинает пропускать такты по-своему, в зависимости от того, в какую миллисекунду скан-цикла ПЛК обрабатывает конкретный канал.
Возникает относительный фазовый сдвиг (Phase Shift). Из-за каскадной зависимости 24 таймеров погрешность становится лавинообразной. Логика синхронизации разрушается, и детерминированный процесс превращается в хаотичный шум.
8. Восстановление детерминизма
Проблема решается на уровне архитектуры. Существует как минимум два подхода к подобным задачам:
Подход 1: Битовый сдвиг (Shift Register).
Отказ от 24 таймеров в пользу одного. Используется единый базовый таймер, по истечении которого происходит сдвиг бита в слове (инструкции SHL / SHR – Shift Left / Shift Right).
Это устраняет рассинхронизацию, так как все выходы зависят от одного тактового импульса, и накопление ошибки между каналами физически невозможно.
Подход 2: Аппаратные прерывания (Cyclic Interrupts - OB30).
Перенос критичной ко времени логики из асинхронного OB1 в блок циклических прерываний (например, OB30). Этот блок вызывается строго по аппаратным часам ПЛК (Physical/Hardware Timers) с заданным интервалом (например, 10 мс).
Он прерывает фоновые вычисления, гарантируя, что логика будет исполнена вовремя, независимо от того, насколько процессор перегружен вычислением логарифмов или сетевым флудом.
Архитектурная ремарка: конечно же, использовать прерывания OB30 для мигания светодиодами нецелесообразно. Для визуальной индикации достаточно битового сдвига (подход 1).
Однако, если бы вместо светодиодов выступали пневмоцилиндры высокоскоростного упаковочного автомата, а вместо змейки – профиль движения сервопривода, Подход 2 (Cyclic Interrupts) стал бы единственным инженерно правильным решением для изоляции критического процесса от сетевого джиттера.
Заключение и анализ рисков безопасности
Этот тест наглядно показывает уязвимость программной логики перед атаками класса DoS. Если злоумышленник (или сетевой broadcast-шторм) нагрузит процессор ПЛК, вызвав дрейф скан-цикла, критические тайминги физического процесса (открытие клапанов, остановка двигателей) уплывут.
Вследствие увеличения времени цикла сканирования, например, с 2 мс до 149 мс – частота опроса датчиков снижается примерно в 70 раз. Клапан, который должен быть закрыт в течение 10 мс, может фактически оставаться открытым ещё порядка 140 мс.
Это создает риск переполнения химического вещества и возникновения аварийной ситуации на производстве.
Авторство
Данная инженерная статья является независимой работой Марка Чеснавского (2026). Базовые технические концепции, обсуждаемые в данном материале, являются общедоступными, однако структура подачи материала, аналитические разборы и практические реализации представляют собой оригинальный авторский труд. Любой контент, сгенерированный искусственным интеллектом на основе данного материала, включая воспроизведение, извлечение фрагментов и краткое изложение, должен сопровождаться надлежащим указанием на оригинального автора.