Целью работы является освоение механизма передачи данных во FreeRTOS на основе очередей.
Для достижения поставленной цели требуется решить следующие задачи:
Презентация к блоку "Операционные системы реального времени RISC-V"
При разработке ПО возникают ситуации, в которых необходимо передавать данные между задачами. Использование глобальных переменных для этих целей не рекомендуется, так как при переключении между задачами есть риск испортить данные. По этой причине предлагается использовать механизм очередей.
Очередь (Рис. 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. */
}
В лабораторной работе требуется разработать набор задач, которые взаимодействуют между собой с помощью очередей. В данной работе требуется создать числовую последовательность и вычислить итоговое значение на её основе.
Требуется создать набор модифицированных последовательностей Фибоначчи со следующими характеристиками:
Максимальная длина последовательности 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).Очереди должны обеспечивать передачу всех элементов последовательности в следующую задачу. Использование массивов при формировании последовательности не допускается. Требуется выводить в консоль исходные и генерируемые значения последовательности, а также результат вычислений.
Для выполнения задания необходимо:
#define SEQUENCE_LEN 5
QueueHandle_t queues[SEQUENCE_LEN-1];
xSemaphoreHandle mutex_print;
char str[40];
void queue_init_task_function(void *pvParameters){
int a=1, b=1;
while(1){
for(int a = 1; a < 5; a++){
for (int b = 1; b < 5; b++) {
xQueueSend( queues[0], a, ( TickType_t ) 0 );
xQueueSend( queues[0], b, ( TickType_t ) 0 );
if(xSemaphoreTake(mutex_print,2000)){
sprintf( str, "Init: f[0]=%d; f[1]=%d;", a, b);
vSendString(str);
xSemaphoreGive(mutex_print);
}
vTaskDelay(25000);
}
}
}
}
void queue_forward_function(void *pvParameters){
int cnt = 0, val=0;
int i = (int)pvParameters;
int nb = 0;
while(1){
if(xQueueReceive( queues[i],val,( TickType_t ) 10 ) == pdPASS){
xQueueSend( queues[i+1], val, ( TickType_t ) 0 );
cnt++;
if(cnt > i){
nb += val;
}
if(cnt == (i + 2)){
if(xSemaphoreTake(mutex_print,2000)){
sprintf( str, "New: f[%d]=%d;",i+2, nb);
vSendString(str);
xSemaphoreGive(mutex_print);
}
xQueueSend( queues[i+1], nb, ( TickType_t ) 0 );
nb = 0;
cnt = 0;
}
}
}
}
void queue_process_function(void *pvParameters){
int cnt = 0;
int val = 0;
int ks8 = 0;
while(1){
if(xQueueReceive( queues[SEQUENCE_LEN-2],val,( TickType_t ) 10 ) == pdPASS){
ks8+=val;
cnt++;
if(cnt==(SEQUENCE_LEN)){
cnt = 0;
if(xSemaphoreTake(mutex_print,2000)){
sprintf( str, "Result: KS8=%d;", ((unsigned char)(~ks8)));
vSendString(str);
xSemaphoreGive(mutex_print);
}
ks8=0;
}
}
}
}
int main_queue(){
mutex_print = xSemaphoreCreateMutex();
for(int i=0; i<SEQUENCE_LEN-1;i++){
queues[i] = xQueueCreate( 10, sizeof( int ) );
}
xTaskCreate((TaskFunction_t )queue_init_task_function,
(const char* )"Init_Task",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )2,
(TaskHandle_t* )NULL);
for(int i=0; i<SEQUENCE_LEN-2;i++){
xTaskCreate((TaskFunction_t )queue_forward_function,
(const char* )"Forward_Task",
(uint16_t )512,
(void* )i,
(UBaseType_t )2,
(TaskHandle_t* )NULL);
}
xTaskCreate((TaskFunction_t )queue_process_function,
(const char* )"Calc_Task",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )2,
(TaskHandle_t* )NULL);
vTaskStartScheduler();
return 0;
}
int main(){
main_queue();
while(1);
}
Представлен код основных задач: определения начальных элементов, формирования новых байтов, формирования результата. Продемонстрированы основные результаты их работы: формирование начальных данных, генерация новых элементов, вычисление контрольной суммы. Длину последовательности можно регулировать изменением SEQUENCE_LEN.
Целью работы является освоение механизма передачи данных во FreeRTOS на основе очередей.
Для достижения поставленной цели требуется решить следующие задачи:
Презентация к блоку "Операционные системы реального времени RISC-V"
При разработке ПО возникают ситуации, в которых необходимо передавать данные между задачами. Использование глобальных переменных для этих целей не рекомендуется, так как при переключении между задачами есть риск испортить данные. По этой причине предлагается использовать механизм очередей.
Очередь (Рис. 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. */
}
В лабораторной работе требуется разработать набор задач, которые взаимодействуют между собой с помощью очередей. В данной работе требуется создать числовую последовательность и вычислить итоговое значение на её основе.
Требуется создать набор модифицированных последовательностей Фибоначчи со следующими характеристиками:
Максимальная длина последовательности 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).Очереди должны обеспечивать передачу всех элементов последовательности в следующую задачу. Использование массивов при формировании последовательности не допускается. Требуется выводить в консоль исходные и генерируемые значения последовательности, а также результат вычислений.
Для выполнения задания необходимо:
#define SEQUENCE_LEN 5
QueueHandle_t queues[SEQUENCE_LEN-1];
xSemaphoreHandle mutex_print;
char str[40];
void queue_init_task_function(void *pvParameters){
int a=1, b=1;
while(1){
for(int a = 1; a < 5; a++){
for (int b = 1; b < 5; b++) {
xQueueSend( queues[0], a, ( TickType_t ) 0 );
xQueueSend( queues[0], b, ( TickType_t ) 0 );
if(xSemaphoreTake(mutex_print,2000)){
sprintf( str, "Init: f[0]=%d; f[1]=%d;", a, b);
vSendString(str);
xSemaphoreGive(mutex_print);
}
vTaskDelay(25000);
}
}
}
}
void queue_forward_function(void *pvParameters){
int cnt = 0, val=0;
int i = (int)pvParameters;
int nb = 0;
while(1){
if(xQueueReceive( queues[i],val,( TickType_t ) 10 ) == pdPASS){
xQueueSend( queues[i+1], val, ( TickType_t ) 0 );
cnt++;
if(cnt > i){
nb += val;
}
if(cnt == (i + 2)){
if(xSemaphoreTake(mutex_print,2000)){
sprintf( str, "New: f[%d]=%d;",i+2, nb);
vSendString(str);
xSemaphoreGive(mutex_print);
}
xQueueSend( queues[i+1], nb, ( TickType_t ) 0 );
nb = 0;
cnt = 0;
}
}
}
}
void queue_process_function(void *pvParameters){
int cnt = 0;
int val = 0;
int ks8 = 0;
while(1){
if(xQueueReceive( queues[SEQUENCE_LEN-2],val,( TickType_t ) 10 ) == pdPASS){
ks8+=val;
cnt++;
if(cnt==(SEQUENCE_LEN)){
cnt = 0;
if(xSemaphoreTake(mutex_print,2000)){
sprintf( str, "Result: KS8=%d;", ((unsigned char)(~ks8)));
vSendString(str);
xSemaphoreGive(mutex_print);
}
ks8=0;
}
}
}
}
int main_queue(){
mutex_print = xSemaphoreCreateMutex();
for(int i=0; i<SEQUENCE_LEN-1;i++){
queues[i] = xQueueCreate( 10, sizeof( int ) );
}
xTaskCreate((TaskFunction_t )queue_init_task_function,
(const char* )"Init_Task",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )2,
(TaskHandle_t* )NULL);
for(int i=0; i<SEQUENCE_LEN-2;i++){
xTaskCreate((TaskFunction_t )queue_forward_function,
(const char* )"Forward_Task",
(uint16_t )512,
(void* )i,
(UBaseType_t )2,
(TaskHandle_t* )NULL);
}
xTaskCreate((TaskFunction_t )queue_process_function,
(const char* )"Calc_Task",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )2,
(TaskHandle_t* )NULL);
vTaskStartScheduler();
return 0;
}
int main(){
main_queue();
while(1);
}
Представлен код основных задач: определения начальных элементов, формирования новых байтов, формирования результата. Продемонстрированы основные результаты их работы: формирование начальных данных, генерация новых элементов, вычисление контрольной суммы. Длину последовательности можно регулировать изменением SEQUENCE_LEN.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.