21.04.2017, 13:27
|
|
Заблокирован
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,486
Сказал спасибо: 396
Сказали Спасибо 2,220 раз(а) в 1,319 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Ну да, есть там некоторые заморочки с передачей параметра. Кароч, по умолчанию он передается как указатель на void, а когда принимается параметр, его надо преобразовать к тому типу, который передается.
Передать можно как единственную переменную, так и структуру, при этом преобразовывать на приеме надо именно к типу структуры.
Еще есть любопытная штука, что создание нескольких задач, использующих одну и ту же функцию, может создавать различные экземпляры задачи, и в списке задач они будут значиться разными задачами и могут выполнять разные действия.
Вот накидал что-то типа такого простого примера.
Вначале создается какая-то задача и запускается планировщик задач.
Затем эта задача, выполняясь, через указанную задержку, уже сама создает три копии (экземпляра) дочерней задачи и через указанную задержку самоуничтожается (удаляется). В дочерние задачи передается параметр в виде структуры. Три копии задачи реализованы одной и той же функцией, аргументами которой являются принятые параметры.
Нажмите, чтобы открыть спойлер
PHP код:
|
/* Global variables */
/* дескрипторы задач */
xTaskHandle xMainParentTsHandle = NULL,
xChildTs1aHandle = NULL,
xChildTs1bHandle = NULL,
xChildTs1cHandle = NULL;
BaseType_t error; // переменная ошибок
/* Function prototypes */
static void prvSetupHardware( void );
static void prvParentTask( void *pvParameters );
void prvChildTask1( void *pvParameters );
/**
**================================================ ===========================
**
** Abstract: main program
**
**================================================ ===========================
*/
int main(void)
{
prvSetupHardware(); // инит портов
//-----------------------------------------------
/* Запуск главной (родительской) задачи */
error = xTaskCreate( prvParentTask, // функция, реализующая задачу
"MainTask", // имя задачи для нужд отладки
configMINIMAL_STACK_SIZE, // запрашиваемый размер стека для задачи
NULL, // нет параметров, передаваемых в задачу
( tskIDLE_PRIORITY + 1 ), // приоритет задачи
&xMainParentTsHandle ); // хэндл (дескриптор) задачи
if (error == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{/* #error Не хватает памяти в куче для размещения задачи */ }
//----------------------------------------------
/* Запускается планировщик задач */
vTaskStartScheduler();
//----------------------------------------------
for (;;) {} // бесконечный цикл, в случае если не был запущен планировщик
} /* main() */
/**
**================================================ ===========================
**
** Abstract: Функции, реализующие задачи
**
**================================================ ===========================
*/
//.................................................. ...
/* Задача запускает дочерние задачи в виде эеземпляров одной
* и той же задачи, но с разными параметрами
*/
static void prvParentTask( void *pvParameters )
{
vTaskDelay(100); // перевод задачи в bloked на указанное время
BLUE_ON; // индикация начала работы задачи
/* Объявляется структура передаваемых параметров */
struct param_t{ // структура с типом param_t
uint8_t numLED; // номер св.диода
uint8_t duration; // длительность его включения
};
const struct param_t SendParam1 = {1, 15}; // Передаваемые параметры для каждого
const struct param_t SendParam2 = {2, 50}; // экземпляра задачи -
const struct param_t SendParam3 = {3, 85}; // номер св.диода и длительность его включения
/* Создаются экземпляры задачи */
//......Первый экземпляр............
error = xTaskCreate( prvChildTask1, // функция, реализующая задачу
"BlinkLED1", // имя задачи для нужд отладки
configMINIMAL_STACK_SIZE, // запрашиваемый размер стека для задачи
(void *)&SendParam1, // передаваемые в задачу параметры при ее создании
( tskIDLE_PRIORITY + 1 ), // приоритет задачи
&xChildTs1aHandle ); // хэндл (дескриптор) задачи
if (error == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{/* #error Не хватает памяти в куче для размещения задачи */ }
//..................................
//......Второй экземпляр............
error = xTaskCreate( prvChildTask1, // функция, реализующая задачу
"BlinkLED2", // имя задачи для нужд отладки
configMINIMAL_STACK_SIZE, // размер стека
(void *)&SendParam2, // передаваемые в задачу параметры при ее создании
( tskIDLE_PRIORITY + 1 ), // приоритет задачи
&xChildTs1bHandle ); // хэндл (дескриптор) задачи
if (error == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{/* #error Не хватает памяти в куче для размещения задачи */ }
//..................................
//......Третий экземпляр............
error = xTaskCreate( prvChildTask1, // функция, реализующая задачу
"BlinkLED3", // имя задачи для нужд отладки
configMINIMAL_STACK_SIZE, // размер стека
(void *)&SendParam3, // передаваемые в задачу параметры при ее создании
( tskIDLE_PRIORITY + 1 ), // приоритет задачи
&xChildTs1cHandle ); // хэндл (дескриптор) задачи
if (error == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{/* #error Не хватает памяти в куче для размещения задачи */ }
//..................................
vTaskDelay(100); // перевод задачи в bloked на указанное время
BLUE_OFF; // Индикация завершения работы задачи
vTaskDelete(NULL); // Удаляется эта же самая задача, она больше не существует в системе,
// память, выделенная для нее, будет очищена в задаче IdleTask.
// При этом обязательно должен использоваться файл heap_2.c или heap_4.c
// в папке MemMang
}
//.................................................. ...
/* Функция, общая для каждого создаваемого экземпляра задачи,
* но задачи создаются отдельные и в списке задач каждый экземпляр
* представлен отдельной задачей.
*/
void LedOn(uint8_t numLED);
void LedOff(uint8_t numLED);
void prvChildTask1( void *pvParameters )
{
/* Объявляется структура для приема параметров */
struct param_t{ // структура с типом param_t
uint8_t numLED; //
uint8_t duration; //
};
/* принятые параметры приводятся к типу созданной структуры */
struct param_t *ReceiveParam; // объявляется указатель на структуру
ReceiveParam = (struct param_t*)pvParameters; // приводится к типу созданной структуры
/* Бесконечный цикл, реализующий работу задачи -
* мигание светодиодами, с заданной длительностью включения */
for (;;)
{
vTaskDelay(ReceiveParam-›duration); // задача переводится в bloked на указанное время
LedOn(ReceiveParam-›numLED); // вкл.св.диод, номер которого указан в параметре
vTaskDelay(100 - ReceiveParam-›duration); // задача переводится в bloked на указанное время
LedOff(ReceiveParam-›numLED); // выкл.вд.диод, номер которого указан в параметре
}
}
//.................................................. ...
/* Функции, управляющие вкл/выкл св.диодов */
void LedOn(uint8_t numLED)
{ GPIOA-›BSRR = 1 ‹‹ (numLED + 7); }
void LedOff(uint8_t numLED)
{ GPIOA-›BRR = 1 ‹‹ (numLED + 7); }
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
/* Задача "бездействие". В настройках РТОС должен быть оперделена
* #define configUSE_IDLE_HOOK 1 для возможности использования этой задачи
* В переменной munRunTasc будет количество запущенных задач
* Переменная absnumTick показывает время (в тиках) от старта планировщика.
*/
UBaseType_t munRunTasc;
void vApplicationIdleHook( void )
{
GREEN_ON; // индикация входа в Idle
munRunTasc = uxTaskGetNumberOfTasks(); // число запущенных задач
absnumTick = xTaskGetTickCount(); // число прошедших тиков от запуска
GREEN_OFF;
}
/*-----------------------------------------------------------*/
|
Видно, что в процессе работы изменяется число существующих в системе задач. Задача Idle (бездействие) - тоже отображается в списке.
|
|
|
Сказали "Спасибо" NewWriter
|
|
|
21.04.2017, 13:58
|
|
Гуру портала
Регистрация: 27.10.2008
Адрес: ЕС
Сообщений: 10,835
Сказал спасибо: 919
Сказали Спасибо 4,308 раз(а) в 2,573 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Надо не забывать, что данные, расположенные по указателю, должны существовать до тех пор, пока задача их не получит и не решит, что они больше не актуальны. И тут становится ясно, для чего нужно динамически выделять память: вы декларируете указатель на структуру, просите дать вам для нее памяти, заполняете память, передаете указатель в задачу, задача его обрабатывает и освобождает память, ссылаясь на тот же самый указатель через vPortFree (если память не изменяет, как там отпускать память назад)
|
|
|
Сказали "Спасибо" Easyrider83
|
|
|
21.04.2017, 15:37
|
|
Заблокирован
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,486
Сказал спасибо: 396
Сказали Спасибо 2,220 раз(а) в 1,319 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
А, да, верно... строго говоря, задачу удалять нельзя, не скопировав принятые данные, поскольку как только освободившаяся память будет занята под другую задачу, данные по тем адресам испортятся и указатели будут не актуальны.
Просто хотел показать, что задачи могут создаваться и удаляться во время работы ОС.
|
|
|
|
21.04.2017, 15:45
|
|
Гуру портала
Регистрация: 27.10.2008
Адрес: ЕС
Сообщений: 10,835
Сказал спасибо: 919
Сказали Спасибо 4,308 раз(а) в 2,573 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Кстати, как раз динамическое выделение памяти больше всего крови и выпивает. При подобном подходе (правильном, кстати говоря) память быстро фрагментируется. Если у вас ее и так не много, то рано или поздно надо ждать, что heap вернет ноль и если исключение не будет обработано, получим hard fault. Честно говоря, на STM32 я смог запустить только heap_1 и heap_2. Остальные просто зависают. Не вдавался в причины, хотя видимо, пора бы уже.
|
|
|
|
21.04.2017, 16:05
|
|
Вид на жительство
Регистрация: 10.04.2010
Сообщений: 301
Сказал спасибо: 25
Сказали Спасибо 136 раз(а) в 79 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Пока не прочитаете Курница и не вникните в каждую строчку, то лучше не приниматься. Задачи-то вы в демо запустите, светодиодиками помигаете и не более.
Вообще тема хорошая, но такое впечатление, что мало кто использует FreeRtos, хотя очень достойная и удобная вещь. Правда если что-то более менее серьезное, то заморочек.... Но без неё ещё хуже.
|
|
|
|
21.04.2017, 16:08
|
|
Вид на жительство
Регистрация: 10.04.2010
Сообщений: 301
Сказал спасибо: 25
Сказали Спасибо 136 раз(а) в 79 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Сообщение от Easyrider83
|
Честно говоря, на STM32 я смог запустить только heap_1 и heap_2. Остальные просто зависают. Не вдавался в причины, хотя видимо, пора бы уже.
|
Стек и кучу проверить надо в настройках линковщика, работают все, хотя у меня наоборот вначале только с третьим шло
|
|
|
|
22.04.2017, 01:21
|
|
Гуру портала
Регистрация: 27.10.2008
Адрес: ЕС
Сообщений: 10,835
Сказал спасибо: 919
Сказали Спасибо 4,308 раз(а) в 2,573 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Вот мой пример вывода сообщений на экран.
Код:
|
typedef struct
{
char text[LCD_STRINGSIZE];
LCD_CMD_TypeDef cmd;
}LCD_MSG_StructTypeDef; |
Где LCD_STRINGSIZE - максимальный размер сообщения. Для 1602 это 16 или 32+1 символа
Эта функция кладет сообщение в очередь.
Код:
|
void LCD_Print (char * Text, LCD_CMD_TypeDef Cmd)
{
/* Dedicate memory for message */
LCD_MSG_StructTypeDef * MSG = pvPortMalloc(sizeof(LCD_MSG_StructTypeDef));
/* If memory available */
if (MSG)
{
/* Cope text to message */
strcpy(MSG-›text, Text);
/* Set command to execute before */
MSG-›cmd = Cmd;
/* Put message to queue */
xQueueSend(xLCD_MSG_Queue, &MSG, NULL);
}
} |
А эта функция забирает сообщение
Код:
|
/* Handle message */
while(1)
{
if (xQueueReceive(xLCD_MSG_Queue, &MSG, portMAX_DELAY) == pdPASS)
{
/* Execute command */
HD44780_SPI_Cmd(&LCD, MSG-›cmd);
if (MSG-›cmd == LCD_CMD_Clear)
HD44780_SPI_Cmd(&LCD, LCD_CMD_Home);
vTaskDelay(10);
/* Print message */
HD44780_SPI_Print(&LCD, MSG-›text);
vPortFree(MSG);
}
} |
И освобождает память. Таким образом, мы занимаем в очереди минимум памяти - там храним только один указатель на сообщение. Сообщение ложится в память и хранится там, пока его не обработают. Очень удобно и красиво.
|
|
|
Сказали "Спасибо" Easyrider83
|
|
|
22.04.2017, 15:56
|
|
Частый гость
Регистрация: 06.10.2015
Сообщений: 15
Сказал спасибо: 14
Сказали Спасибо 3 раз(а) в 2 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Огромная благодарность за примеры! Сейчас какраз разбираюсь с очередями. Радует что можно передать не только байты данных но и указатели на данные.
С созданием задач все получилось. Дело продвигается ☺
|
|
|
|
23.04.2017, 17:07
|
|
Вид на жительство
Регистрация: 07.01.2007
Адрес: Ленинградская обл
Сообщений: 428
Сказал спасибо: 147
Сказали Спасибо 71 раз(а) в 56 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Благодарю за полезную информацию.
Уверен, что разработчикам пригодится опыт применения похожей техники программирования:
1. Каждая задача програмируется как набор вариантов действий
2. На следующем входе в начало кда задачи выбирается вариант того, что нужно сделать в этот раз (в этот заход). Типа конечного автомата. На выходе - не переход на начало кода, а возврат (в диспетчер).
3. Диспетчер по очереди заходит в "начало цикла" каждой задачи.
4. Все циклы задач имеют одинаковую длину по времени выполнения. Это бывает нужно для отслеживания абсолютных временных интервалов (например, звук). Пояснение. Все ветвления (как задачи, так и ветки If внутри задач) сбалансированы по времени выполнения команд в каждом из ветвлений. Конечно, это для програмирования "в кодах".
При таком подходе не необходимы прерывания. При реализации балансировки не необходим высокоточный таймер.
Модификация техники для случаев, когда не требуется точная служба времени:
1. Каждая задача программируется как бесконечный цикл, так, как удобно, как будто нет никакого диспетчера, за исключением:
2. Как минимум один вызов диспетчера без параметров в каждом прохождении цикла задачи
и такие же вызовы во внутренних циклах, в т ч в опросах и задержках.
Диспетчер, которого вызвали, сохраняет контекст и смотрит, в какую задачу возвращать управление (не обязательно в эту)
Эта вторая техника частично используется в виндоуз, но мне представляется более разумной первая (хотя в случае, когда нужжна балансировка времени выполнния, без прогр в кодах не обойтись)
|
|
|
|
23.04.2017, 19:38
|
|
Заблокирован
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,486
Сказал спасибо: 396
Сказали Спасибо 2,220 раз(а) в 1,319 сообщении(ях)
|
Re: FreeRTOS?? Разобраться с демо проектом??
Нуууу ээээ первый вариант - это описана суть кооперативной системы, в втором - вытесняющей (но там вызов планировщика происходит от прерывания аппаратного таймера и не привязан к написанному коду)
Правда, для кооперативной системы вот как раз таки нельзя гарантировать одинаковое время выполнения каждой задачи, длительность выполнения задачи просто невозможно подогнать, особенно на Си. Подгонка отнимет слишком много сил программиста, а как только в задачу надо будет внести правки, предыдущие усилия покатятся к чертям.
Наоборот, в случае кооперативной системы, длительность каждой задачи может быть разной - как меньше, так и больше аналогичного времени кванта в вытесняющей системе. А в конце каждой задачи, когда она завершилась логически, нужно принудительно возвращать управление планировщику задач.
FreeRTOS может работать и в кооперативном режиме и у нее есть такая команда taskYIELD(). В принципе, эту команду можно использовать и в вытесняющей системе, когда выполняющаяся задача больше не нужна на выполнении и ее можно переключить.
В отличие от предыдущей, вытесняющая система весьма точна по времени, ведь кванты времени синхронизируются по аппаратному таймеру, работающему от делителей главной частоты процессора.
Конечно, отдельные (соседние) интервалы могут плавать из-за высокоприоритетных прерываний и приостановок планировщика в критических секциях, но в целом на больших отрезках погрешность будет в пределах одного тика времени. Ну, если программист не наворотил блокирующих прерываний с очень длинным временем обработки или циклами ожидания внешних событий, которые подвесят саму операционку.
В принципе, ядро готовой операционной системы уже разработано и отлажено, и готово к применению. Пользователю остается изучить его интерфейс и научиться его применять.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 20:29.
|
|