====== 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~~