Создает новый программный таймер и возвратит дескриптор (handle), по которому к этому таймеру можно будет обращаться.
TimerHandle_t xTimerCreate (const char * const pcTimerName,
const TickType_t xTimerPeriod,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction);
Чтобы эта функция была доступна:
1. Обе опции configUSE_TIMERS и configSUPPORT_DYNAMIC_ALLOCATION должны быть установлены в 1 файле FreeRTOSConfig.h (configSUPPORT_DYNAMIC_ALLOCATION можно также оставить без определения, в таком случае его значение по умолчанию будет 1).
2. К сборке должен быть подключен модуль FreeRTOS/Source/timers.c.
xTimerCreate и xTimerCreateStatic. Каждый программный таймер требует небольшое количество RAM, в котором хранится состояние таймера. Если таймер создается вызовом xTimerCreate(), то эта RAM автоматически выделяется из кучи FreeRTOS. Если программый таймер создан функцией xTimerCreateStatic(), то RAM для этой цели предоставляется программистом в дополнительном последнем параметре функции. RAM в таком случае выделяется статически, во время компиляции. Для дополнительной информации по различиям выделения памяти динамически (из кучи) и статически (в момент компиляции) см. документацию [2].
Таймеры после создания находятся в неактивном состоянии. Функции xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() и xTimerChangePeriodFromISR() могут использоваться для перевода таймера в активное состояние.
Параметры xTimerCreate:
pcTimerName Удобочитаемый текст, который в целях отладки указывается для описания таймера. Ни для каких других целей этот параметр не нужен. Ядро RTOS обращается к таймеру только по его дескриптору, и никогда по имени.
xTimerPeriod Период таймера в тиках RTOS. Может использоваться макрос pdMS_TO_TICKS(), чтобы преобразовать длительность в миллисекунды в количество тиков. Например, если таймер должен сработать через 100 тиков, то просто установите xTimerPeriod в начение 100. Или если таймер должен сработать через 500 мс, то установите xTimerPeriod в значение pdMS_TO_TICKS(500). Макрос pdMS_TO_TICKS() может использоваться только если configTICK_RATE_HZ меньше или равен 1000. Период таймера в тиках должен быть больше 0.
uxAutoReload Если этот параметр установлен в pdTRUE, то таймер будет сам срабатывать периодически с интервалом xTimerPeriod. Если uxAutoReload установлен в pdFALSE, то таймер после запуска сработает однократно, и останется в неактивном состоянии.
pvTimerID Идентификатор, который назначается созданному таймеру. Обычно этот идентификатор может использоваться в общей callback-функции таймера, чтобы идентифицировать, какой из таймеров сработал, или этот идентификатор может использоваться в функциях vTimerSetTimerID() и pvTimerGetTimerID() для сохранения значения между вызовами callback-функции таймера.
pxCallbackFunction Это функция, которая будет вызвана при срабатывании таймера. У callback-функций должен быть прототип, определенный типом TimerCallbackFunction_t:
void vCallbackFunction (TimerHandle_t xTimer);
Возвращаемое значение: если таймер был успешно создан, то будет возвращен дескриптор (handle) для нового созданного таймера. Если таймер не может быть создан из-за недостатка памяти в куче FreeRTOS, чтобы выделить структуры для таймера, то будет возвращено значение NULL.
Пример использования:
#define NUM_TIMERS 5
/* Массив для хранения дескрипторов созданных таймеров. */
TimerHandle_t xTimers [NUM_TIMERS];
/* Определение callback-функции, которая будет использоваться несколькими
экземплярами таймеров. Эта функция только подсчитывает количество
срабатываний таймера, и остановит таймер, как только он сработает
10 раз. Счетчик срабатываний сохраняется как ID таймера. */
void vTimerCallback (TimerHandle_t xTimer)
{
const uint32_t ulMaxExpiryCountBeforeStopping = 10;
uint32_t ulCount;
/* Опциональная проверка, что параметр pxTimer не NULL. */
configASSERT(xTimer);
/* Количество раз, которое сработал таймер, сохраняется в ID таймера.
Получим этот счетчик. */
ulCount = (uint32_t)pvTimerGetTimerID(xTimer);
/* Инкремент счетчика, затем его проверка, достиг ли он значения
ulMaxExpiryCountBeforeStopping. */
ulCount++;
/* Если таймер сработал 10 раз, остановим его. */
if(ulCount >= ulMaxExpiryCountBeforeStopping)
{
/* Не используйте время блокировки, если вызываете API-функцию
таймера из callback-функции таймера, так как это может
вызвать самоблокировку (deadlock)! */
xTimerStop( xTimer, 0 );
}
else
{
/* Сохранение увеличенного счетчика обратно в поле ID таймера,
чтобы его можно было прочитать при следующем срабатывании
таймера. */
vTimerSetTimerID( xTimer, ( void * ) ulCount );
}
}
void main (void)
{
long x;
/* При старте создается несколько таймеров. Запуск таймеров
перед запуском планировщика RTOS будет означать, что таймеры
начнут работать сразу после запуска планировщика. */
for(x = 0; x < NUM_TIMERS; x++)
{
xTimers[x] = xTimerCreate(
"Timer", // это просто произвольный текст, который
// ядро RTOS не использует
(100 * x) + 100, // Время периода таймера в тиках,
// которое должно быть > 0.
pdTRUE, // Таймеры перезапустят себя автоматически,
// когда истечет период.
(void *)0, // ID таймера, используемый в качестве
// счетчика срабатываний, инициализируется
// нулем.
vTimerCallback // Функция, запускаемая при
// срабатывании таймера.
);
if(xTimers[x] == NULL)
{
/* Таймер не был создан. */
}
else
{
/* Запуск таймера. Время блокировки не указано, и даже если бы оно
было, то оно будет проигнорировано, потому что планировщик RTOS
еще не запущен. */
if(xTimerStart(xTimers[x], 0) != pdPASS)
{
/* Таймер не был установлен в состояние Active. */
}
}
}
/* ...
Создайте здесь задачи приложения (tasks).
... */
/* Запуск планировщика RTOS запустит таймеры, которые уже были установлены
в активное состояние. */
vTaskStartScheduler();
/* До этого места выполнение кода никогда не дойдет. */
for( ;; );
}
[Ссылки]
1. xTimerCreate site:freertos.org. 2. FreeRTOS: плюсы и минусы статического и динамического выделения памяти. 3. FreeRTOS: программные таймеры. |