SlideShare une entreprise Scribd logo
1  sur  19
1
2
3
void ATaskFunction( void *pvParameters )
{
/* Переменные могут быть определены точно так же, как и в обычной функции.
Каждый экземпляр созданной по этой функции задачи будет иметь собственную копию
переменной iVariableExample. Это не верно, если переменная была продекларирована
как статическая (static) – в этом случае будет существовать только одна копия
переменной, и она будет использоваться совместно всеми созданными экземплярами
задачи. */
int iVariableExample = 0;
/* Задача должна быть нормально реализована как бесконечный цикл. */
for( ;; )
{
/* Код, который реализует функционал задачи, должен быть помещен здесь. */
}
/* Код должен быть организован так, чтобы в случае выхода (break) из указанного
выше бесконечного цикла задачи, задача должна быть удалена ПРЕЖДЕ чем
управление достигнет конца этой функции. Параметр NULL, переданный
vTaskDelete(), показывает, что должна быть удалена вызванная (эта, которая работает) задача.
*/
vTaskDelete( NULL );
}
portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode,
const signed portCHAR * const pcName,
unsigned portSHORT usStackDepth,
void *pvParameters,
unsigned portBASE_TYPE uxPriority,
xTaskHandle *pxCreatedTask );
Параметры и значение возврата функции xTaskCreate()
Имя параметра
/
возвращаемое
значение
Описание
pvTaskCode
Задачи - это простые C-функции, которые никогда не делают возврата из своего тела
(постоянно выполняют свой бесконечный цикл). Параметр pvTaskCode - простой указатель на
функцию (т. е. просто имя функции), которая реализует задачу.
pcName
Описательное имя для задачи. Оно никак не используется внутри FreeRTOS, и нужно только
для целей отладки. Идентификация задачи по легкочитаемому имени намного проще, чем по
хендлу задачи (handle).
В приложении указана константа времени компиляции configMAX_TASK_NAME_LEN, которая
задает максимальную длину для этого имени - включая нулевой байт окончания строки. Если в
качестве pcName предоставлена более длинная строка, то она молча урезается до величины,
заданной configMAX_TASK_NAME_LEN.
usStackDepth
Каждая задача имеет собственное уникальное хранилище состояния, выделенное ядром при
создании задачи. Значение параметра usStackDepth говорит ядру, какой величины стек
необходимо создать.
Значение usStackDepth указывает количество слов, которое можно сохранить в стеке, а не
количество байт. Например, если стек имеет ширину 32 бита, и переданное значение
usStackDepth равно 100, то под стек будет выделено 400 байт (100 * 4 байт). Глубина стека,
умноженная на его ширину, не должна превышать максимальное значение, которое может
содержать переменная типа size_t.
Размер стека, используемого для задачи ожидания (idle task, об этой задаче подробнее
4
говорится далее), задается константой configMINIMAL_STACK_SIZE. Значение, назначенное
этой константе в демо-приложении FreeRTOS (для определенной архитектуры
микроконтроллера) может быть использовано как минимально рекомендованное для любой
задачи. Если Ваша программа использует пространство в стеке, то нужно указать для
константы configMINIMAL_STACK_SIZE увеличенное значение.
Нет простого способа узнать, какого размера стек нужен для задачи. Этот размер можно
вычислить, но в большинстве случаев можно просто назначить подходящее значение,
подобранное опытным путем, либо взятое приблизительно. Подобрать правильный размер
стека важно, чтобы обеспечить адекватное использование RAM без ненужных затрат. Часть 6
содержит информацию о том, как запросить размер стека, используемого задачей.
pvParameters
Функции задач принимают параметр, имеющий тип указателя на void (т. е. void*). Значение,
указанное в pvParameters, будет передано в задачу. Несколько примеров в этом документе
демонстрируют, как этот параметр может быть использован в реальных задачах.
uxPriority
Задает приоритет, с которым будет выполняться задача. Приоритеты могут быть назначены в
любое значение от 0 минимальный приоритет до (configMAX_PRIORITIES – 1) максимальный
приоритет.
Константа configMAX_PRIORITIES определяется пользователем. Нет ограничения на верхний
предел для количества приоритетов, которые можно задать (кроме ограничения на лимит
используемого типа данных ограничения по количеству RAM, доступному в микроконтроллере),
но желательно использовать как можно меньшее количество приоритетов, которое
действительно необходимо - с целью уменьшения расхода RAM.
Передача в параметре значения uxPriority выше (configMAX_PRIORITIES – 1) приведет к
молчаливому назначению приоритета задачи в максимально допустимое значение
configMAX_PRIORITIES.
pxCreatedTask
Параметр pxCreatedTask может использоваться для передачи наружу хендла созданной задачи.
Этот хендл можно использовать как ссылку на задачу в вызовах API FreeRTOS, например для
изменения приоритета задачи или для удаления задачи.
Если Ваше приложение не использует хендл задачи, то pxCreatedTask может быть установлен в
NULL.
Возвращаемое
значение
Имеется два возможных возвращаемых значения:
1. pdTRUE показывает, что задача успешно создана.
2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY показывает, что задача не создана, так как в
куче (heap) недостаточно свободной памяти для FreeRTOS, чтобы она могла выделить место
для структур данных задачи и стека. Часть 5 предоставляет больше информации по
управлению памятью.
int main( void )
{
/* Создание одной из двух задач. Имейте в виду, что реальное приложение должно
проверить возвращаемое значение из вызова xTaskCreate(), чтобы удостовериться,
что задача была успешно создана. */
xTaskCreate( vTask1, /* Указатель на функцию, которая реализует задачу. */
"Task 1",/* Текстовое имя задачи. Этот параметр нужен только для
упрощения отладки. */
1000, /* Глубина стека - самые маленькие микроконтроллеры будут
использовать значение намного меньше, чем здесь
указано. */
NULL, /* Мы не используем параметр задачи. */
1, /* Задача будет запущена с приоритетом 1. */
NULL ); /* Мы не будем использовать хендл задачи. */
/* Создание другой задачи полностью совпадает с созданием первой,
приоритет задачи тот же. */
xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL );
/* Запуск шедулера, после чего задачи запустятся на выполнение. */
vTaskStartScheduler();
5
/* Если все хорошо, то управление в main() никогда не дойдет до этой точки,
и теперь шедулер будет управлять задачами. Если main() довела управление
до этого места, то это может означать, что не хватает памяти кучи
(heap) для создания специальной задачи ожидания (idle task, об этой задаче
далее). Часть 5 предоставляет больше информации по управлению памятью. */
for( ;; );
}
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
volatile unsigned long ul;
/* Строка для вывода на печать передается через параметр. Здесь
он преобразуется в указатель на символьную строку. */
pcTaskName = ( char * ) pvParameters;
/* Как и большинство задач, эта задача реализована на основе бесконечного цикла. */
for( ;; )
{
/* Вывод на печать имени этой задачи. */
vPrintString( pcTaskName );
/* Задержка на некоторый период времени. */
for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
{
/* Этот цикл просто реализует задержку очень грубым методом.
В цикле не производится никаких действий. Далее будут приведены
примеры, в которых этот пустой цикл будет заменен соответствующей
функцией задержки / приостановки задачи (введение задачи в состояние
сна - sleep). */
}
}
}
6
void vTaskDelay( portTickType xTicksToDelay );
Параметры функции vTaskDelay()
Имя
параметра
Описание
xTicksToDelay
Количество тиков прерываний, в течение которых вызывающая задача должна оставаться в
состоянии Blocked перед переходом обратно в состояние Ready.
Например, если задача сделала вызов vTaskDelay( 100 ), а счетчик тиков (системная переменная
FreeRTOS) при этом был равен 10000, то задача немедленно войдет в состояние Blocked и
останется в нем до тех пор, пока счетчик тиков не достигнет 10100.
Константа portTICK_RATE_MS может использоваться для преобразования миллисекунд в тики.
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
/* Строка для вывода на печать, переданная через параметр. Здесь
параметр преобразуется в указатель на строку. */
pcTaskName = ( char * ) pvParameters;
/* Как и большинство других задач, эта задача реализована как бесконечный цикл. */
for( ;; )
{
/* Печать имени этой задачи. */
vPrintString( pcTaskName );
/* Задержка на некоторый период времени. Эта задержка создается благодаря
использованию вызова vTaskDelay(), которым задача помещается в состояние
Blocked до истечения периода задержки. Период задержки указывается в 'тиках',
но можно использовать константу portTICK_RATE_MS для преобразования
(более удобной для пользователя) величины миллисекунд в тики.
В нашем случае указан период 250 миллисекунд. */
vTaskDelay( 250 / portTICK_RATE_MS );
}
7
}
8
Функция vTaskDelayUntil() работает аналогично vTaskDelay(). Как было продемонстрировано, параметр функции
vTaskDelay() указывает количество тиков прерываний, которые должны произойти между вызовом из задачи
vTaskDelay() и моментом времени, когда та же самая задача выйдет снова из состояния Blocked. Величина
времени, в течение которого задача остается заблокированной, указывается в параметре vTaskDelay(), но
реальное время, в которое задача покинет заблокированное состояние, отсчитывается относительно времени,
когда был произведен вызов vTaskDelay(). Вместо этого в параметре функции vTaskDelayUntil() указывается
явное значение счетчика тиков, на котором вызывающая эту функцию задача должна перейти из состояние
Blocked в состояние Ready. API функция vTaskDelayUntil() должна использоваться, когда требуется
фиксированный период выполнения задачи (например, Вы хотите, чтобы задача выполнялась периодически с
фиксированной частотой). Так как время разблокировки вызывающей задачи является абсолютным (в отличие от
относительного, отсчитываемого от вызова функции, как в случае с vTaskDelay()).
void vTaskDelayUntil( portTickType * pxPreviousWakeTime,
portTickType xTimeIncrement );
Параметры функции vTaskDelayUntil()
Имя параметра Описание
pxPreviousWakeTime
Этот параметр поименован так из предположения, что vTaskDelayUntil() выполняется
периодически и с фиксированной частотой. В этом случае переменная, на которую
указывает pxPreviousWakeTime, удерживает время, в которое задача покинула состояние
Blocked (т. е. время, когда задача 'проснулась'). Это время используется как точка отсчета
для вычисления момента времени, когда произойдет следующий выход из состояния
Blocked.
Переменная, на которую указывает pxPreviousWakeTime, обновляется автоматически внутри
функции vTaskDelayUntil(), и она обычно не должна быть модифицирована кодом
приложения за исключением первоначальной инициализации. В листинге 14 показано, как
это нужно делать.
xTimeIncrement
Этот параметр также поименован в предположении, что функция vTaskDelayUntil()
используется для реализации, которая выполняется периодически и с фиксированной
частотой - частота устанавливается значением параметра xTimeIncrement. Величина
xTimeIncrement указывается в 'тиках'. Можно использовать константу portTICK_RATE_MS
для преобразования миллисекунд в тики.
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
portTickType xLastWakeTime;
/* Строка для вывода на печать, переданная через параметр. Здесь
параметр преобразуется в указатель на строку. */
pcTaskName = ( char * ) pvParameters;
/* Переменная xLastWakeTime нуждается в инициализации текущим
значением счетчика тиков. Имейте в виду, переменная записывается
явно только в этот момент. Затем xLastWakeTime обновляется
автоматически внутри функции vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount();
/* Как и большинство других задач, эта задача реализована как бесконечный цикл. */
for( ;; )
{
/* Печать имени этой задачи. */
vPrintString( pcTaskName );
/* Эта задача должна выполняться точно каждые 250 миллисекунд. Как и
в функции vTaskDelay(), время измеряется в тиках, и константа
portTICK_RATE_MS используется для преобразования миллисекунд в тики.
Переменная xLastWakeTime автоматически обновляется внутри функции
vTaskDelayUntil(), и нигде явно в коде задачи переменная xLastWakeTime
не обновляется. */
vTaskDelayUntil( &xLastWakeTime, ( 250 / portTICK_RATE_MS ) );
}
}
9
Функции IDLE TASK HOOK
В задачу Idle Task можно добавить функционал приложения пользователя. Это делается через функцию хука Idle
(иначе её называют callback-функцией) - она автоматически будет вызываться изнутри Idle Task, каждый раз в
цикле ожидания.
Можно использовать Idle Task hook следующим образом:
· Выполнение низкоприоритетных задач в фоновом режиме, или продолжительные обработки данных.
· Измерение свободного процессорного времени (т. е. загруженности процессора) - задача Idle Task будет
работать только тогда, когда все другие задачи не выполняют свою работу (им нечего делать), поэтому
измерение процессорного времени, выделенного на Idle Task, явно показывает, сколько процессорного времени
имеется в запасе.
· Перевод процессора в режим пониженного энергопотребления - предоставление автоматического метода
сохранения энергии, когда приложением не выполняется полезная обработка данных.
Ограничения, связанные с использованием функций Idle Task hook
Функции Idle Task hook должны удовлетворять следующим правилам:
1. Они никогда не должны делать попыток приостановки (переход в состояние Suspended) или блокировки
(переход в состояние Blocked). Задача Idle Task будет выполняться только тогда, когда другим задачам нечего
делать (за исключением тех случаев, когда задачи приложения имеют тот же приоритет, что и Idle Task). Поэтому
блокировка Idle Task приведет к тому, что не будет ни одной задачи, которая могла бы войти в состояние
Running!
2. Если приложение использует вызовы API функции vTaskDelete(), то функция Idle Task hook должна всегда
быть завершена в течение подходящего периода времени. Причина этого в том, что задача Idle Task отвечает за
очистку ресурсов ядра после удаления задачи. Если управление потоком выполнения Idle Task остается
постоянно в коде Idle Task hook, то тогда очистка не может быть выполнена.
void vApplicationIdleHook( void );
Имя и прототип функции хука задачи ожидания (Idle Task hook)
Определение функции Idle Task hook
Использование блокирующих вызовов API функции vTaskDelay() в примере 4 создает некоторый интервал
времени ожидания - в это время выполняется задача Idle Task, так как обе задачи приложения находятся в
состоянии Blocked.
/* Определение переменной, которая будет инкрементирована функцией хука. */
unsigned long ulIdleCycleCount = 0UL;
/* Функции хука Idle ДОЛЖНЫ называться vApplicationIdleHook(), не принимать
никаких параметров, и возвращать void. */
void vApplicationIdleHook( void )
{
/* Эта функция хука ничего не делает, кроме инкрементирования счетчика. */
ulIdleCycleCount++;
}
Очень простой пример функции Idle Task hook
Чтобы функция Idle Task hook vApplicationIdleHook вызывалась, в файле FreeRTOSConfig.h нужно установить в 1
макрос configUSE_IDLE_HOOK.
void vTaskFunction( void *pvParameters )
{
char *pcTaskName;
10
/* Строка для вывода на печать, переданная через параметр. Здесь
параметр преобразуется в указатель на строку. */
pcTaskName = ( char * ) pvParameters;
/* Как и большинство других задач, эта задача реализована как бесконечный цикл. */
for( ;; )
{
/* Печать имени этой задачи и количества инкрементов переменной
ulIdleCycleCount. */
vPrintStringAndNumber( pcTaskName, ulIdleCycleCount );
/* Задержка на 250 миллисекунд. */
vTaskDelay( 250 / portTICK_RATE_MS );
}
}
11
API функция vTaskPrioritySet()
Для изменения приоритета любой задачи после старта шедулера может быть использована API функция
vTaskPrioritySet().
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
Параметры функции vTaskPrioritySet()
Имя
параметра
Описание
pxTask
Хендл задачи (субъект задачи), у которой будет изменен приоритет - см. параметр pxCreatedTask
функции API xTaskCreate() для более подробной информации по получению хендлов для задач.
Задача может изменить собственный приоритет путем передачи NULL вместо действительного
хендла задачи.
uxNewPriority
Приоритет, в который будет установлен субъект задачи. Значение, переданное в этом параметре,
автоматически ограничивается величиной максимально доступного приоритета
(configMAX_PRIORITIES – 1), где configMAX_PRIORITIES опция времени компиляции,
установленная в заголовочном файле FreeRTOSConfig.h.
API функция uxTaskPriorityGet()
Для получения текущего приоритета задачи может быть использована API функция uxTaskPriorityGet().
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
Параметры и значение возврата функции uxTaskPriorityGet()
Имя параметра
/
возвращаемое
значение
Описание
pxTask
Хендл задачи, приоритет которой запрашивается - см. параметр pxCreatedTask функции API
xTaskCreate() для более подробной информации по получению хендлов для задач. Задача
может запросить собственный приоритет путем передачи NULL вместо действительного
хендла задачи.
Возвращаемое
значение
Значение запрошенного приоритета, который в настоящий момент назначен задаче.
12
13
Использование очереди]
API функция xQueueCreate()
Очередь перед использованием должна быть явно создана.
Обращение к очереди происходит через переменную типа xQueueHandle. Функция xQueueCreate() используется
для создания очереди и возвращает xQueueHandle в качестве ссылки на созданную очередь.
Для создания очереди FreeRTOS выделяет память RAM из кучи (heap). RAM используется как для структур данных
очереди, так и для элементов, которые будут помещены в очередь или считаны из неё. В случае нехватки памяти
в heap RAM функция xQueueCreate() при попытке создания очереди вернет NULL. Часть 5 более подробно
рассматривает управление памятью heap.
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength,
unsigned portBASE_TYPE uxItemSize);
Параметры и значение возврата функции xQueueCreate()
Имя параметра
/
возвращаемое
значение
Описание
uxQueueLength
Максимальное количество элементов, которое можно сохранить в очереди в любой момент
времени.
uxItemSize Размер в байтах каждого элемента данных, который можно сохранить в очереди.
возвращаемое
значение
Если функция вернула не NULL, то значит очередь создана успешно. Возвращенная
величина в этом случае должна быть сохранена как хендл к созданной очереди.
API функции xQueueSendToBack() и xQueueSendToFront()
Как и можно ожидать, xQueueSendToBack() используется для отправки данных в конец (хвост) очереди, а
xQueueSendToFront() используется для отправки данных в начало (голову) очереди.
Функция xQueueSend() эквивалентна и полностью та же самая, что и xQueueSendToBack().
Никогда не делайте вызов xQueueSendToFront() или xQueueSendToBack() из процедуры обработчика прерывания
(ISR, Interrupt Service Routine). Вместо этого должны использоваться защищенные версии
xQueueSendToFrontFromISR() и xQueueSendToBackFromISR().
portBASE_TYPE xQueueSendToFront( xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait );
Листинг 30. Прототип API функции xQueueSendToFront()
portBASE_TYPE xQueueSendToBack( xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait );
Параметры и значение возврата функций xQueueSendToFront() и xQueueSendToBack()
Имя параметра
/
возвращаемое
значение
Описание
xQueue
Хендл очереди, в которую данные посылаются (записываются). Хендл очереди берут из
значения, которое вернула функция xQueueCreate() при создании очереди.
pvItemToQueue
Указатель на данные, которые копируются в очередь.
14
Размер каждого элемента очереди, который она может хранить, устанавливается при создании
очереди, таким образом это количество байт будет скопировано из памяти по указателю
pvItemToQueue в область хранения данных, принадлежащую очереди.
xTicksToWait
Максимальное количество времени, в течение которого задача должна оставаться в состоянии
Blocked в ожидании, пока не появится в очереди свободное место для записи (если очередь
уже заполнена).
Обе функции и xQueueSendToFront(), и xQueueSendToBack() сделают возврат немедленно,
если xTicksToWait указан 0 и если очередь уже заполнена.
Время блокировки указывается в периодах тика, поэтому абсолютное время ожидания зависит
от частоты следования тиков. Для преобразования времени в миллисекундах во время в тиках
может использоваться константа portTICK_RATE_MS.
Установка xTicksToWait в значение portMAX_DELAY приведет к тому, что задача будет ждать
бесконечно (таймаута разблокировки не будет), что обеспечивается установкой в 1 значения
INCLUDE_vTaskSuspend в файле FreeRTOSConfig.h.
возвращаемое
значение
Возможны две величины возврата:
1. pdPASS - вернется только тогда, когда данные успешно отправлены в очередь.
Если указано время блокировки (xTicksToWait было не равным 0), то возможно что вызвавшая
функцию задача помещается в состояние Blocked для ожидания появления свободного места в
очереди. В этом случае значение pdPASS будет возвращено, если в очереди появилось
свободное место до истечения времени блокировки.
2. errQUEUE_FULL - будет возвращено, если данные не были записаны в очередь, так как
очередь уже полностью заполнена.
Если указано время блокировки (xTicksToWait было не равным 0), то вызвавшая функцию
задача была помещена в состояние Blocked для ожидания, пока другая задача или обработчик
прерывания освободят место в очереди, но указанное время блокировки истекло, а свободное
место в очереди так и не появилось.
API функции xQueueReceive() и xQueuePeek()
Функция xQueueReceive() используется для приема (чтения) элемента из очереди. При этом принятый элемент
удаляется из очереди.
Функция xQueuePeek() используется для приема элемента из очереди без удаления элемента из очереди.
Функция xQueuePeek() читает элемент из головы очереди без модификации данных, которые сохранены в
очереди или, другими словами, без модификации порядка сохраненных данных в очереди (состояние очереди
остается неизменным).
Никогда не делайте вызов xQueueReceive() или xQueuePeek() из процедуры обработчика прерывания (ISR,
Interrupt Service Routine). Защищенная версия xQueueReceiveFromISR() описана в части 3.
portBASE_TYPE xQueueReceive( xQueueHandle xQueue,
const void * pvBuffer,
portTickType xTicksToWait );
portBASE_TYPE xQueuePeek ( xQueueHandle xQueue,
const void * pvBuffer,
portTickType xTicksToWait );
Параметры и значение возврата функций xQueueReceive() и xQueuePeek()
15
Имя параметра
/
возвращаемое
значение
Описание
xQueue
Хендл очереди, из которой данные принимаются (читаются). Хендл очереди берут из
значения, которое вернула функция xQueueCreate() при создании очереди.
pvBuffer
Указатель на память, куда будут копироваться принятые из очереди данные.
Размер каждого элемента данных (в байтах), которые хранит очередь, устанавливается при
создании очереди. Память, на которую указывает pvBuffer, должна быть в байтах объемом не
меньше размера одного элемента данных.
xTicksToWait
Максимальное количество времени, в течение которого задача должна оставаться в состоянии
Blocked в ожидании, пока не появится в очереди доступный для чтения элемент данных (если
очередь уже пуста).
Обе функции и xQueueReceive(), и xQueuePeek() сделают возврат немедленно, если
xTicksToWait указан 0 и если очередь уже пуста.
Время блокировки указывается в периодах тика, поэтому абсолютное время ожидания зависит
от частоты следования тиков. Для преобразования времени в миллисекундах во время в тиках
может использоваться константа portTICK_RATE_MS.
Установка xTicksToWait в значение portMAX_DELAY приведет к тому, что задача будет ждать
бесконечно (таймаута разблокировки не будет), что обеспечивается установкой в 1 значения
INCLUDE_vTaskSuspend в файле FreeRTOSConfig.h.
возвращаемое
значение
Возможны две величины возврата:
1. pdPASS - вернется только тогда, когда данные успешно прочитаны из очереди.
Если указано время блокировки (xTicksToWait было не равным 0), то возможно что вызвавшая
функцию задача помещается в состояние Blocked для ожидания появления доступного
элемента данных в очереди. В этом случае значение pdPASS будет возвращено, если в
очереди появился элемент до истечения времени блокировки.
2. errQUEUE_EMPTY - будет возвращено, если данные не были прочитаны из очереди, так как
очередь уже пуста.
Если указано время блокировки (xTicksToWait было не равным 0), то вызвавшая функцию
задача была помещена в состояние Blocked для ожидания, пока другая задача или обработчик
прерывания не запишут что-нибудь в очередь, но указанное время блокировки истекло, а
доступный для чтения элемент в очереди так и не появился.
API функция uxQueueMessagesWaiting()
Функция uxQueueMessagesWaiting() используется для опроса очереди на количество содержащихся в ней сейчас
элементов.
Никогда не вызывайте uxQueueMessagesWaiting() из процедуры обработчика прерывания (ISR, Interrupt Service
Routine). Вместо этого должна использоваться защищенная версия uxQueueMessagesWaitingFromISR().
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );
Параметры и значение возврата функции uxQueueMessagesWaiting()
16
Имя параметра
/
возвращаемое
значение
Описание
xQueue
Хендл очереди, которая опрашивается. Хендл очереди берут из значения, которое
вернула функция xQueueCreate() при создании очереди.
возвращаемое
значение
Количество элементов, которые сейчас находятся на хранении в очереди. Если функция
вернула 0, то очередь пуста.
Пример 10. Блокировка на приеме из очереди
Этот пример демонстрирует создание очереди, отправку данных в очередь из нескольких задач и прием данных
из очереди одной задачей. Очередь создается для размещения в себе данных типа long. Задачи, которые
отправляют данные в очередь, не указывают при этом время блокировки, а задача, которая принимает данные из
очереди, указывает время блокировки.
Приоритет задач, отправляющих данные в очередь, меньше, чем приоритет задачи, которая эти данные из
очереди принимает. Это означает, что очередь никогда не будет содержать в себе более одного элемента
данных, потому что как только данные будут отправлены в очередь, то сразу будет разблокирована
принимающая данные задача, вытеснит задачу, поместившую данные в очередь, и удалит данные из очереди -
очередь снова сразу станет пустой.
Листинг 34 показывает реализацию задачи, которая записывает в очередь. Будут созданы два экземпляра этой
задачи, один из которых будет постоянно записывать в очередь значение 100, а другой будет постоянно
записывать в ту же самую очередь значение 200. Параметр задачи используется для того, чтобы передать
каждому экземпляру задачи эти значения.
static void vSenderTask( void *pvParameters )
{
long lValueToSend;
portBASE_TYPE xStatus;
/* Будут созданы два экземпляра этой задачи, а величина, посылаемая
в очередь, будет передана в задачу через параметр задачи - благодаря
этому каждый экземпляр задачи будет использовать свое значение.
Очередь была создана для сохранения в себе значений с типом long, и
здесь делается приведение типа данных к требуемому. */
lValueToSend = ( long ) pvParameters;
/* Как и большинство других задач, эта задача реализована как
бесконечный цикл. */
for( ;; )
{
/* Отправка значения в очередь.
Первый параметр определяет очередь, в которую отправляются данные.
Очередь была создана до запуска шедулера, поэтому создание очереди
было до начала выполнения этой задачи.
Второй параметр - адрес посылаемых данных, в нашем случае это будет
адрес локальной переменной lValueToSend.
Третий параметр время блокировки – время, в котором задача должна
удерживаться в состоянии Blocked для ожидания появления свободного
места в очереди, если очередь уже полностью заполнена. В этом случае
время блокировки не указано, потому что по выбранному алгоритму работы
приложения очередь никода не будет содержать больше одного элемента
данных, и поэтому никогда не переполнится. */
xStatus = xQueueSendToBack( xQueue, &lValueToSend, 0 );
if( xStatus != pdPASS )
{
/* Операция отправки не завершена, потому что очередь была заполнена -
это должно означать ошибку, так как в нашем случае очередь никогда
не будет содержать больше одного элемента данных! */
vPrintString( "Could not send to the queue.rn" );
}
/* Разрешение выполняться для других задач, отправляющих данные
в очередь. Вызов taskYIELD() информирует шедулер, что сейчас сразу
17
нужно переключиться к другой задаче, а не поддерживать эту задачу в
состоянии Running до окончания текущего слайса времени. */
taskYIELD();
}
}
показана реализация задачи, которая принимает данные из очереди. Принимающая задача указывает время
блокировки 100 миллисекунд, на которые она войдет в состояние Blocked, пока либо данные не появятся в
очереди, либо не истекут 100 миллисекунд таймаута без появления данных. В нашем примере таймаут 100
миллисекунд никогда не произойдет, так как две задачи постоянно записывают данные в очередь.
static void vReceiverTask( void *pvParameters )
{
/* Декларирование переменной, которая будет хранить значения, принятые
из очереди. */
long lReceivedValue;
portBASE_TYPE xStatus;
const portTickType xTicksToWait = 100 / portTICK_RATE_MS;
/* Эта задача также определена как бесконечный цикл. */
for( ;; )
{
/* Этот опрос очереди всегда должен определять, что очередь пуста, потому
что эта задача будет немедленно удалять данные из очереди, которые туда
были только что записаны. */
if( uxQueueMessagesWaiting( xQueue ) != 0 )
{
//Печать "Очередь должна была быть пустой!"
vPrintString( "Queue should have been empty!rn" );
}
/* Прием данных из очереди.
Первый параметр определяет очередь, из которой данные будут прочитаны.
Очередь была создана перед запуском шедулера, и поэтому перед тем,
как эта задача запустится в первый раз.
Второй параметр - адрес буфера, в который принятые данные будут
помещены. В нашем случае здесь просто указан адрес переменной,
которая имеет нужный размер, чтобы удержать в себе принятые данные.
Последний параметр время блокировки – максимальное время, в котором
задача должна оставаться в состоянии Blocked, ожидая появления
данных на очереди. Здесь используется константа portTICK_RATE_MS
для преобразования 100 миллисекунд во время, указанное в тиках. */
xStatus = xQueueReceive( xQueue, &lReceivedValue, xTicksToWait );
if( xStatus == pdPASS )
{
/* Данные успешно приняты из очереди, печать принятого значения. */
vPrintStringAndNumber( "Received = ", lReceivedValue );
}
else
{
/* Данные не были приняты из очереди даже после ожидания 100 мс.
Это должно означать ошибку, так как отправляющие данные в очередь
задачи работают постоянно записывают данные в очередь. */
vPrintString( "Could not receive from the queue.rn" );
}
}
}
содержит код для функции main(). Она просто создает очередь и три задачи перед запуском шедулера. Очередь
создается для удержания в себе максимум 5 значений чисел типа long, с запасом - даже с учетом того, что
приоритеты задач настроены так, что очередь никогда не будет содержать в себе больше одного элемента в
любой момент времени.
/* Декларирование переменной типа xQueueHandle. Она используется для сохранения
ссылки на очередь, к которой будут обращаться все три задачи. */
xQueueHandle xQueue;
int main( void )
{
/* Очередь создается для удержания в себе до 5 элементов включительно, каждый
из элементов настолько велик, что его размер достаточен для хранения типа
18
long. */
xQueue = xQueueCreate( 5, sizeof( long ) );
if( xQueue != NULL )
{
/* Создание двух экземпляров задач, которые будут отправлять данные
в очередь. Параметр задачи используется для передачи значения,
которое будет писаться задачей в очередь, так что одна задача
будет постоянно записывать в очередь число 100, а другая задача
будет постоянно записывать число 200. Обе задачи создаются
с одинаковым приоритетом 1. */
xTaskCreate( vSenderTask, "Sender1", 1000, ( void * ) 100, 1, NULL );
xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL );
/* Создание задачи, которая будет читать из очереди. Задача создается
с приоритетом 2, что выше приоритета задач, помещающих данные
в очередь. */
xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL );
/* Запуск шедулера, после чего созданные задачи начнут выполняться. */
vTaskStartScheduler();
}
else
{
/* Очередь не может быть создана. */
}
/* Если все хорошо, то управление в main() никогда не дойдет до этой точки,
и теперь шедулер будет управлять задачами. Если main() довела управление
до этого места, то это может означать, что не хватает памяти кучи (heap)
для создания специальной задачи ожидания (idle task, об этой задаче
далее). Часть 5 предоставляет больше информации по управлению памятью. */
for( ;; );
}
19
xSemaphoreHandle BigMac;
BigMac = xSemaphoreCreateCounting( 100, 0 );
if(GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_SET) { xSemaphoreGive(BigMac); } osDelay(200);
xSemaphoreTake( BigMac, portMAX_DELAY);
GPIO_WritePin(GPIOE,GPIO_PIN_15,GPIO_PIN_RESET);

Contenu connexe

Tendances

МАИ, Сети ЭВМ, Лекция №4
МАИ, Сети ЭВМ, Лекция №4МАИ, Сети ЭВМ, Лекция №4
МАИ, Сети ЭВМ, Лекция №4Dima Dzuba
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
Объектно-ориентированное программирование. Лекции 15 и 16
Объектно-ориентированное программирование. Лекции 15 и 16Объектно-ориентированное программирование. Лекции 15 и 16
Объектно-ориентированное программирование. Лекции 15 и 16Dima Dzuba
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...Alexey Paznikov
 
Практика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-серверПрактика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-серверPlatonov Sergey
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...Alexey Paznikov
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...Alexey Paznikov
 
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresProit-people
 
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX ThreadsПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX ThreadsAlexey Paznikov
 
Григорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммыГригорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммыYandex
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыAlexey Paznikov
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Yauheni Akhotnikau
 
разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2Eugeniy Tyumentcev
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3Eugeniy Tyumentcev
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.Igor Shkulipa
 
Сладкое будущее: Phalcon и Zephir
Сладкое будущее: Phalcon и ZephirСладкое будущее: Phalcon и Zephir
Сладкое будущее: Phalcon и ZephirCodeFest
 
Статический анализ: ошибки в медиаплеере и безглючная аська
Статический анализ: ошибки в медиаплеере и безглючная аська Статический анализ: ошибки в медиаплеере и безглючная аська
Статический анализ: ошибки в медиаплеере и безглючная аська Tatyanazaxarova
 
Intel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибкамиIntel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибкамиTatyanazaxarova
 

Tendances (20)

МАИ, Сети ЭВМ, Лекция №4
МАИ, Сети ЭВМ, Лекция №4МАИ, Сети ЭВМ, Лекция №4
МАИ, Сети ЭВМ, Лекция №4
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Объектно-ориентированное программирование. Лекции 15 и 16
Объектно-ориентированное программирование. Лекции 15 и 16Объектно-ориентированное программирование. Лекции 15 и 16
Объектно-ориентированное программирование. Лекции 15 и 16
 
java
javajava
java
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
 
Практика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-серверПрактика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-сервер
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
 
Multimaster2
Multimaster2Multimaster2
Multimaster2
 
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro
 
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX ThreadsПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
 
Григорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммыГригорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммы
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.
 
Сладкое будущее: Phalcon и Zephir
Сладкое будущее: Phalcon и ZephirСладкое будущее: Phalcon и Zephir
Сладкое будущее: Phalcon и Zephir
 
Статический анализ: ошибки в медиаплеере и безглючная аська
Статический анализ: ошибки в медиаплеере и безглючная аська Статический анализ: ошибки в медиаплеере и безглючная аська
Статический анализ: ошибки в медиаплеере и безглючная аська
 
Intel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибкамиIntel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибками
 

En vedette

Ten things about GPS
Ten things about GPSTen things about GPS
Ten things about GPSMBrsoyan
 
Localization using filtered dgps
Localization using filtered dgpsLocalization using filtered dgps
Localization using filtered dgpseSAT Journals
 
Существующие и перспективные системы навигации (Борис Салтовский)
Существующие и перспективные системы навигации (Борис Салтовский)Существующие и перспективные системы навигации (Борис Салтовский)
Существующие и перспективные системы навигации (Борис Салтовский)IT Club Mykolayiv
 
платформа Microsoft Windows Embedded
платформа Microsoft Windows Embeddedплатформа Microsoft Windows Embedded
платформа Microsoft Windows EmbeddedLiudmila Li
 
Satellite Navigation. Present and Future
Satellite Navigation. Present and FutureSatellite Navigation. Present and Future
Satellite Navigation. Present and FutureNikolay Mikhaylov
 
Internet Of Things: возможности Intel Galileo gen 2 и Intel Edison
Internet Of Things: возможности Intel Galileo gen 2 и Intel EdisonInternet Of Things: возможности Intel Galileo gen 2 и Intel Edison
Internet Of Things: возможности Intel Galileo gen 2 и Intel EdisonCodeFest
 
истории успеха. январь 2014
истории успеха. январь 2014истории успеха. январь 2014
истории успеха. январь 2014The Skolkovo Foundation
 
Daniel Khachay - GPS navigation algorithm based on osm data
Daniel Khachay - GPS navigation algorithm based on osm dataDaniel Khachay - GPS navigation algorithm based on osm data
Daniel Khachay - GPS navigation algorithm based on osm dataAIST
 
Introduction of gps global navigation satellite systems
Introduction of gps   global navigation satellite systems Introduction of gps   global navigation satellite systems
Introduction of gps global navigation satellite systems DocumentStory
 
Global Positioning System
Global Positioning SystemGlobal Positioning System
Global Positioning SystemRishi Shukla
 
Global Positioning System
Global Positioning System Global Positioning System
Global Positioning System Varun B P
 
8086 microprocessor instruction set by Er. Swapnil Kaware
8086 microprocessor instruction set by Er. Swapnil Kaware8086 microprocessor instruction set by Er. Swapnil Kaware
8086 microprocessor instruction set by Er. Swapnil KawareProf. Swapnil V. Kaware
 

En vedette (20)

OSM to Garmin
OSM to GarminOSM to Garmin
OSM to Garmin
 
Ten things about GPS
Ten things about GPSTen things about GPS
Ten things about GPS
 
GLONASS forum
GLONASS forumGLONASS forum
GLONASS forum
 
Localization using filtered dgps
Localization using filtered dgpsLocalization using filtered dgps
Localization using filtered dgps
 
Pebble
PebblePebble
Pebble
 
Существующие и перспективные системы навигации (Борис Салтовский)
Существующие и перспективные системы навигации (Борис Салтовский)Существующие и перспективные системы навигации (Борис Салтовский)
Существующие и перспективные системы навигации (Борис Салтовский)
 
платформа Microsoft Windows Embedded
платформа Microsoft Windows Embeddedплатформа Microsoft Windows Embedded
платформа Microsoft Windows Embedded
 
Satellite Navigation. Present and Future
Satellite Navigation. Present and FutureSatellite Navigation. Present and Future
Satellite Navigation. Present and Future
 
Internet Of Things: возможности Intel Galileo gen 2 и Intel Edison
Internet Of Things: возможности Intel Galileo gen 2 и Intel EdisonInternet Of Things: возможности Intel Galileo gen 2 и Intel Edison
Internet Of Things: возможности Intel Galileo gen 2 и Intel Edison
 
era_27Nov2012
era_27Nov2012era_27Nov2012
era_27Nov2012
 
истории успеха. январь 2014
истории успеха. январь 2014истории успеха. январь 2014
истории успеха. январь 2014
 
Daniel Khachay - GPS navigation algorithm based on osm data
Daniel Khachay - GPS navigation algorithm based on osm dataDaniel Khachay - GPS navigation algorithm based on osm data
Daniel Khachay - GPS navigation algorithm based on osm data
 
Iltgel
IltgelIltgel
Iltgel
 
Introduction-of-GNSS-2
Introduction-of-GNSS-2Introduction-of-GNSS-2
Introduction-of-GNSS-2
 
Introduction of gps global navigation satellite systems
Introduction of gps   global navigation satellite systems Introduction of gps   global navigation satellite systems
Introduction of gps global navigation satellite systems
 
Global Positioning System
Global Positioning SystemGlobal Positioning System
Global Positioning System
 
Global Positioning System
Global Positioning System Global Positioning System
Global Positioning System
 
Theme 01
Theme 01Theme 01
Theme 01
 
8086 microprocessor instruction set by Er. Swapnil Kaware
8086 microprocessor instruction set by Er. Swapnil Kaware8086 microprocessor instruction set by Er. Swapnil Kaware
8086 microprocessor instruction set by Er. Swapnil Kaware
 
AUV based on EL - Copy
AUV based on EL - CopyAUV based on EL - Copy
AUV based on EL - Copy
 

Similaire à 9 free rtos

PostgreSQL Vacuum: Nine Circles of Hell
PostgreSQL Vacuum: Nine Circles of HellPostgreSQL Vacuum: Nine Circles of Hell
PostgreSQL Vacuum: Nine Circles of HellAlexey Lesovsky
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
Девять кругов ада или PostgreSQL Vacuum / Алексей Лесовский (PostgreSQL-Consu...
Девять кругов ада или PostgreSQL Vacuum / Алексей Лесовский (PostgreSQL-Consu...Девять кругов ада или PostgreSQL Vacuum / Алексей Лесовский (PostgreSQL-Consu...
Девять кругов ада или PostgreSQL Vacuum / Алексей Лесовский (PostgreSQL-Consu...Ontico
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Yandex
 
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.Anastasia Lubennikova
 
High Load 2009 Dimaa Rus Ready 16 9
High Load 2009 Dimaa Rus Ready 16 9High Load 2009 Dimaa Rus Ready 16 9
High Load 2009 Dimaa Rus Ready 16 9HighLoad2009
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1Michael Karpov
 
C++ весна 2014 лекция 2
C++ весна 2014 лекция 2C++ весна 2014 лекция 2
C++ весна 2014 лекция 2Technopark
 
Многопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиМногопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиDotNetConf
 
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложениеASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложениеAlexander Byndyu
 
C++ Базовый. Занятие 15.
C++ Базовый. Занятие 15.C++ Базовый. Занятие 15.
C++ Базовый. Занятие 15.Igor Shkulipa
 
Паттерны проектирования источников данных
Паттерны проектирования источников данныхПаттерны проектирования источников данных
Паттерны проектирования источников данныхAlex Polorotov
 
паттерны проектирования источников данных
паттерны проектирования источников данныхпаттерны проектирования источников данных
паттерны проектирования источников данныхVitaliy Trenkenshu
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода Pavel Tsukanov
 
Принципы проектирования S.O.L.I.D
Принципы проектирования S.O.L.I.DПринципы проектирования S.O.L.I.D
Принципы проектирования S.O.L.I.DAndreyGeonya
 
Alexander Dymo - Barcamp 2009 - Faster Higher Sql
Alexander Dymo - Barcamp 2009 - Faster Higher SqlAlexander Dymo - Barcamp 2009 - Faster Higher Sql
Alexander Dymo - Barcamp 2009 - Faster Higher SqlAlexander Dymo
 
Adymo Barcamp Presentation Faster Higher Sql
Adymo Barcamp Presentation Faster Higher SqlAdymo Barcamp Presentation Faster Higher Sql
Adymo Barcamp Presentation Faster Higher SqlOleksandr Petrov
 

Similaire à 9 free rtos (20)

PostgreSQL Vacuum: Nine Circles of Hell
PostgreSQL Vacuum: Nine Circles of HellPostgreSQL Vacuum: Nine Circles of Hell
PostgreSQL Vacuum: Nine Circles of Hell
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Девять кругов ада или PostgreSQL Vacuum / Алексей Лесовский (PostgreSQL-Consu...
Девять кругов ада или PostgreSQL Vacuum / Алексей Лесовский (PostgreSQL-Consu...Девять кругов ада или PostgreSQL Vacuum / Алексей Лесовский (PostgreSQL-Consu...
Девять кругов ада или PostgreSQL Vacuum / Алексей Лесовский (PostgreSQL-Consu...
 
Gradle
GradleGradle
Gradle
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
 
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
High Load 2009 Dimaa Rus Ready 16 9
High Load 2009 Dimaa Rus Ready 16 9High Load 2009 Dimaa Rus Ready 16 9
High Load 2009 Dimaa Rus Ready 16 9
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
 
C++ весна 2014 лекция 2
C++ весна 2014 лекция 2C++ весна 2014 лекция 2
C++ весна 2014 лекция 2
 
Многопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиМногопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметки
 
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложениеASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
 
C++ Базовый. Занятие 15.
C++ Базовый. Занятие 15.C++ Базовый. Занятие 15.
C++ Базовый. Занятие 15.
 
Паттерны проектирования источников данных
Паттерны проектирования источников данныхПаттерны проектирования источников данных
Паттерны проектирования источников данных
 
паттерны проектирования источников данных
паттерны проектирования источников данныхпаттерны проектирования источников данных
паттерны проектирования источников данных
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
Принципы проектирования S.O.L.I.D
Принципы проектирования S.O.L.I.DПринципы проектирования S.O.L.I.D
Принципы проектирования S.O.L.I.D
 
Alexander Dymo - Barcamp 2009 - Faster Higher Sql
Alexander Dymo - Barcamp 2009 - Faster Higher SqlAlexander Dymo - Barcamp 2009 - Faster Higher Sql
Alexander Dymo - Barcamp 2009 - Faster Higher Sql
 
Adymo Barcamp Presentation Faster Higher Sql
Adymo Barcamp Presentation Faster Higher SqlAdymo Barcamp Presentation Faster Higher Sql
Adymo Barcamp Presentation Faster Higher Sql
 

Plus de Sergey Savkin

8 lcd восьмое задание
8 lcd восьмое задание8 lcd восьмое задание
8 lcd восьмое заданиеSergey Savkin
 
7 usb седьмое задание
7 usb седьмое задание7 usb седьмое задание
7 usb седьмое заданиеSergey Savkin
 
детали к 7 занятию
детали к 7 занятиюдетали к 7 занятию
детали к 7 занятиюSergey Savkin
 
6 i2c spi шестое занятие
6 i2c spi шестое занятие6 i2c spi шестое занятие
6 i2c spi шестое занятиеSergey Savkin
 
детали к 6 занятию
детали к 6 занятиюдетали к 6 занятию
детали к 6 занятиюSergey Savkin
 
домашнее задание к 5 уроку
домашнее задание к 5 урокудомашнее задание к 5 уроку
домашнее задание к 5 урокуSergey Savkin
 
Детали и комплекты для четвертого занятия.
Детали и комплекты для четвертого занятия.Детали и комплекты для четвертого занятия.
Детали и комплекты для четвертого занятия.Sergey Savkin
 
домашнее задание к 4 уроку
домашнее задание к 4 урокудомашнее задание к 4 уроку
домашнее задание к 4 урокуSergey Savkin
 
Домашнее задание к 3 уроку
Домашнее задание к 3 урокуДомашнее задание к 3 уроку
Домашнее задание к 3 урокуSergey Savkin
 
Детали и комплекты для воторого занятия.
Детали и комплекты для воторого занятия.Детали и комплекты для воторого занятия.
Детали и комплекты для воторого занятия.Sergey Savkin
 
1.stm32 core flash rcc
1.stm32 core flash rcc1.stm32 core flash rcc
1.stm32 core flash rccSergey Savkin
 
STM32 Быстрый старт!
STM32 Быстрый старт!STM32 Быстрый старт!
STM32 Быстрый старт!Sergey Savkin
 

Plus de Sergey Savkin (16)

10 sdio
10 sdio10 sdio
10 sdio
 
8 lcd восьмое задание
8 lcd восьмое задание8 lcd восьмое задание
8 lcd восьмое задание
 
7 usb седьмое задание
7 usb седьмое задание7 usb седьмое задание
7 usb седьмое задание
 
детали к 7 занятию
детали к 7 занятиюдетали к 7 занятию
детали к 7 занятию
 
6 i2c spi шестое занятие
6 i2c spi шестое занятие6 i2c spi шестое занятие
6 i2c spi шестое занятие
 
детали к 6 занятию
детали к 6 занятиюдетали к 6 занятию
детали к 6 занятию
 
5 i2c spi
5 i2c spi5 i2c spi
5 i2c spi
 
домашнее задание к 5 уроку
домашнее задание к 5 урокудомашнее задание к 5 уроку
домашнее задание к 5 уроку
 
Детали и комплекты для четвертого занятия.
Детали и комплекты для четвертого занятия.Детали и комплекты для четвертого занятия.
Детали и комплекты для четвертого занятия.
 
домашнее задание к 4 уроку
домашнее задание к 4 урокудомашнее задание к 4 уроку
домашнее задание к 4 уроку
 
3 stm32 nvic tim
3 stm32 nvic tim3 stm32 nvic tim
3 stm32 nvic tim
 
Домашнее задание к 3 уроку
Домашнее задание к 3 урокуДомашнее задание к 3 уроку
Домашнее задание к 3 уроку
 
2 stm32 gpio
2 stm32 gpio2 stm32 gpio
2 stm32 gpio
 
Детали и комплекты для воторого занятия.
Детали и комплекты для воторого занятия.Детали и комплекты для воторого занятия.
Детали и комплекты для воторого занятия.
 
1.stm32 core flash rcc
1.stm32 core flash rcc1.stm32 core flash rcc
1.stm32 core flash rcc
 
STM32 Быстрый старт!
STM32 Быстрый старт!STM32 Быстрый старт!
STM32 Быстрый старт!
 

9 free rtos

  • 1. 1
  • 2. 2
  • 3. 3 void ATaskFunction( void *pvParameters ) { /* Переменные могут быть определены точно так же, как и в обычной функции. Каждый экземпляр созданной по этой функции задачи будет иметь собственную копию переменной iVariableExample. Это не верно, если переменная была продекларирована как статическая (static) – в этом случае будет существовать только одна копия переменной, и она будет использоваться совместно всеми созданными экземплярами задачи. */ int iVariableExample = 0; /* Задача должна быть нормально реализована как бесконечный цикл. */ for( ;; ) { /* Код, который реализует функционал задачи, должен быть помещен здесь. */ } /* Код должен быть организован так, чтобы в случае выхода (break) из указанного выше бесконечного цикла задачи, задача должна быть удалена ПРЕЖДЕ чем управление достигнет конца этой функции. Параметр NULL, переданный vTaskDelete(), показывает, что должна быть удалена вызванная (эта, которая работает) задача. */ vTaskDelete( NULL ); } portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask ); Параметры и значение возврата функции xTaskCreate() Имя параметра / возвращаемое значение Описание pvTaskCode Задачи - это простые C-функции, которые никогда не делают возврата из своего тела (постоянно выполняют свой бесконечный цикл). Параметр pvTaskCode - простой указатель на функцию (т. е. просто имя функции), которая реализует задачу. pcName Описательное имя для задачи. Оно никак не используется внутри FreeRTOS, и нужно только для целей отладки. Идентификация задачи по легкочитаемому имени намного проще, чем по хендлу задачи (handle). В приложении указана константа времени компиляции configMAX_TASK_NAME_LEN, которая задает максимальную длину для этого имени - включая нулевой байт окончания строки. Если в качестве pcName предоставлена более длинная строка, то она молча урезается до величины, заданной configMAX_TASK_NAME_LEN. usStackDepth Каждая задача имеет собственное уникальное хранилище состояния, выделенное ядром при создании задачи. Значение параметра usStackDepth говорит ядру, какой величины стек необходимо создать. Значение usStackDepth указывает количество слов, которое можно сохранить в стеке, а не количество байт. Например, если стек имеет ширину 32 бита, и переданное значение usStackDepth равно 100, то под стек будет выделено 400 байт (100 * 4 байт). Глубина стека, умноженная на его ширину, не должна превышать максимальное значение, которое может содержать переменная типа size_t. Размер стека, используемого для задачи ожидания (idle task, об этой задаче подробнее
  • 4. 4 говорится далее), задается константой configMINIMAL_STACK_SIZE. Значение, назначенное этой константе в демо-приложении FreeRTOS (для определенной архитектуры микроконтроллера) может быть использовано как минимально рекомендованное для любой задачи. Если Ваша программа использует пространство в стеке, то нужно указать для константы configMINIMAL_STACK_SIZE увеличенное значение. Нет простого способа узнать, какого размера стек нужен для задачи. Этот размер можно вычислить, но в большинстве случаев можно просто назначить подходящее значение, подобранное опытным путем, либо взятое приблизительно. Подобрать правильный размер стека важно, чтобы обеспечить адекватное использование RAM без ненужных затрат. Часть 6 содержит информацию о том, как запросить размер стека, используемого задачей. pvParameters Функции задач принимают параметр, имеющий тип указателя на void (т. е. void*). Значение, указанное в pvParameters, будет передано в задачу. Несколько примеров в этом документе демонстрируют, как этот параметр может быть использован в реальных задачах. uxPriority Задает приоритет, с которым будет выполняться задача. Приоритеты могут быть назначены в любое значение от 0 минимальный приоритет до (configMAX_PRIORITIES – 1) максимальный приоритет. Константа configMAX_PRIORITIES определяется пользователем. Нет ограничения на верхний предел для количества приоритетов, которые можно задать (кроме ограничения на лимит используемого типа данных ограничения по количеству RAM, доступному в микроконтроллере), но желательно использовать как можно меньшее количество приоритетов, которое действительно необходимо - с целью уменьшения расхода RAM. Передача в параметре значения uxPriority выше (configMAX_PRIORITIES – 1) приведет к молчаливому назначению приоритета задачи в максимально допустимое значение configMAX_PRIORITIES. pxCreatedTask Параметр pxCreatedTask может использоваться для передачи наружу хендла созданной задачи. Этот хендл можно использовать как ссылку на задачу в вызовах API FreeRTOS, например для изменения приоритета задачи или для удаления задачи. Если Ваше приложение не использует хендл задачи, то pxCreatedTask может быть установлен в NULL. Возвращаемое значение Имеется два возможных возвращаемых значения: 1. pdTRUE показывает, что задача успешно создана. 2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY показывает, что задача не создана, так как в куче (heap) недостаточно свободной памяти для FreeRTOS, чтобы она могла выделить место для структур данных задачи и стека. Часть 5 предоставляет больше информации по управлению памятью. int main( void ) { /* Создание одной из двух задач. Имейте в виду, что реальное приложение должно проверить возвращаемое значение из вызова xTaskCreate(), чтобы удостовериться, что задача была успешно создана. */ xTaskCreate( vTask1, /* Указатель на функцию, которая реализует задачу. */ "Task 1",/* Текстовое имя задачи. Этот параметр нужен только для упрощения отладки. */ 1000, /* Глубина стека - самые маленькие микроконтроллеры будут использовать значение намного меньше, чем здесь указано. */ NULL, /* Мы не используем параметр задачи. */ 1, /* Задача будет запущена с приоритетом 1. */ NULL ); /* Мы не будем использовать хендл задачи. */ /* Создание другой задачи полностью совпадает с созданием первой, приоритет задачи тот же. */ xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL ); /* Запуск шедулера, после чего задачи запустятся на выполнение. */ vTaskStartScheduler();
  • 5. 5 /* Если все хорошо, то управление в main() никогда не дойдет до этой точки, и теперь шедулер будет управлять задачами. Если main() довела управление до этого места, то это может означать, что не хватает памяти кучи (heap) для создания специальной задачи ожидания (idle task, об этой задаче далее). Часть 5 предоставляет больше информации по управлению памятью. */ for( ;; ); } void vTaskFunction( void *pvParameters ) { char *pcTaskName; volatile unsigned long ul; /* Строка для вывода на печать передается через параметр. Здесь он преобразуется в указатель на символьную строку. */ pcTaskName = ( char * ) pvParameters; /* Как и большинство задач, эта задача реализована на основе бесконечного цикла. */ for( ;; ) { /* Вывод на печать имени этой задачи. */ vPrintString( pcTaskName ); /* Задержка на некоторый период времени. */ for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { /* Этот цикл просто реализует задержку очень грубым методом. В цикле не производится никаких действий. Далее будут приведены примеры, в которых этот пустой цикл будет заменен соответствующей функцией задержки / приостановки задачи (введение задачи в состояние сна - sleep). */ } } }
  • 6. 6 void vTaskDelay( portTickType xTicksToDelay ); Параметры функции vTaskDelay() Имя параметра Описание xTicksToDelay Количество тиков прерываний, в течение которых вызывающая задача должна оставаться в состоянии Blocked перед переходом обратно в состояние Ready. Например, если задача сделала вызов vTaskDelay( 100 ), а счетчик тиков (системная переменная FreeRTOS) при этом был равен 10000, то задача немедленно войдет в состояние Blocked и останется в нем до тех пор, пока счетчик тиков не достигнет 10100. Константа portTICK_RATE_MS может использоваться для преобразования миллисекунд в тики. void vTaskFunction( void *pvParameters ) { char *pcTaskName; /* Строка для вывода на печать, переданная через параметр. Здесь параметр преобразуется в указатель на строку. */ pcTaskName = ( char * ) pvParameters; /* Как и большинство других задач, эта задача реализована как бесконечный цикл. */ for( ;; ) { /* Печать имени этой задачи. */ vPrintString( pcTaskName ); /* Задержка на некоторый период времени. Эта задержка создается благодаря использованию вызова vTaskDelay(), которым задача помещается в состояние Blocked до истечения периода задержки. Период задержки указывается в 'тиках', но можно использовать константу portTICK_RATE_MS для преобразования (более удобной для пользователя) величины миллисекунд в тики. В нашем случае указан период 250 миллисекунд. */ vTaskDelay( 250 / portTICK_RATE_MS ); }
  • 7. 7 }
  • 8. 8 Функция vTaskDelayUntil() работает аналогично vTaskDelay(). Как было продемонстрировано, параметр функции vTaskDelay() указывает количество тиков прерываний, которые должны произойти между вызовом из задачи vTaskDelay() и моментом времени, когда та же самая задача выйдет снова из состояния Blocked. Величина времени, в течение которого задача остается заблокированной, указывается в параметре vTaskDelay(), но реальное время, в которое задача покинет заблокированное состояние, отсчитывается относительно времени, когда был произведен вызов vTaskDelay(). Вместо этого в параметре функции vTaskDelayUntil() указывается явное значение счетчика тиков, на котором вызывающая эту функцию задача должна перейти из состояние Blocked в состояние Ready. API функция vTaskDelayUntil() должна использоваться, когда требуется фиксированный период выполнения задачи (например, Вы хотите, чтобы задача выполнялась периодически с фиксированной частотой). Так как время разблокировки вызывающей задачи является абсолютным (в отличие от относительного, отсчитываемого от вызова функции, как в случае с vTaskDelay()). void vTaskDelayUntil( portTickType * pxPreviousWakeTime, portTickType xTimeIncrement ); Параметры функции vTaskDelayUntil() Имя параметра Описание pxPreviousWakeTime Этот параметр поименован так из предположения, что vTaskDelayUntil() выполняется периодически и с фиксированной частотой. В этом случае переменная, на которую указывает pxPreviousWakeTime, удерживает время, в которое задача покинула состояние Blocked (т. е. время, когда задача 'проснулась'). Это время используется как точка отсчета для вычисления момента времени, когда произойдет следующий выход из состояния Blocked. Переменная, на которую указывает pxPreviousWakeTime, обновляется автоматически внутри функции vTaskDelayUntil(), и она обычно не должна быть модифицирована кодом приложения за исключением первоначальной инициализации. В листинге 14 показано, как это нужно делать. xTimeIncrement Этот параметр также поименован в предположении, что функция vTaskDelayUntil() используется для реализации, которая выполняется периодически и с фиксированной частотой - частота устанавливается значением параметра xTimeIncrement. Величина xTimeIncrement указывается в 'тиках'. Можно использовать константу portTICK_RATE_MS для преобразования миллисекунд в тики. void vTaskFunction( void *pvParameters ) { char *pcTaskName; portTickType xLastWakeTime; /* Строка для вывода на печать, переданная через параметр. Здесь параметр преобразуется в указатель на строку. */ pcTaskName = ( char * ) pvParameters; /* Переменная xLastWakeTime нуждается в инициализации текущим значением счетчика тиков. Имейте в виду, переменная записывается явно только в этот момент. Затем xLastWakeTime обновляется автоматически внутри функции vTaskDelayUntil(). */ xLastWakeTime = xTaskGetTickCount(); /* Как и большинство других задач, эта задача реализована как бесконечный цикл. */ for( ;; ) { /* Печать имени этой задачи. */ vPrintString( pcTaskName ); /* Эта задача должна выполняться точно каждые 250 миллисекунд. Как и в функции vTaskDelay(), время измеряется в тиках, и константа portTICK_RATE_MS используется для преобразования миллисекунд в тики. Переменная xLastWakeTime автоматически обновляется внутри функции vTaskDelayUntil(), и нигде явно в коде задачи переменная xLastWakeTime не обновляется. */ vTaskDelayUntil( &xLastWakeTime, ( 250 / portTICK_RATE_MS ) ); } }
  • 9. 9 Функции IDLE TASK HOOK В задачу Idle Task можно добавить функционал приложения пользователя. Это делается через функцию хука Idle (иначе её называют callback-функцией) - она автоматически будет вызываться изнутри Idle Task, каждый раз в цикле ожидания. Можно использовать Idle Task hook следующим образом: · Выполнение низкоприоритетных задач в фоновом режиме, или продолжительные обработки данных. · Измерение свободного процессорного времени (т. е. загруженности процессора) - задача Idle Task будет работать только тогда, когда все другие задачи не выполняют свою работу (им нечего делать), поэтому измерение процессорного времени, выделенного на Idle Task, явно показывает, сколько процессорного времени имеется в запасе. · Перевод процессора в режим пониженного энергопотребления - предоставление автоматического метода сохранения энергии, когда приложением не выполняется полезная обработка данных. Ограничения, связанные с использованием функций Idle Task hook Функции Idle Task hook должны удовлетворять следующим правилам: 1. Они никогда не должны делать попыток приостановки (переход в состояние Suspended) или блокировки (переход в состояние Blocked). Задача Idle Task будет выполняться только тогда, когда другим задачам нечего делать (за исключением тех случаев, когда задачи приложения имеют тот же приоритет, что и Idle Task). Поэтому блокировка Idle Task приведет к тому, что не будет ни одной задачи, которая могла бы войти в состояние Running! 2. Если приложение использует вызовы API функции vTaskDelete(), то функция Idle Task hook должна всегда быть завершена в течение подходящего периода времени. Причина этого в том, что задача Idle Task отвечает за очистку ресурсов ядра после удаления задачи. Если управление потоком выполнения Idle Task остается постоянно в коде Idle Task hook, то тогда очистка не может быть выполнена. void vApplicationIdleHook( void ); Имя и прототип функции хука задачи ожидания (Idle Task hook) Определение функции Idle Task hook Использование блокирующих вызовов API функции vTaskDelay() в примере 4 создает некоторый интервал времени ожидания - в это время выполняется задача Idle Task, так как обе задачи приложения находятся в состоянии Blocked. /* Определение переменной, которая будет инкрементирована функцией хука. */ unsigned long ulIdleCycleCount = 0UL; /* Функции хука Idle ДОЛЖНЫ называться vApplicationIdleHook(), не принимать никаких параметров, и возвращать void. */ void vApplicationIdleHook( void ) { /* Эта функция хука ничего не делает, кроме инкрементирования счетчика. */ ulIdleCycleCount++; } Очень простой пример функции Idle Task hook Чтобы функция Idle Task hook vApplicationIdleHook вызывалась, в файле FreeRTOSConfig.h нужно установить в 1 макрос configUSE_IDLE_HOOK. void vTaskFunction( void *pvParameters ) { char *pcTaskName;
  • 10. 10 /* Строка для вывода на печать, переданная через параметр. Здесь параметр преобразуется в указатель на строку. */ pcTaskName = ( char * ) pvParameters; /* Как и большинство других задач, эта задача реализована как бесконечный цикл. */ for( ;; ) { /* Печать имени этой задачи и количества инкрементов переменной ulIdleCycleCount. */ vPrintStringAndNumber( pcTaskName, ulIdleCycleCount ); /* Задержка на 250 миллисекунд. */ vTaskDelay( 250 / portTICK_RATE_MS ); } }
  • 11. 11 API функция vTaskPrioritySet() Для изменения приоритета любой задачи после старта шедулера может быть использована API функция vTaskPrioritySet(). void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ); Параметры функции vTaskPrioritySet() Имя параметра Описание pxTask Хендл задачи (субъект задачи), у которой будет изменен приоритет - см. параметр pxCreatedTask функции API xTaskCreate() для более подробной информации по получению хендлов для задач. Задача может изменить собственный приоритет путем передачи NULL вместо действительного хендла задачи. uxNewPriority Приоритет, в который будет установлен субъект задачи. Значение, переданное в этом параметре, автоматически ограничивается величиной максимально доступного приоритета (configMAX_PRIORITIES – 1), где configMAX_PRIORITIES опция времени компиляции, установленная в заголовочном файле FreeRTOSConfig.h. API функция uxTaskPriorityGet() Для получения текущего приоритета задачи может быть использована API функция uxTaskPriorityGet(). unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ); Параметры и значение возврата функции uxTaskPriorityGet() Имя параметра / возвращаемое значение Описание pxTask Хендл задачи, приоритет которой запрашивается - см. параметр pxCreatedTask функции API xTaskCreate() для более подробной информации по получению хендлов для задач. Задача может запросить собственный приоритет путем передачи NULL вместо действительного хендла задачи. Возвращаемое значение Значение запрошенного приоритета, который в настоящий момент назначен задаче.
  • 12. 12
  • 13. 13 Использование очереди] API функция xQueueCreate() Очередь перед использованием должна быть явно создана. Обращение к очереди происходит через переменную типа xQueueHandle. Функция xQueueCreate() используется для создания очереди и возвращает xQueueHandle в качестве ссылки на созданную очередь. Для создания очереди FreeRTOS выделяет память RAM из кучи (heap). RAM используется как для структур данных очереди, так и для элементов, которые будут помещены в очередь или считаны из неё. В случае нехватки памяти в heap RAM функция xQueueCreate() при попытке создания очереди вернет NULL. Часть 5 более подробно рассматривает управление памятью heap. xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize); Параметры и значение возврата функции xQueueCreate() Имя параметра / возвращаемое значение Описание uxQueueLength Максимальное количество элементов, которое можно сохранить в очереди в любой момент времени. uxItemSize Размер в байтах каждого элемента данных, который можно сохранить в очереди. возвращаемое значение Если функция вернула не NULL, то значит очередь создана успешно. Возвращенная величина в этом случае должна быть сохранена как хендл к созданной очереди. API функции xQueueSendToBack() и xQueueSendToFront() Как и можно ожидать, xQueueSendToBack() используется для отправки данных в конец (хвост) очереди, а xQueueSendToFront() используется для отправки данных в начало (голову) очереди. Функция xQueueSend() эквивалентна и полностью та же самая, что и xQueueSendToBack(). Никогда не делайте вызов xQueueSendToFront() или xQueueSendToBack() из процедуры обработчика прерывания (ISR, Interrupt Service Routine). Вместо этого должны использоваться защищенные версии xQueueSendToFrontFromISR() и xQueueSendToBackFromISR(). portBASE_TYPE xQueueSendToFront( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait ); Листинг 30. Прототип API функции xQueueSendToFront() portBASE_TYPE xQueueSendToBack( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait ); Параметры и значение возврата функций xQueueSendToFront() и xQueueSendToBack() Имя параметра / возвращаемое значение Описание xQueue Хендл очереди, в которую данные посылаются (записываются). Хендл очереди берут из значения, которое вернула функция xQueueCreate() при создании очереди. pvItemToQueue Указатель на данные, которые копируются в очередь.
  • 14. 14 Размер каждого элемента очереди, который она может хранить, устанавливается при создании очереди, таким образом это количество байт будет скопировано из памяти по указателю pvItemToQueue в область хранения данных, принадлежащую очереди. xTicksToWait Максимальное количество времени, в течение которого задача должна оставаться в состоянии Blocked в ожидании, пока не появится в очереди свободное место для записи (если очередь уже заполнена). Обе функции и xQueueSendToFront(), и xQueueSendToBack() сделают возврат немедленно, если xTicksToWait указан 0 и если очередь уже заполнена. Время блокировки указывается в периодах тика, поэтому абсолютное время ожидания зависит от частоты следования тиков. Для преобразования времени в миллисекундах во время в тиках может использоваться константа portTICK_RATE_MS. Установка xTicksToWait в значение portMAX_DELAY приведет к тому, что задача будет ждать бесконечно (таймаута разблокировки не будет), что обеспечивается установкой в 1 значения INCLUDE_vTaskSuspend в файле FreeRTOSConfig.h. возвращаемое значение Возможны две величины возврата: 1. pdPASS - вернется только тогда, когда данные успешно отправлены в очередь. Если указано время блокировки (xTicksToWait было не равным 0), то возможно что вызвавшая функцию задача помещается в состояние Blocked для ожидания появления свободного места в очереди. В этом случае значение pdPASS будет возвращено, если в очереди появилось свободное место до истечения времени блокировки. 2. errQUEUE_FULL - будет возвращено, если данные не были записаны в очередь, так как очередь уже полностью заполнена. Если указано время блокировки (xTicksToWait было не равным 0), то вызвавшая функцию задача была помещена в состояние Blocked для ожидания, пока другая задача или обработчик прерывания освободят место в очереди, но указанное время блокировки истекло, а свободное место в очереди так и не появилось. API функции xQueueReceive() и xQueuePeek() Функция xQueueReceive() используется для приема (чтения) элемента из очереди. При этом принятый элемент удаляется из очереди. Функция xQueuePeek() используется для приема элемента из очереди без удаления элемента из очереди. Функция xQueuePeek() читает элемент из головы очереди без модификации данных, которые сохранены в очереди или, другими словами, без модификации порядка сохраненных данных в очереди (состояние очереди остается неизменным). Никогда не делайте вызов xQueueReceive() или xQueuePeek() из процедуры обработчика прерывания (ISR, Interrupt Service Routine). Защищенная версия xQueueReceiveFromISR() описана в части 3. portBASE_TYPE xQueueReceive( xQueueHandle xQueue, const void * pvBuffer, portTickType xTicksToWait ); portBASE_TYPE xQueuePeek ( xQueueHandle xQueue, const void * pvBuffer, portTickType xTicksToWait ); Параметры и значение возврата функций xQueueReceive() и xQueuePeek()
  • 15. 15 Имя параметра / возвращаемое значение Описание xQueue Хендл очереди, из которой данные принимаются (читаются). Хендл очереди берут из значения, которое вернула функция xQueueCreate() при создании очереди. pvBuffer Указатель на память, куда будут копироваться принятые из очереди данные. Размер каждого элемента данных (в байтах), которые хранит очередь, устанавливается при создании очереди. Память, на которую указывает pvBuffer, должна быть в байтах объемом не меньше размера одного элемента данных. xTicksToWait Максимальное количество времени, в течение которого задача должна оставаться в состоянии Blocked в ожидании, пока не появится в очереди доступный для чтения элемент данных (если очередь уже пуста). Обе функции и xQueueReceive(), и xQueuePeek() сделают возврат немедленно, если xTicksToWait указан 0 и если очередь уже пуста. Время блокировки указывается в периодах тика, поэтому абсолютное время ожидания зависит от частоты следования тиков. Для преобразования времени в миллисекундах во время в тиках может использоваться константа portTICK_RATE_MS. Установка xTicksToWait в значение portMAX_DELAY приведет к тому, что задача будет ждать бесконечно (таймаута разблокировки не будет), что обеспечивается установкой в 1 значения INCLUDE_vTaskSuspend в файле FreeRTOSConfig.h. возвращаемое значение Возможны две величины возврата: 1. pdPASS - вернется только тогда, когда данные успешно прочитаны из очереди. Если указано время блокировки (xTicksToWait было не равным 0), то возможно что вызвавшая функцию задача помещается в состояние Blocked для ожидания появления доступного элемента данных в очереди. В этом случае значение pdPASS будет возвращено, если в очереди появился элемент до истечения времени блокировки. 2. errQUEUE_EMPTY - будет возвращено, если данные не были прочитаны из очереди, так как очередь уже пуста. Если указано время блокировки (xTicksToWait было не равным 0), то вызвавшая функцию задача была помещена в состояние Blocked для ожидания, пока другая задача или обработчик прерывания не запишут что-нибудь в очередь, но указанное время блокировки истекло, а доступный для чтения элемент в очереди так и не появился. API функция uxQueueMessagesWaiting() Функция uxQueueMessagesWaiting() используется для опроса очереди на количество содержащихся в ней сейчас элементов. Никогда не вызывайте uxQueueMessagesWaiting() из процедуры обработчика прерывания (ISR, Interrupt Service Routine). Вместо этого должна использоваться защищенная версия uxQueueMessagesWaitingFromISR(). unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue ); Параметры и значение возврата функции uxQueueMessagesWaiting()
  • 16. 16 Имя параметра / возвращаемое значение Описание xQueue Хендл очереди, которая опрашивается. Хендл очереди берут из значения, которое вернула функция xQueueCreate() при создании очереди. возвращаемое значение Количество элементов, которые сейчас находятся на хранении в очереди. Если функция вернула 0, то очередь пуста. Пример 10. Блокировка на приеме из очереди Этот пример демонстрирует создание очереди, отправку данных в очередь из нескольких задач и прием данных из очереди одной задачей. Очередь создается для размещения в себе данных типа long. Задачи, которые отправляют данные в очередь, не указывают при этом время блокировки, а задача, которая принимает данные из очереди, указывает время блокировки. Приоритет задач, отправляющих данные в очередь, меньше, чем приоритет задачи, которая эти данные из очереди принимает. Это означает, что очередь никогда не будет содержать в себе более одного элемента данных, потому что как только данные будут отправлены в очередь, то сразу будет разблокирована принимающая данные задача, вытеснит задачу, поместившую данные в очередь, и удалит данные из очереди - очередь снова сразу станет пустой. Листинг 34 показывает реализацию задачи, которая записывает в очередь. Будут созданы два экземпляра этой задачи, один из которых будет постоянно записывать в очередь значение 100, а другой будет постоянно записывать в ту же самую очередь значение 200. Параметр задачи используется для того, чтобы передать каждому экземпляру задачи эти значения. static void vSenderTask( void *pvParameters ) { long lValueToSend; portBASE_TYPE xStatus; /* Будут созданы два экземпляра этой задачи, а величина, посылаемая в очередь, будет передана в задачу через параметр задачи - благодаря этому каждый экземпляр задачи будет использовать свое значение. Очередь была создана для сохранения в себе значений с типом long, и здесь делается приведение типа данных к требуемому. */ lValueToSend = ( long ) pvParameters; /* Как и большинство других задач, эта задача реализована как бесконечный цикл. */ for( ;; ) { /* Отправка значения в очередь. Первый параметр определяет очередь, в которую отправляются данные. Очередь была создана до запуска шедулера, поэтому создание очереди было до начала выполнения этой задачи. Второй параметр - адрес посылаемых данных, в нашем случае это будет адрес локальной переменной lValueToSend. Третий параметр время блокировки – время, в котором задача должна удерживаться в состоянии Blocked для ожидания появления свободного места в очереди, если очередь уже полностью заполнена. В этом случае время блокировки не указано, потому что по выбранному алгоритму работы приложения очередь никода не будет содержать больше одного элемента данных, и поэтому никогда не переполнится. */ xStatus = xQueueSendToBack( xQueue, &lValueToSend, 0 ); if( xStatus != pdPASS ) { /* Операция отправки не завершена, потому что очередь была заполнена - это должно означать ошибку, так как в нашем случае очередь никогда не будет содержать больше одного элемента данных! */ vPrintString( "Could not send to the queue.rn" ); } /* Разрешение выполняться для других задач, отправляющих данные в очередь. Вызов taskYIELD() информирует шедулер, что сейчас сразу
  • 17. 17 нужно переключиться к другой задаче, а не поддерживать эту задачу в состоянии Running до окончания текущего слайса времени. */ taskYIELD(); } } показана реализация задачи, которая принимает данные из очереди. Принимающая задача указывает время блокировки 100 миллисекунд, на которые она войдет в состояние Blocked, пока либо данные не появятся в очереди, либо не истекут 100 миллисекунд таймаута без появления данных. В нашем примере таймаут 100 миллисекунд никогда не произойдет, так как две задачи постоянно записывают данные в очередь. static void vReceiverTask( void *pvParameters ) { /* Декларирование переменной, которая будет хранить значения, принятые из очереди. */ long lReceivedValue; portBASE_TYPE xStatus; const portTickType xTicksToWait = 100 / portTICK_RATE_MS; /* Эта задача также определена как бесконечный цикл. */ for( ;; ) { /* Этот опрос очереди всегда должен определять, что очередь пуста, потому что эта задача будет немедленно удалять данные из очереди, которые туда были только что записаны. */ if( uxQueueMessagesWaiting( xQueue ) != 0 ) { //Печать "Очередь должна была быть пустой!" vPrintString( "Queue should have been empty!rn" ); } /* Прием данных из очереди. Первый параметр определяет очередь, из которой данные будут прочитаны. Очередь была создана перед запуском шедулера, и поэтому перед тем, как эта задача запустится в первый раз. Второй параметр - адрес буфера, в который принятые данные будут помещены. В нашем случае здесь просто указан адрес переменной, которая имеет нужный размер, чтобы удержать в себе принятые данные. Последний параметр время блокировки – максимальное время, в котором задача должна оставаться в состоянии Blocked, ожидая появления данных на очереди. Здесь используется константа portTICK_RATE_MS для преобразования 100 миллисекунд во время, указанное в тиках. */ xStatus = xQueueReceive( xQueue, &lReceivedValue, xTicksToWait ); if( xStatus == pdPASS ) { /* Данные успешно приняты из очереди, печать принятого значения. */ vPrintStringAndNumber( "Received = ", lReceivedValue ); } else { /* Данные не были приняты из очереди даже после ожидания 100 мс. Это должно означать ошибку, так как отправляющие данные в очередь задачи работают постоянно записывают данные в очередь. */ vPrintString( "Could not receive from the queue.rn" ); } } } содержит код для функции main(). Она просто создает очередь и три задачи перед запуском шедулера. Очередь создается для удержания в себе максимум 5 значений чисел типа long, с запасом - даже с учетом того, что приоритеты задач настроены так, что очередь никогда не будет содержать в себе больше одного элемента в любой момент времени. /* Декларирование переменной типа xQueueHandle. Она используется для сохранения ссылки на очередь, к которой будут обращаться все три задачи. */ xQueueHandle xQueue; int main( void ) { /* Очередь создается для удержания в себе до 5 элементов включительно, каждый из элементов настолько велик, что его размер достаточен для хранения типа
  • 18. 18 long. */ xQueue = xQueueCreate( 5, sizeof( long ) ); if( xQueue != NULL ) { /* Создание двух экземпляров задач, которые будут отправлять данные в очередь. Параметр задачи используется для передачи значения, которое будет писаться задачей в очередь, так что одна задача будет постоянно записывать в очередь число 100, а другая задача будет постоянно записывать число 200. Обе задачи создаются с одинаковым приоритетом 1. */ xTaskCreate( vSenderTask, "Sender1", 1000, ( void * ) 100, 1, NULL ); xTaskCreate( vSenderTask, "Sender2", 1000, ( void * ) 200, 1, NULL ); /* Создание задачи, которая будет читать из очереди. Задача создается с приоритетом 2, что выше приоритета задач, помещающих данные в очередь. */ xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 2, NULL ); /* Запуск шедулера, после чего созданные задачи начнут выполняться. */ vTaskStartScheduler(); } else { /* Очередь не может быть создана. */ } /* Если все хорошо, то управление в main() никогда не дойдет до этой точки, и теперь шедулер будет управлять задачами. Если main() довела управление до этого места, то это может означать, что не хватает памяти кучи (heap) для создания специальной задачи ожидания (idle task, об этой задаче далее). Часть 5 предоставляет больше информации по управлению памятью. */ for( ;; ); }
  • 19. 19 xSemaphoreHandle BigMac; BigMac = xSemaphoreCreateCounting( 100, 0 ); if(GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_SET) { xSemaphoreGive(BigMac); } osDelay(200); xSemaphoreTake( BigMac, portMAX_DELAY); GPIO_WritePin(GPIOE,GPIO_PIN_15,GPIO_PIN_RESET);