Опубликован: 19.01.2025 | Доступ: свободный | Студентов: 0 / 0 | Длительность: 05:57:00
Лекция 13:

Лабораторная работа №12. Очереди FreeRTOS (на основе очередей)

< Лекция 12 || Лекция 13: 12 || Лекция 14 >

12.1 Цели и задачи

Целью работы является освоение механизма передачи данных во FreeRTOS на основе очередей.

Для достижения поставленной цели требуется решить следующие задачи:

  1. Изучить назначение очередей и вариантов их применения.
  2. Ознакомиться с процессом использования очередей во FreeRTOS.
  3. Разработать задачи в FreeRTOS с передачей данных между ними.

Презентация к блоку "Операционные системы реального времени RISC-V"

12.2 Основные теоретические сведения

При разработке ПО возникают ситуации, в которых необходимо передавать данные между задачами. Использование глобальных переменных для этих целей не рекомендуется, так как при переключении между задачами есть риск испортить данные. По этой причине предлагается использовать механизм очередей.

Очередь (Рис. 12.1) создается с помощью функции QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize ). Она использует 2 параметра: количество элементов в очереди и их размер.

Применение очереди

Рис. 12.1. Применение очереди

Для отправки данных в очередь есть группа методов: xQueueSendToBack( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait ) и xQueueSendToFront( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait ). Они отправляют новый элемент в конец или в начало очереди. Параметрами функций являются указатель на используемую очередь, указатель на копируемый параметр и время ожидание на помещение элемента в очередь, если она полностью заполнена.

Следует отметить, что существует функция xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait ). Эта функция аналогична xQueueSendToBack и используется для совместимости со старыми версиями FreeRTOS.

Для получения элемента из очереди используется функция BaseType_t xQueueReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait ). Она извлекает элемент из очереди и помещает его в буфер, из которого с ним будет вестись работа. В числе параметров функции есть время ожидания, которая указывает сколько времени ждать элемент, если очередь пуста. Существует аналогичная функция xQueuePeek( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait ), которая копирует элемент из очереди без его извлечения. То есть эта функция используется, когда первый в очереди элемент не должен извлекаться.

Функция извлечения получает и удаляет элемент в начале очереди. Таким образом с помощью функций в конец и в начало очереди реализуются примитивы очереди и стека соответственно.

Пример кода работы с очередями:

struct AMessage
{
   char ucMessageID;
   char ucData[ 20 ];
} xMessage;

QueueHandle_t xStructQueue = NULL;
QueueHandle_t xPointerQueue = NULL;


void vCreateQueues( void )
{
   xMessage.ucMessageID = 0xab;
   memset( &( xMessage.ucData ), 0x12, 20 );

   xStructQueue = xQueueCreate(
                         /* The number of items the queue can hold. */
                         10,
                         /* Size of each item is big enough to hold the
                         whole structure. */
                         sizeof( xMessage ) );

   /* Create the queue used to send pointers to struct AMessage structures. */
   xPointerQueue = xQueueCreate(
                         /* The number of items the queue can hold. */
                         10,
                         sizeof( &xMessage ) );

   if( ( xStructQueue == NULL ) || ( xPointerQueue == NULL ) )
   {
   }
}

/* Task that writes to the queues. */
void vATask( void *pvParameters )
{
struct AMessage *pxPointerToxMessage;

   xQueueSend( xStructQueue,
               ( void * ) &xMessage,
               ( TickType_t ) 0 );
   pxPointerToxMessage = &xMessage;

   xQueueSend( xPointerQueue,
               ( void * ) &pxPointerToxMessage,
               ( TickType_t ) 0 );

   /* ... Rest of task code goes here. */
}

/* Task that reads from the queues. */
void vADifferentTask( void *pvParameters )
{
struct AMessage xRxedStructure, *pxRxedPointer;

   if( xStructQueue != NULL )
   {
      if( xQueueReceive( xStructQueue,
                         &( xRxedStructure ),
                         ( TickType_t ) 10 ) == pdPASS )
      {
         /* xRxedStructure now contains a copy of xMessage. */
      }
   }

   if( xPointerQueue != NULL )
   {
      if( xQueueReceive( xPointerQueue,
                         &( pxRxedPointer ),
                         ( TickType_t ) 10 ) == pdPASS )
      {
         /* *pxRxedPointer now points to xMessage. */
      }
   }

   /* ... Rest of task code goes here. */
}
  

12.3 Задание к лабораторной работе

  1. Подготовить проект с настроенной FreeRTOS для QEMU.
  2. Реализовать задачи, согласно требованиям.
  3. Запустить программу в эмуляторе и убедиться в работоспособности задач.

В лабораторной работе требуется разработать набор задач, которые взаимодействуют между собой с помощью очередей. В данной работе требуется создать числовую последовательность и вычислить итоговое значение на её основе.

Требуется создать набор модифицированных последовательностей Фибоначчи со следующими характеристиками:

Максимальная длина последовательности l = 5 + (a % 6);

f[0] = a;
f[1] = a+b+s;
f[i] = (f[i-1] + f[i-2]) & 0xFF (младший байт)

где где а = номер варианта, b = количество букв в фамилии, s = номер последовательности от 0 до 10.

Требуется реализовать следующий набор задач:

  • Задача формирования начальных значений последовательности
  • Задачи для вычисления последующих значений.
  • Вычисление контрольной суммы КС8 сформированной последовательности (младший байт суммы всех значений в последовательности XOR 0xFF).

Очереди должны обеспечивать передачу всех элементов последовательности в следующую задачу. Использование массивов при формировании последовательности не допускается. Требуется выводить в консоль исходные и генерируемые значения последовательности, а также результат вычислений.

12.3.1 Описание последовательности выполнения работы

Для выполнения задания необходимо:

  1. Настроить среду для работы согласно инструкции из п. 10.2.1.
  2. Вычислить параметры вашего варианта задания.
  3. С помощью функций управления задачами FreeRTOS модифицировать поведение светодиодов.
  4. Реализовать взаимодействие задач через очереди.
  5. Выполнить сборку и запуск модифицированного примера, зафиксировать результат работы в отчете.
< Лекция 12 || Лекция 13: 12 || Лекция 14 >