Содержание

OSA : Статические таймеры старого типа

Введение

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

Эти таймеры рекомендуется использовать тогда, когда код программы критичен к скорости, либо есть необходимость экономии RAM и ROM. В остальных случаях рекомендуется использовать динамические таймеры.

Описание

Есть четыре типа статических таймеров (они отличаются разрядностью): 8-, 16- 24- и 32-разрядные. 8-разрядные занимают по одному байту на таймер, 16- и 24-х разрядные - по 2, 32-х - 4 байта. Тип таймера следует выбирать исходя из максимального времени работы этого таймера. Одновременно в программе могут работать статические таймеры всех 4-х типов.

В погоне за экономией RAM и ROM организация работы с таймерами не очень удобна. Количество используемых таймеров и их тип должны быть определены на этапе компиляции. Количество таймеров задается в файле OSAcfg.h:

// Количество 8-разрядных таймеров
#define OS_TIMERS8    5
// Количество 16-разрядных таймеров
#define OS_TIMERS16   2
// Количество 24-разрядных таймеров
#define OS_TIMERS24   0
// Количество 32-разрядных таймеров
#define OS_TIMERS32   1

При этом в памяти создаются массивы соответствующих типов, где и будут храниться таймеры. Кроме того, если в программе есть хотя бы один статический таймер, то создаются битовые переменных для индикации переполнения. Например, в программе используются 5 8-разрядных таймеров, 2 16-разрядных и 1 32-разрядный. Всего 8, следовательно, создастся байтовая переменная, каждый бит которой будет отвечать за свой таймер.

Обращение к статическим таймерам производится через их ID - порядковый номер, причем младшие номера принадлежат 8-разрядным таймерам, а старшие - 32-разрядным. Все номера последовательны. Для нашего примера определено 8 таймеров: 0..4 - 8-разрядные таймеры 5..6 - 16-разрядные 7 - 32-разрядный

Удобно все ID таймеров определять через enum:

enum OSA_TIMERS_ENUM
{
            // 8-битные
    T8_TIMER0,
    T8_TIMER1,
    T8_TIMER2,
    T8_TIMER3,
    T8_TIMER4,
            // 16-битные
    T16_TIMER0,
    T16_TIMER1,
            // 24-битные
 
            // 32-битные
    T32_TIMER0
};

Тогда упростится обращение к таймерам и есть гарантия, что случайно не появится двух таймеров с одним и тем же ID. Все сервисы для таймеров разных типов одинаковы, за исключением сервиса OS_RunTimerX, который запускает таймер в работу, - этот сервис свой для каждого типа таймера.

После выполнения OS_Init() все статические таймеры остановлены. Ниже приведен пример использования таймера для выделения кванта времени задаче поиска информации на карте памяти (т.к. память большая, то поиск может затянуться).

// Определения в OAScfg.h
#define OS_ENABLE_TIMER
#define OS_TIMERS8  1
 
enum OS_TIMERS_ENUM {
   T8_Timer                  // Таймер для выделения кванта времени задаче поиска
}
 
----------------------------------------------------------------------
 
// Фрагмент программы (предполагаем, что интервал OS_Timer = 1 ms)
OST_MSG msg_cb, msg_cb2;
 
void Task1 (void)
{
    OST_MSG msg;
    static unsigned long Data;
    for (;;) {
        ...
        OS_Msg_Send(msg_cb, (OST_MSG)&Data);    // Нужно найти данные Data
        OS_Msg_Wait(msg_cb2, msg);              // Ждем завершения поиска
        ...
    }
}
 
 
void Task_SearchData (void)
{
    OST_SMSG msg;
    static unsigned long Data;
    static unsigned long Addr;
 
    for (;;) {
       OS_Msg_Wait(msg_cb, msg);
       Data = (unsigned long)(*msg);
 
       OS_RunTimer(T8_Timer, 10);                 // Запустить таймер на 10 мс
       for (Addr = 0; Addr < MAX_ADDRESS; Addr++) {
           if (MemoryRead(Addr) == Data) {        // Если нашли нужные данные,
               OS_Msg_Send(msg_cb2, (OST_MSG)&Addr); // отправить сообщение и выйти из цикла
               break;
           }
           if (OS_Oldtimer_Check(T8_Timer)) {         // Таймер переполнился?
                OS_Yield();                       // Передать управление планировщику
                OS_RunTimer(T8_Timer, 10);        // Запустить таймер снова
           }
       }
       if (Addr == MAX_ADDRESS) {                 // Если не нашли данных
            Addr = 0xFFFFFFFF;
            OS_Msg_Send(msg_cb2, (OST_MSG)&Addr);    // Отправляем -1
       }
    }
}

После получения задания на поиск (после получения сообщения msg_cb) задача Task_Search будет полностью захватывать время процессора, передавая упарвление другим задачам раз в 10мс.

Примечания для статических таймеров

Размещение статических таймеров в памяти

Размещение статических таймеров программист указывает в файле OSAcfg.h. Для этого есть константы OS_BANK_TIMEOUTS и OS_BANK_TIMERSx (x = 8, 16, 24, 32). Эти константы описаны в главе Конфигурация.

Примечание о 24-х разрядных таймерах

Эти таймеры фактически 16-разрядные, но увеличиваются они один раз в 256 тиков. Они не годятся для формирования точных задержек из-за такой дискретности, но позволяют формировать довольно большие задержки, не прибегая к использованию 32-разрядного. Получается экономия RAM на 2 байта с одного такого таймера и некоторая экономия ROM за счет работы с 2-х, а не 4-х байтовыми переменными.

Максимальные задержки статических таймеров

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

Интервал вызова OS_Timer8-разрядные16-разрядные24-разрядные32-разрядные
1 ms 256 мс 65.5 сек 4 ч 40 мин 49 суток
10 ms 2.5 сек 10 мин 46 ч 497 суток
18.2 ms 4.6 сек 19 мин 84 ч 900 суток
256 us 65 мс 16 сек 1 ч 10 мин 12 суток
512 us 130 мс 32.5 сек 2 ч 20 мин 24 суток
1024 us 260 мс 67 сек 4 ч 45 мин 50 суток
2048 us 528 мс 2 мин 15 сек 9 ч 30 мин 100 суток
4096 us 1 с 4 мин 30 сек 19 ч 200 суток
8192 us 2 с 9 мин 38 ч 400 суток

Для всех таймеров, кроме 24-разрядных, дискретность = 1 системному тику. Для 24-разрядных дискретность = 256 системным тикам = полному периоду 8-разрядного таймера.

Сервисы управления статическими таймерами.

Сервис Описание Свойства
Запуск
OS_Oldtimer_Run8 (timer8_id, time) Запустить 8-разрядный таймер для отсчета Сервис использует таймаут
OS_Oldtimer_Run16 (timer16_id, time) Запустить 16-разрядный таймер для отсчета Сервис использует таймаут
OS_Oldtimer_Run24 (timer24_id, time) Запустить 24-разрядный таймер для отсчета Сервис использует таймаут
OS_Oldtimer_Run32 (timer32_id, time) Запустить 32-разрядный таймер для отсчета Сервис использует таймаут
Остановка
OS_Oldtimer_Stop (timer_id) Останавливаем таймер (при этом устанавливается флаг Timeout для этого таймера) Сервис использует таймаут
Проверка
bool OS_Oldtimer_Check (timer_id) Проверить, закончил ли таймер счет. Сервис использует таймаут
Ожидание
OS_Oldtimer_Wait (timer_id) Ожидаем завершения счета таймера Разрешен вызов только в контексте задачиПереключает контекстСервис использует таймаут