Компоненты и технологии • №2 '2011 компоненты


компоненты микроконтроллеры iMeaning



Pdf көрінісі
бет55/129
Дата28.09.2023
өлшемі4.1 Mb.
#478975
1   ...   51   52   53   54   55   56   57   58   ...   129
Kurniz

компоненты
микроконтроллеры
iMeaning
• 
значение, смысл передаваемо-
го через очередь параметра;
iValue
• 
— числовое значение параметра.
Задача ПИД-регулятора частоты враще-
ния двигателя ответственна за главную 
функцию устройства — поддержание ча-
стоты вращения на заданном уровне. Задача 
ПИД-регулятора должна соответствующим 
образом реагировать на действия оператора 
и команды по CAN-интерфейсу, она полу-
чает информацию о внешних воздействиях, 
считывая сообщения из очереди.
Задача обслуживания CAN-интерфейса 
отвечает за обработку входящих по CAN-
шине сообщений, декодирует их и посылает 
сообщение в виде структуры xData в задачу 
ПИД-регулятора. Значение члена структу-
ры iMeaning «установка скорости» позволяет 
задаче ПИД-регулятора определить, что зна-
чение iValue, равное 600, есть не что иное, как 
новое значение уставки скорости вращения.
Задача обслуживания человеко-машин-
ного интерфейса ответственна за взаимодей-
ствие оператора с контроллером двигателя. 
Оператор может вводить значения параме-
тров, давать команды контроллеру, наблюдать 
его текущее состояние. Когда оператор нажал 
кнопку аварийной остановки двигателя, за-
дача обслуживания человеко-машинного ин-
терфейса сформировала соответствующую 
структуру xData. Поле iMeaning указывает 
на нажатие оператором некоторой кноп-
ки, а поле iValue — уточняет какой именно: 
кнопки аварийного останова. Такого рода со-
общения (связанные с возникновением ава-
рийной ситуации) целесообразно помещать 
не в конец, а в начало очереди, так, чтобы за-
дача ПИД-контроллера обработала их раньше 
остальных находящихся в очереди, сократив, 
таким образом, время реакции системы.
Рассмотрим учебную программу № 3, в ко-
торой, как и в учебной программе № 2, будет 
две задачи-передатчика сообщений и одна 
задача-приемник. Однако в качестве едини-
цы передаваемой информации на этот раз 
выступает структура, которая содержит све-
дения о задаче, которая передала это сообще-
ние. Кроме того, продемонстрирована дру-
гая схема назначения приоритетов задачам, 
когда задача-приемник имеет более низкий 
приоритет, чем задачи-передатчики.
#include
#include
#include
#include “FreeRTOS.h”
#include “task.h”
#include “queue.h”
/* Номера функций-передатчиков сообщений */
#define mainSENDER_1 
1
#define mainSENDER_2 
2
/* Объявить переменную-дескриптор очереди. Эта переменная 
* будет использоваться для ссылки на очередь после ее создания. */
xQueueHandle xQueue;
/* Определить структуру, которая будет элементом очереди */
typedef struct
{
unsigned char ucValue;
unsigned char ucSource;
} xData;
/* Определить массив из двух структур, которые будут 
* записываться в очередь */
static const xData xStructsToSend[ 2 ] =
{
{ 100, mainSENDER_1 }, /* Используется задачей-передатчиком 1 */
{ 200, mainSENDER_2 } /* Используется задачей-передатчиком 2 */
};
/*-----------------------------------------------------------*/
/* Функция, реализующая задачи-передатчики */
void vSenderTask(void *pvParameters) {
/* Будет создано несколько экземпляров задачи. В качестве 
* параметра задаче будет передан указатель на структуру xData. */
/* Переменная, которая будет хранить результат выполнения 
* xQueueSendToBack(): */
portBASE_TYPE 
xStatus;
/* Бесконечный цикл */
for (;;) {
/* Записать структуру в конец очереди.
* 1-й параметр — дескриптор очереди, в которую будет 
* производиться запись, очередь создана до запуска 
* планировщика, и ее дескриптор сохранен в глобальной 

переменной 
xQueue.
* 2-й параметр — указатель на структуру, которая будет 
* записана в очередь, в данном случае указатель передается 
* при создании экземпляра задачи (pvParameters).
* 3-й параметр — продолжительность тайм-аута, в течение 

которого 
задача 
будет находиться в блокированном 
* состоянии, ожидая появления свободного места в очереди.
* Макроопределение portTICK_RATE_MS используется для 
* преобразования времени 100 мс в количество системных 

квантов. 
*/
xStatus = xQueueSendToBack(xQueue, pvParameters, 100 / 
portTICK_RATE_MS);
if (xStatus != pdPASS) {
/* Запись в очередь не произошла по причине того, что 
* очередь на протяжении тайм-аута оставалась заполненной.
* Такая ситуация свидетельствует об ошибке, так как 
* очередь-приемник создаст свободное место в очереди, 
* как только обе задачи-передатчика перейдут 
* в блокированное состояние */
puts(“Could not send to the queue.\r\n”);
}
/* Сделать принудительный вызов планировщика, позволив, 
* таким образом, выполняться другой задаче-передатчику.
* Переключение на другую задачу произойдет быстрее, чем 
* окончится текущий квант времени. */
taskYIELD();
}
}
/*------------------------------------------------------------------------*/
/* Функция, реализующая задачу-приемник */
void vReceiverTask(void *pvParameters) {
/* Структура, в которую будет копироваться прочитанная из 
* очереди структура */
xData xReceivedStructure;
/* Переменная, которая будет хранить результат выполнения 
* xQueueReceive() */
portBASE_TYPE 
xStatus;
/* Бесконечный цикл */
for (;;) {
/* Эта задача выполняется, только когда задачи-передатчики 
* находятся в блокированном состоянии, а за счет того, что 
* приоритет у них выше, блокироваться они могут, только 
* если очередь полна. Поэтому очередь в этот момент должна 
* быть полна. То есть текущее количество элементов 
* очереди должно быть равно ее размеру — 3. */
if (uxQueueMessagesWaiting(xQueue) != 3) {
puts(“Queue should have been full!\r\n”);
}
/* Прочитать структуру из начала очереди.
* 1-й параметр — дескриптор очереди, из которой будет 
* происходить чтение, очередь создана до запуска 
* планировщика, и ее дескриптор сохранен в глобальной 

переменной 
xQueue.
* 2-й параметр — указатель на буфер, в который будет 
* скопирована структура из очереди. В данном случае — 
* указатель на структуру xReceivedStructure.
* 3-й параметр — продолжительность тайм-аута. В данном 
* случае задана равной 0, что означает задача не будет 
* “ожидать”, если очередь пуста. Однако так как эта задача
* получает управление, только если очередь полна, то чтение 
* элемента из нее будет всегда возможно.
*/
xStatus = xQueueReceive(xQueue, &xReceivedStructure, 0);
if (xStatus == pdPASS) {
/* Структура успешно принята, вывести на экран название 
* задачи, которая эту структуру поместила в очередь, 
* и значение абстрактного параметра */
if (xReceivedStructure.ucSource == mainSENDER_1) {
printf(“From Sender 1 = %d\r\n”, xReceivedStructure.ucValue);

else 
{
printf(“From Sender 2 = %d\r\n”, xReceivedStructure.ucValue);
}

else 
{
/* Данные не были прочитаны из очереди.
* При условии, что очередь должна быть полна, означает 

аварийную 
ситуацию 
*/
puts(“Could not receive from the queue.\r\n”);
}
}
}
/*------------------------------------------------------------------------*/
/* Точка входа. С функции main() начнется выполнение программы. */
int main(void) {
/* Создать очередь размером 3 элемента для хранения 
* структуры типа xData.
* Размер элемента установлен равным размеру структуры xData.
* Дескриптор созданной очереди сохранить в глобальной 
* переменной xQueue. */
xQueue = xQueueCreate(3, sizeof(xData));
/* Если очередь успешно создана (дескриптор не равен NULL) */
if (xQueue != NULL) {
/* Создать 2 экземпляра задачи-передатчика. Параметр, 
* передаваемый задаче при ее создании, указатель на структуру, 
* которую экземпляр задачи-передатчика
* будет записывать в очередь.

Задача-передатчик 

будет постоянно записывать структуру 
* xStructsToSend[ 0 ].

Задача-передатчик 

будет постоянно записывать структуру 
* xStructsToSend[ 1 ].
* Обе задачи создаются с приоритетом 1.
*/
xTaskCreate(vSenderTask, “Sender1”, 1000, ( void * ) &( 
xStructsToSend[ 0 ] ), 2, NULL);
xTaskCreate(vSenderTask, “Sender2”, 1000, ( void * ) &( 
xStructsToSend[ 1 ] ), 2, NULL);
/* Создать задачу-приемник, которая будет считывать числа 
* из очереди.
* Приоритет = 2, то есть выше, чем у задач-передатчиков.
*/
xTaskCreate(vReceiverTask, “Receiver”, 1000, NULL, 1, NULL);
/* Запуск планировщика. Задачи начнут выполняться. */
vTaskStartScheduler();
} else {
/* Если очередь не создана */
}
/* При успешном создании очереди и запуске планировщика 
* программа никогда “не дойдет” до этого места. */
for 
(;;)
;
}
Результат выполнения учебной програм-
мы № 3 показан на рис. 6, на котором видно, 
что теперь задача-приемник владеет инфор-
мацией о том, какая именно задача передала 
то или иное сообщение.
В момент времени (1) (рис. 7) управление 
получает одна из задач-передатчиков, так как 
приоритет их выше, чем у задачи-приемника. 
Пусть это будет задача-передатчик 1. Она 
записывает первый элемент в пустую оче-
редь и вызывает планировщик (момент 
времени (2)). Планировщик передает управ-
ление другой задаче с таким же приорите-
том, то есть задаче-передатчику 2. Та запи-
сывает еще один элемент в очередь (теперь 
в очереди 2 элемента) и отдает управление 
задаче-передатчику 1 (момент времени (3)). 
Задача-передатчик 1 записывает 3-й элемент 
в очередь, теперь очередь заполнена. Когда 
управление передается задаче-передатчику 2, 
она обнаруживает, что не может запи-
сать новый элемент в очередь, и переходит 
в блокированное состояние (момент вре-
мени (5)). Управление снова получает задача-
передатчик 1, однако очередь по-прежнему 
заполнена, и задача-передатчик 1 также бло-
кируется в ожидании освобождения места 
в очереди (момент времени (6)).
Так как все задачи с приоритетом 2 теперь 
блокированы, управление получает задача-
приемник, приоритет которой ниже и ра-
вен «1» (момент времени (6)). Она считывает 
один элемент из очереди, освобождая таким 




Достарыңызбен бөлісу:
1   ...   51   52   53   54   55   56   57   58   ...   129




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет