Есть четыре типа статических таймеров (они отличаются разрядностью): 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). Эти константы описаны в главе Конфигурация.
Эти таймеры фактически 16-разрядные, но увеличиваются они один раз в 256 тиков. Они не годятся для формирования точных задержек из-за такой дискретности, но позволяют формировать довольно большие задержки, не прибегая к использованию 32-разрядного. Получается экономия RAM на 2 байта с одного такого таймера и некоторая экономия ROM за счет работы с 2-х, а не 4-х байтовыми переменными.
Разрядность статического таймера выбирается на этапе проектирования с учетом того, какие временные интервалы предполагается отмерять. Здесь для удобства сведены максимально допустимые задержки (округлены в меньшую сторону) для наиболее часто используемых значений системного тика:
Интервал вызова OS_Timer | 8-разрядные | 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) | Ожидаем завершения счета таймера |