AVR. Учебный курс. Операционная система. Введение.

Рано или поздно наступает момент когда сложность алгоритма становится такой, что дальнейшее развитие и усложнение программы превращается в нетривиальную задачу. Очень легко запутаться и тяжело отлаживать эту портянку. Многие бегут от этих сложностей в языки высокого уровня, впрочем это не особо спасает — разница минимальна на самом деле и проще не становится.
Самое верное решение в данном случае — внедрение в проект операционной системы. Которая бы предоставляла API для решения задач, а также обеспечивала порядок работы всей системы.

В результате было написано микроядро. Камрад Serg2x2 подглядел концепцию в прошивке сотового телефона Motorola и портировал на микроконтроллер АТ89С2051, после ее перенесли на AVR, а я привел все в библиотечный и структурированный вид, обвязал все удобными макросами, а также подробно описал и задокументировал. Так что теперь интеграция ядра операционки в проект под микроконтроллер AVR занимает буквально пару минут работы Copy-Paste.

Ядро обеспечивает очередь задач (пока без приоритетов, но это в планах) и службу таймеров. Многозадачность кооперативная, что накладывает соответствующие ограничения на стиль написания. Фактически, каждую процедуру мы пишем как прерывание, максимально коротко и быстро, все задержки вешая на службу таймеров.

Параметры и системные требования микроядра:

  • Занимаемый обьем в Flash — 500 байт, при желании можно ужать до 400 байт, выкинув ненужные функции.
  • Рекомендуемый объем RAM — не менее 20 байт+стек, впрочем, можно еще ужать если нагрузка небольшая.
  • Крайне желательная поддержка команд STS и LDS, можно и без них, но неудобно. Впрочем, макросы решают.


Суть всех заморочек
Представь что ты пишешь простейшую программу — мигнуть светодиодом. Как ты это будешь реализовывать?
На ум сразу же приходит следующий алгоритм:

  • Зажечь диод.
  • Потупить в цикле
  • Погасить диод.

Просто, логично, понятно.

А если усложнить? Мигать будем не одним диодом, а тремя, да еще чтобы первый мигал с частотой в 1кГц, второй в 500Гц, а третий 200Гц. Представил сразу же в голове алгоритм? Наверняка тут же получил переклин мозга и немудрено. Линейно развернуть такую структуру весьма сложно, даже если применить таймеры. Да, на таймерах выкрутишься, но это пока диодов три, а если десять?

Как то же самое делается на микроядре:

Главный цикл

  • Вызов задачи 1
  • Вызов задачи 3
  • Вызов задачи 5
  • Бесконечный цикл ожидания с опросом очереди

Таблица задач

  • Задача_1: Зажечь диод 1. Поставить вызов задачи 2 в очередь с задержкой 1мс
  • Задача_2: Погасить диод 1. Поставить вызов задачи 1 в очередь с задержкой 1мс
  • Задача_3: Зажечь диод 2. Поставить вызов задачи 4 в очередь с задержкой 2мс
  • Задача_4: Погасить диод 2. Поставить вызов задачи 3 в очередь с задержкой 2мс
  • Задача_5: Зажечь диод 3. Поставить вызов задачи 6 в очередь с задержкой 5мс
  • Задача_6: Погасить диод 3. Поставить вызов задачи 5 в очередь с задержкой 5мс

Все. Основной алгоритм получается практически линейным. Остальное делает ядро. Не меняя структуры можно добавить еще задач, навешать их в любом порядке. И это практически не повлияет на выполнение остального кода, разве что придется немного скорректировать настройки таймера.

По договоренности с издательством Gameland я, до выхода журнала не буду раскрывать всех подробностей. В мартовском журнале Хакер будет статья по микроядру, после выхода журнала я еще немного подожду и со спокойной душой продолжу.

Пока же можете скачать готовую программу на микроядре и посмотреть что там как. Может разберетесь :)

30 thoughts on “AVR. Учебный курс. Операционная система. Введение.”

  1. Тююю. Так не интересно. Называется Поматросил и бросил… Вот после выхода статьи и писал бы. А со светодиодами задачка просто решается. Тут надо понимать, что тупить можно не только в цикле, но и занимаясь при этом полезными делами. И ещё — что алгоритм, разрезаный на 10 кусочков, работает точно так же, как был бы единым. Так что две переменных и один таймер. Причём всё «в лоб». Крутим цикл, каждый раз проверяем на соответствие граничным значениям, и в зависимости от — гасим или зажигаем. Ещё и скважность мигания регулироваться будет. Так что пример крайне неудачный, тут никакая «система» не нужна. Лучшая система, парни, находится у вас на плечах. Типа шапку вы на ей носите, а ещё туда кушаете.

  2. Посмотрите _русскую_ доку на операционку «JacOS»: jacos.narod.ru — там очень хорошо рассказывается, что такое ОС в применении к микроконтроллерам, зачем это нужно и как применять. Сам JacOS, к сожалению, сдох, но вот описалово — «нетленка» forever!

    Я лично сейчас осваиваю AvrX: http://www.barello.net/avrx/ — операционка для AVR, заточена под использование из C (WinAVR), но сама написана на АСМе ;) Пока нравится.

  3. Конкретно с 10 (и вообще любым количеством) светодиодов довольно просто решается через переменные-счетчики. На каждый диод заводится свой счетчик и инициализируется некоторым значением. За каждый проход цикла уменьшается значение всех счетчиков, и те из них, которые достигли нуля, означают что пора включать (выключать) соответствующий диод. После этого значение этого счетчика перезагружается. Естественно, они должны быть рассчитаны заранее, чтобы обеспечить требуемую задержку.

    1. В любом случае надо городить кучу проверяющих условий. Проверку каждого на совпадение, замедление таймера и еще дофига параметров.

    2. Я в таких случаях делаю проще. Делаю прерывание по таймеру, например, 1 мсек. В обработчике прерывания проверяю счетчики, если не 0, — декремент.
      Главный проверяет состояния счетчиков, если не 0 включает светодиод, иначе выключает. Остается по мере надобности забрасывать в программные счетчики нужные значения в мс. Аналогично делаю встроенные часы и календарь, только там инкремент до нужного значения и, например, при 60 в счетчике секунд обнуляю его с инкрементом минутного, если он достиг 60, сбрасываю в 0, и инкрементирую счетчик часов, и т.д.
      Для больших задержек делаю декремент нужного по инкременту секунд, или минут, или часов и т.д.

    3. кстати можно не создавать на каждый светодиод по переменной, которая считает время, а создать на все светодиоды только ОДНУ переменную. Да)
      Метод очень хорошо сработает, сэкономив оперативку, загруженность, количество переменных, но при условии что периоды мигания светодиодов относятся как относительно небольшие целые числа и не нужно менять скорость мигания во время исполнения программы.

      Как сказал SWG, делаем прерывание по таймеру 1 мс вместо дилэя и увеличиваем эту переменную на единицу. Когда переменная доходит до величины НОК(период мигания1; период мигания2; … пер.мигN), то присваиваем ей единицу (не ноль!). Затем для каждого светодиода проверяем : кратно ли значение переменной полупериоду мигания светодиода. Если да, то выцключаем\включаем его.

      Преимущества: выше скорость работы(так как не тратим время чтобы увеличить КАЖДУЮ переменную светодиода), меньше жрёт оперативки(если периоды мигания светодиодов относятся как относительно небольшие целые числа), экономим ценные имена (типа a,b,c,d) для переменных XD

      *НОК — наибольшее общее кратное, если кто забыл
      **в принципе можно и менять периоды мигания светодиодов во время работы, при этом пересчитав НОК, но тогда применение этого алгоритма становится нецелесообразно по ряду причин.

      1. Такого понятия как «найбольшее общее кратное» — нет. Есть НОД — «найбольший общий делитель»,и НОК -«найменьшее общее кратное»

    1. Больно универсальна. А намек на то, что дескать для понятности написана в основном на си уже говорит о том, что жирная и неторопливая. Критические вещи надо писать на асме, тем более такие как ОС :)

      НУ и запустится она скорей на МК не младше чем АТМега64

    1. Видел. Слишком тяжела. Надо чтобы на Тини2313 запускалась и еще места под прикладную часть было хотя бы 70%

  4. дык ето что ж —чтобы например на atmege8 32-мя каналами светодиодов мигать с шимом и читать из внешней пэзэушки(twi) значения шим надо обязательно rtos?

    1. Нет конечно, можно и на флагах сфигачить, но на РТОС будет проще. Я так уже все на ней делаю, обленился :) Тем более после обрезки ядро занимает 300+ байт всего.

      1. Программист и не ленивый—это не программист(ни сисадмин и даже не сисоп(если кто помнит что это такое)

        первое знакомство с микроконтролерами начал с пиков на асме. Но так как паскаль
        ближе решил на АДА(для AVR)-быстро, классно и главное как роман читаешь не то что Си. Ну не нраятся мне эти printf(~%’зю зю :~»Если в программе есть циклы она зацикливается, если в программе есть лупы она…

        т.е. асм для AVR учить..видно не отвертишься —БЛИН. Жаль task(ВОТ ЭТО МОЩА) адовский для AVR не работает(мозги б были реализовал на уровне компилятора я имею Ввиду).

        1. ADA дееспособен в восьмиразрядных системах? Знание механизмов ADA позволяет его использовать в этом случае лишь как язык проектирования с некоторыми упрощениями при трансляции. Здесь полезней язык подобный FORTH (неструктурный разумеется, в виде байт-кода (псевдокода), реализованный под обработку событий и распределенный мультипроцессор — это уже ОС

          1. При переходе к 32-разрядным системам подобный Forth&OS (здесь ModBus=> ForthBus) стал бы хорошей «подложкой» (нижним уровнем Ada-системы) для среды исполнения Ada — распределяя для ее подпрограмм память и процессоры (стеки и Forth-домены)

    1. По RTOS написано как минимум уже статьи четыре. Архитектура, принцип работы, пример работы. Пошарь по метке RTOS и найдешь.

  5. Знаю заранее, что спрошу неинтересную вещь… но!
    эта ОС, судя по дальнейшей разработке, предназначается для мигания светодиодами (может не так, тогда я что-то не до читал или не понял).
    просто есть идея ОС типа Монитор для AVR Atmega 16.
    И нужен овет знающего человека.

    1. Ну у меня на ней не только светодиоды мигают, а вращается несколько довольно крупных проектов. Куча задач таскается по диспетчеру.

      Шо есть Монитор?

      1. Монитор — есть управляющая программа (как на совковых бытовых компах), могущая записывать/считывать байт память, передавать/принимать с порта данные и запускать программу в памяти.
        Это ещё ничего, но дело в том, что данные ей надо передавать с клавиатуры. И не с зачататочной шестнадцатиразрядной, а с полноценной PC/XT…
        но я посоветовался с народом, и народ говорит, что так как монитор наш для Прибора, то все эти премудрости не к чему, поэтому придумали мы меню с выбором программ вместо монитора… но я гляжу это ещё сложнее…. гораздо…

        1. На AVR это практически нереально. Т.к. во флеш мы писать не можем. Разве что через бутлоадер и страницами. Но толку от этого немного, т.к. в бутлоадер много не засунешь. Да и перезаписывать под каждую задачу тоже не выход.

          Разве что насовать в память разных программ и переходит к их исполнению через меню. Ну так это элементарно и никаких заморочек не требует.

          1. так, зачит с этим частично разобрались. Вопрос второй: есть два AVR.
            МОЖНО ЛИ сделать следующее (а если можно, то коротко как): один использовать как ЦП, второй как контроллер дисплея (хотя, это надо ещё подумать и перечитать статью по дсиплей к AVR…). На первый навесить вычисления и клавиатуру (проблема — как подключать?!!), на второй — вывод на дисплей.

            1. От типа дисплея зависит. Если обычный, текстовый, вроде HD44780 то можно и на одном реализовать. Если графический или телевизор, то один будет дисплеем загружен по самые помидоры, а второй может ему данные на вывод гнать по SPI или по UART если скорость большая не нужна.

              Вопрос зачем это нужно? Как бы не МК не для тех задач предназначен.

              1. Я говорил srg-2811 об этом, но меня не послушали. Польстились на простоту железа и понятный асемблер.
                Дисплей текстовый. Телевизионный слишком жирно для ПРИБОРА.
                Но с монитором/меню все равно какая-то ерунда…

          2. Ему нужна учебная система (не ОС, не итнерпретатор приказов) — реально. Сам того не подозревая, он завел вас на нижний уровень описываемой вами ОС — уровень загрузчика (самопрограммирование). Полагаю, такой учебник следует начинать с конфигурационных ячеек, загрузчика, связанных с загрузчиком сегментов сброса (кроме того, Вы его не рассматриваете долнжным образом, событие — исключены аппаратные модули bod, wd, extreset, jtag) и прерываний.

Добавить комментарий

Ваш e-mail не будет опубликован.

Перед отправкой формы:
Human test by Not Captcha