279 lines
18 KiB
C
279 lines
18 KiB
C
/***************************************************************************//**
|
||
@defgroup ltimer Таймер
|
||
Модуль представляет собой набор функций для реализации таймера на основе
|
||
системных часов процессора (контроллера) или ОС.
|
||
|
||
Работа таймера основана на системном счетчике, который должен равномерно
|
||
увеличиваться с течением времени.
|
||
Реализация функций для инициализации системного счетчика и получения его значения
|
||
реализуются для каждой платформы своим портом. Также порт определяет количество
|
||
тиков системного счетчика за секунду с помощью константы #LCLOCK_TICKS_PER_SECOND
|
||
и тип #t_lclock_ticks для представления текущего значения системного счетчика.
|
||
Эти функции могут использоваться как напрямую, так и через общее API для работы
|
||
с таймером из ltimer.h, который может использоваться для отсчета интервалов
|
||
времени.
|
||
|
||
Все функции принимают значения в отсчетах системного счетчика, поэтому необходимо
|
||
использовать константу #LCLOCK_TICKS_PER_SECOND для перевода времени в количество отсчетов.
|
||
Также можно использовать макросы LTIMER_MS_TO_CLOCK_TICKS() и LTIMER_CLOCK_TICKS_TO_MS()
|
||
для перевода интервалов в миллисекундах в количество отсчетов и наоборот.
|
||
|
||
Для работы с модулем в проекте нужно добавить в стандартные пути
|
||
для включения заголовочных файлов пути к файлу ltimer.h и к директории с портом
|
||
для используемой платформы, а также путь к файлу lcspec.h, в котором
|
||
описаны специфические для компилятора макросы (в данном случае используется
|
||
#LINLINE для определения inline-функций). Также необходимо в исходники
|
||
добавить файл lclock.c из нужного порта.
|
||
|
||
При работе с системным счетчиком контроллера перед вызовом функций данного модуля
|
||
необходимо вызвать функцию lclock_init() (или lclock_init_val(), если нужно задать
|
||
начальное значение системного счетчика). При работе с системными часами ОС
|
||
обычно эта функция не требуется, так как таймер ОС уже инициализирован
|
||
самой ОС (однако ее вызов можно оставить, так как каждый порт реализует хотя бы
|
||
"пустую" версию этой функции).
|
||
|
||
Для работы с системным счетчиком напрямую используется функция lclock_get_ticks(),
|
||
возвращающая значение системного счетчика.
|
||
|
||
Для работы с API таймера, необходимо объявить переменную типа #t_ltimer, которая
|
||
будет хранить состояние таймра. Работать с полями структуры напрямую не рекомендуется.
|
||
Вместо этого следует использовать функции из ltimer.h, которые принимают эту
|
||
переменную в качестве первого аргумента.
|
||
|
||
При стандартной работе, сперва таймер устанавливается для отсчета заданного
|
||
интервала с помощью ltimer_set(). Проверить, истек ли заданный интервал,
|
||
можно с помощью ltimer_expired(). Количество отсчетов системного счетчика
|
||
до истечения интервала можно получить с помощью ltimer_expiration().
|
||
Перезапустить таймер на установленный в предыдущем ltimer_set() интервал можно
|
||
с помощью ltimer_reset() или ltimer_restart() (относительно времени последнего
|
||
истечения таймера или текущего времени соответственно).
|
||
|
||
Например, если какие-то действия нужно выполнять в течении заданного интервала,
|
||
то это можно сделать следующим образом:
|
||
|
||
@code
|
||
//время интервала в мс
|
||
#define TIMEOUT_MS 200
|
||
|
||
void main(void) {
|
||
t_ltimer tmr;
|
||
//инициализируем системный счетчик
|
||
lclock_init();
|
||
// устанавливаем таймер на заданное кол-во мс
|
||
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(TIMEOUT_MS));
|
||
while (!ltimer_expired(&tmr)) {
|
||
//выполняем требуемые действия
|
||
|
||
}
|
||
|
||
//интервал завершился
|
||
}
|
||
@endcode
|
||
|
||
|
||
В качестве основной идеи была взята реализация таймера для стека uIP от
|
||
Adam Dunkels <adam@sics.se>
|
||
*****************************************************************************/
|
||
|
||
/***************************************************************************//**
|
||
@addtogroup ltimer
|
||
@{
|
||
@file ltimer.h
|
||
Файл содержит описание функций для работы с таймером. Все функции реализованы
|
||
как inline-функции, так что файл содержит и реализацию функций
|
||
@author Borisov Alexey <borisov@lcard.ru>
|
||
*****************************************************************************/
|
||
#ifndef __LTIMER_H__
|
||
#define __LTIMER_H__
|
||
|
||
#include "lclock.h"
|
||
#include "lcspec.h"
|
||
|
||
/** Структура для описания состояния таймера */
|
||
typedef struct ltimer {
|
||
t_lclock_ticks start; /**< Значение системного таймера, с которого ведется отсчет */
|
||
t_lclock_ticks interval; /**< Интервал времени, после которого таймер считается истекшим */
|
||
} t_ltimer;
|
||
|
||
|
||
/***************************************************************************//**
|
||
@brief Получить время запуска таймера
|
||
|
||
@param[in] t Указатель на состояние таймера
|
||
@return Значение времени запуска таймера в системных клоках
|
||
******************************************************************************/
|
||
static LINLINE t_lclock_ticks ltimer_start_time(t_ltimer *t) {
|
||
return t->start;
|
||
}
|
||
|
||
/***************************************************************************//**
|
||
@brief Получить время срабатывания таймера
|
||
|
||
@param[in] t Указатель на состояние таймера
|
||
@return Значение времени срабатывания таймера в системных клоках
|
||
******************************************************************************/
|
||
static LINLINE t_lclock_ticks ltimer_expiration_time(t_ltimer *t) {
|
||
return t->start + t->interval;
|
||
}
|
||
|
||
/***************************************************************************//**
|
||
@brief Получить установленный интервал для таймера
|
||
|
||
@param[in] t Указатель на состояние таймера
|
||
@return Значение установленного интервала в системных клоках
|
||
******************************************************************************/
|
||
static LINLINE t_lclock_ticks ltimer_interval(t_ltimer *t) {
|
||
return t->interval;
|
||
}
|
||
|
||
|
||
|
||
/***************************************************************************//**
|
||
@brief Установить временной интервал относительно заданного времени
|
||
|
||
Функция устанавливает таймер на заданный интервал, аналогично ltimer_set(),
|
||
но относительно заданного времени (значения системного счетчика), а не
|
||
относительно текущего.
|
||
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
|
||
заданный интервал.
|
||
@param[in] t Указатель на состояние таймера
|
||
@param[in] interval Интервал, через который таймер истечет в системных клоках.
|
||
@param[in] start_time Значение системного счетчика, относительно которого
|
||
устанавливается временной интервал
|
||
******************************************************************************/
|
||
static LINLINE void ltimer_set_at(t_ltimer *t, t_lclock_ticks interval, t_lclock_ticks start_time) {
|
||
t->interval = interval;
|
||
t->start = start_time;
|
||
}
|
||
|
||
/***************************************************************************//**
|
||
@brief Установить временной интервал
|
||
|
||
Функция устанавливает таймер на заданный интервал относительно текущего времени.
|
||
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
|
||
заданный интервал.
|
||
@param[in] t Указатель на состояние таймера
|
||
@param[in] interval Интервал, через который таймер истечет в системных клоках.
|
||
******************************************************************************/
|
||
static LINLINE void ltimer_set(t_ltimer *t, t_lclock_ticks interval) {
|
||
ltimer_set_at(t, interval, lclock_get_ticks());
|
||
}
|
||
|
||
/***************************************************************************//**
|
||
@brief Установить временной интервал в мс
|
||
|
||
Функция устанавливает таймер на заданный интервал в милисекундах относительно
|
||
текущего времени.
|
||
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
|
||
заданный интервал.
|
||
@param[in] t Указатель на состояние таймера
|
||
@param[in] ms Интервал, через который таймер истечет в милисекундах.
|
||
******************************************************************************/
|
||
static LINLINE void ltimer_set_ms(t_ltimer *t, unsigned ms) {
|
||
ltimer_set(t, LTIMER_MS_TO_CLOCK_TICKS(ms));
|
||
}
|
||
|
||
|
||
|
||
/***************************************************************************//**
|
||
@brief Сброс таймера.
|
||
|
||
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set()
|
||
относительно времени последнего истечения таймера (а не текущего времени, как
|
||
ltimer_restart()). По сути функция продлевает время истечения таймера на тот
|
||
же интервал, что был задан. Интервалы между срабатыванием таймеров
|
||
сохраняется во времени, в отличие от использования ltimer_restart().
|
||
@param[in] t Указатель на состояние таймера
|
||
*****************************************************************************/
|
||
static LINLINE void ltimer_reset(t_ltimer *t) {
|
||
t->start += t->interval;
|
||
}
|
||
|
||
|
||
|
||
/***************************************************************************//**
|
||
@brief Перезапуск таймера с заданного времени.
|
||
|
||
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set(),
|
||
относительно текущего времени, начиная с указанного времени.
|
||
@param[in] t Указатель на состояние таймера
|
||
@param[in] start_time Значение системного счетчика, соответствующего времени,
|
||
с которого перезапускается таймер
|
||
*****************************************************************************/
|
||
static LINLINE void ltimer_restart_at(t_ltimer *t, t_lclock_ticks time) {
|
||
t->start = time;
|
||
}
|
||
|
||
|
||
/***************************************************************************//**
|
||
@brief Перезапуск таймера.
|
||
|
||
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set(),
|
||
относительно текущего времени.
|
||
@note Время срабатывания периодического таймер будет "плыть" при использовании
|
||
данной функции (из-за случайной разницы между текущим временем и временем
|
||
завершения предыдущего интервала). Для периодического таймера можно использовать
|
||
ltimer_reset()
|
||
@param[in] t Указатель на состояние таймера
|
||
*****************************************************************************/
|
||
static LINLINE void ltimer_restart(t_ltimer *t) {
|
||
ltimer_restart_at(t, lclock_get_ticks());
|
||
}
|
||
|
||
/***************************************************************************//**
|
||
@brief Проверка, истечет ли заданный интервал в определенное время
|
||
|
||
Функция проверяет, истечет ли установленный с помощью ltimer_set() интервал
|
||
в моент времени, определяемый заданным значением системного счетчика.
|
||
@param[in] t Указатель на состояние таймера
|
||
@param[in] exp_time Значение системного счетчика, для которого проверяется,
|
||
истечет ли таймер в данный момент
|
||
@return Не ноль, если интервал истечет, иначе --- ноль
|
||
******************************************************************************/
|
||
static LINLINE int ltimer_expired_at(const t_ltimer *t, t_lclock_ticks exp_time) {
|
||
return (t_lclock_ticks)(exp_time - t->start) > (t_lclock_ticks)t->interval;
|
||
}
|
||
|
||
/***************************************************************************//**
|
||
@brief Проверка, истек ли заданный интервал
|
||
|
||
Функция проверяет, истек ли заданный с помощью ltimer_set() интервал.
|
||
@param[in] t Указатель на состояние таймера
|
||
@return Не ноль, если интервал истек, иначе --- ноль
|
||
******************************************************************************/
|
||
static LINLINE int ltimer_expired(const t_ltimer *t) {
|
||
return ltimer_expired_at(t, lclock_get_ticks());
|
||
}
|
||
|
||
/***************************************************************************//**
|
||
@brief Получить время до истечения интервала от заданного момента
|
||
|
||
Функция возвращает значение интервала времени (в системных клоках) от заданного
|
||
момента до времени истечения установленного с помощью ltimer_set() интервала.
|
||
@param[in] t Указатель на состояние таймера
|
||
@param[in] cur_time Значение системного счетчика, от которого считается время
|
||
до момента истечения интервала
|
||
@return Время (в клоках системного счетчика) до истечения интервала
|
||
*******************************************************************************/
|
||
static LINLINE t_lclock_ticks ltimer_expiration_from(const t_ltimer *t, t_lclock_ticks cur_time) {
|
||
t_lclock_ticks expired = (cur_time-t->start);
|
||
return (expired > t->interval) ? 0 : t->interval - expired;
|
||
}
|
||
|
||
/***************************************************************************//**
|
||
@brief Получить время до истечения интервала
|
||
|
||
Функция возвращает значение интервала времени (в системных клоках) от текущего
|
||
момента до времени истечения установленного с помощью ltimer_set() интервала.
|
||
@param[in] t Указатель на состояние таймера
|
||
@return Время (в клоках системного счетчика) до истечения интервала
|
||
*******************************************************************************/
|
||
static LINLINE t_lclock_ticks ltimer_expiration(const t_ltimer *t) {
|
||
return ltimer_expiration_from(t, lclock_get_ticks());
|
||
}
|
||
|
||
#endif /* __LTIMER_H__ */
|
||
|
||
/** @} */
|
||
|