====== OSA : Статические таймеры старого типа ======
===== Введение =====
(Начиная с версии 81010, статические таймеры обновлены. Статические таймеры старого типа также остаются доступны, но, ввиду неудобства их применения, их использовать не рекомендуется. Новые статические таймеры описаны в разделе [[osa:ref:services:timers#Статические таймеры|Статические таймеры]])
Эти таймеры рекомендуется использовать тогда, когда код программы критичен к скорости, либо есть необходимость экономии RAM и ROM. В остальных случаях рекомендуется использовать динамические таймеры.
===== Описание =====
Есть четыре типа статических таймеров (они отличаются разрядностью): 8-, 16- 24- и 32-разрядные. 8-разрядные занимают по одному байту на таймер, 16- и 24-х разрядные - по 2, 32-х - 4 байта. Тип таймера следует выбирать исходя из максимального времени работы этого таймера. Одновременно в программе могут работать статические таймеры всех 4-х типов.
В погоне за экономией RAM и ROM организация работы с таймерами не очень удобна. Количество используемых таймеров и их тип должны быть определены на этапе компиляции. Количество таймеров задается в файле ##[[osa:ref:appendix:configuration|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**. Все сервисы для таймеров разных типов одинаковы, за исключением сервиса ##[[osa:ref:allservices:OS_RunTimerX|OS_RunTimerX]]##, который запускает таймер в работу, - этот сервис свой для каждого типа таймера.
После выполнения ##[[osa:ref:allservices:OS_Init|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мс.
~~UP~~
===== Примечания для статических таймеров =====
=== Размещение статических таймеров в памяти ===
Размещение статических таймеров программист указывает в файле ##[[osa:ref:appendix:configuration|OSAcfg.h.]]## Для этого есть константы ##[[osa:ref:appendix:configuration|OS_BANK_TIMEOUTS]]## и ##[[osa:ref:appendix:configuration|OS_BANK_TIMERSx]]## (x = 8, 16, 24, 32). Эти константы описаны в главе [[osa:ref:appendix:configuration#Размещение данных|Конфигурация]].
=== Примечание о 24-х разрядных таймерах ===
Эти таймеры фактически 16-разрядные, но увеличиваются они один раз в 256 тиков. Они не годятся для формирования точных задержек из-за такой дискретности, но позволяют формировать довольно большие задержки, не прибегая к использованию 32-разрядного. Получается экономия RAM на 2 байта с одного такого таймера и некоторая экономия ROM за счет работы с 2-х, а не 4-х байтовыми переменными.
=== Максимальные задержки статических таймеров ===
Разрядность статического таймера выбирается на этапе проектирования с учетом того, какие временные интервалы предполагается отмерять. Здесь для удобства сведены максимально допустимые задержки (округлены в меньшую сторону) для наиболее часто используемых значений системного тика:
^Интервал вызова ##[[osa:ref:allservices:OS_Timer|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-разрядного таймера.
===== Сервисы управления статическими таймерами. =====
^ Сервис ^ Описание ^ Свойства ^
|**Запуск**|||
|[[osa:ref:allservices:OS_Oldtimer_Run8|OS_Oldtimer_Run8]] (//timer8_id, time//) |Запустить 8-разрядный таймер для отсчета| {{osa:ref:attr_call_to.png|Сервис использует таймаут}} |
|[[osa:ref:allservices:OS_Oldtimer_Run16|OS_Oldtimer_Run16]] (//timer16_id, time//) |Запустить 16-разрядный таймер для отсчета| {{osa:ref:attr_call_to.png|Сервис использует таймаут}} |
|[[osa:ref:allservices:OS_Oldtimer_Run24|OS_Oldtimer_Run24]] (//timer24_id, time//) |Запустить 24-разрядный таймер для отсчета| {{osa:ref:attr_call_to.png|Сервис использует таймаут}} |
|[[osa:ref:allservices:OS_Oldtimer_Run32|OS_Oldtimer_Run32]] (//timer32_id, time//) |Запустить 32-разрядный таймер для отсчета | {{osa:ref:attr_call_to.png|Сервис использует таймаут}} |
|**Остановка**|||
|[[osa:ref:allservices:OS_Oldtimer_Stop|OS_Oldtimer_Stop]] (//timer_id//) |Останавливаем таймер (при этом устанавливается флаг Timeout для этого таймера) | {{osa:ref:attr_call_to.png|Сервис использует таймаут}} |
|**Проверка**|||
|//bool// [[osa:ref:allservices:OS_Oldtimer_Check|OS_Oldtimer_Check]] (//timer_id//) |Проверить, закончил ли таймер счет. | {{osa:ref:attr_call_to.png|Сервис использует таймаут}} |
|**Ожидание**|||
|[[osa:ref:allservices:OS_Oldtimer_Wait|OS_Oldtimer_Wait]] (//timer_id//) |Ожидаем завершения счета таймера | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}}{{osa:ref:attr_call_to.png|Сервис использует таймаут}} |
~~UP~~