Процессы
Каждый процесс в scmRTOS представляет собой отдельный класс, который описан с использованием шаблонов C++. Для создания процесса нужно определить его тип, объявить объект этого типа и написать функцию процесса Exec().
Создание процесса выглядит следующим образом:// Определяем тип процесса
typedef OS::process<OS::pr0, 40, 10> TProc1;
//Объявляем объект
TProc1 Proc1;
//функция процесса, выполняющая полезную работу
OS_PROCESS void TProc1::Exec()
{
//объявления
//инициализация данных процесса
for(;;)
{
//полезный код
}
}
//0 соответствует варианту, когда pr0 наиболее приоритетный процесс
//1 соответствует варианту, когда pr0 наименее приоритетный процесс
#define scmRTOS_PRIORITY_ORDER 0
Приоритеты процессов должны идти подряд и не должны повторяться. Приоритеты процессов задаются на этапе объявления типа процесса и не могут быть изменены по ходу программы.
Операционная система scmRTOS позволяет объявить до 31 процесса. Количество объявленных процессов должно быть указано в конфигурационном файле scmRTOS_CONFIG.h.
//количество пользовательских процессов
#define scmRTOS_PROCESS_COUNT 2
Помимо процессов определенных пользователем, в операционной системе существует системный процесс - IdleProcess (его не нужно создавать, он прописан в коде ОС). У него всегда самый низкий приоритет, не зависимо от заданного порядка старшинства приоритетов.
В конфигурационном файле scmRTOS_config.h для системного процесса есть несколько настроек.
//размер стека данных и стека возвратов для системного процесса
#define scmRTOS_IDLE_PROCESS_DATA_STACK_SIZE 70
#define scmRTOS_IDLE_PROCESS_RETURN_STACK_SIZE 10
//0 – откл./1 – вкл. в системном процессе вызов функции IdleProcessUserHook()
//если указанная функция включена, то она должна быть определена пользователем
#define scmRTOS_IDLE_HOOK_ENABLE 0
функция IdleProcessUserHook() определяется так:
void OS::IdleProcessUserHook()
{
//какой-нибудь пользовательский код
}
Изменив размеры стеков системного процесса (исключительно ради любопытства) и запустив компиляцию, я получил ошибку. Полез в код, где описана функция системного процесса и обнаружил следующее. process<prIDLE, scmRTOS_IDLE_PROCESS_DATA_STACK_SIZE, scmRTOS_IDLE_PROCESS_RETURN_STACK_SIZE> IdleProcess; OS_PROCESS void process<prIDLE, 70, 10>::Exec() { for(;;) { #if scmRTOS_IDLE_HOOK_ENABLE == 1 IdleProcessUserHook(); #endif } } Ошибка при описании функции Exec()! Заменил заданные значения размера стеков на именованные константы, и все откомпилировалось. OS_PROCESS void process<prIDLE, scmRTOS_IDLE_PROCESS_DATA_STACK_SIZE, scmRTOS_IDLE_PROCESS_RETURN_STACK_SIZE >::Exec() { …… } Посмотрел код в scmRTOS 3.10 – там этот баг устранили. |
Планировщик
Собственно сама процедура передачи управления реализована в scmRTOS двумя способами:
Способ передачи управления задается в конфигурационном файле scmRTOS_config.h.
//0 - прямая передача управления,
//1 — передача управления с помощью программного прерывания
#define scmRTOS_CONTEXT_SWITCH_SCHEME 0
Системный таймер
//0 — выкл./1 — вкл. использование счетчика тиков системного таймера
#define scmRTOS_SYSTEM_TICKS_ENABLE 1
//0 — запрещает/1 — разрешает вложенные прерывания
//в обработчике прерывания от системного таймера
#define scmRTOS_SYSTIMER_NEST_INTS_ENABLE 0
//0 — выкл./1 — вкл. в обработчике прерывания системного таймера
//вызов функции SystemTimerUserHook()
//в этом случае указанная функция
//должна быть определена в пользовательском коде
#define scmRTOS_SYSTIMER_HOOK_ENABLE 1
Функция SystemTimerUserHook() определяется так:
void OS::SystemTimerUserHook()
{
//перезапуск таймера Т0 или какой-нибудь другой код
}
Первая программа на scmRTOS для AVR
В начале main.cpp подключаем заголовочные файлы.
#include <ioavr.h>
#include <scmRTOS.h>
typedef OS::process<OS::pr0, 40, 10> TProc1;
typedef OS::process<OS::pr1, 40, 10> TProc2;
Объявляем объекты процессов.
TProc1 Proc1;
TProc2 Proc2;
#define LED1 0
#define LED2 1
#define LED_DDR DDRB
#define LED_PORT PORTB
int main()
{
//настройка порта
LED_DDR = 0xff;
LED_PORT = (1<<LED1)|(1<<LED2);
// инициализация системного таймера - период 1 мс
TCNT0 = 0xf0;
TCCR0 = 0x05;
TIMSK |= (1 << TOIE0);
//запуск операционной системы
OS::Run();
}
Описываем процессы.
OS_PROCESS void TProc1::Exec()
{
for(;;)
{
LED_PORT ^= (1<<LED1);
Sleep(500);
}
}
OS_PROCESS void TProc2::Exec()
{
for(;;)
{
LED_PORT ^= (1<<LED2);
Sleep(120);
}
}
Описываем функцию перезапуска системного таймера.
//функция перезапуска системного таймера
//она вызывается в прерывании
void OS::SystemTimerUserHook()
{
TCNT0 = 0xf0;
}
//количество пользовательских процессов
#define scmRTOS_PROCESS_COUNT 2
//запретить вложенные прерывания в обработчике прерывания системного таймера
#define scmRTOS_SYSTIMER_NEST_INTS_ENABLE 0
//включить использование счетчика тиков системного таймера
#define scmRTOS_SYSTEM_TICKS_ENABLE 1
//включить в обработчике прерывания системного таймера
// вызов функции SystemTimerUserHook()
#define scmRTOS_SYSTIMER_HOOK_ENABLE 1
//выключить в системном процессе вызво функции IdleProcessUserHook()
#define scmRTOS_IDLE_HOOK_ENABLE 0
//прямая передача управления
#define scmRTOS_CONTEXT_SWITCH_SCHEME 0
//порядок приоритетов — pr0 имеет наивысший приоритет
#define scmRTOS_PRIORITY_ORDER 0
Остальные настройки, не указанные здесь, трогать не нужно.
Компилируем проект и запускаем в железе или Proteus`e.
Файлы
Документация на scmRTOS v2Дистрибутив scmRTOS v3.05
Проект для IARa - первая программа на scmRTOS
Проект для Proteus`a
Comments
Только вот я разочарован в ОС'ах (((Мне казалось, что на нее больше можно возложить(
Я к тому, что ОСРВ на АВРах себя оправдывает лишь в приложениях, ориентированных на работу с пользователем.. . К примеру, если мне надо каким-нибудь двигателем трехфазным ШИМом управлять, я не выберу ОС я сделаю на прерываниях... и буду прав
P.S. Я все-таки зануда)))))
И еще раз: scmRTOS система простая, в которой есть все, что ОСРВ требует: семафоры, события, очереди. Простота и подкупает. Разобраться, как писать для неё, можно за пару часов. Не в пример freeRTOS.
Лично "перешёл" на ОС т.к. требовалось параллельное асинхронное обращение к устройству, висящему на SPI, из разных процессов.
"Таким образом, при использовании компиляторов от IAR Systems име-
ется два стека: один стек для данных, второй – для адресов возвратов.
scmRTOS учитывает этот момент и поддерживает по два стека для ка-
ждого процесса, причем размер каждого стека можно задать индивидуально,
исходя из требований ресурсоемкости прикладной задачи."
RSS feed for comments to this post