Введение в разработку приложений для встроенных систем на платформе Intel Atom

Автоматизированное управление мобильным роботом

Показывать лекцию целиком

7.1. Введение: Особенности операционных систем реального времени

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

Операционные системы реального времени (ОСРВ) предназначены для обеспечения интерфейса к ресурсам критических по времени систем реального времени. Основной задачей в таких системах является своевременность (timeliness) выполнения обработки данных.

В качестве основного требования к ОСРВ выдвигается требование обеспечения предсказуемости или детерминированности поведения системы в наихудших внешних условиях, что резко отличается от требований к производительности и быстродействию универсальных ОС. Хорошая ОСРВ имеет предсказуемое поведение при всех сценариях системной загрузки (одновременные прерывания и выполнение потоков).

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

Принято различать системы мягкого (soft) и жесткого (hard) реального времени. В системах жесткого реального времени неспособность обеспечить реакцию на какие-либо события в заданное время ведет к отказам и невозможности выполнения поставленной задачи. В большинстве русскоязычной литературы такие системы называют системами с детерминированным временем. При практическом применении время реакции должно быть минимальным. Системами мягкого реального времени называются системы, не попадающие под определение "жесткие", т.к. в литературе четкого определения для них пока нет. Системы мягкого реального времени могут не успевать решать задачу, но это не приводит к отказу системы в целом. В системах реального времени необходимо введение некоторого директивного срока (в англоязычной литературе - deadline), до истечения которого задача должна обязательно (для систем мягкого реального времени - желательно) выполниться. Этот директивный срок используется планировщиком задач как для назначения приоритета задачи при ее запу ске, так и при выборе задачи на выполнение.

Мартин Тиммерман сформулировал следующие необходимые требования для ОСРВ:

  • ОС должна быть многозадачной и допускающей вытеснение (preemptable),
  • ОС должна обладать понятием приоритета для потоков,
  • ОС должна поддерживать предсказуемые механизмы синхронизации,
  • ОС должна обеспечивать механизм наследования приоритетов,
  • поведение ОС должно быть известным и предсказуемым (задержки обработки прерываний, задержки переключения задач, задержки драйверов и т.д.); это значит, что во всех сценариях рабочей нагрузки системы должно быть определено максимальное время отклика.
  • В течение последних 25-30 лет структура операционных систем эволюционировала от монолитной к многослойной структуре ОС и далее к архитектуре клиент-сервер. При монолитной структуре ОС состоит из набора модулей, и изменения одного модуля влияют на другие модули. Чем больше модулей, тем больше хаоса при эксплуатации такой системы. Кроме того, невозможно распределить ОС в многопроцессорной системе. В многослойной структуре изменения одного слоя влияют на соседние слои; кроме того, обращение через слой невозможно. Для систем реального времени должно быть обеспечено прямое обращение к каждому слою ОС, а иногда напрямую к аппаратуре.

    Основной идеей клиент-серверной технологии в ОС является сведение базиса ОС к минимуму (планировщик и примитивы синхронизации). Вся остальная функциональность выносится на другой уровень и реализуется через потоки или задачи. Совокупность таких серверных задач отвечает за системные вызовы. Приложения являются клиентами, которые запрашивают сервисы через системные вызовы.

    Клиент-серверная технология позволяет создавать масштабируемые ОС и упрощает распределение в многопроцессорной системе. При эксплуатации системы замена одного модуля не вызывает эффекта "снежного кома"; кроме того, сбой модуля не всегда влечет за собой отказ системы в целом. Появилась возможность динамической загрузки и отгрузки модулей. Главной проблемой в этой модели является защита памяти, поскольку серверные процессы должны быть защищены. При каждом запросе сервиса система должна переключаться с контекста приложения на контекст сервера. При поддержке защиты памяти время переключения с одного процесса на другой увеличивается.

    Как правило, большинство современных ОСРВ построено на основе микроядра (kernel или nucleus), которое обеспечивает планирование и диспетчеризацию задач, а также осуществляет их взаимодействие. Несмотря на сведение к минимуму в ядре абстракций ОС, микроядро все же должно иметь представление об абстракции процесса. Все остальные концептуальные абстракции операционных систем вынесены за пределы ядра, вызываются по запросу и выполняются как приложения.

    Рассмотрим концептуальные абстракции операционной системы через призму требований к системам реального времени.

    7.2. Процессы, потоки, задачи

    Концепция многозадачности (псевдопараллелизм) является существенной для системы реального времени с одним процессором, приложения которой должны быть способны обрабатывать многочисленные внешние события, происходящие практически одновременно. Концепция процесса, пришедшая из мира UNIX, плохо реализуется в многозадачной системе, поскольку процесс имеет тяжелый контекст. Возникает понятие потока (thread), который понимается как подпроцесс, или легковесный процесс (light-weight process). Потоки существуют в одном контексте процесса, поэтому переключение между потоками происходит очень быстро, а вопросы безопасности не принимаются во внимание. Потоки являются легковесными, потому что их регистровый контекст меньше, т.е. их управляющие блоки намного компактнее. Уменьшаются накладные расходы, вызванные сохранением и восстановлением управляющих блоков прерываемых потоков. Объем управляющих блоков зависит от конфигурации памяти. Если потоки выполняются в разных адресных пространствах, система должна поддерживать отображение памяти для каждого набора потоков.

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

    7.3. Планирование, приоритеты

    В связи с проблемой дедлайнов главной проблемой в ОСРВ становится планирование задач (scheduling), которое обеспечивало бы предсказуемое поведение системы при всех обстоятельствах. Процесс с дедлайнами должен стартовать и выполняться так, чтобы он не пропустил ни одного своего дедлайна. Если это невозможно, процесс должен быть отклонен.

    В связи с проблемами планирования в ОСРВ изучаются и развиваются два подхода - статические алгоритмы планирования (RMS - Rate Monotonic Scheduling) и динамические алгоритмы планирования (EDF - Earliest Deadline First).

    RMS используется для формального доказательства условий предсказуемости системы. Для реализации этой теории необходимо планирование на основе приоритетов, прерывающих обслуживание (preemptive priority scheduling). В теории RMS приоритет заранее назначается каждому процессу. Процессы должны удовлетворять следующим условиям:

  • процесс должен быть завершен за время его периода,
  • процессы не зависят друг от друга,
  • каждому процессу требуется одинаковое процессорное время на каждом интервале,
  • у непериодических процессов нет жестких сроков,
  • прерывание процесса происходит за ограниченное время.
  • Процессы выполняются в соответствии с приоритетами. При планировании RMS предпочтение отдается задачам с самыми короткими периодами выполнения.

    В EDF приоритет присваивается динамически, и наибольший приоритет выставляется процессу, у которого осталось наименьшее время выполнения. При больших загрузках системы у EDF имеются преимущества перед RMS.

    Во всех системах реального времени требуется политика планирования, управляемая дедлайнами (deadline-driven scheduling). Однако этот подход находится в стадии разработки.

    Обычно в ОСРВ используется планирование с приоритетами, прерывающими обслуживание, которое основано на RMS. Приоритетное прерывание обслуживания (preemption) является неотъемлемой составляющей ОСРВ, т.к. в системе реального времени должны существовать гарантии того, что событие с высоким приоритетом будет обработано перед событием более низкого приоритета. Все это ведет к тому, что ОСРВ нуждается не только в механизме планирования на основе приоритетов, прерывающих обслуживание, но также и в соответствующем механизме управления прерываниями. Более того, ОСРВ должна быть способна запрещать прерывания, когда необходимо выполнить критический код, который нельзя прерывать. Длительность обработки прерываний должна быть сведена к минимуму.

    ОСРВ должна обладать развитой системой приоритетов. Во-первых, это требуется потому, что система сама может рассматриваться как набор серверных приложений, подразделяющихся на потоки, и несколько высоких уровней приоритетов должно быть выделено системным процессам и потокам. Во-вторых, в сложных приложениях необходимо все потоки реального времени помещать на разные приоритетные уровни, а потоки не реального времени помещать на один уровень (ниже, чем любые потоки реального времени). При этом потоки не реального времени можно обрабатывать в режиме циклического планирования (RRS - round-robin scheduling), при котором каждому процессу предоставляется квант времени процессора, а когда квант заканчивается, контекст процесса сохраняется, и он ставится в конец очереди. Во многих ОСРВ для планирования задач на одном уровне используется RRS. Приоритетный уровень 0 обычно используется для холостого режима.

    При планировании на основе приоритетов необходимо решить две обязательные проблемы:

  • обеспечить выполнение процесса с наивысшим приоритетом,
  • не допустить инверсии приоритетов, когда задачи с высокими приоритетами ожидают ресурсы, захваченные задачами с более низкими приоритетами.
  • Для борьбы с инверсией приоритетов в ОСРВ часто используется механизм наследования приоритетов, однако при этом приходится отказываться от планирования на основе RMS, поскольку приоритеты становятся динамическими.

    7.4. Прерывания

    При описании управления прерываниями обычно различают две процедуры, а именно:

  • программа обработки прерывания (ISR - interrupt servicing routine) - программа низкого уровня в ядре с ограниченными системными вызовами,
  • поток обработки прерывания (IST - interrupt servicing thread) - поток уровня приложения, который управляет прерыванием, с доступом ко всем системным вызовам.
  • Обычно ISR реализуются производителем аппаратуры, а драйверы устройств выполняют управление прерываниями с помощью IST. Потоки обработки прерываний действуют как любые другие потоки и используют ту же самую систему приоритетов. Это означает, что проектировщик системы может придать IST более низкий приоритет, чем приоритет потока приложения.

    7.5. Часы и таймеры

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

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

    Большинство ОСРВ оперируют относительным временем. Что-то происходит "до" и "после" некоторого другого события. В системе, полностью управляемой событиями, необходим часовой механизм (ticker), т.к. там нет квантования времени (time slicing). Однако, если нужны временные метки для некоторых событий или необходим системный вызов типа "ждать одну секунду", то нужен тактовый генератор и/или таймер.

    Синхронизация в ОСРВ осуществляется с помощью механизма блокирования (или ожидания) до наступления некоторого события. Абсолютное время не используется.

    Реализации в ОСРВ других концептуальных абстракций подобны их реализациям в традиционных ОС.

    7.6. Стандарты ОСРВ

    Большие различия в спецификациях ОСРВ и огромное количество существующих микроконтроллеров выдвигают на передний план проблему стандартизации в области систем реального времени.

    Наиболее ранним и распространенным стандартом ОСРВ является стандарт POSIX (IEEE Portable Operating System Interface for Computer Environments, IEEE 1003.1). Первоначальный вариант стандарта POSIX появился в 1990 г. и был предназначен для UNIX-систем, первые версии которых появились в 70-х годах прошлого века. Спецификации POSIX определяют стандартный механизм взаимодействия прикладной программы и операционной системы и в настоящее время включают набор более чем из 30 стандартов. Для ОСРВ наиболее важны семь из них (1003.1a, 1003.1b, 1003.1c, 1003.1d, 1003.1j, 1003.21, 1003.2h), но широкую поддержку в коммерческих ОС получили только три первых.

    Несмотря на явно устаревшие положения стандарта POSIX и большую востребованность обновлений стандартизации для ОСРВ, заметного продвижения в этом направлении не наблюдается.

    Некоторые наиболее успешные компании в области систем реального времени объявляют о своем решении принять в качестве стандарта спецификации одной из своих продвинутых ОСРВ. Так поступила компания TRON (the RTOS Nucleus), которая в 1987г. выпустила в свет первые ITRON спецификации - ITRON1. Далее в 1989г. она разработала и выпустила спецификации µITRON для 8- и 16- битовых микроконтроллеров, а также спецификации ITRON2 для 32-битовых процессоров. ОСРВ ITRON описывается ниже в соответствующем разделе. Этот стандарт является очень распространенным в Японии.

    Военная и аэрокосмическая отрасли предъявляют жесткие требования к вычислительным средствам, влияющим на степень безопасности целевой системы. В настоящее время имеются следующие стандарты для ОСРВ в авиации - стандарт DO-178B и стандарт ARINC-653. Поскольку эти стандарты разработаны в США, стоит отметить еще европейский стандарт ED-12B, который является аналогом DO-178B.

    Распространенным также является стандарт OSEK/VDX, который первоначально развивался для систем автомобильной индустрии.

    7.7. OSEK/VDX

    Стандарт OSEK/VDX является комбинацией стандартов, которые изначально разрабатывались в двух отдельных консорциумах, впоследствии слившихся. OSEK берет свое название от немецкого акронима консорциума, в состав которого входили ведущие немецкие производители автомобилей - BMW, Bosch, Daimler Benz (теперь Daimler Chrysler), Opel, Siemens и Volkswagen, а также университет в Карлсруэ (Германия). Проект VDX (Vehicle Distributed eXecutive) развивался совместными усилиями французских компаний PSA и Renault. Команды OSEK и VDX слились в 1994г.

    Первоначально проект OSEK/VDX предназначался для разработки стандарта открытой архитектуры ОС и стандарта API для систем, применяющихся в автомобильной промышленности. Однако разработанный стандарт получился более абстрактным и не ограничивается использованием только в автомобильной индустрии.

    Стандарт OSEK/VDX состоит из трех частей - стандарт для операционной системы (OS), коммуникационный стандарт (COM) и стандарт для сетевого менеджера (NM). В дополнение к этим стандартам определяется некий реализационный язык (OIL). Первым компонентом стандарта OSEK является стандарт для ОС, поэтому часто стандарт OSEK ошибочно воспринимается как стандарт ОСРВ. Хотя ОС и есть большая порция данного стандарта, мощность его состоит в интеграции всех его компонент.

    ОС OSEK оперирует такими объектами, как задачи, события, ресурсы. Кроме того, обеспечиваются такие возможности, как управление ошибками и средства для пользовательских функций отслеживания изменений в состоянии системы.

    ОС OSEK обеспечивает определенный набор интерфейсов для пользователя. Интерфейсы используются сущностями, конкурирующими за центральный процессор. ОС OSEK оперирует двумя типами таких сущностей - задачи и прерывания - и определяет три уровня обработки - уровень прерываний, логический уровень планировщика и уровень задач. Задачи выбираются на выполнение в соответствии с присвоенными им приоритетами.

    Задача в ОС OSEK может быть

  • базовой или расширенной,
  • вытесняемой или невытесняемой.
  • Главное различие между базовой и расширенной задачами заключается в том, может ли задача впасть в состояние ожидания (в котором она ждет появления события). Только расширенная задача может ожидать события. Вытесняемая задача может быть вытеснена задачей более высокого приоритета или прервана прерыванием. Невытесняемая задача может быть вытеснена только с помощью прерывания (когда прерывания не запрещены).

    (рис 7.1)

    Концепция двух типов задач потребовала введения нового понятия - класс соответствия (conformance class) для описания своеобразной реализации ОС OSEK и системных сервисов. Определяются четыре класса соответствия - два для базового соответствия (BCC1 и BCC2 - Basic conformance Classes 1 и 2) и два для расширенного (ECC1 и ECC2 - Extended Conformance Classes 1 и 2). Реализации, которые соответствуют базовым классам, требуют использования только базовых задач, в то время как для расширенных классов нужны как расширенные, так и базовые задачи. Числа 1 и 2 в именах классов указывают количество запросов на задачу для базовых задач и количество задач на приоритет для всех задач. Таким образом, в BCC1 и ECC1 имеется только одна задача на приоритет, и базовые задачи могут быть запрошены только один раз. В BCC2 и ECC2 допускается множественность задач на приоритет и множественное запрашивание базовых задач.

    Каждая задача должна находиться в одном из четырех состояний

  • Выполняющаяся - только одна задача может быть в этом состоянии,
  • Готовая к выполнению - планировщик может выбрать ее на выполнение на основании приоритетов и правил вытеснения,
  • Ожидающая - задача ждет появления события,
  • Приостановленная - задача в пассивном состоянии и ждет активации.
  • (рис 7.2) Модель состояний задачи в ОС OSEK

    Каждая задача имеет приоритет. Стандарт ОС OSEK не ограничивает максимальное количество приоритетов - это определяет реализация.

    ОС OSEK определяет два уровня программ управления прерываниями, которые различаются возможностями вызова системных сервисов. Прерывания уровня 1 выполняются независимо от ОС очень быстро. Уровень 2 обеспечивает выполнение функций приложений, которые содержат вызовы ОС.

    События в ОС OSEK используются для синхронизации различных задач. События являются собственностью задач. Любая задача, в том числе и базовая, может установить событие, и только собственник события может ожидать или снять его.

    Управление ресурсами обеспечивает доступ к разделяемым ресурсам, таким как память, аппаратура и т.п. Планировщик также считается специальным ресурсом, который может быть захвачен задачами. Чтобы избежать инверсии приоритетов и тупиковых ситуаций, OSEK применяет потолочный протокол приоритетов. Согласно этому протоколу задаче, захватившей ресурс, временно повышается приоритет, и, таким образом, никакие другие задачи, обращающиеся к данному ресурсу, не смогут выполняться до тех пор, пока ресурс остается захваченным. Однако, все задачи с более высоким приоритетом, чем приоритет задачи, захватившей ресурс, все еще могут выполняться.

    Аварийные сигналы и счетчики в OSEK используются для синхронизации активации задач с повторяющимися событиями. Аварийный сигнал статически присваивается счетчику, задаче и воздействию. Воздействие может либо активировать задачу, либо установить событие. Счетчики оперируют тактами и могут представлять время, количество принятых импульсов и т.п. Каждая реализация обеспечивает один временной счетчик, который используется для планирования периодических событий. Все другие счетчики управляются через API, являются специфическими для конкретной реализации и не могут быть переносимыми.

    В OSEK существует два типа аварийных сигналов: циклические и одинарные. Циклические аварийные сигналы применяются для диспетчеризации задачи, которая должна запускаться периодически. Счетчик аварийного сигнала может быть установлен в относительное или абсолютное значение. Параметры цикла и значение счетчика могут переустанавливаться динамически.

    ОС OSEK обеспечивает минимальные средства для управления ошибками времени выполнения. Однако имеется возможность дополнительного управления ошибками во время разработки благодаря расширенной функциональности возврата управления. Причина такого решения состоит в том, что после того как продукт запущен в производство, большинство возможных ошибок может быть выявлено во время тестирования (такие как "неверный идентификатор задачи", "ресурс занят", "непредусмотренный вызов с уровня прерываний" и т.д.). Во время выполнения большинство системных сервисов не возвращает коды ошибок, но некоторые сервисы, такие как аварийные сигналы, которые могут стартовать и останавливаться динамически, возвращают код ошибки, если данный аварийный сигнал уже использовался.

    ОС OSEK определяет два типа ошибок - ошибки приложения и фатальные ошибки. При ошибке приложения, когда приложение пытается выполнить несанкционированную операцию (например, активизировать несуществующую задачу), целостность внутренних данных все еще сохраняется. Фатальные ошибки возникают, если ОС обнаруживает нарушение целостности внутренних данных. При выявлении таких ошибок вызывается сервис завершения работы ОС.

    7.8. nxtOSEK C/C++ API

    ОС РВ nxtOSEK имеет программный интерфейс для С и С++, который используется в пакете ECRobot . Изначально программный интерфейс для С разрабатывался исключительно для автоматической генерации кода пакетом Simulink® (в рамках реализации модельно-ориентированного подхода пакета ECRobot), и, как следствие, его не очень удобно использовать при написании программы на чистом С. Другое дело интерфейс для С++, его структура и имена более приспособлены для написания программ вручную. Ниже приведен пример программы HelloWorld на С++, после знакомства с API для C будет очевидно, что эта программа реализована проще, чем ее аналог на C.

    /* sample.cpp для TOPPERS/ATK(OSEK) */ 
    
    //nxtOSEK C++ API
    #include "Lcd.h"   //подключаем класс работы с дисплеем
    using namespace ecrobot;
    extern "C"
    {
    //стандартные заголовочные файлы
    #include "kernel.h"
    #include "kernel_id.h"
    #include "ecrobot_interface.h"
    
    // nxtOSEK обработчик прерываний
    void user_1ms_isr_type2(void){}
    //точка входа
    TASK(TaskMain)
    {
      Lcd lcd;  //создаем объект lсd
    
      lcd.clear();  //очищаем дисплей
      lcd.putf("s", "Hello World");  //вывод Hello World
      lcd.disp();  //перерисовываем картинку на дисплее
    
      while(1);
    }
    }
    

    Сама система nxtOSEK базируется на ОС TOPPERS ATK1, которая очень похожа на версию ОС OSEK OS/OIL, используемую в проекте TOPPERS. Подробное описание API OSEK можно найти на сайте OSEK/VDX (см. OSEK OS Version 2.2.1, OSEK OIL Version 2.5). Однако в ОС РВ nxtOSEK не реализована некоторая функциональность TOPPERS ATK1 из-за особенностей архитектуры системы. Например, не следует использовать объявления процедур обработки прерываний (ISR) и API обработки прерываний.

    К сожалению, подробная документация TOPPERS ATK1 доступна только на японском языке, тем не менее, желающие смогут найти ее в папке nxtOSEK\toppers_osek\doc.

    7.9. nxtOSEK C

    7.9.1. API nxtOSEK

    Программный интерфейс ОС РВ nxtOSEK содержит низкоуровневые функции доступа к устройствам и функции-обертки (wrapper) для пакета ECRobot (последние имеют префикс ecrobot_) которые разработаны для создания программ управления устройствами в режиме реального времени.

    При описании программного интерфейса отдельно помечались функции, которые являются надстройками над низкоуровневыми функциями (функции-обертки). Чтобы не иметь лишних потерь времени при выполнении программы, лучше воздержаться от их использования. Для использования программного интерфейса необходимо подключить в исходном коде заголовочный файл ecrobot_interface.h

    7.9.2. Специальные процедуры nxtOSEK

    В программе, написанной для ОС РВ nxtOSEK, должны быть описаны три специальные процедуры, так называемые функции-обработчики или функции-ловушки (hook routines): ecrobot_device_initialize, ecrobot_device_terminate, user_1ms_isr_type2. Их определение и описание должны быть в главном с-файле программы. Система вызывает их автоматически, первую в начале работы программы, вторую в конце, а третью периодически каждую миллисекунду. Что бы легче было понять, как правильно их использовать, рассмотрим примеры этих процедур из файла ecrobot_main.c программы NXTway.

  • void ecrobot_device_initialize(void): Эта процедура вызывается в самом начале работы программы. В ней нужно помещать вызовы функций инициализации датчиков и моторов.
    void ecrobot_device_initialize(void)
    {
        /* Инициализировать используемые устройства */
        ecrobot_set_light_sensor_active(NXT_PORT_S1);
        ecrobot_set_light_sensor_active(NXT_PORT_S3);
        ecrobot_init_sonar_sensor(NXT_PORT_S2); 
        ecrobot_set_motor_speed(NXT_PORT_B, 0);
        ecrobot_set_motor_speed(NXT_PORT_C, 0);
        ecrobot_init_bt_connection();
    }
    
  • void ecrobot_device_terminate(void): Эта процедура вызывается в случае, если нажали кнопку STOP или EXIT. В ней нужно помещать вызовы функций, корректно завершающих работу датчиков и моторов.
    void ecrobot_device_terminate(void)
    {
        /* Завершить работу датчиков, остановить моторы */
        ecrobot_set_light_sensor_inactive(NXT_PORT_S1);
        ecrobot_set_light_sensor_inactive(NXT_PORT_S3);
        ecrobot_set_motor_speed(NXT_PORT_B, 0);
        ecrobot_set_motor_speed(NXT_PORT_C, 0);
        ecrobot_term_sonar_sensor(NXT_PORT_S2);
        ecrobot_term_bt_connection();
    }
    
  • void user_1ms_isr_type2(void): Эта процедура вызывается процедурой обработки прерываний второго типа, работающей с периодом 1 мсек. В ней, например, можно реализовать счетчик системных тактов подсистемы запуска задач (OSEK Alarm) для реализации Планировщика Периодических Вызовов Задач.
    #include "kernel.h"
    #include "kernel_id.h"
    void user_1ms_isr_type2(void)
    {
        StatusType ercd;
        /* Увеличить счетчик системного времени */
        ercd = SignalCounter(SysTimerCnt);
        if (ercd != E_OK)
        {
            ShutdownOS(ercd);
        }
    }
    
  • Пример

    Опишем простой пример для демонстрации общих принцпов построения программ с использованием API для С nxtOSEK. Текст примера предоставил студент математико- механического факультета Михаил Липкович. В этом примере реализована управляющая программа для робота, движущегося вдоль стенки.

    Прежде всего рассмотрим файл описания OSEK Implementation Language (OIL). Подробную справку по синтаксису OIL-файла можно найти на сайте концерна VXD/OSEK.

    /* wall_osek.oil*/
    #include "implementation.oil"
    
    CPU ATMEL_AT91SAM7S256
    {
      OS LEJOS_OSEK
      {
        STATUS = EXTENDED;
        STARTUPHOOK = FALSE;
        ERRORHOOK = FALSE;
        SHUTDOWNHOOK = FALSE;
        PRETASKHOOK = FALSE;
        POSTTASKHOOK = FALSE;
        USEGETSERVICEID = FALSE;
        USEPARAMETERACCESS = FALSE;
        USERESSCHEDULER = FALSE;
      };
    
      
      APPMODE appmode1{}; 
    
    
      TASK Motion    //определение свойств задачи Motion
      {
        AUTOSTART = FALSE;  //не запускаться самой при запуске //программы
    PRIORITY = 2;  //приоритет. чем больше число, тем //выше приоритет
    ACTIVATION = 1;  //максимально число одновременно //работающих задач Motion
    SCHEDULE = FULL;    //возможность вытеснять эту задачу //задачами более высокого приоритета
        STACKSIZE = 512;    //размер стека
      };
      
      
      ALARM cyclic_alarm1  //определение будильника (генератора //событий запуска задачи)
      {
        COUNTER = SysTimerCnt;  //счетчик SysTimerCnt
        ACTION = ACTIVATETASK  //при запуске будильника вызвать //задачу Motion
        {
            TASK = Motion;
        };
        AUTOSTART = TRUE  //автоазапуск будильника
          {
            ALARMTIME = 1;  //время запуска будильника впервый //раз
            CYCLETIME = 50;    //период последующих запусков 
            APPMODE = appmode1;
          };
        };
    
    
     
      
      COUNTER SysTimerCnt  //определение счетчика
      {
        MINCYCLE = 1;  //минимально возможное число тиков //счетчика для использования //будильником
        MAXALLOWEDVALUE = 10000;  //максимально
    //возможноезначение счетчика
        TICKSPERBASE = 1;  //размер тика (в миллисекундах) 
      };
    };
    

    Сам текст программы находится в файле wall_osek.c. Точкой входа этой программы (места с которого начинается выполнение программы) является задача task(Motion), как следует из файла wall_osek.oil, эта задача вызывается раз в 50 миллисекунд. Не следует забывать, что необходимо реализовать еще три процедуры ecrobot_device_initialize, ecrobot_device_terminate, user_1ms_isr_type2, которые формально нигде не используются, но система вызывает их автоматически.

    /* wall_osek.c*/
    
    #include "kernel.h"
    #include "kernel_id.h"
    #include "ecrobot_interface.h"
    
    //определение констант
    #define MOTOR_R    NXT_PORT_C
    #define MOTOR_L    NXT_PORT_A 
    #define SONAR     NXT_PORT_S1
    #define K  1.2  //коэффициент //пропорционального регулятора
    #define D      20  //расстояние до стены
    
    
    DeclareTask(Motion);
    DeclareCounter(SysTimerCnt);
    
    
    //инициализация моторов и ультразвукового датчика 
    //(выполняется перед всеми задачами)
    void ecrobot_device_initialize() 
    {
      
      ecrobot_set_motor_speed(MOTOR_R, 0);
      ecrobot_set_motor_speed(MOTOR_L, 0);
    
      ecrobot_init_sonar_sensor(SONAR);
    }
    //выполняется после завершения всех задач
    void ecrobot_device_terminate() 
    {
    
      ecrobot_set_motor_speed(MOTOR_R, 0);
      ecrobot_set_motor_speed(MOTOR_L, 0);
    
      ecrobot_term_sonar_sensor(SONAR);
    }
    
    
    //процедура обработки прерываний. необходима для получения //доступа к датчикам и сервомоторам
    void user_1ms_isr_type2(void) {
    (void)SignalCounter(SysTimerCnt);  //увеличить счетчик //SysTimerCnt для вызова периодических задач
    }
    
    
    TASK(Motion)      //задача, реализующая движение  
    {
      S8 base_speed = 25, u = 0;
    
        u = (ecrobot_get_sonar_sensor(SONAR)-D)*K;
    
      ecrobot_set_motor_speed(MOTOR_L, (base_speed + u)%100);
      ecrobot_set_motor_speed(MOTOR_R, (base_speed - u)%100);
    
      TerminateTask();  //завершение задачи
    }
    

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

    7.10. nxtOSEK C++

    Более удобный программный интерфейс реализован для C++. Каждый датчик и мотор является экземпляром соответствующего класса, а это перекладывает работу по инициализации и завершения работы переферийных устройств на конструкторы и деструкторы соответствующих классов, инкапсуирует методы, деля синтаксии интуитивно понятным. Хоть необходимость использования процедур ecrobot_device_initialize, ecrobot_device_terminate пропадает, тем не менее, для того что бы согласовать обектно ориентированный подход с функционалом ОС РВ nxtOSEK и предоставлять классам взаимодействие с процедурами обработки прерываний, все же необходимо использовать процедуру user_1ms_isr_type2 и описать событие ОС РВ.

    Как правило, в процедуре user_1ms_isr_type2 достаточно вызывать одну функцию SleeperMonitor() которая необходима для корректной работы класса Clock и корректного взаимодействия с устройвами через I2C интерфейс.

    Так же необходимо указать в описании основной задачи в OIL файле события EventSleepI2C и EventSleep. Это может выглядеть, например, так:

    //событие EventSleepI2C
    EVENT EventSleepI2C
    {
        MASK = AUTO;
    };
    //событие EventSleepI
    EVENT EventSleep
    {
        MASK = AUTO;
    };
    //описание основной задачи с названием, например, TaskMain
    TASK TaskMain
    {
        AUTOSTART = TRUE
        {
          APPMODE = appmode1;
        };
        PRIORITY = 1;
        ACTIVATION = 1;
        SCHEDULE = FULL;
        STACKSIZE = 512;
        EVENT = EventSleepI2C;  //добавили событие EventSleepI2C
        EVENT = EventSleep;  //добавили событие EventSleepI2C
    };
    

    Надо помнить, что так как объектам 18ти классов (датчикам, соединениям, моторам) требуется инициализация и корректное завершение работы, их необходимо определять как глобальные объекты. В противном случае на дисплее появится сообщение об ошибке и для корректной работы устройство надо будет перезапустить. Глобальными должны быть экземпляры следующих классов: AccelSensor, Bluetooth, Camera, ColorSensor, CompassSensor, SonarSensor, IrSeeker, LegoLight, Motor, NxtColorSensor, PSPNx, Rs485, GyroSensor, LightSensor, RcxLightSensor, SoundSensor, TouchSensor.

    7.10.1. Иерархия классов

    В этом параграфе приведен список классов в алавитном порядке с учетом наследования. Многие методы классов созвучны функциям С интерфейса, поэтому подробно их описывать здесь не будем.

    Все классы находятся в пространстве имен (namespace) "ecrobot", что бы использовать классы без приставки ecrobot:: необходимо указасть в начале программы using namespace ecrobot. Так же, что бы генерировался корректный машинный код, необходимо сделать указание компановщику (linker) компановать программу в стиле С, т.е. код программы должен быть заключен между extern "C"{ …код программы… }(см. пример в начале главы).

  • ecrobot::AccelSensor

    Клаcс работы с датчиком ускорения HiTechnic.

  • ecrobot::Bluetooth

    Класс работы с Bluetooth.

  • ecrobot::BTConnection

    Устанавливает соединение через Bluetooth.

  • ecrobot::Camera

    Класс работы с камерой NXTCamv2.

  • ecrobot::Clock

    Класс работы с системными часами.

  • ecrobot::ColorSensor

    Класс работы с датчиком цвета NXT.

  • ecrobot::CompassSensor

    Класс работы с компасом HiTechnic

  • ecrobot::Daq

    Класс для отправки внутренних данных NXT программе NXT GamePad.

  • ecrobot::GamePad

    Класс для дистанционного управления с помощью джойстика GamePad.

  • ecrobot::I2c
  • ecrobot::SonarSensor

    Класс работы с ультразвуковым датчиком.

  • ecrobot::IrSeeker

    Класс работы с инфракрасным датчиком.

  • ecrobot::Lcd

    Класс работы с дисплеем устройства NXT.

  • ecrobot::LegoLight

    Класс работы с датчиком освещенности NXT.

  • ecrobot::Motor

    Класс работы с серводвигателями NXT.

  • ecrobot::Nxt

    Класс работы с внутренними функциями устройства NXT (работа с кнопками, получение уровня заряда батареи).

  • ecrobot::NxtColorSensor

    Класс работы с датчиком цвета NXT.

  • ecrobot::PSPNx

    Класс работы с портом расширения для Sony Play Station.

  • ecrobot::Camera::Rectangle_T

    Вспомогательный класс для работы с камерой NXTCamv2.

  • ecrobot::Rs485

    Класс работы с интрфейсом RS485.

  • ecrobot::Sensor
  • ecrobot::GyroSensor

    Класс работы с гироскопом.

  • ecrobot::LightSensor

    Класс работы с датчиком освещенности.

  • ecrobot::RcxLightSensor

    Класс работы с датчиком освещенности RCX.

  • ecrobot::SoundSensor

    Класс работы со звуковым датчиком.

  • ecrobot::TouchSensor

    Класс работы с датчиком касания.

  • ecrobot::Speaker

    Класс работы с воспроизведением звука.

  • ecrobot::Usb

    Класс работы с USB.

  • ecrobot::VectorT < T >

    Класс, реализующий вектор из двух компонент.

  • Вернуться к учебному плану