Думаю каждый при разработке более или менее сложной программы для МК сталкивался с ситуацией когда скорость выполнения программы меньше чем нужно. И дело даже не в производительности МК, а в алгоритме программы. Скажем при опросе кнопок для защиты от дребезга использованы функции задержки выполняя которые МК зря расходует энергию. А ведь вместо этой задержки можно выполнить другой код, что позволит более рационально использовать ресурсы МК. Но такой подход может значительно усложнить код сделав его запутанным. Видимо это обстоятельство привело к появлению RTOS - операционных систем реального времени для МК. Они представляют из себя планировщик задач, т. е. позволяют реализовать многозадачность, которая может быть нескольких видов, основные из которых это кооперативная и вытесняющая. В первом случае, активная задача сама решает когда она ей больше не нужно процессорное время и она может отдать его другим задачам, а во втором случае, задачу "никто не спрашивает" выполнила она все или нет, ее работу "наглым образом" прерывает планировщик и отдает процессорное время другой задаче. По такому принципу реализована многозадачность в винде. Такой подход хорош тем что если зависнет одна задача, другие будут нормально работать и более или менее гарантируется периодичность выполнения задач, а не как в корпоративной многозадачности, в которой одна задача может выполняться сколько угодно долго в то время как другие будут ждать пока она отдаст им процессорное время.
ОСь FreeRTOS позволяет реализовать как корпоративную, так и вытесняющую многозадачность и она поддерживает многие модели МК среди которые есть AVR и STM32.
В сети можно найти много статей о использовании FreeRTOS с STM32.
https://habrahabr.ru/post/249273/
https://habrahabr.ru/post/249283/
https://habrahabr.ru/post/249381/
https://habrahabr.ru/post/249395/
https://habrahabr.ru/post/249975/https://habrahabr.ru/post/261807/
http://easyelectronics.ru/ustanovka-i-k … ertos.html
http://microtechnics.ru/stm32-uchebnyj- … s-chast-1/
http://blablacode.ru/programmirovanie/285http://microsin.net/programming/arm/freertos-part1.html
http://microsin.net/programming/arm/freertos-part2.html
http://microsin.net/programming/arm/freertos-part3.html
http://microsin.net/programming/arm/freertos-part4.html
http://microsin.net/programming/arm/freertos-part5.html
http://microsin.net/programming/arm/freertos-part6.html
http://microsin.net/programming/arm/fre … endix.html
Итак, для того чтобы добавить FreeRTOS в проект, ее нужно скачать с официального сайта на котором сейчас доступная версия 9.0.0. В архиве много файлов и папок, но нам понадобится всего несколько.
Нужно скопировать все *.c файлы и папку include из папки "FreeRTOS\Source".
Также нужно скопировать папку "FreeRTOS\Source\portable\GCC\ARM_CM3".
Нужно из папки "FreeRTOS\Source\portable\MemMang" скопировать один из *.c файлов в зависимости от ситуации. Обычно хватает файла heap_1.c.
heap_1.c — собственный хитрый Malloc без Free. Т.е. мы можем создавать задачи (семафоры, очереди и т.д.), но не можем удалять их, чтобы освободить память. В принципе, для не слишком замороченных программ его хватает чуть более чем всегда. Задачи/очереди/семафоры всякие обычно создаются единожды и редко уничтожаются.
heap_2.c — динамичная фрагментированная память. Т.е. память динамически выделяется, освобождается, но при этом участки памяти получаются фрагментированными, с дырками на месте освободившейся памяти. И мы не сможем выделить большой кусок памяти, пусть даже у нас будет куча маленьких свободных секторов суммарно нужного обьема. А если новая задача укладывается в какой-либо из этих просветов, то будет выбран наиболее подходящий по размеру свободный кусок и задача развернется там.
heap_3.c — использован классический для Си Malloc/Free механизм с небольшой допилкой для невозожности запуска его из двух разных потоков.
heap_4.c — Динамическое выделение памяти, может дефрагментировать память, чтобы получить нужный кусок. Разумеется за все приходится платить. Временем в первую очередь.
heap_5.c — Тоже что и heap_4.c, но добавлена поддержка нескольких куч.[/b]
Также понадобится файл конфигурации ОС FreeRTOSConfig.h который можно взять скажем из папки "FreeRTOS\Demo\CORTEX_STM32F103_Primer_GCC".
Теперь нужно добавить все эти файлы в проект и приступать к разработке программы с поддержкой многозадачности. Для примера была создана программа с четырьмя задачами в которых находится код мигания светодиодами с разной длительностью задержки, т. е. мигают они асинхронно.
Код:#include "stm32f10x_conf.h" #include "FreeRTOS.h" #include "task.h" TaskHandle_t Task_1_Handle; TaskHandle_t Task_2_Handle; TaskHandle_t Task_3_Handle; TaskHandle_t Task_4_Handle; void Task_1(void const *argument) // Задача 1. { while(1) { GPIO_SetBits(GPIOA, GPIO_Pin_4); vTaskDelay(200); GPIO_ResetBits(GPIOA, GPIO_Pin_4); vTaskDelay(100); } } void Task_2(void const *argument) // Задача 2. { while(1) { GPIO_SetBits(GPIOA, GPIO_Pin_5); vTaskDelay(50); GPIO_ResetBits(GPIOA, GPIO_Pin_5); vTaskDelay(400); } } void Task_3(void const *argument) // Задача 3. { while(1) { GPIO_SetBits(GPIOA, GPIO_Pin_6); vTaskDelay(100); GPIO_ResetBits(GPIOA, GPIO_Pin_6); vTaskDelay(500); } } void Task_4(void const *argument) // Задача 4. { while(1) { GPIO_SetBits(GPIOA, GPIO_Pin_7); vTaskDelay(200); GPIO_ResetBits(GPIOA, GPIO_Pin_7); vTaskDelay(200); } } void vApplicationIdleHook(void) // Функция вызывается когда МК делать нечего, т. е. все задачи неактивны. { __WFI(); // Отправляем МК спать до ближайшего прерывания. } int main(void) { { GPIO_InitTypeDef GPIO_InitStructure; // Настройка портов A4, A5, A6 и A7 на выход RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } // Создание задач. xTaskCreate((TaskFunction_t) Task_1, "Blinker 1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, Task_1_Handle); xTaskCreate((TaskFunction_t) Task_2, "Blinker 2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, Task_2_Handle); xTaskCreate((TaskFunction_t) Task_3, "Blinker 3", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, Task_3_Handle); xTaskCreate((TaskFunction_t) Task_4, "Blinker 4", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, Task_4_Handle); // Запуск планировщика задач. vTaskStartScheduler(); while(1) { } }
Сами по себе задачи (потоки) это обычные функции код которых регулярно выполняется по мере переключения задач и в функции должен быть бесконечный цикл.
Задача создается функцией xTaskCreate.
Task_1 - это имя функции которая будет задачей.
"Blinker 1" - текстовая строка для отладки. Может быть любой, но длина ограничена в конфиге ОС.
configMINIMAL_STACK_SIZE - размер стека для задачи. Определяется опытным путем. В данном случае стоит системный минимум, т. к. задачи используют очень мало памяти.
NULL - передаваемый argument в задачу. В данном случае не нужен, потому NULL.
tskIDLE_PRIORITY + 1 - приоритет задачи. Выбран минимально возможный. На 1 пункт выше чем IDLE.
Task_1_Handle - адрес переменной типа xTaskHandle в которую запишется дескриптор задачи. Зная этот дескриптор мы можем ею управлять, например приостановить или завершить ее работу.
Функция vTaskStartScheduler() запускает планировщик задач и с этого момента на ОСи начинают крутиться задачи.
Среда EmBitz при отладке обнаружила использование FreeRTOS в проекте и показала все задачи и некоторую информацию о них.
Теперь о том что наверное интересует многих - сколько ресурсов требует ОСь. Как оказалось, сравнительно не много. Нужно примерно 1.5 КБ flash и по 602 байта ОЗУ на каждую задачу. Учитывая что в МК 20 КБ ОЗУ, это позволит запустить до 30 задач, что на мой взгляд больше чем достаточно. А ведь есть МК с гораздо большим объемом ОЗУ... Например STM32F03RET6 содержит 512 КБ flash и 64 КБ ОЗУ.
Файлы примера. http://pure-basic.narod.ru/forum_files/ … askLed.zip
Светодиоды нужно подключить к выводам A4, A5, A6 и A7.