26
КОМПОНЕНТЫ И ТЕХНОЛОГИИ •
№ 7 '2011
микроконтроллеры
это время реакции системы на прерывание, ко-
торое может составлять до одного системного
кванта: величина dT на рис. 3.
Далее в учебной программе № 1 будет
приведен пример использования значения
*pxHigherPriorityTaskWoken для принуди-
тельного переключения контекста.
В случае использования API-функции
xSemaphoreGive() переключение контекста
происходит автоматически, и нет необходи-
мости в его принудительном переключении.
Рассмотрим учебную программу № 1, в ко-
торой продемонстрировано использование
двоичного семафора для синхронизации
прерывания и задачи-обработчика этого пре-
рывания:
#include
#include
#include
#include
#include “FreeRTOS.h”
#include “task.h”
#include “semphr.h”
#include “portasm.h”
/* Двоичный семафор – глобальная переменная */
xSemaphoreHandle xBinarySemaphore;
/*-----------------------------------------------------------*/
/* Периодическая задача */
static void vPeriodicTask(void *pvParameters) {
for (;;) {
* Эта задача используется только с целью генерации
прерывания каждые 500 мс */
vTaskDelay(500 / portTICK_RATE_MS);
/* Сгенерировать прерывание.
Вывести сообщение до этого и после. */
puts(“Periodic task - About to generate an interrupt.\r\n”);
__asm {int 0x82} /* Сгенерировать прерывание MS-DOS */
puts(“Periodic task - Interrupt generated.\r\n\r\n\r\n”);
}
}
/*-----------------------------------------------------------*/
/* Обработчик прерывания */
static void __interrupt __far vExampleInterruptHandler( void )
{
static portBASE_TYPE xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
/* Отдать семафор задаче-обработчику */
x S e m a p h o r e G i v e F r o m I S R ( x B i n a r y S e m a p h o r e ,
&xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE )
{
/* Это разблокирует задачу-обработчик. При этом
приоритет задачи-обработчика выше приоритета
выполняющейся в данный момент периодической
задачи. Поэтому переключаем контекст
принудительно – так мы добьемся того, что после
выполнения обработчика прерывания управление
получит задача-обработчик.*/
/* Макрос, выполняющий переключение контекста.
* На других платформах имя макроса может быть другое! */
portSWITCH_CONTEXT();
}
}
/*-----------------------------------------------------------*/
/* Задача-обработчик */
static void vHandlerTask(void *pvParameters) {
/* Как и большинство задач, реализована как бесконечный цикл */
for (;;) {
/* Реализовано ожидание события с помощью двоичного
семафора. Семафор после создания становится
доступен (так, как будто его кто-то отдал).
Поэтому сразу после запуска планировщика задача
захватит его. Второй раз сделать это ей не удастся,
и она будет ожидать, находясь в блокированном
состоянии, пока семафор не отдаст обработчик
прерывания. Время ожидания задано равным
бесконечности, поэтому нет необходимости проверять
возвращаемое функцией xSemaphoreTake() значение. */
xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);
/* Если программа “дошла” до этого места, значит,
семафор был успешно захвачен.
Обработка события, связанного с семафором.
В нашем случае – индикация на дисплей. */
puts(“Handler task - Processing event.\r\n”);
}
}
/*-----------------------------------------------------------*/
/* Точка входа. С функции main() начнется выполнение
программы. */
int main(void) {
/* Перед использованием семафор необходимо создать. */
vSemaphoreCreateBinary(xBinarySemaphore);
/* Связать прерывание MS-DOS с обработчиком прерывания
vExampleInterruptHandler(). */
_dos_setvect(0x82, vExampleInterruptHandler);
/* Если семафор успешно создан */
if (xBinarySemaphore != NULL) {
/* Создать задачу-обработчик, которая будет
синхронизирована с прерыванием.
Приоритет задачи-обработчика выше,
чем у периодической задачи. */
xTaskCreate(vHandlerTask, “Handler”, 1000, NULL, 3, NULL);
/* Создать периодическую задачу, которая будет
генерировать прерывание с некоторым интервалом.
Ее приоритет – ниже, чем у задачи-обработчика. */
xTaskCreate(vPeriodicTask, “Periodic”, 1000, NULL, 1, NULL);
/* Запуск планировщика. */
vTaskStartScheduler();
}
/* При нормальном выполнении программа до этого места
“не дойдет” */
for (;;)
;
}
В демонстрационных целях использовано
не аппаратное, а программное прерывание
MS-DOS, которое «вручную» вызывается
из служебной периодической задачи каждые
500 мс. Заметьте, что сообщение на дисплей
выводится как до генерации прерывания, так
и после него, что позволяет проследить по-
следовательность выполнения задач (рис. 4).
Следует обратить внимание на использо-
вание параметра xHigherPriorityTaskWoken
в API-функции xSemaphoreGiveFromISR().
До вызова функции ему присваивается значе-
ние pdFALSE, а после вызова — проверяется
на равенство pdTRUE. Таким образом отсле-
живается необходимость принудительного
переключения контекста. В данной учебной
программе такая необходимость возникает
каждый раз, так как в системе постоянно на-
ходится более высокоприоритетная задача-
обработчик, которая ожидает возможности
захватить семафор.
Для принудительного переключения кон-
текста служит API-макрос portSWITCH_
Достарыңызбен бөлісу: