Текущий раздел:

Описания RDS

Руководство программиста

Глава 2. Создание моделей блоков

§2.9. Использование таймеров

§2.9.3. Однократно срабатывающий таймер

# Руководство программиста

## Глава 2. Создание моделей блоков

### §2.9. Использование таймеров

#### §2.9.3. Однократно срабатывающий таймер

Описывается таймер, однократно вызывающий модель блока по истечении заданного интервала. Рассматривается пример блока, изображающего мигающую индикаторную лампочку, длительность горения которой не равна длительности паузы (после каждого срабатывания таймер перезапускается с новой задержкой).

В приведенном в §2.9.2 примере использовался циклический таймер – рассмотрим теперь работу с однократно срабатывающим. Допустим, нам нужен похожий индикатор, но скважность его мигания не должна равняться двум, то есть время «горения» и время «паузы» индикатора должно быть разным. Создадим блок, который при единичном значении входа «Flash» будет зажигаться на 500 миллисекунд, затем гаснуть на одну секунду, затем снова зажигаться на 500 мс и т.д. Циклический таймер нам здесь не поможет – интервал между его срабатываниями постоянен. Воспользуемся однократно срабатывающим таймером, запуская его то на 500 мс, то на тысячу. При той же структуре переменных модель нового блока будет очень похожа на модель из предыдущего примера с некоторыми отличиями (выделены цветом):

      //====== Модель неравномерно мигающего блока ======
      // Функция модели блока
      extern "C" __declspec(dllexport) int RDSCALL SimpleFlash1(
              int CallMode,
              RDS_PBLOCKDATA BlockData,
              LPVOID ExtParam)
      {
      // Макроопределения для статических переменных
      #define pStart ((char *)(BlockData->VarTreeData))
      #define Start (*((char *)(pStart)))
      #define Ready (*((char *)(pStart+RDS_VSZ_S)))
      #define Flash (*((char *)(pStart+2*RDS_VSZ_S)))
      #define State (*((char *)(pStart+2*RDS_VSZ_S+RDS_VSZ_L)))
        // Вспомогательная переменная – указатель на личную область
        // В личной области хранится только идентификатор таймера
        RDS_TIMERID *data=(RDS_TIMERID*)(BlockData->BlockData);
        RDS_TIMERDESCRIPTION descr;

        switch(CallMode)
          { // Инициализация блока
            case RDS_BFM_INIT:
              // Отводим место для хранения идентификатора таймера
              BlockData->BlockData=data=new RDS_TIMERID;
              // Создаем таймер, интервал пока не устанавливаем
              *data=rdsSetBlockTimer(NULL,0,
                      RDS_TIMERM_STOP|RDS_TIMERS_TIMER,FALSE);
              break;

            // Очистка данных блока
            case RDS_BFM_CLEANUP:
              // Уничтожаем таймер
              rdsDeleteBlockTimer(*data);
              // Освобождаем память, где он хранился
              delete data;
              break;

            // Проверка типа статических переменных
            case RDS_BFM_VARCHECK:
              if(strcmp((char*)ExtParam,"{SSLL}"))
                return RDS_BFR_BADVARSMSG;
              return RDS_BFR_DONE;

            // Такт расчета
            case RDS_BFM_MODEL:
              // Запрашиваем параметры таймера
              descr.servSize=sizeof(descr);
              rdsGetBlockTimerDescr(*data,&descr);
              if(Flash) // Включаем мигание, если таймер остановлен
                { if(!descr.On) // Таймер остановлен
                    { // Запускаем таймер на 500 мс
                      rdsRestartBlockTimer(*data,500);
                      State=1;
                    }
                }
              else // Выключаем мигание, если таймер работает
                { if(descr.On) // Таймер работает
                    { // Останавливаем таймер
                      rdsStopBlockTimer(*data);
                      State=0;
                    }
                }
              break;

            // Срабатывание таймера
            case RDS_BFM_TIMER:
              if(State) // Индикатор был "зажжен"
                { // Гасим и запускаем таймер на 1 сек
                  State=0;
                  rdsRestartBlockTimer(*data,1000);
                }
              else // Индикатор был "погашен"
                { // Зажигаем и запускаем таймер на 500 мс
                  State=1;
                  rdsRestartBlockTimer(*data,500);
                }
              break;
          }
        return RDS_BFR_DONE;
      // Отмена макроопределений для переменных
      #undef State
      #undef Flash
      #undef Ready
      #undef Start
      #undef pStart
      }
      //=================================================

Фактически, в модели изменились только параметры функции создания таймера и реакция на срабатывание таймера. Таймер теперь создается с параметром RDS_TIMERM_STOP вместо RDS_TIMERM_LOOP (однократное срабатывание вместо циклического). В реакции на срабатывание таймера (RDS_BFM_TIMER) теперь анализируется значение переменной State. Если оно равно 1 (индикатор был зажжен), ей присваивается 0 и таймер запускается на одну секунду для отработки паузы. Если же оно равно нулю (индикатор погашен), ей присваивается единица и таймер запускается на 500 мс для отработки «горения». Таким образом, остановившийся таймер немедленно перезапускается с новым значением задержки.

Реакцию на срабатывание таймера можно переписать компактнее – в тексте модели выше она просто расписана подробно с комментариями для большей ясности программы. Те же действия могут быть выполнены и так:

            case RDS_BFM_TIMER:
              rdsRestartBlockTimer(*data,State?1000:500);
              State=!State;
              break;

Мы в любом случае заново запускаем таймер, просто его интервал зависит от значения State. Само значение State инвертируется, как и в предыдущей модели с циклическим таймером.