Comments 26
Было дело, я как то писал простого планировщика под ардуино с похожим принципом работы, только задачам при их создании не задавался интервал времени, а задавался только приоритет. Частота вызова задачи зависит от неё самой, то есть от вызова sleep() или yield() и т.д.. Также можно в процессе работы задачи изменить её приоритет. А планировщик раскидывает очередь выполнения задач в зависимости от их состояния и приоритетов.
FreeRTOS вполне работает на PC на базе родных потоков. Я работал над проектами использующими FreeRTOS, где целевым устройством был микроконтроллер на PowerPC, а отладка так же велась на PC.
Я работал над проектами использующими FreeRTOS, где целевым устройством был микроконтроллер на PowerPC
А что это был конкретно за PowerPC микроконтроллер? Случайно не этот
https://www.st.com/en/automotive-microcontrollers/spc58nn84e7.html
SPC58NN84E7RMHBR, ядро e200z4, 200Mhz, 32bit, Flash:6576 MByte, SRAM: 128 KByte, QFP 177pins, 3x cores, Arch: Harvard, D-Cache: 8kByte, big endian?
В свое время делал так: https://community.alexgyver.ru/threads/programmirovanie-konechnyx-avtomatov-bez-delay.2657/
Ещё где-то был вариант вытесняющей работы на прерывании от watchdog, а не кооперативный.
Всё-таки думается, что для кооперативного планировщика очень нужна функция yield, которую можно внутри задачи вызвать, чтоб вернуть управление планировщику и уступить процессор другой задаче. Без этого не торт :(
Зачем?
Если это набор конечных автоматов, которые чем-то там управляют, то включи/выключил, сменил состояние. Всё, работа этого шага завершена. Если это некий сьем показаний, то .. а в общем-то тоже самое - снял, сложил в очередь на обработку и .. всё, ждем активации заново.
Сложный и долгий числодробильный алгоритм, который надо прервать, передать управление системе? Так опять же это не задача для yield() .. Суть этой функции - вызвать нечто, когда задача не знает что делать (ожидает ввода-вывода, замера и т.д.) но и отдавать управление не хочет, а простаивать - плохо.. Решается реорганизаций архитектуры: разбиваем задачу на отдельные конечные автоматы (они там есть) и работаем с ними как обычно.
YAGNI.
из RTOS для МК есть еще https://github.com/scmrtos/scmrtos
Для еспЭшек удобным оказалось применять библиотеку Ticker (в ардуинах можно неблокирующим миллисом хотя есть и библиотеки, аналогичные тикеру) . Определяя тикером тайминг каждого процесса я выставляю по времени флаг запроса на обслуживание внутри вектора, а обслуживаю процесс и сбрасываю флаг уже в основном цикле по порядку. В общем то можно и очередь с приоритетами организовать но мне это не требуется. Обслуживаемые процессы работают с массивным тепловым оборудованием и высокая частота обслуживания не требуется. Самый частый процесс - сбор данных с датчиков и актуализация сформированных состояний исполнительных устройств - раз в одну секунду.
Пожалуйста, добавьте в опрос " Какую RTOS вы использовали при программировании микроконтроллеров?" вариант "Свою самописную".
Думаю, понятно, что это вариант большинства. Вытесняющая многозадачность, приоритеты, виртуальная память и контексты доступа для МК, выполняющего конкретную узкоспециализированную задачу редко или вообще не нужны. А написать простенький велосипед с очередью задач и планировщиком на прерываниях системного таймера - дело пары часов.
когда для писал для pic16 делал просто главный цикл из которого вызывал всё. Ну да, клавиатуру можно не опрашивать так часто как датчик позиции, но если мы не упираемся в производительность процессора то почему бы и не опросить.
Но теперь на freertos делаю - намного удобнее писать логику не конечными автоматами а в явном виде. Послать запрос, подождать ответа, если чексумма сошлась обработать, повторить. Из минусов freertos разве что тики не быстрее 1мс, но это легко решается - запускаю таймер на 100мкс, в нем выставляю семафор, а в задаче вместо vTaskDelay делаю ожидание семафора.
А вот если опрашивать клавиатуру раз в 200мсек то не нужно отслеживать дребезг. А если функция вызывается через строгое время то этим вполне можно внутри функции пользоваться для отсчета времени ))
Ну и поймаете вместо дребезга (часто меняющегося значения) неверное значение, потому что опрос с периодом 200ms выпал неудачно на время дребезга...
0.2с ? Мне казалось я быстрее клавиши нажимаю, т.е. просто будете пропускать нажатия...
Проголсовал за пункт "супер-цикл, который прокручивает конечные автоматы + прерывания"
В своем планировщике кроме периода выполнения таски добаввил еще и фазу. Так можно таски распределять блолее равномерно, плюс можно легко делать связанные таски, выполняющиеся с равным периодом, но с задержекой друг от друга. Например при опросе датчиков по OneWire, одна таска отпрравляет команду на измерение, а другая через несколько милисекунд считывает показания и обе выполняются раз в несколько секунд.
PS мой планировщик:
mkLoop :: SystemClock -> [Task] -> Def ('[] :-> ())
mkLoop systemClock tasks = proc "loop" $ body $ do
let (scheduled, immediately) = partition (isJust . period) tasks
clocks <- replicateM (length scheduled) (local (ival 0))
forever $ do
t <- getSystemTime systemClock
zipWithM_ (run t) clocks scheduled
mapM_ runTask immediately
where
run t1 clock task = do
t0 <- deref clock
let Period interval phase = fromJust $ period task
when (t1 - t0 >=? interval + phase) $ do
runTask task
store clock $ t1 - phase
И пример тасков:
addTask $ delay 15_000 (name <> "_search" ) $ searchDevices
addTask $ delayPhase 15_000 6_000 (name <> "_measure_temperature") $ measureTemperature
addTask $ delayPhase 15_000 6_700 (name <> "_get_temperature" ) $ getTemperature
Гениально! Управлять фазой запуска задач.
Это я подсмотрел вот здесь: https://copilot-language.github.io/
Там алгоритмы пишутся как обработка виртуальных бесконечных потоков изменения состояния системы. И таймер реализуется как раз периодом и фазой
Я так понял, пример кода на Rust. Верно?
Это Haskell =)
Я время от времени сравниваю языки программирования.
Если не сложно, то я был бы признателен за заполнение строчки про Haskell
https://docs.google.com/spreadsheets/d/1GJQqpEBGsIMhReNVLeo6LmvwbcFg2ttXLAXgHXlaqjQ/edit#gid=0
Диспетчер Задач для Микроконтроллера