Руководство по микропрограммному обеспечению джек рассел

Книга написана как сборник статей различных авторов, и в этом ее плюс и минус. Бывают статьи просто очень слабые или очень старые.

Например глава 1 «основы электроники» – если честно, просто для полноты картины не более, описание работы с осциллографом так это вообще зря потраченные листы бумаги.

Часть 2 Попытка объяснить философию «правильной» разработки железа и ПО.

Глава 5 – очень сжатый (в этом ее плюс) пересказ книги Рефакторинг (Мартина Фаулера) а именно части касаемо функций на языке Си.

Глава 7 – Святой Грааль данной книги. Описание реализации встраиваемого конечного автомата (КА) на массиве функций, обрабатывающих текущее состояние. Именно такие КА используются в мелких контроллерах как самые быстрые и простые. Теперь можно новичку, просто показать где об этом почитать.

Глава 10 пример того, что статья родом из 90-ых, автор даже не упоминает слово git, так как его еще не было! (можно смело пропустить) но если вы любитель истории, то можно прочитать как произведение Брукса (Мифический человеко-месяц)

Часть 3 – Математика – обязательно к прочтению и осознанию всех кто программирует.

Часть 4 – Системы реального времени. Тоже очень достойно, но опять привет из 90х, при описании assert-а нет описания static_assert так как походу еще не наступил 2011 год! Особо хочу выделить Главу 18. Очень интересно, автор, который работал в команде IAR-а, очень хорошо и интересно пишет про то, как компилятор старается оптимизировать код.

Часть 5 – Ошибки и исправления. Мало реальных примеров, и все примеры для ой как давно не современных микроконтроллеров.

В целом, если читать выборочно, то можно найти что-то интересное.

Книга адресована разработчикам микрокода, пишущим те самые программы, на которых работают технологии XXI века. Она заполняет важнейший пробел в литературе по встраиваемому программному обеспечению. Существует настоятельная потребность в сборнике идей и концепций, справочнике, настольной книге инженеров, куда они заглядывали бы, чтобы найти решение своих задач и освежить в памяти забытый материал. Главной темой этой книги является микрокод, однако суровая реальность мира встраиваемого ПО такова, что код и аппаратура взаимозависимы. Они не могут существовать в изоляции; ни в одной другой области программирования нет такой глубокой связи между реальным и виртуальным. Аналоговые инженеры постоянно твердят, что у них прекрасная профессия. Конечно, очень здорово ворочать операционными усилителями. Но бедняги не ведают, как это увлекательно — сделать так, чтобы все двигалось, огоньки мигали, газ тек. Это мы, разработчики встраиваемого ПО, управляем работой моторов, перекачиваем кровь, приводим в действие автомобильные тормоза, и выдвигаем компакт-диски из дисководов. Что может сравниться по притягательности с этой размытой границей между микрокодом и реальным миром? В книге описываются инструментальные средства и методы улучшения качества программного кода, эволюционная разработка ПО, встраиваемые конечные автоматы, системы реального времени, обработка и управление ошибками. Примеры сопровождаются многочисленными листингами на языках С и С++. Издание предназначено инженерам и программистам, использующих встраиваемое ПО в своей работе, а также будет полезно студентам вузов и всем читателям, интересующимся микропрограммным обеспечением.

2016 г., мягкая обложка, 408 страниц, 510 г

Перейти к характеристикам

  • Журналы
    • Естественные науки и математика
    • Здравоохранение и физическая культура
    • Информатика и вычислительная техника
    • История и исторические дисциплины
      • Отечественная история
    • Культура и искусство
    • Образование и педагогика
    • Политология и юриспруденция
    • Психология
    • Религиоведение
    • Сельское, лесное и рыбное хозяйство
    • Социология
    • Технические науки
    • Филология
    • Философия
    • Экономика и управление
    • Языкознание
  • Учебная литература
    • Автоматика и управление
    • Архитектура и строительство
    • Безопасность жизнедеятельности, природообустройство и защита окружающей среды
    • Библиотечно-информационные ресурсы
    • Воспроизводство и переработка лесных ресурсов
    • Геодезия и землеустройство
    • Геология, разведка полезных ископаемых
    • Гуманитарные науки
      • Документоведение и архивоведение
      • Журналистика
      • Искусствоведение
      • История
      • Книжное дело
      • Культурология
      • Лингвистика
      • Международные отношения
      • Политология
      • Психология
      • Регионоведение
      • Реклама
      • Религиоведение
      • Физическая культура и спорт
      • Филология
      • Философия
      • Юриспруденция
    • Естественные науки
      • Биология
      • Ботаника
      • География и картография
      • Геология
      • Гидрометеорология
      • Зоология
      • Почвоведение
      • Физико-математические науки
      • Химия
      • Экология и природопользование
    • Здравоохранение
    • Информатика и вычислительная техника
    • Культура и искусство
      • Библиотечно-информационные ресурсы
      • Декоративно-прикладное искусство и народные промыслы
      • Дизайн
      • Изобразительное искусство (графика, живопись, скульптура)
      • Искусствознание
      • Киноискусство
      • Музыкальное искусство
      • Театральное искусство
    • Металлургия, машиностроение и материалообработка
    • Морская техника
    • Образование и педагогика
      • Естественно-научное образование
      • Педагогика
      • Русский язык и литература
      • Социально-экономическое образование
      • Технологическое образование
      • Физико-математическое образование
      • Филологическое образование
      • Художественное образование
    • Приборостроение и оптотехника
    • Сельское, лесное и рыбное хозяйство
    • Социальные науки
      • Социальная работа
      • Социология
    • Сфера обслуживания
    • Технология производства продовольственных продуктов и потребительских товаров
    • Транспортные средства
    • Физико-математические науки
      • Математика
      • Механика
      • Физика
      • Химия
    • Химия и биотехнологии
    • Экономика и управление
      • Менеджмент
      • Статистика
      • Экономика
    • Электронная техника, радиотехника и связь
    • Энергетика, энергетическое машиностроение и электротехника
  • Художественная литература
    • Драматургия
    • Литературные обзоры. Критика
    • Мемуары, биографии, дневники
    • Очерки, эссе
    • Поэзия
    • Прочие литературные жанры
    • Романы, повести, рассказы, новеллы
    • Сборники различных произведений
    • Художественная литература для детей
    • Эпистолярные произведения
    • Юмор, сатира, пародия
  • Ноты
  • Авиационная и ракетно-космическая техника
  • Архитектура
  • Биологические науки
  • Ветеринария и зоотехника
  • Здравоохранение и медицинские науки
    • Здравоохранение
    • Лечебное дело
    • Организация здравоохранения
    • Сестринское дело
    • Фармакология
    • Фундаментальная медицина
  • Информатика и вычислительная техника
  • Информационная безопасность
  • Искусствознание
    • Изобразительное и прикладные виды искусства
  • История и археология
    • Археология
    • Всеобщая история
      • История Древнего мира
      • История Нового времени
      • История Средних веков
      • Современная история
    • Вспомогательные исторические дисциплины
      • Геральдика
      • Историческая география
      • Источниковедение
      • Палеография
      • Хронология
    • Отечественная история
      • История России в древности (до середины XII в.)
      • История России в средние века (середина XII — XVI вв.)
      • История России новейшего времени (XX в.)
      • История России нового времени (XVII — XIX вв.)
    • Теория и методология истории
    • Этнография
  • Культурология и социокультурные проекты
  • Математика и механика
  • Машиностроение
  • Международные отношения
  • Музыкальное искусство
  • Нанотехнологии и материалы
  • Научно-популярная литература
  • Науки о Земле
  • Образование и педагогические науки
    • История образования и педагогики
    • Общая педагогика
    • Педагогика и методика высшего образования
    • Педагогика и методика дошкольного образования
    • Педагогика и методика начального и среднего образования
    • Педагогика и психология
    • Социальная педагогика
      • Специальная педагогика
    • Школьная литература
  • Оружие и системы вооружения
  • Политические науки и регионоведение
  • Прикладная геология, горное дело, нефтегазовое дело и геодезия
  • Промышленная экология и биотехнологии
    • Продукты питания
    • Экология
  • Психологические науки
    • История и теория психологии
    • Отдельные направления в психологии
    • Прикладная психология
  • Сельское, лесное и рыбное хозяйство
  • Сервис и туризм
  • Социология и социальная работа
    • Общая социология
    • Региональная социология
    • Социальная антропология
    • Социальная работа
  • Средства массовой информации и информационно-библиотечное дело
  • Сценические искусства и литературное творчество
  • Техника и технологии кораблестроения и водного транспорта
  • Техника и технологии наземного транспорта
  • Техника и технологии строительства
  • Технологии легкой промышленности
  • Технологии материалов
  • Техносферная безопасность и природообустройство
  • Управление в технических системах
  • Физика и астрономия
  • Физико-технические науки и технологии
  • Физическая культура и спорт
  • Философия, этика и религиоведение
    • Зарубежная философия
    • История философии
      • Современная философия
      • Философия Древнего Мира
    • Отдельные направления и философские школы
    • Отечественная философия
    • Политическая философия
    • Религиоведение
    • Религиозная философия
    • Философия науки
    • Эстетика
    • Этика
  • Фотоника, приборостроение, оптические и биотехнические системы и технологии
  • Химия
    • Химические технологии. Химические производства
  • Экономика и управление
    • Банковское дело
    • Коммерция
    • Менеджмент
      • Антикризисное управление
      • Государственное и муниципальное управление
      • Менеджмент организации
      • Управление персоналом
      • Экономика и управление на предприятии
    • Регионоведение
    • Статистика
    • Товароведение и экспертиза товаров
    • Экономика
      • Банковское дело
      • Бухгалтерский учет, анализ и аудит
      • Маркетинг
      • Математические методы в экономике
      • Мировая экономика
      • Налоги и налогообложение
      • Национальная экономика
      • Страховое дело
      • Таможенное дело
      • Теория экономики
      • Финансы и кредит
      • Экономика труда
      • Экономическая теория
  • Электро и теплоэнергетика
  • Электроника, радиотехника и системы связи
  • Юриспруденция
  • Ядерная энергетика и технологии
  • Языкознание и литературоведение
    • Издательское дело и редактирование
    • История всемирной литературы
    • История филологии
    • Общее языкознание
    • Перевод и межкультурная коммуникация
    • Теория литературы
    • Фольклор и культурная антропология
    • Языки мира
      • Азербайджанский язык
      • Английский язык
      • Арабский язык
      • Армянский язык
      • Белорусский язык
      • Болгарский язык
      • Венгерский язык
      • Восточные языки
      • Вьетнамский язык
      • Греческий язык
      • Грузинский язык
      • Датский язык
      • Древние и мертвые языки
      • Иврит
      • Испанский язык
      • Итальянский язык
      • Казахский язык
      • Киргизский язык
      • Китайский язык
      • Корейский язык
      • Латинский язык
      • Латышский язык
      • Литовский язык
      • Молдавский язык
      • Немецкий язык
      • Нидерландский язык
      • Норвежский язык
      • Персидский язык
      • Польский язык
      • Португальский язык
      • Румынский язык
      • Русский язык
      • Сербский и хорватский языки
      • Таджикский язык
      • Татарский язык
      • Турецкий язык
      • Туркменский язык
      • Узбекский язык
      • Украинский язык
      • Финский язык
      • Французский язык
      • Хинди
      • Чешский и словацкий языки
      • Шведский язык
      • Эстонский язык
      • Японский язык

Страница недоступна для просмотра

Руководство по микропрограммному обеспечению Под редакцией Джека Ганссла The Filmware Handbook Edited by Jack Ganssle AMSTERDAM • BOSTON • HEIDELBERG • LONDON • NEW YORK • OXFORD • PARIS SAN DIEGO • SAN FRANCISCO • SINGAPORE • SYDNEY • TOKYO Newnes is an imprint of Elsevier Руководство по микропрограммному обеспечению Под редакцией Джека Ганссла Москва, 2016 УДК 004.41 ББК 32.972.1 Г19 Г19 Руководство по микропрограммному обеспечению / под ред. Дж. Ганссла; пер. с англ. А. О. Семенкович. – М.: ДМК Пресс, 2016. – 408 с. ISBN 978-5-97060-173-0 Книга адресована разработчикам микрокода, пишущим те самые программы, на которых работают технологии XXI века. Она заполняет важнейший пробел в литературе по встраиваемому ПО. Сущест вует настоятельная потребность в сборнике идей и концепций, справочнике, на стольной книге инженеров, куда они заглядывали бы, чтобы найти решение своих задач и освежить в памяти забытый материал. В книге описываются инструментальные средства и методы улучшения качества программного кода, эволюционная разработка ПО, встраиваемые конечные авто маты, системы реального времени, обработка и управление ошибками. Примеры сопровождаются многочисленные листингами на языках С и С++. Издание предназначено инженерам и программистам, использующих встраивае мое ПО в своей работе, а также будет полезно студентам вузов и всем читателям, интересующимся микропрограммным обеспечением УДК 004.41 ББК 32.972.1 This edition of The Firmware Handbook by Jack Ganssle is published by arrangement with Elsevier INC of 200 Wheeler Road, 6th Floor, Burlington, MA01803, USA. Все права защищены. Любая часть этой книги не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения вла дельцев авторских прав. Материал, изложенный в данной книге, многократно проверен. Но, поскольку вероятность технических ошибок все равно существует, издательство не может гарантировать абсолютную точность и правильность приводимых сведений. В связи с этим издательство не несет ответ ственности за возможные ошибки, связанные с использованием книги. ISBN 0-7506-7606-X (анг.) Copyright © Elsevier Inc. ISBN 978-5-97060-173-0 (рус.) © Издание, оформление, перевод, ДМК Пресс, 2016 Содержание Благодарности………………………………………………………………………………………………….14 Введение……………………………………………………………………………………………………………15 I Основы оборудования. ……………………………………………………………………….16 Введение……………………………………………………………………………………………………………17 Глава 1. Основы электроники. . ………………………………………………………………………19 Цепи постоянного тока…………………………………………………………………………………………..19 Напряжение и сила тока………………………………………………………………………………….19 Резисторы………………………………………………………………………………………………………….21 Электрические цепи…………………………………………………………………………………………24 Мощность………………………………………………………………………………………………………….27 Цепи переменного тока………………………………………………………………………………………….28 Конденсаторы……………………………………………………………………………………………………29 Индуктивности…………………………………………………………………………………………………34 Активные компоненты. . ………………………………………………………………………………………….35 Собираем все элементы вместе – источник питания. . ……………………………………….39 Осциллограф……………………………………………………………………………………………………………43 Средства управления……………………………………………………………………………………….43 Зонды…………………………………………………………………………………………………………………46 Глава 2. Логические цепи. ………………………………………………………………………………49 Кодирование чисел…………………………………………………………………………………………………49 Двоично-десятичное представление……………………………………………………………..52 Комбинаторная логика…………………………………………………………………………………………..52 Логический элемент НЕ………………………………………………………………………………….53 Логические элементы И и НЕ-И……………………………………………………………………53 Логические элементы ИЛИ и НЕ-ИЛИ……………………………………………………….55 Исключающее ИЛИ…………………………………………………………………………………………55 Схемы…………………………………………………………………………………………………………………56 Устройства с тремя состояниями. . ………………………………………………………………….59 Последовательностная логика………………………………………………………………………………59 Логическое резюме. . ………………………………………………………………………………………………..64 Глава 3. Советы по разработке аппаратных средств………………………………..65 Диагностика. . ……………………………………………………………………………………………………………65 Средства подключения…………………………………………………………………………………………..66 Другие рекомендации…………………………………………………………………………………………….67 Резюме………………………………………………………………………………………………………………………69 6 СОДЕРЖАНИЕ II Проектирование. ………………………………………………………………………………….70 Введение……………………………………………………………………………………………………………71 Глава 4. Инструментальные средства и методы улучшения качества программного кода…………………………………………………………………………73 Введение…………………………………………………………………………………………………………………..73 Традиционный цикл последовательной разработки встраиваемой системы ……………………………………………………………………………………………………………………73 Типичные проблемы современного рынка встраиваемых систем……………………74 Общие методы повышения качества кода и сокращения сроков выхода на рынок. . …………………………………………………………………………………………………….75 Фиксируйте спецификацию и работайте параллельно………………………………75 Создавайте контрольные отметки. . ………………………………………………………………..75 Используйте доступные ресурсы…………………………………………………………………..75 Непрерывно обучайте своих сотрудников……………………………………………………76 Основные факторы, влияющие на продолжительность цикла разработки………………………………………………………………………………………………………………..76 Какой этап длится дольше других?………………………………………………………………………77 Как снизить время разработки ПО и повысить качество кода. . ……………………….77 Пишите код в соответствии с внутренним руководством по оформлению ПО . ……………………………………………………………………………………….77 Выполняйте проверку кода…………………………………………………………………………….79 Выбирайте подходящие инструментальные средства разработки……………79 Повторное использование вместо повторного изобретения. . …………………….82 Как сократить сроки проектирования аппаратной части системы………………….83 Используйте как можно больше готовой продукции………………………………….83 Тщательно подбирайте микроконтроллер……………………………………………………83 Пример микроконтроллеров, сокращающих сроки выхода на рынок, – микроконтроллеры Philips. . ……………………………………………………….84 Резюме и перспективы. . ………………………………………………………………………………………….84 Глава 5. Советы по улучшению функций. . …………………………………………………..86 Минимизируйте функциональные возможности………………………………………………86 Инкапсулируйте……………………………………………………………………………………………………..87 Избавляйтесь от избыточности…………………………………………………………………………….88 Сокращайте код реального времени…………………………………………………………………….88 Ход программы должен быть грациозным………………………………………………………….89 Беспощадно улучшайте программы. . ……………………………………………………………………89 Применяйте стандарты и экспертизу…………………………………………………………………..90 Тщательно комментируйте программу………………………………………………………………..91 Резюме………………………………………………………………………………………………………………………93 Глава 6. Эволюционная разработка. …………………………………………………………….95 Введение…………………………………………………………………………………………………………………..95 1. История………………………………………………………………………………………………………………..96 СОДЕРЖАНИЕ 7 2. Проблемы, решаемые методом Эво………………………………………………………………….97 A. Парадоксы требований……………………………………………………………………………….97 B. Очень короткие циклы………………………………………………………………………………..98 C. Быстрая и частая обратная связь…………………………………………………………… 100 D. Фиксация сроков……………………………………………………………………………………… 101 E. Оценка, планирование и контроль. . ……………………………………………………….. 103 F. Разница между напряженной работой и выполнением заказа…………… 104 G. Обязательства…………………………………………………………………………………………… 106 H. Риски…………………………………………………………………………………………………………. 107 I. Производственные совещания………………………………………………………………… 107 J. Волшебные слова………………………………………………………………………………………. 108 3. Как мы используем метод Эво в работе над проектом. . ……………………………… 109 A. День Эво…………………………………………………………………………………………………….. 109 B. Последний день цикла…………………………………………………………………………….. 110 C. Производственное совещание………………………………………………………………… 111 4. Памятки . ………………………………………………………………………………………………………….. 112 А. Критерии назначения приоритетов заданиям……………………………………… 112 В. Критерии назначения приоритетных сроков завершения промежуточных этапов………………………………………………………………………………… 112 С. Критерии завершения задания………………………………………………………………. 113 5. Использование метода Эво в новых проектах…………………………………………….. 114 6. Тестирование в методе Эво…………………………………………………………………………….. 116 7. Запросы об изменениях и отчеты о проблемах…………………………………………… 117 8. Инструментальные средства………………………………………………………………………….. 117 9. Выводы. . …………………………………………………………………………………………………………….. 119 Благодарности……………………………………………………………………………………………………… 121 Ссылки………………………………………………………………………………………………………………….. 121 Глава 7. Реализация встраиваемого конечного автомата………………………123 Конечные автоматы…………………………………………………………………………………………….. 123 Пример………………………………………………………………………………………………………………….. 124 Реализация……………………………………………………………………………………………………………. 127 Тестирование………………………………………………………………………………………………………… 130 Запуск системы……………………………………………………………………………………………………. 131 Ссылки………………………………………………………………………………………………………………….. 131 Глава 8. Иерархические конечные автоматы. . ………………………………………….132 Пример традиционного конечного автомата…………………………………………………… 133 Пример иерархического конечного автомата………………………………………………….. 135 Глава 9. Разработка приложений, критически важных для обеспечения безопасности. …………………………………………………………………..140 Введение……………………………………………………………………………………………………………….. 140 Надежность и безопасность……………………………………………………………………………….. 141 История документа DO-178B……………………………………………………………………………. 141 Обзор стандарта DO-178B…………………………………………………………………………………. 142 8 СОДЕРЖАНИЕ Классификация неисправных состояний………………………………………………………… 143 Анализ архитектуры системы……………………………………………………………………………. 144 Разбиение на разделы…………………………………………………………………………………… 144 Несколько версий разнородного ПО…………………………………………………………. 145 Мониторинг безопасности…………………………………………………………………………… 145 Документация по архитектуре системы…………………………………………………………… 146 Жизненный цикл программного обеспечения согласно стандарту DO-178B……………………………………………………………………………………………………………….. 146 Планирование……………………………………………………………………………………………….. 146 Разработка……………………………………………………………………………………………………… 147 Процесс разработки. . …………………………………………………………………………………….. 147 Виды деятельности при разработке ПО……………………………………………………. 148 Верификация требований к ПО. . ………………………………………………………………… 148 Верификация проектирования ПО……………………………………………………………. 149 Верификация программного кода………………………………………………………………. 149 Верификация процесса интеграции…………………………………………………………… 149 Верификация процесса верификации……………………………………………………….. 149 Управление конфигурацией………………………………………………………………………… 150 Обеспечение качества ПО (SQA)……………………………………………………………….. 151 Технология объектно-ориентированного программирования и проблемы приложений, критически важных для обеспечения безопасности. . ……………………………………………………………………………………………………….. 151 Итеративный процесс…………………………………………………………………………………………. 152 Проблемы сертификации объектно-ориентированных приложений………….. 152 Автоматическая генерация кода…………………………………………………………………. 153 Автоматическая генерация тестов……………………………………………………………… 155 Возможность оперативного контроля……………………………………………………….. 155 Управление конфигурацией………………………………………………………………………… 155 Структурный охват………………………………………………………………………………………. 156 Невыполняемые/деактивированные участки программы……………………… 156 Наследование и множественное наследование………………………………………… 156 Резюме…………………………………………………………………………………………………………………… 157 Ссылки………………………………………………………………………………………………………………….. 157 Глава 10. Установка и использование системы контроля версий…………158 Введение……………………………………………………………………………………………………………….. 158 Мощь и элегантность простоты…………………………………………………………………………. 159 Контроль версий………………………………………………………………………………………………….. 160 Типичные признаки отказа от использования (неполного использования) системы контроля версий……………………………………………………… 160 Простые системы контроля версий. . …………………………………………………………………. 161 Усовершенствованные системы контроля версий………………………………………….. 161 Для каких файлов нужно использовать контроль версий…………………………….. 162 Совместная работа с файлами и клиенты системы контроля версий………….. 162 Нет локального клиента, нет общей файловой системы…………………………. 163 Нет локального клиента, но есть общая файловая система……………………. 163 СОДЕРЖАНИЕ 9 Есть локальный клиент, но нет общей файловой системы…………………….. 163 Есть и локальный клиент, и общая файловая система……………………………. 163 Проблемы интегрированной среды разработки……………………………………………… 164 Проблемы графического интерфейса пользователя………………………………………. 164 Спецификация SCC …………………………………………………………………………………………… 165 Интерфейс для веб-браузера или клиент-Java-систем контроля версий……. 165 Основные положения концепции контроля версий………………………………… 166 Советы. . …………………………………………………………………………………………………………… 171 Отслеживание ошибок……………………………………………………………………………………….. 174 Неконфигурационные средства управления…………………………………………………… 176 ПО для зеркального отображения информации. . …………………………………….. 176 Автоматизированное резервное копирование………………………………………….. 176 Веб-браузер……………………………………………………………………………………………………. 176 Группы новостей в Интернете…………………………………………………………………….. 177 Заключительные комментарии…………………………………………………………………………. 177 Рекомендованная литература, ссылки и ресурсы…………………………………………… 178 III Математика…………………………………………………………………………………………180 Введение………………………………………………………………………………………………………….181 Глава 11. Введение в машинные вычисления. …………………………………………..182 Введение……………………………………………………………………………………………………………….. 182 Целочисленная арифметика………………………………………………………………………………. 182 Деление и отрицательные числа……………………………………………………………………….. 182 Целые типы и их размер………………………………………………………………………………. 185 Переполнение или исчезновение значащих разрядов……………………………………. 186 Математические операции с плавающей запятой. . …………………………………………. 189 Неожиданный результат………………………………………………………………………………. 189 Форматы с плавающей запятой………………………………………………………………….. 190 Погрешности округления. . …………………………………………………………………………… 192 Ошибки при умножении и делении…………………………………………………………… 194 Ошибки при сложении и вычитании…………………………………………………………. 195 Обработка ошибок при вычислениях с плавающей запятой………………….. 197 Использование эквивалентных выражений для устранения катастрофической потери точности…………………………………………………………… 199 Арифметические операции с фиксированной запятой………………………………….. 201 Область применимости………………………………………………………………………………… 201 Представление чисел с фиксированной запятой и операции над ними…………………………………………………………………………………………………………. 202 Обработка ошибок при выполнении операций с фиксированной запятой……………………………………………………………………………………………………………. 203 Заключение…………………………………………………………………………………………………………… 204 Библиография……………………………………………………………………………………………………… 204 Благодарности Я хотел бы поблагодарить всех авторов, чьи материалы вошли в состав данной книги. Это был огромный труд, но наконец-то все готово! Также спасибо Кэрол Льюис, редактору издательства Newnes по новым проек там, и ее мужу Джеку, которые терроризировали меня целый год, пока я не при шел к такой концепции книги, которая, как мне кажется, должна быть понятна и читателям, и авторам. Кэрол положила начало моей авторской карьере более десяти лет назад, подвигнув меня на написание книги «The Art of Programming Embedded Systems» («Искусство программирования встраиваемых систем»). Спа сибо ей за участие на протяжении всех этих лет. И особая благодарность – моей жене Мэрибет за помощь и поддержку, а также за колоссальный объем работы по форматированию материалов и администра тивному руководству проектом. – Джек Ганссл, пристань Анкоридж, г. Балтимор, штат Мэриленд Введение Вот оно – «Руководство по микропрограммному обеспечению»! Эта книга за полняет важнейший пробел в литературе по встраиваемому ПО. Существует на стоятельная потребность в сборнике идей и концепций, справочнике, настольной книге инженеров, куда они заглядывали бы, чтобы найти решение своих задач и освежить в памяти забытый материал. Главной темой этой книги является микрокод, однако суровая реальность мира встраиваемого ПО такова, что код и аппаратура взаимозависимы. Они не могут существовать в изоляции; ни в од ной другой области программирования нет такой глубокой связи между реаль ным и виртуальным. Аналоговые инженеры постоянно твердят, что у них прекрасная профессия. Конечно, очень здорово ворочать операционными усилителями. Но бедняги не ведают, как это увлекательно – сделать так, чтобы все двигалось, огоньки мигали, газ тек. Это мы, разработчики встраиваемого ПО, управляем работой моторов, перекачиваем кровь, приводим в действие автомобильные тормоза, контроли руем развертку телевизионного изображения по горизонтали и по вертикали и выдвигаем компакт-диски из дисководов. Что может сравниться по притя гательности с этой размытой границей между микрокодом и реальным миром? Книга адресована разработчикам микрокода, пишущим те самые программы, на которых работают технологии XXI века. Эта книга создавалась не как учеб ник или вводный курс по написанию микрокода. Существует множество других пособий, цель которых – научить людей азам разработки встраиваемых систем. Не является она и введением в основы программирования. Каждый разработчик должен знать, что такое конструктивная стоимостная модель (COCOMO) Бё ма, используемая для оценки затрат на разработку ПО; методы экстремального программирования; подходы Фагена и Гильба к инспектированию программного обеспечения; персональный метод разработки по Хамфри; модель оценки зрело сти процессов разработки и сопровождения программного обеспечения, создан ная в институте Software Engineering Institute, и ряд других хорошо известных и постоянно развивающихся методов. Тщательное программирование – ключе вая составляющая успеха при создании любой большой системы, и мир встраи ваемого ПО в этом не оригинален. В данном руководстве очень мало информации по операционным системам реального времени, TCP/IP, цифровым сигнальным процессорам и другим по добным темам. Эти актуальные вопросы крайне важны для огромного множества встраиваемых приложений. Однако для освещения каждого из таких вопросов требуется отдельное издание – и таких книг уже очень и очень много. РАЗДЕЛ СТРАНИЦА I Основы оборудования II Проектирование 72 III Математика 183 IV Системы реального времени 232 V Ошибки и исправления 312 21 Глава 1. Основы электроники 51 Глава 2. Логические цепи 67 Глава 3. Советы по разработке аппаратных средств Введение Первые электронные вычислительные машины были аналоговыми, в действи тельности они представляли собой совокупность операционных усилителей и ничего более. Того, что мы сейчас называем «программами», вообще не су ществовало, вместо них разработчики алгоритмов использовали массивы элек тронных компонентов, помещавшихся в петли обратной связи таких усилителей. Программирование сводилось в буквальном смысле к переключению проводов в машине. Только инженеры, хорошо разбиравшиеся в электротехнике, могли управляться с подобными монстрами. С появлением в 1940-х гг. цифровых компьютеров, способных записывать ин формацию, программы превратились из электрических схем в биты, хранящиеся на различных носителях… хотя это было совершенно не похоже на то, что мы имеем сегодня! Менее очевидным преимуществом стало абстрагирование про граммиста от машины. Цифровая сущность вычислительных машин преодолела ограничения электрических параметров – больше не существовало ничего, кроме нуля и единицы. Возможности машинных вычислений открылись для огром ной группы людей, гораздо более широкой, чем специалисты по электротехнике. Программирование стало самостоятельной дисциплиной со своими профессио нальными приемами, ни один из которых не требовал даже самых элементарных знаний электроники и схемотехники. Единственное исключение – встраиваемые системы. Изобретение микропро цессора корпорацией Intel (1971 г.) вернуло компьютеры назад – к самым ис токам. Вычислительные машины сразу стали достаточно доступными по цене и небольшими по размерам, чтобы их можно было встраивать в какую-либо про дукцию. Несмотря на низкую стоимость процессора, снижение общей стоимости систем снова оказалось проблемой для проектировщиков новой и программистов интеллектуальной продукции. Это последний рубеж вычислительной техники, на котором оборудование и микропрограммное обеспечение (микрокод, firmware) не отделимы друг от друга. Зачастую можно понизить стоимость системы, используя компоненты с более интеллектуальной программой, или повысить производительность, при менив другой способ крепления. Наши микропрограммы тесно связаны с осо бенностями периферийного оборудования и датчиков, а также cо множеством явлений реального мира. Хотя и существует тенденция приглашать на работу «чистых» программистов, самыми лучшими разработчиками всегда оказываются те, кто имеет не только богатый опыт в разработке программного обеспечения, но и практические навыки в области электроники. Каждый разработчик встраиваемого ПО должен – нет, просто обязан! – знать содержание этой главы. Вы не имеете права заявить: «Ну, поскольку я програм мист-разработчик микропрограммного обеспечения, мне не нужно знать, что такое резистор». Ваша задача как разработчика встраиваемого ПО – создание системы, которая будет больше, чем просто программным кодом. Более глубокие сведения по всем аспектам электроники содержатся в заме чательной книге «The Art of Electronics» (русский перевод: Хоровиц П., Хилл У. Искусство схемотехники: в 2 т. М.: Мир, 1986). Джек Ганссл – автор ежемесячной колонки «Breakpoints» в разделе «Embedded электронного еженедельника «Embedded Pulse», выходя Systems Programming» 18 ВВЕДЕНИЕ щего на веб-сайте embedded.com; он написал четыре книги по встраиваемым си стемам и одну о своем неудачном опыте мореплавателя. Он начал заниматься встраиваемыми системами в начале 70-х гг. еще на процессоре 8008. С тех пор успел основать и продать три электронные компании, в том числе одно из круп нейших предприятий по созданию инструментальных средств для разработки встраиваемого ПО. Как программист и руководитель Джек принимал участие в работах по созданию более 100 встраиваемых продуктов: от глубоководного на вигационного оборудования до системы безопасности Белого дома. В настоя щ ее время он ведет семинары, посвященные наилучшим способам создания встраи ваемых систем, для компаний по всему миру. Глава 1. ОСНОВЫ ЭЛЕКТРОНИКИ Джек Ганссл Цепи постоянного тока Постоянный ток (DC) – замечательный термин, обозначающий сигналы, не изменяющиеся со временем. Здесь отсутствуют пики, как на электроэнцефало грамме мертвого мозга или на выходе аккумуляторной батареи. Источник пи тания вашего ПК получает постоянный ток из переменного тока (AC) обычной электросети. Рис. 1.1. Постоянный ток характеризуется сигналом постоянной, неменяющейся амплитуды Напряжение и сила тока Для характеристики электрического тока обычно пользуются напряжением и си лой тока, не задумываясь, что за обеими величинами стоят фундаментальные закономерности физики. Атомы, имеющие недостаток или избыток электронов, называются ионами. Ионы могут иметь как положительный, так и отрицательный заряд. Два иона с противоположным зарядом (один положительный, что означает нехватку у него электронов, а другой отрицательный, обладающий одним или более дополнительным электроном) притягивают друг друга. Сила такого при тяжения называется электродвижущей силой и обычно обозначается как ЭДС . 1 Заряды измеряются в кулонах (Кл), 1 кулон равен заряду 6,25×10 электро 18 нов (для отрицательных зарядов) или протонов (для положительных). Ампер (А) – это заряд в 1 Кл, протекающий через данную точку за одну секунду. Напряжение 1 В – это разность потенциалов, благодаря которой прово дник с текущим по нему током в 1 ампер совершит работу в 1 джоуль. Джоуль в секунду называется ваттом. Вообще говоря, сила взаимодействия точечных зарядов называется кулоновской, а под 1 термином ЭДС понимается физическая величина, равная отношению работы сторон них сил по перемещению заряда вдоль замкнутого контура к величине этого заряда. – Прим. пер. 20 ОСНОВЫ ЭЛЕКТРОНИКИ Следует заметить, что на самом деле редкие специалисты по электротехнике помнят эти определения и практически никто ими не пользуется. Рис. 1.2. Даже старомодный недорогой аналоговый вольт-омметр, подобный изображенной на рисунке модели Radio Shack, измеряет постоянный ток, как минимум, не хуже осциллографа Старинная, но очень удачная аналогия представляет электрический ток как воду, текущую по трубе: в этом случае сила тока будет количеством воды, про пускаемой трубой в единицу времени, а напряжение – давлением воды. Хотя обычно сила тока измеряется в амперах, для компьютера значение силы тока 1 А является крайне высоким. Большинству цифровых и аналоговых цепей тре буются гораздо меньшие токи. В табл. 1.1 приведен перечень наиболее употре бительных единиц силы тока. Таблица 1.1. Единицы измерения силы тока Сокращенное Значение Название Где встречается обозначение [А] Ампер А 1 Источники питания; наиболее высокопроизводительным процессорам может потребоваться ток силой во многие десятки ампер Миллиампер мА 0,001 Логические схемы, процессоры (десятки или сотни мА), обычные аналоговые схемы Микроампер мкА (µA) 10 Экономичные логические и аналоговые схемы, –6 ОЗУ с резервным питанием от батарей Пикоампер пкА 10 Очень чувствительные аналоговые входные цепи –12 Фемтоампер фА 10 Измерение аналоговых сигналов с помощью –15 новейших технологий Для большинства встраиваемых систем характерен не столь экстремальный диапазон напряжений. Типичные источники питания для логических схем и мик р опроцессоров обеспечивают напряжение от одного–двух до пяти вольт. Напряжение источников питания аналоговых устройств редко выходит за преде ЦЕПИ ПОСТОЯННОГО ТОКА 21 лы диапазона плюс или минус 15 В. Некоторые аналоговые сигналы от датчиков могут достигать значений милливольтового (0,001 В) диапазона. Радиоприемни ки способны обнаруживать сигналы микровольтового уровня, однако для этого используются довольно сложные методы шумоподавления. Резисторы Когда электроны движутся по проводам, внутри компонентов или – при не счастном случае – через тело человека, они встречают сопротивление, то есть стремление проводника ограничить ток электронов. Совершенным резистором является вакуум – через него электрический ток вообще не течет. Сходными ха рактеристиками обладает и воздух, но влажный воздух может в некоторой степе ни проводить электрический ток, так как вода – достаточно хороший проводник. Сверхпроводники, единственные материалы с нулевым сопротивлением, об ладают этим свойством благодаря волшебной силе квантовой механики при крайне низких температурах – порядка температуры кипения азота или ниже. Остальные материалы, даже самые лучшие проводники, имеют сопротивление. Потрогайте шнур питания своего 1500-ваттного керамического нагревателя – он теплый, поскольку некоторое количество электрической мощности рассеивается в шнуре вследствие сопротивления провода. Сопротивление измеряется в омах; чем больше эта величина, тем хуже провод ник. Международное обозначение ома – большая греческая буква «омега» (Ω). Сопротивление, напряжение и сила тока связаны наиболее фундаментальным из всех законов электротехники – законом Ома: V = I×R, где V – напряжение [В], I – сила тока [А], а R – сопротивление [Ом]. (Инжене рам-электрикам нравится использовать букву «E» для обозначения напряжения, поскольку она может обозначать и электродвижущую силу). Что это означает на практике? Подайте ток силой 1 А на нагрузку величиной 1 Ом и между ее контактами вы получите напряжение в 1 В. Увеличьте напря жение вдвое, и, если сопротивление осталось неизменным, сила тока удвоится. Хотя все электронные компоненты имеют сопротивление, резисторы использу ются специально для снижения проводимости. Они применяются везде. Регуля тор громкости в стереосистеме (не в цифровой) – это сопротивление, значение которого меняется, когда вы вращаете ручку; при повышении сопротивления снижается уровень сигнала и, следовательно, уровень громкости динамиков. Рис. 1.3. Зигзагообразная линия слева – стандартное обозначение резистора на электрических схемах. Справа приведено обозначение, принятое в Великобритании. Как говаривал Черчилль, «мы – два народа, разделенных общим языком» 22 ОСНОВЫ ЭЛЕКТРОНИКИ Таблица 1.2. Номиналы реальных резисторов Сокращенное Значение Название Где встречается обозначение [Ом] Миллиом мОм (mΩ) 0,001 Сопротивление проводов и других хороших проводников Ом Ом (Ω) 1 В источниках питания используются большие понижающие сопротивления с номиналом от нескольких ом до нескольких десятков Ом Сотни ом Во встраиваемых системах довольно часто можно обнаружить резисторы с номинальным сопротивлением в несколько сотен ом, которые используются для ограничения высокоскоростных сигналов Килоом кОм (kΩ, или 1000 Резисторы с номинальным значением от половины просто k) кОм до сотни или более кОм можно встретить во всех электронных приборах. Типичные значения «нагрузки» составляют от нескольких до десятков кОм Мегаом МОм (МΩ) 10 Аналоговые цепи с сигналом низкого уровня 6 Сотни 10 Счетчики Гейгера и другие крайне чувствительные 8 мегаом и более приборы; в резисторах встречается редко, поскольку близко по значению к сопротивлению воздуха Что произойдет, если соединить несколько сопротивлений? Полное эффек тивное сопротивление системы последовательно соединенных резисторов будет равно сумме их значений: R = R + R . 1 2 EFF Для двух резисторов, соединенных параллельно, эффективное сопротивление можно вычислить по формуле: (Таким образом, два одинаковых резистора, соединенные параллельно, дей ствуют как одно эффективное сопротивление, равное половине любого из них: если взять два сопротивления по 1 кОм, то эффективное сопротивление составит 500 Ом. Добавим третий резистор: это эквивалентно тому, что параллельно с ре зистором в 500 Ом подключен резистор 1 кОм, и эффективное сопротивление составит 333 Ом.) Обобщенная формула для цепи, содержащей более двух параллельно соеди ненных резисторов: Для обозначения номинальных сопротивлений отдельных резисторов произ водители используют цветовую маркировку. Хотя на первый взгляд этот подход может показаться слишком загадочным, на практике он себя оправдывает – неза висимо от ориентации и способа установки резистора на печатной плате цветные полоски на нем всегда остаются видимыми. 24 ОСНОВЫ ЭЛЕКТРОНИКИ Две первые полосы слева определяют целую часть номинала резистора. Третья – это множитель. Прочитайте численное значение, зашифрованное дву мя первыми полосами, и умножьте его на коэффициент, определяемый третьей полосой. Например: коричневая-черная-красная = 1 (коричневая) 0 (черная) умножить на 100 (красная), или 1000 Ом, то есть 1 кОм. В табл. 1.4 приведены дополнительные примеры. Таблица 1.4. Примеры чтения цветовой маркировки и вычисления сопротивления Первая Вторая Третья Значение Общепринятое Расчет полоса полоса полоса [Ом] написание Коричневая Красная Оранжевая 12 × 1000 12 000 12 кОм Красная Красная Красная 22 × 100 2200 2,2 кОм Оранжевая Оранжевая Желтая 33 × 10 000 330 000 330 кОм Зеленая Синяя Красная 56 × 100 5600 5,6 кОм Зеленая Синяя Зеленая 56 × 100 000 5 600 000 5,6 МОм Красная Красная Черная 22 × 1 22 22 Ом Коричневая Черная Золотая 10 ÷ 10 1 1 Ом Синяя Серая Красная 68 × 100 6800 6,8 кОм Существует набор стандартных номинальных значений выпускаемых резисто ров. Новички в схемотехнике часто пытаются заказать компоненты, не сущест вующие на практике; более опытные инженеры знают, что, например, резисторы с сопротивлением 1,9 кОм не выпускаются. Инженерия – весьма прикладное искусство; хороший конструктор всегда использует стандартные и легкодоступ ные компоненты. Электрические цепи Электрический ток всегда течет по замкнутому контуру. Отсоединенная от цепи аккумуляторная батарея разряжается очень медленно, поскольку нет замкнутого контура, нет никакого контакта (за исключением ненулевого сопротивления во дяных паров воздуха) между ее выводами. Чтобы лампочка загорелась, подсо едините концы провода к клеммам батареи; теперь электроны смогут двигаться по замкнутому контуру от отрицательного вывода батареи через лампу и снова к батарее. Есть только два типа электрических цепей: последовательные и параллель ные. Все существующие схемы являются их комбинацией. В последовательной цепи нагрузки подключаются по кругу друг за другом, ток также течет по кру гу, проходя через все нагрузки по очереди. В последовательной цепи сила тока одинакова на всех нагрузках. Все параметры последовательной цепи рассчитываются просто. На рис. 1.6 12-вольтовая аккумуляторная батарея служит источником питания для двух по следовательно соединенных резисторов. Согласно закону Ома сила тока, про текающего в цепи, равна напряжению (в данном случае 12 В), деленному на сопротивление (сумму сопротивлений двух резисторов, или 12 кОм). Следова тельно, сила тока: ЦЕПИ ПОСТОЯННОГО ТОКА 25 I = V÷R = (12 В)÷(2000 + 10 000 Ом) = 12÷12 000 = 0,001 А = 1 мА (напомним, что мА – это сокращенное обозначение миллиампера). R 1 2 кОм 12 В R 2 10 кОм Рис. 1.6. В последовательной цепи электроны текут сначала через одну нагрузку, затем через другую. Сила тока на каждом резисторе одинакова, а падение напряжения зависит от сопротивления А теперь попробуем определить падение напряжения на каждом из резисто ров. В последовательной цепи сила тока одинакова на всех нагрузках, а падение напряжения зависит от сопротивления нагрузки. Ответ снова можно узнать с по мощью закона Ома. Падение напряжения на R равно силе тока, умноженной на 1 сопротивление, или × V = I R = 0,001 А 2000 Ом = 2 В. R1 1 Поскольку батарея обеспечивает напряжение 12 В на концах всей цепочки сопротивлений, падение напряжения на R должно равняться (12 – 2) В, или 2 10 В. Не верите? Воспользуйтесь замечательным уравнением господина Ома для резистора R : 2 × V = I R = 0,001 А 10 000 Ом = 10 В. R2 2 Очень просто распространить эту закономерность на случай любого количест ва нагрузок, соединенных последовательно. В параллельных цепях компоненты соединяются друг с другом обоими выво дами. Ток протекает через оба компонента, при этом количество электричества, текущего через каждую ветвь электрической цепи, зависит от ее сопротивления, а напряжения на всех компонентах одинаковы. R R 12 В 2 1 10 кОм 2 кОм Рис. 1.7. R и R , соединенные параллельно, 1 2 питаются от аккумуляторной батареи напряжением 12 В ЦЕПИ ПОСТОЯННОГО ТОКА 27 Закон Ома остается ключом ко всем основным параметрам цепи и позволяет легко узнать падение напряжения на R : 1 × V = I R = 0,004 А 1000 Ом = 4 В. 1 Поскольку напряжение на выводах батареи 10 В, очевидно, что на соединен ных параллельно R и R падение напряжения составляет 6 В. 2 3 Мощность Мощность – это физическая величина, численно равная произведению напряжения на силу тока и измеряемая в ваттах. Один ватт равен произведению одного вольта на один ампер. Милливатт – это тысячная часть ватта, а микроватт – миллионная. Вы можете считать мощность мерой общего количества электричества. «На пряжение тысяча вольт» – звучит впечатляюще, но если сила тока при этом составляет всего лишь один микроампер, то мощность будет только милливатт – совсем немного. Мощность можно вычислить и как квадрат силы тока, умноженный на со противление: P = I R. 2 Электронные компоненты, такие как интегральные схемы (ИС) и резисторы, «потребляют» определенное количество вольтов и ампер. ИС не перемещается, не издает никаких звуков и не расходует энергию другими способами (если не учитывать минимальные затраты энергии на передачу сигналов другим подклю ченным к цепи устройствам), поэтому потребляемая энергия почти полностью преобразуется в тепловую. Все компоненты имеют максимально допустимые значения рассеиваемой тепловой энергии, превышать которые не следует. Если компонент кажется теплым на ощупь, значит, он рассеивает приемлемое количество энергии. Если он кажется горячим, но вы можете удержать палец на нем, по-видимому, он работает в допустимом режиме, хотя для многих ана логовых компонентов желательна более низкая рабочая температура. Если вы непроизвольно отдернули руку, хотя и не обожглись, то есть компонент кажется слишком горячим (будьте осторожны, некоторые люди особенно чувствительны к повышенным температурам) – это может означать, что требуется внешнее ох лаждение (теплоотвод, вентиляция и т. п.), он вышел из строя, или ваша цепь находится за пределами допустимого теплового режима. В исключительных си туациях некоторые радиодетали (например, силовые резисторы, выделяющие большое количество тепловой энергии) могут представлять опасность – мож но даже получить ожог – поэтому будьте особо осторожны, если заметите, что окрас к а компонента изменилась. Процессоры персональных компьютеров (ПК) содержат очень большое число транзисторов, каждый из которых рассеивает немного тепла, так что все устрой ство в целом может потреблять и рассеивать 100 Вт и больше. Заметим, что для выхода микросхемы из строя требуется гораздо большая мощность. Тем не менее конструкторы прикладывают огромные усилия, чтобы оборудо вать эти устройства радиаторами и вентиляторами для отвода тепла воздушным путем. 28 ОСНОВЫ ЭЛЕКТРОНИКИ Назначение радиаторов и вентиляторов – отвести тепловую энергию от элект рических цепей и рассеять ее в воздухе, чтобы устройство не загорелось. Тот факт, что какой-либо компонент рассеивает большое количество энергии и на гревается, не представляет угрозы, если выбран правильный режим охлаждения и теплоотвод обеспечен таким образом, чтобы не допустить превышения допус тимой рабочей температуры. Рис. 1.9. Через этот резистор с сопротивлением 10 Ом при напряжении 12 В протекает ток 833 мА. P = I R, поэтому потребляемая мощность около 7 Вт. 2 К сожалению, данный элемент был рассчитан на потребление не более 0,25 Вт, поэтому он и загорелся. Группа недавних выпускников колледжа имела смутные представления о взаимосвязи силы тока, мощности и теплоты, поэтому во время данной демонстрации их глаза стали огромными, как блюдца Цепи переменного тока АС – это сокращенное обозначение переменного тока, которым является любой сигнал, не относящийся к постоянному току. Эти сигналы изменяются с тече нием времени. Сетевые розетки у вас дома являются источниками переменного тока с сигналом синусоидальной формы: напряжение меняется от минимального отрицательного к максимальному положительному значению 60 раз в секунду (в США и Японии) или 50 раз (в большинстве остальных стран мира). АС-сигналы могут быть периодическими, что означает их бесконечное посто янное повторение, или – в противном случае. Радиопомехи, апериодическими которые слышны в вашем радиоприемнике, практически идеально апериодич ны, поскольку возникают совершенно случайно. Поток двоичных битов в лю бом адресе или строке данных, передаваемых микросхемой, обычно апериодичен, по крайней мере, на достаточно коротком временном отрезке, поскольку имеет сложную изменяющуюся структуру, генерируемую программой. Быстрота изменения периодического АС-сигнала характеризуется его часто измеряемой в герцах (краткое обозначение – Гц). Один герц означает, что той, волна повторяется один раз в секунду. Величина 1000 Гц называется кГц (кило герц), миллион Гц – тот самый МГц (мегагерц), который используется для из ЦЕПИ ПЕРЕМЕННОГО ТОКА 29 мерения тактовых частот многих микропроцессоров, а миллиард Гц называется ГГц (гигагерц). Величина, обратная частоте, называется периодом колебаний. То есть если час тота, выраженная в герцах, определяет быстроту повторения сигнала, то пери од – время, необходимое этому сигналу, чтобы пройти весь цикл. Математически: ÷ Период [c] = 1 частота [Гц]. Таким образом, тактовый период процессора, работающего на частоте 1 ГГц, составляет 1 наносекунду – миллиардную часть секунды. Я не шучу! За столь краткое мгновение даже свет проходит расстояние, равное всего лишь длине ступни взрослого человека. Даже когда вам кажется, что ПК, работающий на частоте 1,8 ГГц, слишком медленно загружает текстовый редактор Word , на са ® мом деле он «перемалывает» инструкции с поражающей воображение скоростью. Длина волны связывает период сигнала, а значит, и его частоту, с физическим «размером» сигнала. Это расстояние между его повторяющимися элементами, которое можно вычислить по формуле: где с – скорость света. FM-радиостанции, вещающие в диапазоне 100 МГц, излучают сигналы с дли ной волны, равной 3 м. Синусоидальная волна AM-сигналов (частота около 1 МГц) имеет длину 300 м. Длина волны сигналов беспроводных телефонов, работающих в диапазоне 2,4 МГц, чуть больше 10 см. С повышением частоты сигналов переменного тока становится все труднее понимать их поведение. Основные идеи, используемые для цепей постоянного тока, верны и в этом случае, но они требуют значительного расширения. Подобно релятивистской теории, построенной на ньютоновской механике и описываю щей быстро движущиеся системы, электронике для правильного описания це пей высокочастотного переменного тока нужны новые концепции. В частности, сопротивление оказывается лишь подмножеством компонентов, встречающихся в реальных цепях. Оно заменяется тремя основными типами резистивных ком понентов, при этом для каждого типа характерны специфические особенности поведения. Мы уже рассмотрели резисторы. Два других типа компонентов – конденсаторы и индуктивности. Оба типа обладают некоторым сопротивлением, зависящим от частоты сигнала; мера этого «сопротивления переменному току» называется реактивным сопротивлением. Конденсаторы Конденсатор принципиально представляет собой две металлические пластины, разделенные тонким слоем изолятора. Разумеется, изоляция означает, что по стоянный ток не может течь через конденсатор. Это напоминает незамкнутый контур. Но в мире переменного тока случаются странные вещи. Оказывается, пере менный ток может проходить через этот зазор; при этом чем выше частота, тем 30 ОСНОВЫ ЭЛЕКТРОНИКИ ниже эффективное сопротивление зазора. Такой эффект называется реактивным сопротивлением; а для конденсаторов – емкостным сопротивлением. В электро нике для каждой зависимости есть формула. В случае емкостного сопротивления она выглядит так: где X – емкостное сопротивление; f – частота [Гц]; C – емкость [Ф]. C 160 140 120 100 80 60 40 20 0 10 13 00 16 00 19 0 00 22 0 00 250 0 00 0 2800 0 00 31 00 0 0 Частота [Гц] Рис. 1.10. Емкостное сопротивление конденсаторов емкостью 0,1 мкФ (верхняя кривая) и 0,5 мкФ (нижняя кривая). По вертикальной оси отложено реактивное сопротивление [Ом]. Обратите внимание: конденсаторы большей емкости обладают меньшим реактивным сопротивлением, которое с ростом частоты уменьшается. Другими словами, чем выше емкость конденсатора, тем лучше он пропускает переменный ток, а при более высоких частотах все конденсаторы пропускают больше переменного тока. На рисунке не показано: при частоте 0 Гц (постоянный ток) реактивное сопротивление всех конденсаторов, по сути, равно бесконечности Таким образом, конденсаторы пропускают лишь сигналы. Сила изменяющиеся тока, протекающего через конденсатор: (Пояснение для тех, кто подзабыл дифференциальное исчисление или вообще не знаком с ним: это просто означает, что сила тока пропорциональна изменению напряжения с течением времени.) Итак, чем быстрее изменяется сигнал, тем больший ток протекает. 34 ОСНОВЫ ЭЛЕКТРОНИКИ пичные емкости используемых в таких приложениях конденсаторов составляют от 100 пФ до долей мкФ. Индуктивности Индуктивность в известном смысле противоположна конденсатору. Конденсатор блокирует постоянный ток, но имеет сопротивление (на самом деле реактивное сопротивление) переменному току, которое убывает с ростом частоты. Индук тивность, напротив, пропускает постоянный ток с нулевым сопротивлением (в идеальном случае), однако ее сопротивление (реактивное сопротивление) воз растает пропорционально частоте. С физической точки зрения, индуктивность представляет собой провод, намо танный на катушку, ее часто так и называют катушкой. Простой прямой провод совсем не имеет индуктивности. Сверните провод в петлю, и он станет относить ся к переменному току менее дружелюбно. Увеличьте количество витков либо сделайте их меньше, либо поместите немного железа внутрь витка – индуктив ность возрастет. Электромагниты являются индуктивностями, как и обмотки возбуждения генераторов переменного тока и электромоторов. Катушки со стальным сердечником наматываются на кусок металла, который существенно повышает индуктивность компонента. Индуктивность измеряется в генри (Гн). Индуктивное сопротивление – стрем ление катушки препятствовать течению переменного тока – можно вычислить по формуле: X = 2πLf, L где X – индуктивное сопротивление; f – частота [Гц]; L – индуктивность [Гн]. L Очевидно, что если частота стремится к нулю (постоянный ток), индуктивное сопротивление также убывает до нуля. Рис. 1.13. Два схематических обозначения индуктивностей. Слева – катушка с «воздушным сердечником», справа – со «стальным сердечником» Для индуктивностей справедливы те же правила, что для параллельного и по следовательного подключения резисторов: индуктивности [Гн] складываются при последовательном соединении, а при параллельном используется правило с делением. Во встраиваемых системах индуктивности порой оказываются очень полез ными, хотя встречаются гораздо реже, чем конденсаторы. Самое распростра ненное применение – импульсные источники питания. Во многих цепях для АКТИВНЫЕ КОМПОНЕНТЫ 35 передачи данных используются небольшие индуктивности (обычно несколько мГн) для согласования с управляемой сетью. В источниках питания обычно имеются трансформаторы, понижающие напря жение питающей сети (из розетки) до нужного для встраиваемых систем уровня. Трансформаторы представляют собой две катушки, намотанные на один сталь ной сердечник. Входной переменный ток генерирует изменяющееся магнитное поле, которое индуцирует напряжение в выходной («вторичной») индуктивности. Рис. 1.14. Схематическое обозначение трансформатора Если число витков обеих катушек индуктивности одинаково, выходное на пряжение будет равно входному. Если же во вторичной обмотке витков меньше, напряжение будет меньше. Иногда сигналы, особенно поступающие с печатной платы, пропускают через ферритовую шайбу, надетую на проводник. Эти шайбы представляют собой не большие цилиндры (высотой несколько мм), изготовленные из ферромагнитного материала. Как и любая индуктивность, они помогают блокировать переменный ток и поэтому используются для подавления шумов, возникающих в проводни ке, по которому передается сигнал. Активные компоненты Резисторы, конденсаторы и индуктивностями являются основными пассивными компонентами. Эти компоненты не могут усиливать или заметно изменять по ступившие сигналы. Напротив, активные компоненты могут ограничивать, уси ливать, искажать или иным образом изменять входящий сигнал. Самыми первыми активными компонентами были вакуумные трубки, кото рые в Великобритании (и в России) назывались электронными лампами. Анод Сетка Катод Нить накала Рис. 1.15. Слева – схематическое изображение двойной триодной вакуумной трубки. Сама трубка изображена справа 36 ОСНОВЫ ЭЛЕКТРОНИКИ Рассмотрим схематическое изображение на рис. 1.15, здесь показана одна трубка, содержащая два одинаковых активных элемента, называющихся трио дами, поскольку они содержат три вывода. Устройство трубки легко понять; да вайте посмотрим, как она работает. нагревает катод, излучающий поток электронов. Они проходят Нить накала через сетку, ячейки которой образованы проводниками, и притягиваются к ано ду. Электроны имеют отрицательный заряд, поэтому приложив к сетке очень малое отрицательное напряжение, можно существенно сократить их поток. На этом основан принцип усиления: небольшой управляющий сигнал оказывает значительное влияние на выходной сигнал устройства. Конечно же, в реальной жизни трубки сегодня не встречаются. Когда в 1947 го ду Бардин, Браттейн и Шокли изобрели в электронике началась транзистор, революция, продолжающаяся и поныне. Трубки потребляют большую мощность, имеют большой размер и являются хрупкими. Транзисторы – тоже трехвывод ные компоненты, способные усиливать сигнал – пока не исчерпали возможно стей миниатюризации и потребляют пиковатты энергии. Транзистор изготавливается из монокристалла, обычно кремния, допирован ного примесями, которые изменяют свойства материала. На примере трубки мы увидели, как работает компонент, управляемый напряжением; биполярные тран зисторы управляются током. Авторы книг по электронике любят описывать работу транзистора, пользуясь аналогией с течением воды или движением дырок и носителей заряда внутри кристалла кремния. Но в лучшем случае это лишь робкие попытки описать ис пользуемые механизмы квантовой механики. Поэтому достаточно просто ска зать, что на рис. 1.16 ток, питающий базу, управляет движением электричества между коллектором и эмиттером. Коллектор База Эмиттер Рис. 1.16. Схематическое изображение биполярного n-p-n-транзистора Это практически все, что нужно знать для понимания принципа работы тран зисторного усилителя. Цепь на рис. 1.17 представляет упрощенный пример та кого усилителя. Ток от микрофона, дающего очень слабый выходной сигнал, на правляется на базу транзистора, усиливающего этот сигнал – в результате лампа мигает в такт динамику. СОБИРАЕМ ВСЕ ЭЛЕМЕНТЫ ВМЕСТЕ – ИСТОЧНИК ПИТАНИЯ 39 состоянии сопротивление участка исток–сток намного ниже, чем в биполярном транзисторе. Значит, данный элемент рассеивает очень малую мощность, это оказывается крайне важным, когда в одну ИС помещаются миллионы таких транзисторов. Рис. 1.20. Схематическое обозначение диода Диод – двухвыводной полупроводник, пропускающий ток лишь в одном на правлении. На рис. 1.20 ток будет течь слева направо, но не в обратном направ лении. Казалось бы – простая вещь, однако это свойство чрезвычайно полезно. На следующей схеме (рис. 1.21) реализован логический элемент ИЛИ без тран зисторов. Выход Вход 1 Вход 2 +5 В Рис. 1.21. Диодная логическая схема ИЛИ Если на оба входа подана логическая единица, на выходе будет единица (ограниченная резистором до уровня +5 В). Низкий уровень входного сигнала обуслов л ивает низкий уровень сигнала на выходе. При этом диоды гарантируют, что низкое напряжение входного сигнала не приведет к понижению напряжения на другом входе. Собираем все элементы вместе – источник питания Источник питания – простая, однако распространенная схема, в которой ис пользованы многие из обсуждавшихся нами компонентов. Входное напряжение составляет 110 В переменного тока (в Европе 220 В, в Японии 100 В, в Вели кобритании 240 В). На выходе требуется 5 В постоянного тока для логических цепей. Как получить из переменного тока с высоким напряжением постоянный ток напряжением 5 В? 40 ОСНОВЫ ЭЛЕКТРОНИКИ На первом этапе нужно преобразовать переменный ток бытовой электросети в переменный ток более низкого напряжения следующим образом: Бытовая электросеть 20 В(АС) 110 В(АС) Рис. 1.22. Понижение напряжения бытовой электросети Теперь преобразуем переменный ток низкого напряжения в постоянный ток. С этим замечательно справляется диод: Бытовая электросеть 20 В(АС) 110 В(АС) Рис. 1.23. Выпрямление переменного тока с пониженным напряжением Конечно же, переменный ток бытовой электросети представляет собой си нусоиду. Так как диод пропускает ток лишь в одном направлении, на выходе получим: 25 20 15 10 5 0 Рис. 1.24. Форма сигнала выпрямленного переменного тока Это не постоянный ток… но диод удалил все отрицательные части синусоиды. Отбрасывать половину сигнала – это слишком расточительно. В более удачной схеме использованы четыре диода, расположенные в виде моста следующим об разом: ОСЦИЛЛОГРАФ 43 Осциллограф Рис. 1.28. Море кнопок. Не пугайтесь. Все они сгруппированы по логическому принципу. Освойте этот принцип – и вы поразите своих друзей и близких. Фотография любезно предоставлена компанией Tektronix, Inc. Осциллограф – важнейший прибор для поиска неисправностей и анализа элект ронных схем. Не разобравшись в его работе, вы будете похожи на слепого, пы тающегося понять, что такое цвет. Единственная функция осциллографа: показывать графики тестируемых сиг налов. По горизонтальной оси обычно откладывается время, по вертикальной – амплитуда напряжения. Средства управления Рис. 1.29. Передняя панель типичного осциллографа. Рисунок любезно предоставлен компанией Tektronix, Inc. 44 ОСНОВЫ ЭЛЕКТРОНИКИ Обратите внимание на две первых группы средств управления на рис. 1.29, помеченные надписями «vertical input 1» и «vertical input 2» (вертикальная раз вертка входных сигналов). Это двухканальный осциллограф самой распростра ненной модификации, позволяющий измерять и графически отображать два раз личных сигнала одновременно. Средства вертикального управления просты. Регулятор «Position» (положе ние) позволяет перемещать сигнал вверх-вниз по экрану для удобства наблю дения. При одновременном наблюдении двух сигналов можно пространственно разделить их, чтобы они не перекрывались. «Volts/div» – это сокращение от «Вольт/деление». Обратите внимание, экран разделен на квадраты размером 1×1 см, каждый из которых называется «деле ние». Если регулятор «volts/div» установлен в значение 2, сигнал с амплиту дой 2 В будет занимать на экране одно деление. Пятивольтовый сигнал займет 2,5 деления. Установите этот регулятор в такое положение, при котором будет удобнее наблюдать сигнал. Для транзисторно-транзисторных логических (ТТЛ) схем (5 В) разумно установить регулятор в положение 2 В/деление. Рис. 1.30. Наблюдаемый сигнал представляет собой синусоиду AC, наложенную на постоянный сигнал DC. Слева можно наблюдать его при настройке осциллографа на связь по постоянному току; обратите внимание, что компонент AC сигнала сместился вверх на величину DC (то есть результирующий сигнал равен сумме компонентов AC и DC). Справа мы изменили настройку связи на значение «AC» – это устранило смещение DC, и теперь компонент AC сигнала располагается в центре экрана Регулятор «coupling» (связь) можно установить в положение «DC», что озна чает: вы получите непреобразованный сигнал. То есть сигнал поступает в ос циллограф без изменений. «AC» означает, что входной сигнал проходит через конденсатор, а поскольку конденсаторы не пропускают постоянный ток, это по существу приводит к вычитанию смещения DC из сигнала. Регулятор «mode» (режим) позволяет нам смотреть сигнал на любом из ка налов или на двух одновременно. Теперь перейдем к средствам управления горизонтальной разверткой. Они управляют «масштабом по оси времени», который называется так, поскольку горизонтальная ось – всегда ось времени. Регулятор «position» (положение) перемещает график влево или вправо, ана логично ручке управления вертикальным каналом с таким же названием. 46 ОСНОВЫ ЭЛЕКТРОНИКИ Установите уровень триггера в положение 2 В или около того, и когда циф ровой сигнал начнет изменяться от 0 до 5 В, точка станет двигаться, теперь уже синхронно с сигналом. Очень важно научиться управлять этим параметром при наблюдении синусои ды. Поворачивая ручку по часовой стрелке (от низкого напряжения триггера к более высокому), вы смещаете синусоиду влево. То есть сканирование будет начинаться все позже и позже, поскольку триггерная схема будет ожидать, пока напряжение достигнет установленного вами стартового значения. «Trigger menu» (меню триггера) позволяет задавать некоторые свойства триг гера. Выберите «trigger on positive edge» (положительный фронт), и осциллограф начнет сканирование сигнала, в тот момент, когда он, достигнет напряжения, за данного регулятором «Уровень сигнала», увеличиваясь со стороны низких зна чений. «Trigger on negative edge» (отрицательный фронт) начнет сканирование, когда сигнал достигнет заданного значения, убывая от максимального уровня. У современного осциллографа настроек больше, чем нормальный человек спо собен запомнить, а тем более использовать. Различные экранные меню позволя ют проводить математическую обработку входных сигналов (складывать их и т. д.), записывать одиночные сигналы и многое–многое другое. Этот прибор похож на новое приложение для ПК. Конечно же, неплохо бы почитать руководство по эксплуатации, но не бойтесь нажимать различные кнопки и смотреть, к чему это приводит. Большинство функций интуитивно понятно. Зонды Рис. 1.32. Всегда подключайте нулевой вывод зонда к системе «Зонд» нужен для подключения осциллографа к вашей системе. У опытных инженеров пальцы слегка деформированы из-за многолетней работы с зондом осциллографа. Хотя, с электрической точки зрения, зонд – всего лишь провод, на самом деле в нем есть какая-то электронная магия, позволяющая электрическим сигналам доходить от исследуемой системы до осциллографа без искажений. Это же относится ко многим компонентам тестового оборудования. Острый конец зонда – всего лишь один из двух контактов, которые должны быть между ос циллографом и тестируемой системой. Требуется обратный контур – заземление. ОСЦИЛЛОГРАФ 47 Без него на экране будет отображаться множество бессмысленно вращающихся волновых сигналов. Однако часто можно видеть, как инженеры невозмутимо зондируют сигналы, не обеспечив, на первый взгляд, никакого заземления. Как ни странно, волны на осциллографе при этом выглядят отлично. В чем дело? Где же спрятан об ратный контур? В стене лаборатории. Большинство электрических шнуров, в том числе шнур осциллографа и, возможно, исследуемой системы, имеют три провода. Один из них – «земля». Довольно часто этот третий электропровод из розетки в стене используется для заземления исследуемой системы на осциллограф. Можно твердо быть уверенным лишь в одном: даже если это заземление существует – его качество безобразно. По меньшей мере, это худшее из возможных подклю чений, особенно если речь идет о высокоскоростных логических сигналах или чувствительных к слабым помехам аналоговых входах. Никогда не доверяйте ему, даже если все выглядит нормально. Это заземление совместно используется практически всеми приборами в лаборатории, а может быть, и во всем здании. Если на третьем этаже кто-нибудь включит «Ксерокс», большой индукционный выброс напряжения при запуске двигателя исказит сигнал на осциллографе. Рис. 1.33. Здесь мы зондируем сложную невстраиваемую схему. Обратите внимание на отображаемый сигнал. Человек выступает в роли антенны, принимающей сетевые радиопомехи от линий электропроводки, расположенных в стенах вокруг нас. Говорят, что особенно чувствительны инженеры (впрочем, их супруги с этим не согласны) Ни один осциллограф не сможет адекватно читать высокоскоростные входные цифровые данные, если он не заземлен Я даже не могу со должным образом. считать, сколько раз специалисты устанавливали неправильное смещение напря жения генератора частоты на 2 В, думая, что нашли причину отказа конкретной системы, а затем со смущением обнаружить, что при правильном заземлении ос циллографа сигнал предстает перед ними во всем своем великолепии от нуля до Глава 2. ЛОГИЧЕСКИЕ ЦЕПИ Джек Ганссл Кодирование чисел Тот факт, что большинство книг по микропроцессорам начинаются главой, посвященной кодированию чисел и системам счисления, отражает общий уро вень путаницы в этом вопросе, наиболее фундаментальном из всех, связанных с компью т ерами. Число – это экзистенциальное ничто, просто представление абстрактных ко личественных понятий. Людям нужно измерять мир и приумножать свои бан ковские сбережения, поэтому они придумали различные способы счета. Все системы счисления имеют – количество уникальных иденти основание фикаторов, используемых совместно для записи чисел. Самая известная из этих систем – десятичная с основанием 10, в которой используются десять символов от 0 до 9. В двоичной системе с основанием 2 для записи целых чисел исполь зуются только символы 0 и 1 – и ничего больше. В принципе, возможна любая система счисления, построенная на любом основании, и на самом деле уже про веден огромный объем работы в системах более высокого порядка, , например, с основанием 64, в которой, конечно же, есть множество дополнительных сим волов, составляющих набор из 64 уникальных идентификаторов. В основном в компьютерах применяются двоичная, восьмеричная (основание 8) и шестнад цатеричная (основание 16, обычно обозначается как «hex») системы счисления. Почему используется двоичная система? Просто потому, что логические це пи представляют собой примитивные недорогие конструкции, собранные из большого количества элементов. Ограничив электронику только двумя состоя ниями – «включено» и «выключено» – мы можем не думать об изменении напряжения от 2 до 5 В. Можно построить и троичную логику с основанием 3, использующую цифры 0, 1 и 2. Сигнал на выходе устройства, попадающий в определенный диапазон, представляет каждую из этих величин. Например, можно определить три полосы значений так: 0…1 В – это ноль, 2…3 В – это единица и 4…5 В – двойка. В двоичной логике, напротив, все сигналы ниже 0,8 В (ТТЛ-логика) считаются нулевыми, а выше 2 В – единичными. Это можно реализовать намного дешевле. Для чего нужна шестнадцатеричная система? Новички считают использова ние букв для записи чисел очень сложным. Запомните, «А» не имеет никакого смысла, точно так же, как и «5»; оба символа просто представляют значения. К сожалению, «А» интуитивно значит кое-что, отличное от числа, для тех из нас, кто научился читать. В шестнадцатеричной системе четыре двоичных цифры заменяются одной. Это компактнее. Запись «8В» гораздо легче для запоминания и вероятность сде лать ошибку в ней меньше, чем в «10001011». Для чего используется восьмеричная система? Основание 8 – необычное решение первых программистов, не желавших использовать буквы для обозна чения чисел. Здесь для представления величин от нуля до семи используются группы из трех двоичных цифр. Менее компактная, чем шестнадцатеричная, она 50 ЛОГИЧЕСКИЕ ЦЕПИ тем не менее была очень удобна для первых ЭВМ, в которых использовались 36-разрядные слова. Для записи 36-разрядного слова требуется ровно 12 вось меричных цифр (12 раз по три бита на одну цифру). Казалось, что записывать 36-разрядные числа в шестнадцатеричной системе будет не так удобно. Однако сегодня практически все компьютеры являются 8-, 16-, 32- или 64-разрядными; в них число разрядов делится на 4 без остатка, так что восьмеричные динозавры используются крайне редко. Таблица 2.1. Различные способы записи чисел (двоично-десятичный рассматривается чуть ниже) Десятичный Двоичный Восьмеричный Шестнадцатеричный Двоично-десятичный 00 000000 00 00 0000 0000 01 000001 01 01 0000 0001 02 000010 02 02 0000 0010 03 000011 03 03 0000 0011 04 000100 04 04 0000 0100 05 000101 05 05 0000 0101 06 000110 06 06 0000 0110 07 000111 07 07 0000 0111 08 001000 10 08 0000 1000 09 001001 11 09 0000 1001 10 001010 12 0A 0001 0000 11 001011 13 0B 0001 0001 12 001100 14 0C 0001 0010 13 001101 15 0D 0001 0011 14 001110 16 0E 0001 0100 15 001111 17 0F 0001 0101 16 010000 20 10 0001 0110 17 010001 21 11 0001 0111 18 010010 22 12 0001 1000 19 010011 23 13 0001 1001 20 010100 24 14 0010 0000 21 010101 25 15 0010 0001 22 010110 26 16 0010 0010 23 010111 27 17 0010 0011 24 011000 30 18 0010 0100 25 011001 31 19 0010 0101 26 011010 32 1A 0010 0110 27 011011 33 1B 0010 0111 28 011100 34 1C 0010 1000 29 011101 35 1D 0010 1001 30 011110 36 1E 0011 0000 31 011111 37 1F 0011 0001 32 100000 40 20 0011 0010 Для перевода чисел из одной системы счисления в другую нужно просто за помнить, что при любом основании число представляется в виде суммы раз рядных слагаемых: ×b ×b ×b ×b Число = … + + + + + . C 4 C 3 C 2 C 1 C 4 3 2 1 0 52 ЛОГИЧЕСКИЕ ЦЕПИ Вторая цифра = D. Остаток = 210 – 13×16 = 2. Следуя тому же алгоритму для разряда 16 , получаем окончательный резуль 0 тат: 4D2. Еще один пример: переведем в шестнадцатеричную систему десятичное число 41007: 16 можно из 41007 вычесть 10 раз, пока разность не станет отрицательной, 3 поэтому первая цифра 10 (в шестнадцатеричном представлении A). Остаток = 41007 – 10×16 = 47. 3 16 больше чем 47. Поэтому вторая цифра 0, 2 16 входит в 47 дважды. Следующая цифра 2. 1 Остаток = 47 – 2×16 = 15. 1 Последняя цифра 15 (в шестнадцатеричном представлении F). В итоге получаем: A02F. Двоично-десятичное представление В двоично-десятичном (BCD) представлении число разбивается на группы из четырех битов, каждая из которых представляет одну десятичную цифру. Для представления десятичных цифр 0…9 используется обычная двоичная запись. Поскольку для десятичного представления числа 10 требуется две цифры, в BCD-представлении будет использовано две группы по 4 бита. Каждая группа будет представлять одну из десятичных цифр. Эта система записи крайне неэффективна, поскольку двоичные коды от 1010 до 1111 никогда не используются. Однако BCD-запись отражает способ, кото рым мы представляем числа. Она часто применяется в дисплеях, отображающих цифровую информацию. Комбинаторная логика Комбинаторная логика описывает системы, состояние которых определяется только входными данными. Никакая информация не запоминается; прошедшие события не оказывают никакого влияния на текущие входные данные. Типичное комбинаторное устройство – сумматор: его выходной сигнал всегда равен сумме входных сигналов. Ни больше, ни меньше. Самый простой способ понять, как работает любая комбинаторная цепь – со стоящая из одного компонента или из сотен взаимосвязанных ИС – изучить ее таблицу истинности, матрицу, определяющую все возможные сочетания вход ных и выходных данных. Например, мы знаем, что выходной сигнал электро провода всегда совпадает с его входным сигналом; это отражено в табл. 2.3: Таблица 2.3. Таблица истинности электрического провода Вход Выход 0 0 1 1 КОМБИНАТОРНАЯ ЛОГИКА 53 Логические элементы – основные компоновочные блоки комбинаторных це пей. Хотя никаких ограничений на используемые элементы не накладывается, большинство цепей строится из логических элементов И, ИЛИ и НЕ. Логический элемент НЕ Простейший из всех логических элементов используется для отрицания вход ных данных. Его логические характеристики противоположны характеристикам электропровода, что иллюстрируется таблицей истинности (табл. 2.4): Таблица 2.4. Таблица истинности логического элемента НЕ Вход Выход 0 1 1 0 Для обозначения логической операции НЕ (NOT) используется надчеркива ние: NOT(А), обозначается A. Операцию отрицания можно применить к любому выражению: + означает NOT (A + A В B). Схематическое обозначение этого элемента показано на рис. 2.1. Рис. 2.1. Схематическое обозначение элемента НЕ Обратите внимание на окружность на выходном узле элемента. Принято, что окружность всегда обозначает отрицание. Без нее этот элемент будет означать буфер: устройство, вообще не выполняющее логических операций (которое на поминает отрезок электропровода, но используется для повышения напряжения сигнала). Окружность на схематическом обозначении логического элемента обо значает операцию инверсии. Логические элементы И и НЕ-И Логический элемент И объединяет два или более входных сигнала в один вы ходной сигнал, равный единице, если все входные сигналы равны единице. Если хотя бы на одном входе будет ноль, выходной сигнал также будет равен нулю. Таблица 2.5. Таблица истинности логического элемента И Вход 1 Вход 2 Выход 0 0 0 0 1 0 1 0 0 1 1 1 54 ЛОГИЧЕСКИЕ ЦЕПИ Операция И (AND) для входных сигналов A и B записывается так: вы ход = AB. На схеме логический элемент И с двумя входами выглядит следующим об разом: Рис. 2.2. Схематическое обозначение элемента И Операция НЕ-И (NOT-AND, или более кратко NAND), означает, что вы ходной сигнал равен нулю, если оба входных сигнала единицы. Это инверсия операции И для входных сигналов. Итак, НЕ-И для входных сигналов A и B записывается следующим образом: выход = AВ. На схеме окружность обозначает инверсию: Рис. 2.3. Схематическое обозначение элемента НЕ-И Таблица 2.6. Таблица истинности логического элемента НЕ-И Вход1 Вход2 Выход 0 0 1 0 1 1 1 0 1 1 1 0 Как мы уже заметили, оба логических элемента И и НЕ-И имеют два входа. Хотя это наиболее распространенная ситуация, нет причин для того, чтобы не использовать устройства с тремя, четырьмя и более входами. Ниже приведено обозначение для элемента НЕ-И с тринадцатью входами… его выходной сигнал будет равен нулю, только если все входные сигналы равны единице: Рис. 2.4. Схематическое обозначение элемента НЕ-И с тринадцатью входами КОМБИНАТОРНАЯ ЛОГИКА 55 Логические элементы ИЛИ и НЕ-ИЛИ На выходе логического элемента ИЛИ (OR) получится «истина» (единица), ес ли хотя бы один из входов будет равен единице. То есть на выходе будет ноль только в том случае, когда на всех входах будут нули. Таблица 2.7. Таблица истинности логического элемента ИЛИ Вход 1 Вход 2 Выход 0 0 0 0 1 1 1 0 1 1 1 1 Операция OR для входных сигналов A и B обозначается так: выход = A + B. На схемах: Рис. 2.5. Схематическое обозначение элемента ИЛИ Операция NOR (сокращенное обозначение NOT-OR, элемент НЕ-ИЛИ) дает результат, противоположный операции OR: Таблица 2.8. Таблица истинности логического элемента НЕ-ИЛИ Вход 1 Вход 2 Выход 0 0 1 0 1 0 1 0 0 1 1 0 Математическая запись операции NOR: выход = A + В. На схемах этот эле мент выглядит так: Рис. 2.6. Схематическое обозначение элемента НЕ-ИЛИ Исключающее ИЛИ Сокращенное обозначение операции исключающее ИЛИ – XOR. Такие элемен ты часто используются в схемах коррекции ошибок. На их выходе получается «истина», если на одном из входов, но не на обоих одновременно, входной сигнал 56 ЛОГИЧЕСКИЕ ЦЕПИ будет «истина». Можно рассматривать его работу и так: результат будет «исти на», если сигналы на входах различны. Таблица 2.9. Таблица истинности логического элемента Исключающее ИЛИ Вход 1 Вход 2 Выход 0 0 0 0 1 1 1 0 1 1 1 0 Исключающее ИЛИ А и В обозначается так: выход = A B. Схематическое обозначение логического элемента исключающее ИЛИ: Рис. 2.7. Схематическое обозначение элемента Исключающее ИЛИ Схемы Иногда комбинаторные схемы выглядят пугающе сложными, сулящими кон структору огромный объем работы. Это не так. Все они могут быть сведены к таблице истинности, полностью описывающей влияние каждого входного сиг нала на выход(ы). Хотя существуют различные методики анализа схем, таблицы истинности обычно являются наиболее простыми и понятными. В правильно составленной таблице истинности перечислены все возможные значения входных и выходных параметров. При наличии полной таблицы истин ности изготовление схемы становится тривиальным. Один из возможных под ходов заключается в том, чтобы не принимать во внимание те строки таблицы, для которых выход равен нулю. Вместо этого записать уравнение для каждой строки с выходным значением «истина» и применить ко всем выражениям опе рацию OR. Рассмотрим описанный выше логический элемент XOR (исключающее ИЛИ). Из таблицы истинности видно, что результат операции будет истинным, только если значения входных сигналов различны. Логическое выражение, эквивалент ное этому утверждению (A и B – входные параметры): XOR = AB + AВ. Соответствующая схема получается очень просто (рис. 2.8). Обратим внимание, что один логический элемент И объединяет входные сиг налы A и B в выражение AB, а другой – A и В в AВ логический элемент ИЛИ объединяет два результирующих выражения, давая в результате исключающее ИЛИ. Как насчет чего-нибудь более сложного? Давайте построим схему сумматора, устройства, находящего сумму двух 16-разрядных двоичных чисел. КОМБИНАТОРНАЯ ЛОГИКА 57 А XOR В Рис. 2.8. Эквивалентная схема логического элемента исключающее ИЛИ Мы могли бы записать исполинскую таблицу истинности для 32 входных па раметров, но это так же неразумно, как писать программы, состоящие из одной main(), огромной функции вместо того чтобы использовать подпрограммы. Мы можем учесть, что каждое из 16 выходных значений (S …S ) – всего лишь сумма 0 15 двух входных битов и бита переноса из предыдущего разряда. На самом деле 16-разрядный сумматор – это 16 суммирующих одноразрядных схем и ничего более. Каждая из них характеризуется следующей таблицей истинности: Таблица 2.10. Таблица истинности одноразрядного сумматора A B C S C n n IN n OUT 0 0 0 0 0 0 1 0 1 0 1 0 0 1 0 1 1 0 0 1 0 0 1 1 0 0 1 1 0 1 1 0 1 0 1 1 1 1 1 1 Сумма входных значений A и B плюс бит переноса из предыдущего разряда n n (C ) представлена двумя выходными значения – суммой (S ) и битом переноса IN n (C ). (Для самого первого разряда – A и B – вход C подключен к нулю.) OUT 0 0 IN Одноразрядный сумматор имеет два выхода: сумма и перенос в следующий разряд. Рассматривайте их независимо: у нас будет отдельная схема для каждого выхода. При построении комбинаторных схем применяется следующий прием: нужно свести к минимуму количество использованных логических элементов, удалив те, которые при реализации не будут работать. В таблице истинности (табл. 2.10) на самом деле нас интересуют лишь те комбинации входных параметров, при которых в результате получаются единицы… поскольку очевидно, что любые другие комбинации дают ноль. Для каждой строки таблицы истинности, дающей в результате единицу, за пишем логический член, а затем объединим эти слагаемые с помощью операции OR следующим образом: = + + + ; S A B C A B C A B C A B C n n n IN n n IN n n IN n n IN C A B = + + + . C A B B C A C A B C IN n n OUT n n n IN n IN n n IN ПОСЛЕДОВАТЕЛЬНОСТНАЯ ЛОГИКА 59 Рисунок 2.9 выглядит замысловатым, но это всего лишь графическое изобра жение двух приведенных выше уравнений. Полная схема устройства для сложения двух 16-разрядных чисел займет очень много места, при этом она будет просто набором повторяющихся простых схем. Аналогично тому, как программисты для создания приложений манипули руют огромным числом простейших понятий (единицы и нули), разработчики цифровых устройств используют логические элементы и другие примитивные компоненты для построения компьютеров. В этом сущность всех комбинаторных схем. Опытные конструкторы старают ся упростить схемы, а значит, и сократить число использованных компонентов с помощью таблицы истинности, теоремы де Моргана и других средств, отыски вая повторяющиеся структурные элементы. Иногда бывает трудно понять в том, как работает схема, поскольку мы видим конечный результат огромной работы по минимизации числа использованных компонентов. Это аналогично попытке разобраться в объектном файле, не имея исходного кода. Возможно, но очень утомительно. Устройства с тремя состояниями Хотя все реальные цифровые схемы двоичные, бывают ситуации, когда было бы полезно иметь еще одно возможное состояние, кроме нуля и единицы. Возьмем, к примеру, шины данных: десяток связанных микросхем ОЗУ может использо вать одну и ту же шину данных. Если в какой-то момент времени больше чем од но устройство будет контролировать эту шину, результатом станет перекрестный шум и полный беспорядок. В схемах с использованием шин предполагается, что каждый компонент будет «говорить» только тогда, когда остальные «молчат». Однако что на самом деле происходит с устройством, которое считается неак тивным? Передача только нулей и единиц оказывается действительно серьезным недостатком, поскольку они могут перемешаться с сигналами других устройств. Ведь только единицы и нули являются допустимыми двоичными кодами. Перейдем к системам с тремя состояниями. Это недвоичное состояние, ког да устройство, подключенное к шине, физически выключено. Оно не предает ни нулей, ни единиц… Еще бы! Ведь выходы перешли в третье состояние: они электрически отключены от остальной схемы. Такие шинные устройства, как память имеют управляющий вывод, называю щийся «Output Enable» (или более коротко «OE») – разрешение выдачи вы ходных сигналов, который, если компонент не активен, переводит его выводы в третье состояние, отключая их от цепи. Последовательностная логика Выходное значение в последовательностных логических схемах зависит не толь ко от входных параметров, но Таким об и от предыдущего состояния схемы. разом, они запоминают прошлое и включают историю в настоящее. Например, счетчик, находящийся в состоянии 101, помнит его, чтобы знать, что следующее состояние должно быть 110. 60 ЛОГИЧЕСКИЕ ЦЕПИ Последовательностные схемы всегда управляются тактовыми импульсами. Тактовый импульс – это прямоугольная (или, по крайней мере, похожая на пря моугольную) волна, имеющая постоянную частоту. Все последовательностные схемы находятся в состоянии ожидания до момента тактового перехода, когда все очень быстро изменяется. Счетчики считают. Таймеры «тикают». Универсальные асинхронные приемопередатчики посылают последовательности битов. Тактовые импульсы вызывают серию последовательных изменений; после этого схема пере ходит в состояние ожидания, для того чтобы система пришла в равновесие. Тактовые импульсы нужны компьютеру, чтобы предоставить каждой опера ции время, необходимое для ее правильного завершения. Например, для доступа к памяти необходимо некоторое время. После получения инструкции, к какой именно ячейке нужно осуществить доступ 50-наносекундному ОЗУ, требуется 50 нс для извлечения данных. Системный тактовый генератор задерживает вы полнение операций, чтобы процессор успел извлечь данные из ОЗУ. Подобно логическим элементам, являющимся основными строительными элементами комбинаторных цепей, триггеры – строительный материал для всех схем последовательностной логики. Триггеры (устройства с двумя устойчивыми состояниями) изменяют свое состояние в зависимости от одного или нескольких входных значений – в результате тактовых переходов. В справочниках можно найти информацию о самых разнообразных триггерах. Простейший из них – триггер с установочными входами (SR-триггер), который выглядит примерно так, как показано на рис. 2.10. + 1 A 2 B + Рис. 2.10. SR-триггер Чтобы понять принцип его работы, предположим, что на вход A поступило значение ноль. Оставим B открытым. Значение единица на нем поддерживается резистором. При низком уровне сигнала на входе A логический элемент НЕ-И 1 должен перейти в состояние единица и подать единицу на вход элемента 2, который (поскольку на входе В высокий уровень сигнала) из-за этого перейдет в состояние с низким уровнем сигнала. Уберите входной сигнал и логический A, 64 ЛОГИЧЕСКИЕ ЦЕПИ говый регистр, выводиться через выход QH по одному разряду за такт. Простой транзисторный усилитель преобразует сигнал 5 В логической схемы в 12 В для устройства RS-232. S 0 S 1 — — — — — — E N P R C O — — — E N T СИНХР СИНХР A QA B QB C QC D QD E QE — — F QF SH/ L D G QG CLKINH H QH СИНХР +12 В SER A B C D Выход E RS 232 F LOAD G Шина данных H QH — — Q H Рис. 2.16. Упрощенный приемопередатчик UART Логическое резюме В современных встраиваемых системах действительно используются все эти ви ды компонентов. Однако множеству логических элементов и триггеров большин ство разработчиков предпочитает интегральные схемы, в которых реализованы сложные функции. Типичные ИС могут быть 8-разрядным синхронным счетчи ком или 4-разрядным арифметическо-логическим устройством (выполняющим операции сложения, вычитания, сдвига и др.). Однако пока еще можно встретить отдельные логические элементы и тригге ры, используемые в виде связующих логических схем – элементов, необходимых для сопряжения больших сложных ИС. Глава 3. СОВЕТЫ ПО РАЗРАБОТКЕ АППАРАТНЫХ СРЕДСТВ Диагностика Любимый отладочный прием в мире невстраиваемого ПО – поместить оператор print в программный код. Это позволяет узнать, достигла программа контроль print ной точки с оператором или нет. Однако при создании встраиваемого ПО редко предоставляется такая возможность. Поэтому следует вводить полезные зарезервированные биты параллельного ввода/вывода. Разработчикам микро программного обеспечения совершенно необходимы такие недорогие способы проверки работы их программного кода. Помещение инструкций ввода/вывода в программу, управляющую этими выводами – простой и быстрый способ узнать, чем в данный момент занимается программа. Разработчики могут установить значение бита в единицу при вызове под программы или обработчика прерывания, а затем сбросить его при возврате. Осциллограф или логический анализатор сразу же позволят определить время исполнения данного фрагмента программы. Еще один прием состоит в периодическом присвоении биту вывода значения единица, когда система работает, и нулевого значения при ее простое. Подключи те вольтметр (один из старомодных приборов с аналоговой стрелкой) к выводу устройства. Прибор усреднит поток двоичных импульсов, так что измеренное напряжение будет пропорционально загрузке системы. Если позволяют размеры и стоимость системы, установите целый 8-разряд ный регистр, подключенный к ряду контактов или контактных отверстий, рас положенных на плате с шагом 0,1 дюйма (2,5 мм). Реализованные программно конечные автоматы могут выводить свое текущее «состояние» в этот порт. Ло гический анализатор соберет данные и отобразит всю последовательность, прак тически не влияя на время исполнения программного кода. Имеет смысл установить хотя бы один светодиод, который будет сигнализи ровать разработчику, а может быть, и пользователям, что система подключена к питанию и работает. Индикатор, управляемый задачей с низким приоритетом или пустым циклом, позволяет узнать, что система подключена к питанию и не «застряла» в каком-нибудь бесконечном цикле. Многие встраиваемые системы не имеют пользовательского интерфейса; в этом случае мигающий светодиод позволяет простым способом сообщить: «система в порядке». Сегодня высокоинтегрированные процессоры содержат много встроенных пе риферийных устройств, иногда больше, чем необходимо для конкретной систе мы. Если у вас есть дополнительный приемопередатчик UART, можно подклю чить его выводы к микросхеме сдвига уровней RS-232 (например, MAX232A или аналогичной). На самом деле необходимость установки микросхемы на плату возникает только при создании прототипа. Разработчики микропрограммного обеспечения иногда сталкиваются с тем, что имеющиеся у них инструменталь ные средства просто не эффективны, в этом случае может помочь добавление к коду программного монитора (см. www.simtel.com ). Порт RS-232 позволяет лег ко решить эту задачу. 66 СОВЕТЫ ПО РАЗРАБОТКЕ АППАРАТНЫХ СРЕДСТВ Если в итоге на печатной плате не осталось места для монтажа схемы сдвига уровня, постарайтесь хотя бы подвести выводы Tx, Rx и землю к доступным контактным отверстиям, чтобы можно было временно подключить микросхему MAX232 прямо над платой. (Внимание, разработчики: если вы действительно используете этот порт, не бой тесь реализовывать в программном мониторе драйверы ввода/вывода по запросу через RS-232. Найдите время, чтобы написать соответствующий, управляемый прерываниями программный код. Как показывает мой опыт, функция ввода/вы вода по запросу в программном мониторе часто приводит к пропуску символов, ненадежности инструментального средства и полному разочарованию.) Выведите шину сброса на переключатель или перемычку, чтобы инженеры могли подавать этот сигнал независимо от обычной процедуры запуска при включении питания. Проблемы, возникающие при включении питания, иногда удается решить, подключив шину сброса к импульсному генератору, создающему сигнал воспроизводимой формы, удобный для изучения с помощью осцилло графа. Средства подключения Располагайте микросхему процессора так, чтобы при желании можно было под ключить эмулятор. Иногда нужная плата так далеко спрятана в корпусе, что доступ к ней в лучшем случае затруднен. Большинство переходных устройств для эмуляторов чувствительны к направлению вставки. Следите также за вер тикальными габаритами! Переходное устройство, размещенное поверх большого SMT-адаптера (surface mount technology – технология поверхностного монтажа), может возвышаться над платой на 4–6 дюймов (10–15 см). Убедитесь, что над платой нет ничего, что могло бы помешать установке такого переходника. Не используйте «пристегивающиеся» адаптеры на корпусах SMT. Они совер шенно ненадежны (единственное исключение – корпуса PLCC, имеющие боль шое расстояние между выводами) и могут повредить установленные компонен ты. Лучше уберите ЦПУ и установите адаптер, припаяв его снизу. Печатная пла та – это прототип, но, по крайней мере, она должна быть надежным прототипом. Оставляйте запас времени для синхронизации системы. Если на счету каж дая наносекунда, ни один эмулятор надежно работать не будет. Примерно 5 до полнительных наносекунд в циклах чтения и записи – и особенно в состоянии ожидания – не окажут существенного влияния на работу большинства схем. Если ваш процессор оснащен отладочным портом BDM или JTAG, установите соответствующий разъем на печатной плате. Даже если вы планируете исполь зовать полнофункциональный эмулятор или другие средства разработки, преду смотрите на печатной плате контактные выводы и соедините их проводником с коннектором BDM. Он практически ничего не стоит, однако поможет уберечь ваш проект от повреждения при тестировании. Логический анализатор – фантастически мощный отладочный инструмент, который, однако, может разочаровать вас. К тому времени, как вы заканчивае те подключать сотый контактный зажим, первые 50 уже отстегиваются. Есть ДРУГИЕ РЕКОМЕНДАЦИИ 67 решение получше: окружите свой ЦПУ разъемами Mictor компании AMP. Это компоненты высокой плотности с контролируемым импедансом, способ ные передавать системные адреса, данные и информацию шины управления за пределы платы. Разъемы типа Mictor поддерживаются компаниями Tektronix и Agilent. Обе компании поставляют кабели для прямого подключения логи ческого анализатора к разъему Mictor. Никаких контактных клипсов, никаких кабелей штучного производства и гарантированное надежное подключение в те чение несколько секунд. В серийной версии можно удалить разъемы с платы или оставить контактные площадки на печатной плате, не устанавливая компоненты. При подключении инструментальных средств некоторые сигналы особенно под вержены искажениям. На компонентах компании Motorola для разделения адре сов и данных, передаваемых по мультиплексным шинам, используется сигнал ALE (разрешение защелки адреса), который по-другому называется AS (строб адреса). Малейшие шумы, наведенные на сигнал эмулятором или даже зондом, приведут к аварийному отказу системы. То же относится к любому входному сигналу, запускаемому фронтом (например, немаскируемые прерывания многих процессоров). Для согласования сигналов используйте цепь из двух резисторов. Ваша схема может прекрасно работать и без согласования, однако при подключе нии инструментальных средств или подаче тестовых сигналов полезный сигнал может искажаться. Добавляйте контрольные точки! Если заземление недостаточно короткое, осциллограф не сможет точно отображать высокоскоростные сигналы, прису щие современным схемам. В добрые старые времена достаточно было припаять небольшой кусочек провода к выводам логического устройства, чтобы быстро получить заземление. С компонентами для поверхностного монтажа это либо сложно, либо вообще невозможно. Поэтому размещайте заземляющие контакты по всей плате. Другие сигналы, которые мы будем постоянно контролировать и которые должны быть доступны – это сигналы таймера, ввода, вывода и все прерывания. Убедитесь в том, что для них имеются контрольные точки или соответствующие отверстия в плате достаточного размера, к которым разработчик сможет припа ять проводник (обычно контакт резистора) для получения сигнала. Обязательно установите контрольную точку для измерения V . Логические CC пробники – старые, но все еще очень полезные инструменты. Большинству из них необходим источник питания. Другие рекомендации Обеспечьте возможность чтения информации через все выходные порты. Это особенно важно для командных регистров в специализированных ИС, посколь ку других способов контроля содержащейся в них информации не существует. Внимательно следите за порядком битов. Например, при чтении аналогово- цифровой информации очень плохо после ввода бита номер 7 перескакивать на нулевой бит, потом с шестого на первый и т. д. – это просто кошмар. Конечно, разработчики микропрограммного обеспечения могут написать программный 68 СОВЕТЫ ПО РАЗРАБОТКЕ АППАРАТНЫХ СРЕДСТВ код, исправляющий эту путаницу, но для большинства процессоров это все равно будет плохо. Программа будет медленной и безобразной. Используйте множество узкоспециализированных портов ввода/вывода вмес то нескольких портов широкого назначения. Когда один порт контролирует три светодиода, две маски прерываний и шаговый двигатель, изменение любого из выходных значений означает необходимость координации всех выходов. Про грамма превращается в клубок логических операций AND/OR. Замена даже не большой части оборудования требует большой работы по переделке ПО. Пор ты широкого назначения, реализованные на дискретной логике, действительно позволяют минимизировать количество используемых компонентов, но в про граммируемых логических устройствах или в микросхемах FPGA выигрыша в стоимости это не дает. Старайтесь не подключать неиспользуемые цифровые входы напрямик к V . CC Раньше такая практика была запрещена, поскольку входы 74LS были более чувствительны к одиночным импульсам, чем контакт V . Все неиспользуемые CC входы соединялись с V через резисторную нагрузку. При использовании логи CC ческих устройств в этом больше нет необходимости. Гораздо проще исследовать и заменять узел, не имеющий постоянного подключения к источнику питания. Однако если вам необходимо подключиться непосредственно к этим неис пользуемым входам, будьте особенно осторожны с компонентами печатной пла ты. Не подводите питание через штыревые контакты, то есть не используйте их как удобный способ подать питание на другие выводы или на другую сторону платы. Гораздо лучше для этих целей, а также для заземления входных сигналов использовать дорожки на внешних слоях печатной платы, которые просматри ваются во время пайки ИС на место. Впоследствии разработчик может легко перерезать эти дорожки с помощью комбинированного резака (X-Acto knife), чтобы внести изменения в схему. Нагрузочные резисторы приводят к возникновению других проблем. Многие отладочные инструментальные средства обладают собственными нагрузками, способными вносить неравномерные искажения в измеряемый сигнал. Лучше использовать более низкие, а не высокие значения, допускаемые программой настройки системы (скажем, 10 Кбайт вместо 100 Кбайт). Сетчатые трафареты печатной платы – средства отладки, которыми часто пре небрегают. Помечайте переключатели и перемычки. Всегда обозначайте первый штырьковый вывод, поскольку в мире SMT-компонентов нет общепринятого расположения вывода № 1. Для больших SMT-корпусов помечайте каждый 5-й или 10-й контакт и указывайте, в каком направлении увеличиваются номера выводов – по часовой стрелке или против. Иначе поиск 139-го контакта станет настоящим кошмаром, особенно для разработчиков в бифокальных очках и с ру ками, дрожащими от избытка кофеина. Устанавливайте ключ на разъемах, чтобы не гадать, как ориентировать под ключаемый кабель. Добавляйте комментарии к своим принципиальным схемам! На всех выходя щих за пределы чертежа дорожках указывайте, на какую страницу они ведут. Не забывайте подписывать номера контактных выводов, обеспечивающих питание и заземление, – подробно помечайте их. РЕЗЮМЕ 69 Завершив проектирование схемы, проверьте каждый ввод всех устройств и на 100 процентов убедитесь, что он к чему-нибудь подключен, даже если он не используется. Я видел сотни систем, не работавших на месте из-за того, что неиспользуемый ввод в определенном состоянии вызывал скачки напряжения. Возможно, вы надеетесь, что программисты смогут с помощью кода обойти эту ошибку, но это не всегда возможно, а когда возможно – об этом часто забывают. Старайтесь не использовать аппаратно реализованные конечные автоматов. Их очень трудно отлаживать, и они сильно связаны с микропрограммой, что еще больше усложняет отладку. Гораздо проще реализовать их программно. Ин струментальные средства (например, VisualState компании IAR) могут автома тически генерировать программный код конечного автомата. Резюме Встраиваемые системы представляют собой комплекс аппаратуры и про граммного обеспечения. Эти компоненты должны дополнять друг друга. Про граммистам, знакомым с оборудованием, легче реализовать микропрограммное обеспечение. Многие советы, приведенные выше, могут облегчить отладку системы. Запом ните: хорошая модель работает, а великолепную модель еще и легко отлаживать. РАЗДЕЛ СТРАНИЦА I Основы оборудования 18 II Проектирование III Математика 183 IV Системы реального времени 232 V Ошибки и исправления 312 75 Глава 4. Инструментальные средства и методы улучшения качества программного кода 88 Глава 5. Советы по улучшению функций 97 Глава 6. Эволюционная разработка 125 Глава 7. Реализация встраиваемого конечного автомата 134 Глава 8. Иерархические конечные автоматы 142 Глава 9. Разработка приложений, критически важных для обеспечения безопасности 161 Глава 10. Установка и использование системы контроля версий Введение Джек Ганссл Я разговаривал со многими инженерами по всему миру и всегда слышал одно и то же. Они признают, что новые методики разработки помогают быстрее соз давать программы более высокого качества, но их пугает перспектива этих ме тодик. Подобно морякам с тонущего корабля, они слишком заняты откачкой воды, чтобы устранять течь. Вода неотвратимо поднимается, поэтому работа идет все яростней. Рано или поздно корабль пойдет на дно, но, работая все на стойчивее и все быстрее, моряки оттягивают неизбежный финал всего лишь на мгновения. На старой карикатуре изображена жестокая битва, солдаты вооружены меча ми и копьями. Генерал повернулся к коммивояжеру, предлагающему ему пуле мет, и сетует: «Некогда мне с тобой разговаривать, не видишь – мы сражаемся!» Почему многие проекты по созданию микропрограммного обеспечения за вершаются с большим запозданием и содержат так много ошибок? Существует огромное количество теорий, объясняющих это сложностью ПО и другими фак торами, но я считаю, что непосредственная причина в том, что программиро вание – это занятие, не предназначенное для homo sapiens. Здесь нужна такая скрупулезность, которой может обладать только суперчеловек. А большинство из нас – не супермены. Пещерным людям не было необходимости убивать каждую газель, на которую они охотились – лишь столько, сколько нужно, чтобы не голодать. Фермеры никогда не рассчитывают, что у них взойдут все семена – приходится смирить ся с неизбежностью определенных потерь. Любой коммерсант, предлагающий какую-либо услугу, надеется удовлетворить спрос большинства, но не всех поль зователей. Ребенок, который приносит домой одни пятерки (к сожалению, не мой), раду ет своих родителей. Нам ставят пять за 90% правильных ответов. Совершенство не требуется. В жизни большинство усилий завершается успешно, если мы полу чаем пятерку, то есть теряем не больше 10% от возможного. В программировании это не так. Программа, верная на 90% – это абсолютная катастрофа, означающая полную бесполезность продукции. 99,9% верного кода означает плавание на дырявой посудине. 100 тысяч строк программы, надежной на 99,9% содержат около 100 невыявленных ошибок. Это никуда не годится. Программное обеспечение требует почти полного совершенства, что противо речит природе человека, внутренне склонного ошибаться. Программное обеспечение также высокоэнтропийно. Любому по силам напи сать совершенную системную программу длиной в 100 строк, но при увеличении ее размера для достижения полного (или почти полного) совершенства потребу ются все более возрастающие вложения энергии. Это похоже на ситуацию, когда биты, подобно коровам, «бродят» по загону, пытаясь выбраться на свободу; чем крупнее становится стадо, тем больше и больше приходится работать ковбоямпрограммистам, старающимся отыскать отбившихся от стада животных. Итак, каково решение? И есть ли у этой задачи ответ? 72 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ По моему мнению, программное обеспечение всегда будет проблемой и никог да не удастся найти решение, которое удовлетворило бы все заинтересованные стороны. Однако есть хорошо известные, хотя и редко применяемые стратеги ческие подходы, которые дают нам надежду. Некоторые из них кратко изложены в этой главе. Найдите время, чтобы оз накомиться с ними. Хватит откачивать воду, давайте устраним течь. Глава 4. ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА И МЕТОДЫ УЛУЧШЕНИЯ КАЧЕСТВА ПРОГРАММНОГО КОДА Крис Кейдел и Олаф Мединг [email protected] Академия встраиваемых систем www.esacademy.com Кристиан Кейдел – директор Академии встраиваемых систем, в которой он руководит разработкой новых классов и консультирует клиентов по встраиваемым технологиям, включая CAN и CANopen. Он часто выступает с докладами на конферециях Embedded Systems Conference (Конференция по встраиваемым системам) и RealTime and Embedded Computing Conferences (Конференция по системам реального времени и встраиваемой вычислительной технике). Олаф Мединг периодически преподает в Академии встраиваемых систем в ка ч ест ве внештатного сотрудника. Олаф имеет пятнадцатилетний опыт во всех аспектах проектирования и разработки ПО. Ранее он был ведущим разработчиком ПО в рамках проекта НАСА по выращиванию растений в космосе, а также руководил коллективом из 40 программистов, в течение года работавших над ответственным приложением с архитектурой клиент-сервер. Олаф имеет степень бакалавра по электротехнике Мэдисонского университета (штат Висконсин). Введение Сегодня кажется, что не хватает всего. Не хватает жилья, денег, полос на авто магистралях и (совершенно точно и в первую очередь) всегда не хватает време ни. Это относится и к срокам, отпущенным на разработку встраиваемых систем. Разработка программного обеспечения и оборудования – две задачи, решение которых отнимает очень много времени. В данной главе описаны некоторые спо собы, которые не только позволяют сократить время, необходимое для решения трудоемких задач проектирования аппаратной и программной части системы, но и одновременно обеспечивают повышение качества программного кода. Традиционный цикл последовательной разработки встраиваемой системы Прежде чем улучшать цикл разработки встраиваемой системы, необходимо вкратце проанализировать весь объем работ, чтобы лучше понять, сколько вре мени (зачастую лишнего) будет затрачено на различных стадиях этого цикла; одновременно мы попытаемся понять, как достичь определенного уровня качест ва нашей продукции. Серьезнейшая ошибка: каждый знает, что сегодня время очень дорого, поэтому разработка новой продукции часто начинается слишком поспешно, что в конеч ном итоге приводит к гораздо большим затратам времени, чем должно было быть. 74 ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА И МЕТОДЫ УЛУЧШЕНИЯ КАЧЕСТВА Очень часто новая продукция начинается с великой идеи. Затем эта идея быстро (обычно чересчур быстро) превращается в предварительную специфи кацию, которая представляется в отдел маркетинга и/или руководству. После нескольких совещаний и некоторых маркетинговых исследований принимает ся решение о разработке продукции. Кампания по маркетингу и продвижению продукции может начаться незамедлительно, часто на основе все еще черновой предварительной спецификации. Тем временем технический персонал в поте ли ца трудится над созданием первого прототипа нового устройства. Готовый про тотип представляется в отдел производства, там вам могут заявить, что в таком виде устройство нетехнологично (т. е. его невозможно изготавливать большими партиями)! Поэтому система отправляется на доработку, где ее пытаются подготовить к серийному производству, одновременно стараясь реализовать ряд изменений, предложенных различными сотрудниками всевозможных подразделений (в том числе и руководством). Каждая стадия занимает некоторое время, и когда го товая продукция, наконец, отгружается заказчику, велика вероятность, что она не соответствует требованиям первоначальной спецификации, кроме того, это происходит на несколько месяцев позже, а стоимость ее производства заметно превосходит запланированную первоначально. И эта схема – не фантастика. Некоторые многомиллиардные (в долларовом выражении) компании делают все описанные выше ошибки, тратя миллионы долларов на разработку продукции, которую они не смогут производить. Типичные проблемы современного рынка встраиваемых систем Похоже, на современном рынке есть тенденция: все сокращается – за исключе нием разве что времени, необходимого для проведения ваших научных исследо ваний, и списка ваших конкурентов. Определенно становится все труднее удовлетворять запросы потребителей своевременно, потому что времени просто НЕТ. За последние десять лет срок, в течение которого потребители готовы ждать появления новой продукции, значительно уменьшился. Причина проста: технологии в своем развитии шаг нули вперед настолько, что жизненный цикл продукции стал гораздо короче, чем раньше, это в свою очередь кардинально сократило сроки, в течение кото рых устройство может обеспечить максимальную окупаемость (или хоть какую- нибудь окупаемость вообще) средств, затраченных на его разработку. Поэтому совершенно естественно, что время разработки продукции также должно быть значительно сокращено, при условии что сохранится возможность ее серийного выпуска. Чем меньше будут общие затраты времени, тем выше будет размер прибыли. Возможно, наиболее показательным примером может служить производство жестких дисков, где промежуток оптимальной окупаемости составляет всего 6–8 недель. Если выпуск нового жесткого диска задерживается больше чем на 6 недель, весь оптимальный промежуток проходит, и устройству приходится ОБЩИЕ МЕТОДЫ ПОВЫШЕНИЯ КАЧЕСТВА КОДА И СОКРАЩЕНИЯ СРОКОВ ВЫХОДА НА РЫНОК 75 конкурировать с продукцией нового поколения, выпущенной другими произво дителями. Итог: задержка стоит реальных денег! Хотя это экстремальный пример, даже отраслям с такими традиционно дол гими циклами разработки, как автомобильная промышленность, не удалось из бежать тенденции сокращения жизненных циклов продукции. Общие методы повышения качества кода и сокращения сроков выхода на рынок Ниже описано несколько общих мер, которые можно предпринять для улучше ния цикла проектирования новой продукции. Некоторые из упомянутых тем будут подробнее рассмотрены в этой главе. Фиксируйте спецификацию и работайте параллельно Одна из важнейших проблем состоит в том, что в разработке спецификации на новое устройство должны принимать участие ВСЕ подразделения, включая службы маркетинга, сбыта, разработки документации, производства, техническо го контроля, и, возможно, даже обработки заказов. Такой процесс называется совместной или параллельной разработкой (в отличие от описанного выше по следовательного подхода). Это особенно важно в отношении продукции, успех которой может принести славу компании или разорить ее в случае неудачи. После того как все подразделения согласовали конечную редакцию специфи кации, она должна быть зафиксирована и не может изменяться, даже если на следующий день кто-либо заявит о новой возможности, «которая должна быть реализована немедленно». Такие пожелания следует собирать для следующей версии данной продукции. Создавайте контрольные отметки Только приняв окончательную фиксированную спецификацию, можно при ступать к параллельной разработке аппаратуры и программного обеспечения, а также документации. Установите достаточное количество контрольных отметок для интеграции компонентов и модулей. Здесь проявляется одно очень важное отличие от традиционной (последовательной) разработки продукции: все дело в согласованности сроков, а не в скорости. Кто из нас устанавливает контроль ные отметки для различных подразделений, результаты которых должны объ единиться на определенной стадии цикла разработки? Поторопившись в начале цикла, вы можете быстрее получить прототип, но в долговременной перспекти ве могут потребоваться значительные дополнительные затраты времени, прежде чем продукция попадет к покупателю. Используйте доступные ресурсы В ходе цикла разработки не нужно изобретать велосипед. Хороший пример: не стоит создавать собственную операционную систему реального времени (ОСРВ) 76 ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА И МЕТОДЫ УЛУЧШЕНИЯ КАЧЕСТВА для выбранного вами микроконтроллера. (Если коммерческой ОСРВ для ва шего микроконтроллера не существует, возможно, вам стоит еще раз подумать над правильностью своего выбора.) Не нужно также разрабатывать собственный сетевой протокол. Существует множество проверенных временем протоколов, удовлетворяющих самым разным требованиям (например, CAN (Controller Area Network), шина I C (Inter-Integrated Circuit), шина USB (универсальная после 2 довательная шина), RS485 и, наконец, старый добрый RS232). Просто проверьте, поддерживается ли нужный интерфейс выбранным вами микроконтроллером. Не экономьте на инструментальных средствах разработки, даже если при этом вырастут ваши авансовые затраты. Время, затраченное на разработку ПО, также очень дорого, и вы сможете его хотя бы немного сократить, предоставив команде разработчиков подходящие инструментальные средства для ускорения работы; причем некоторые примеры программ, поставляемые с этим инструмен тарием, могут служить образцом при написании кода или содержать встроен ный эмулятор. Непрерывно обучайте своих сотрудников Сегодня технологии развиваются настолько быстро, что самообразование или обучение на собственном опыте оказываются неэффективными и поглощают слишком много драгоценного времени разработчиков ПО. Приобретения встро енного эмулятора может оказаться недостаточно, если его комплексные средства отладки не используются из-за того, что ни один разработчик не знает об их существовании или о том, как их использовать. Экспертные знания обо всех имеющихся в распоряжении ресурсах, особенно средствах разработки оборудо вания и программного обеспечения, очень важны для максимально эффективно го использования этих ресурсов. Несколько дней обучения работе на выбранной микроконтроллерной платформе – и инструментальные средства разработки по могут значительно сократить сроки реализации проекта и повысить мотивацию сотрудников. Профессиональные тренинги, посвященные разрабатываемой про дукции, – также отличный способ ускорить интеграцию новичков в команду. Основные факторы, влияющие на продолжительность цикла разработки Общие затраты времени, необходимого для реализации встраиваемого прило жения после утверждения спецификации, можно разделить на четыре основных части. ПРИМЕЧАНИЕ. Мы не включили сюда затраты времени на создание доку ментации для конечного пользователя, поскольку при наличии тщательно про работанной окончательной версии спецификации эта документация может быть написана параллельно, за время разработки продукции. Четыре главных части цикла разработки продукции: 1)  разработка оборудования; 2)  разработка ПО; КАК СНИЗИТЬ ВРЕМЯ РАЗРАБОТКИ ПО И ПОВЫСИТЬ КАЧЕСТВО КОДА 77 3) #7; интеграция системы: время, необходимое для объединения всех компонен тов приложения (возможно, включая продукцию других компаний); 4)  испытания и контроль качества: затраты времени на испытание продукции. Можно было бы выделить и пятый этап – отладку, однако отладка не является самостоятельной стадией, поскольку может быть включена в состав четвертой части цикла разработки продукции. Какой этап длится дольше других? Встраиваемые приложения значительно отличаются друг от друга, поэтому поч ти невозможно провести обобщение и определить, какую долю в процентном отношении от длительности всего цикла разработки занимает данный этап. Вот лишь приблизительная оценка: 1)  разработка оборудования: 10…40%; 2)  разработка ПО: 20…50% (в будущем, возможно, будет увеличиваться); 3)  интеграция системы: 10…40%; 4)  испытания и контроль качества: 10…50%; 5)  общая отладка системы: 25…75%. Как снизить время разработки ПО и повысить качество кода Прежде чем обсуждать способы улучшения работы над программным обеспече нием для встраиваемых приложений, необходимо рассмотреть некоторые проб лемы. Для разработки встраиваемых приложений нужны все более и более раз нообразные навыки программирования. Разработчик ПО должен уметь управ лять структурой прерываний с различными уровнями приоритета и знать, как организовать высокоуровневое согласование приложений с операционной систе мой реального времени, библиотеками устройств и с сетевыми устройствами. Кроме того, разработчику действительно необходимы некоторые навыки рабо ты с оборудованием для интеграции программируемых логических компонентов и кодирования элементов программного сопряжения с основными аппаратными компонентами. Ниже будет уделено внимание некоторым способам сокращения сроков разработки ПО. Пишите код в соответствии с внутренним руководством по оформлению ПО Следование руководству по оформлению программного обеспечения становится обязательным для компаний, стремящихся каким-либо образом сертифициро вать качество создаваемого ПО. В основе идеи использования руководства по оформлению ПО лежит стремление к стандартизации способов написания про грамм. Это немного ограничивает «свободу творчества» программистов, которые, например, стараются втискивать в одну строку программы как можно больше операторов. Одно из главных преимуществ такого подхода состоит в улучшении 78 ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА И МЕТОДЫ УЛУЧШЕНИЯ КАЧЕСТВА читаемости кода, поскольку читателю не нужно разбираться в индивидуальных предпочтениях каждого программиста. К сожалению, нет единого руководства по оформлению программ на языке С – таких документов сотни, большинство из них имеет гриф «для внутренне го использования» или «конфиденциально» и не предназначено для открытого доступа. Давайте взглянем на некоторые правила, которые можно найти в таких руко водствах. Одно из них заключается в том, что длина шестнадцатеричных и дво ичных значений, помещаемых непосредственно в код программы, должна соот ветствовать типу данных, к которому они относятся. Например, 16-разрядной беззнаковой целой переменной должно быть присвоено значение из четырех шестнадцатеричных цифр – 0x000F, а не 0x0F. Правило выбора названий для процедур и функций требует, чтобы каждое имя имело префикс, обозначающий название модуля, к которому принадлежит данная функция или процедура. Само имя должно быть глаголом, за которым следует название объекта. Так, «Com_InitChannel» – название процедуры моду ля «Com» (соmmunication – передача информации). Если функция возвращает значение, оно должно быть отражено в ее названии, например, «Com Get Error Code». Другой раздел руководства по оформлению программ обычно регламентирует использование комментариев и может содержать указания, когда следует давать пояснения в конце строки, а когда оформлять в виде строки комментария. Ком ментарии в конце строки обычно стараются не применять, поскольку их труднее обслуживать. В блоках комментариев в начале или в конце строки не следует употреблять какие-либо символы форматирования (например, «*» или «|»), по скольку это также затрудняет обслуживание комментария. Затем руководства переходят к форматированию составных операторов с по мощью фигурных скобок «{» и «}». Наиболее предпочтительное использование отступов: оператор { операторы; } вместо оператор { операторы; } или оператор { операторы; } КАК СНИЗИТЬ ВРЕМЯ РАЗРАБОТКИ ПО И ПОВЫСИТЬ КАЧЕСТВО КОДА 79 Выполняйте проверку кода Процедура проверки кода состоит в том, что каждая строка, написанная од ним программистом, должна быть просмотрена и понята (т. е. подтверждена) другим программистом. Такие проверки должны проводиться сразу же после начала работы над проектом. Хотя на первый взгляд кажется, что это – излиш няя работа, в долговременной перспективе вы можете получить существенное преимущество. Каждая ошибка, обнаруженная в программе до начала реаль ного процесса отладки, может сэкономить часы работы. Так что это поможет минимизировать трудно предсказуемое время, необходимое для отладки про граммы, при дополнительной небольшой, легко поддающейся оценке затрате времени на проверку. У этого подхода есть и хороший побочный эффект для программистов, про веряющих чужой код: взаимное обучение разработчиков программ! Когда один из программистов по каким-либо причинам выбывает из проекта, остальным будет проще заполнить пробел в команде, если они участвовали в проверках программы. Выбирайте подходящие инструментальные средства разработки Безусловно, необходима интегрированная среда разработки с графическим пользовательским интерфейсом, связывающая в единое целое такие программ ные средства, как компилятор, ассемблер, компоновщик, локатор и, возможно, уже встроенные эмулятор и диспетчер отладки. Однако существует еще несколь ко инструментальных средств разработки, способных заметно сократить срок работы над приложением и сделать его код более надежным и одновременно пригодным к повторному использованию в других приложениях. Текстовый редактор позволяет ускорить работу в интегрированной среде и га рантирует более высокую продуктивность программиста, подсвечивая разными цветами ключевые слова, предоставляет функции автоматического форматиро вания и навигации, а также обеспечивает высокую гибкость настройки. Обо зреватель кода (рис. 4.1) заметно облегчает понимание и анализ написанной программы, позволяя визуализировать такие компоненты кода, как функции, переменные, константы, типы и макросы. Одним из примеров подобных инструментальных средств служит «Development Assistant for C» (DA-C – помощник разработчика на языке C) швейцарской компании RistanCASE GmbH. Сделав один щелчок мышью, программист мо жет просмотреть описание переменной, все строки, в которых эта переменная используется, так же как и все строки, где ее значение изменяется. Возмож ность просмотра деревьев вызова функций и графические схемы, помогающие понять состав сложных структур данных, крайне полезны, особенно при внесе нии изменений в код. В состав этого инструментального средства входит также синтаксический анализатор языка C на уровне проектов, который без помощи компилятора проверяет программу на соответствие стандарту «Safe C» и требуе мой метрике программного обеспечения. 80 ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА И МЕТОДЫ УЛУЧШЕНИЯ КАЧЕСТВА Рис. 4.1. Окно обозревателя кода Однако самая замечательная возможность – блок-схемы (рис. 4.2), генерируе мые приложением DA-C на основе программного кода и комментариев к нему. Эта функция позволяет вам параллельно просматривать строки исходного кода и блок-схему и даже использовать отладчики других фирм для поиска ошибок в программе, написанной по этой блок-схеме. Система контроля версий (например, MKS Source Integrity или Visual SourceSafe компании Microsoft) может существенно повысить согласованность действий группы разработчиков, гарантируя (по умолчанию), что в каждый момент времени только один программист редактирует данный файл. Это по могает избежать потери информации при случайном изменении файла другим пользователем. Обычно настройку можно изменить, чтобы сделать возможной одновременную отладку одного и того же файла и предотвратить уничтожение исправлений, сделанных другими программистами. Старые версии исходного кода и другие файлы могут быть заархивированы или восстановлены из архива при поиске ошибок или в других целях. Системы контроля версий позволя ют также отслеживать использование модулей различными программами, что упрощает повторное применение готового кода. Во второй части этого докумен та будут подробно описаны возможности и преимущества системы контроля версий. Средства автоматической генерации кода, запускаемые на локальном ПК (на пример, Digital Application Engineer (DAvE) компании Infinenon или MakeApp компании IAR) или через Web-интерфейс, как средство CodeArchitect компа нии ES Academy (www.codearchitect.org), позволяют программисту визуально конфигурировать выбранный микроконтроллер с помощью простых диалого вых окон настройки. Оптимизированный исходный код может генерироваться автоматически для реализации драйверов сконфигурированных периферийных модулей, что позволяет добиться значительной экономии дорогостоящего труда разработчиков П . 82 ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА И МЕТОДЫ УЛУЧШЕНИЯ КАЧЕСТВА • • Для отладки не должны требоваться дополнительные ресурсы (например, встроенные в микросхему последовательные информационные каналы или таймеры). • • Память эмулятора должна быть отображаемой. – #7; Желательно, чтобы она была двухпортовой и обеспечивала доступ в ре жиме реального времени без нарушений работы программы. • • Встроенная память результатов трассировки должна показывать протокол запуска программ. – #7; Профессиональные системы должны содержать временные метки и/или обрабатывать сигналы от внешних устройств. – #7; Профессиональные системы должны уметь фильтровать запись событий, позволяя регистрировать доступ к определенным шинам или областям программного кода (например, заданиям, функциям или подпрограммам обработки прерываний). • • Комплексные инициирующие события (запускаемые, например, при пере ходе шины в определенное состояние) ускоряют и упрощают отладку. • • Функции защиты памяти предотвращают доступ обычными средствами к выбранным участкам памяти (например, доступа из программы к данным или неиспользуемым адресам памяти). • • Необходима возможность выполнения детального анализа производитель ности с вычислением минимального, максимального и среднего времени работы выбранных функций. • • Профессиональные системы способны обнаруживать нарушения времени работы указанного цикла. Эти системы могут останавливать работу про граммы, если обработка прерывания длится дольше указанного времени x или если прерывание не происходит в течение указанного интервала y. Повторное использование вместо повторного изобретения Использование готовой операционной системы реального времени (ОСРВ) мо жет сберечь многие часы рабочего времени программистов, которое в против ном случае им пришлось бы потратить на разработку структуры ПО для вашей микроконтроллерной платформы, чтобы добиться возможности параллельного исполнения нескольких заданий. Сегодня выпускаются разнообразные ОСРВ для различных микроконтроллеров. Многие из них не требуют выплаты автор ского гонорара и распространяются вместе с полной версией исходного кода. Выбирайте ОСРВ с поддержкой приоритетных прерываний, то есть способную прервать выполнение задания A для того чтобы запустить задание B с более высоким приоритетом до завершения обработки задания A. Если создаваемое вами приложение имеет устройства распределенного управ ления, понадобится протокол связи для обмена информацией между этими устройства. Не изобретайте собственный протокол, когда имеется такой широ кий выбор проверенных. Например, для низкоуровневого обмена информацией между устройствами на плате подойдет I C, а для обмена информацией между 2 несколькими узлами – RS232 (UART). Если вам нужен надежный протокол свя КАК СОКРАТИТЬ СРОКИ ПРОЕКТИРОВАНИЯ АППАРАТНОЙ ЧАСТИ СИСТЕМЫ 83 зи, обеспечивающий работу сети с большим числом узлов, правильным выбором будет протокол Controller Area Network (CAN). Если же вы хотите обеспечить обмен, ориентированный на передачу объектов данных, добавьте протокол CAN высокого уровня, например, CAN open или Device Net. В приложениях, исполь зующих интегрированный адаптер для подключения к Интернету, следует вы брать протокол TCP/IP. Как сократить сроки проектирования аппаратной части системы Как упоминалось ранее, срок проектирования оборудования – первый и очень важный фактор при создании встраиваемых систем. Давайте еще раз обратим внимание на требования к группе разработки. Ва ша команда должна быть знакома с самыми различными компонентами. Разра ботчики обязаны знать, как собрать приложение из таких составных частей, как интеллектуальные модули (микроконтроллер, микропроцессор или цифровой процессор сигналов), модули памяти (например, флеш-память, электронное пере программируемое ПЗУ, ОЗУ), программируемые логические схемы, компоненты ввода/вывода и аналоговые компоненты. Кроме того, может понадобиться и сете вая инфраструктура. Группе разработчиков ПО нужно предоставить соответствую щий программный интерфейс. Иногда необходимые для работы навыки настолько различны, что приходится привлекать специалистов из самых разных областей. Рекомендация номер один: чтобы сократить срок проектирования оборудова ния, не занимайтесь проектированием. Используйте как можно больше готовой продукции Применение готовой продукции в виде одноплатных компьютеров (SBC) кар динально сокращает сроки проектирования оборудования. Раньше выпускались только высокопроизводительные платы, близкие по уровню к встроенным ПК. Сегодня существует несколько компаний, таких как PHYTEC, предлагающих продукцию в секторе SBC низкой и средней производительности на базе 8- или 16-разрядных микроконтроллеров. Такие микрокомпьютеры обычно изготавли ваются на основе многослойных плат со всеми схемными решениями, необходи мыми для работы микроконтроллера. Возможно, ваше приложение может быть разработано и реализовано путем использования двухслойной платы с компо нентами ввода/вывода, характерными для вашего проекта. Тщательно подбирайте микроконтроллер Определившись с архитектурой микроконтроллера для вашего будущего при ложения, тщательно изучите ответы на следующие вопросы: • • Какие существуют инструментальные средства разработки для данной ар хитектуры? • • Достаточно ли у ваших разработчиков опыта использования подобных устройств и инструментальных средств разработки? 84 ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА И МЕТОДЫ УЛУЧШЕНИЯ КАЧЕСТВА • • Сколько компонентов/периферийных устройств реализовано в микросхе мах, сколько еще придется разрабатывать (каждый дополнительный ком понент ведет к удорожанию проекта и удлиняет сроки его реализации!). • • Можно ли найти замену (от другого производителя) для этой микросхемы? Вообще имеет смысл использовать ту архитектуру, с которой ваши разработ чики знакомы лучше всего. Если же вы должны перейти на другую платформу, постарайтесь хотя бы немного познакомиться с выбранным микроконтроллером и приобретите инструментальные средства разработки (компиляторы и встроен ные эмуляторы). Пример микроконтроллеров, сокращающих сроки выхода на рынок, – микроконтроллеры Philips Связующие логические схемы – один из компонентов оборудования (о кото ром часто забывают), повышающий стоимость и удлиняющий сроки разработки оборудования. Эти схемы требуют использования дополнительных компонентов, дополнительной разводки, занимают значительное место на печатной плате и по вышают вероятность конструкторских ошибок. Хороший способ избавиться от связующих логических схем – использование микроконтроллеров серии 51LPC, совместимых с микроконтроллерами Philips 8051. Продукция этого семейства не требует внешней синхронизации и внешних цепей для установки в начальное состояние. Она оснащена внутренней памятью команд и контактами ввода/вы вода, полностью достаточными для управления светодиодами. Все это экономит внешние компоненты, а значит, и время. Для запуска и работы микроконтроллеров 51LPC нужны всего лишь два кон такта: земля и V , все остальные могут использоваться для ввода/вывода. CC Резюме и перспективы К сожалению, нет волшебного средства для ускоренного выхода на рынок, как нет и единственного решения, которое чудесным образом сократило бы вдвое сроки создания новой продукции. Только сочетание многих или даже всех ма леньких хитростей, о которых мы рассказали, поможет вам сократить время раз работки или хотя бы сделать его более предсказуемыми. Если смотреть в будущее, принимая во внимание тенденцию наделять встраи ваемые системы все большими возможностями (которые требуют более сложно го ПО), проблема ускорения разработки программного обеспечения становится все более важной. В этом отношении может быть полезной появляющаяся в наши дни архи тектура микросхем, способная стать стандартом для встраиваемых приложений. Имеющийся сегодня широкий ассортимент различных архитектур, предлагае мых разными производителями, усложняет разработчикам проблему выбора одной из них для постоянного использования во всех проектах. Архитектура ARM определенно может изменить эту ситуацию. Поскольку ARM-микропроцессоры лицензированы и выпускаются многими производи РЕЗЮМЕ И ПЕРСПЕКТИВЫ 85 телями микросхем, они вполне могут стать стандартными контроллерами для встраиваемых приложений, которым требуется мощность 32-разрядных вычис лений. Среди младших моделей одним из лучших вариантов до сих пор является микроконтроллер 8051. Благодаря широкому выбору компонентов, выпускаемых различными компаниями, и хорошо зарекомендовавших себя инструментальных средств разработки можно найти подходящую модификацию почти для любого приложения, которое поддерживает работу под управлением 8-разрядного мик роконтроллера. Если же продукция данного поставщика вам не подходит, анало гичный компонент другого производителя можно найти буквально «за углом». Ссылки на веб-сайты упомянутых в данной главе компаний и/или разделы, посвященные их продукции: Code Architect Интерактивное средство автоматической генерации кода для микроконтроллеров: www.codearchitect.org . Embedded Links База данных, содержащая ссылки, относящиеся к рынку встраиваемых систем, а также календарь событий: www.embeddedlinks.com . Embedded Systems Academy Интерактивные и многодневные обучающие курсы по архитектуре микроконт роллеров и сетевым технологиям для встраиваемых систем: www.esacademy.com . Infineon Technologies – DavE Средство автоматической генерации кода для микроконтроллеров компании Infineon: www.infineon.com/dave/ . Philips Semiconductors 8- и 16-разрядные микроконтроллеры, 51LPC – микроконтроллер, позволяю щий максимально сократить сроки выхода на рынок: www.philipsmcu.com . Phytec Одноплатные микрокомпьютеры с 8- и 16-разрядными микроконтроллерами: www.phytec.com . Ristan CASE Обозреватель кода: Development Assistant – C: www.ristancase.ch . Triscend Микроконтроллеры со встроенными матричными БИС FPGA для заказных периферийных устройств: www.triscend.com. Глава 5. СОВЕТЫ ПО УЛУЧШЕНИЮ ФУНКЦИЙ Джек Ганссл Можно написать безобразный, сбивающий с толку, ужасно запутанный недо кументированный код, который будет работать. Одному Богу известно, сколько таких ужасных программ сегодня контролирует все: от доступных потребитель ских товаров до важнейших приложений авиационной радиоэлектроники. Но также можно, и даже немного проще, написать ясные, профессионально сделан ные функции, чья внутренняя безошибочность очевидна, с которыми действи тельно очень удобно работать. Вот несколько рекомендаций. Минимизируйте функциональные возможности Вы – специалист по электротехнике? Мои неофициальные исследования показа ли, что около 60–70% сотрудников, занятых производством микропрограммного обеспечения, имеют высшее электротехническое образование. Такие знания по могают хорошо разбираться не только в физических моделях наших приложе ний, но и в лабиринтах оборудования, которым мы управляем. До сих пор в учебных курсах большинства университетов игнорируются во просы проектирования программного обеспечения. Конечно, профессора учат нас программированию и искусству создания программ. Но они методично об ходят стороной важнейшие принципы проектирования ПО, без которых нельзя построить большие надежные системы. Навыки, необходимые для создания ра ботающей программы из 500 строк кода, несопоставимы с опытом, требующимся для работы с программой в 100 000 строк. Вероятно, наиболее широко известное и широко используемое правило про граммирования – создание коротких функций. На своих лекциях по микропро граммному обеспечению я спрашиваю слушателей: «Кто из вас принудительно ограничивает размеры своих функций?» Очень редко поднимается хотя бы одна рука. Хотя мы знаем, что написать хорошую программу с длинными подпро граммами практически невозможно. Если ваши функции имеют длину больше 50 строк (одной страницы) – они слишком длинные. Экспериментальный факт: практически невозможно запом нить последовательность длиной более 8 или 10 цифр больше чем на одну ми нуту; как же можно надеяться охватить разумом тысячи ASCII-символов, из которых состоит длинная функция? Еще хуже то, что задача проследить ход работы программы, длина которой больше страницы, практически невыполнима: листая страницы вперед и назад, мы тщетно пытаемся понять, чем занимается это множество вложенных циклов. Пишите короткие функции. Это значит, что функция должна решать всего од ну задачу. Запутанный код, пытающийся контролировать множество несопоста вимых процессов, слишком сложен для того, чтобы быть надежным и удобным в обслуживании. Мне довелось видеть огромное множество функций, имевших ИНКАПСУЛИРУЙТЕ 87 50 аргументов, управлявших дюжиной взаимосвязанных режимов. Лишь считан ные процедуры работали хорошо. Выражайте независимые мысли независимо, каждую – с помощью отдельной, предельно понятной функции. Единственное практическое правило: если у вас возникли проблемы с выбором информативного названия функции, вероятно, она решает слишком много разных задач. Инкапсулируйте Адепты ООП (объектно-ориентированного программирования) подобно ярым кришнаитам распевают объектные мантры «инкапсуляция, наследование и по лиморфизм». ООП – полезный инструмент, помогающий решить множество проблем, но это не единственное средство, которым мы располагаем. И оно под ходит не для всех приложений. К инкапсуляции это не относится. Если объем ПЗУ настолько ограничен, что на счету каждый байт, инкапсуляция может оказаться невозможной. Однако сле дует признать, что разработка таких приложений оказывается очень дорогостоя щей. Очевидно, что в некоторых приложениях, где стоимость является одним из главных параметров (например, в электронных поздравительных открытках), очень важно добиться минимально возможной потребности в памяти. Однако если число байтов ограничено, расчетные затраты на освоение резко взмывают вверх. Инкапсуляция означает объединение данных и программного кода, оперирую щего этими данными, в единый объект. То есть ни один другой бит кода не по лу ч ит прямого доступа к вашим данным. Инкапсуляцию можно осуществить на языках С++ или Java. Она в равной степени доступна программистам на С и на ассемблере. Описывайте переменные внутри использующих их функций и стремитесь к тому, чтобы видимость этих переменных для других подпрограмм ограничивалась их областью действия. Инкапсуляция – это больше чем простое ограничение доступа к данным. Пра вильно инкапсулированный объект или функция имеют высокую связность. Они полностью выполняют свои задачи, не отвлекаясь на посторонние действия. Они защищены от исключений и от других вычислительных потоков. Объект или функция представляют собой полностью функциональный черный ящик, тре бующий минимальной поддержки или не требующий ее вовсе. Последовательному обработчику может потребоваться вызов прерывания для передачи полученных символов в кольцевой буфер, вызов функции «get_data», извлекающей данные из структуры данных, и функции «is_data_available», про веряющей полученные символы. Он также обрабатывает переполнение буфе ра, потерю символов при последовательном обмене данными, ошибки четности и все другие возможные состояния ошибки. Объект реентерабелен, поэтому дру гие прерывания не могут разрушить его данные. Ограничения, накладываемые инкапсуляцией, предназначены для разрыва зависимостей. Сильное сцепление модулей (высокая связность частей внутри подсистемы) должно сопровождаться их низкой связанностью – малой зависи мостью от действий других модулей. Мы все знакомы с программами, где на 88 СОВЕТЫ ПО УЛУЧШЕНИЮ ФУНКЦИЙ первый взгляд простые действия переплетены с кодом десятка других модулей. И тогда простейшие изменения в программе требуют отслеживания переменных и вызовов функций на протяжении тысяч строк программы – задача, определен но вызывающая у разработчика желание напиться. Я вижу десятки таких про граммистов здесь, на улицах Балтимора, – горстка бедных душ в потрепанной одежонке, голодных и небритых, выпрашивающих апплеты у прохожих. Жаль, они не смогли устоять перед соблазном использования глобальных переменных. Избавляйтесь от избыточности Избавляйтесь от избыточного кода. Исследователи в Стэнфорде изучили 1,6 млн строк ОС Linux и обнаружили, что избыточный код в программе, даже безобид ный, хорошо коррелирует с ошибками (см. www.stanford.edu/~engler/p401-xie.pdf ). Избыточность определяется как фрагменты кода, работа которых ни к чему не приводит, например присваивание переменной собственного значения, ини циализация или установка значения переменной, которая затем никогда не ис пользуется, невыполняемые участки программы или сложные условные опера торы, часть логического выражения которых никогда не вычисляется, поскольку входит в состав предыдущего условия. Они достаточно обоснованно не считали избыточными такие специальные случаи, как установка значений отображаемого в памяти порта ввода/вывода, так как эта операция, хотя и выглядит избыточ ной, на самом деле таковой не является. Проблемным является даже безобидный избыточный код, который не содер жит ошибок, поскольку функции с таким кодом на 50% чаще других содержат серьезные ошибки по сравнению с подпрограммами без избыточного кода. Из быточность – индикатор ошибки разработчика, она сигнализирует о том, что программист, вполне мог совершить целую серию ошибок. Остерегайтесь копирования программных блоков. Я сам горячий сторонник повторного использования кода и поддерживаю применение протестированных ранее фрагментов исходного кода. Однако разработчики слишком часто копиру ют код, не изучив как следует его работу. Можете ли вы заранее быть уверены в том, что все переменные инициализированы так, как ожидается, даже если данный фрагмент взят из другой части этой же программы? Или в том, что небольшая ошибка – неправильное предположение о значении семафора – не вызовет инверсию приоритетов? Мы копируем код для экономии времени разработки, но следует также пом нить о ее стоимости. Проверяйте такой код даже более тщательно, чем новый материал, написанный вами с нуля. И когда анализатор кода или компилятор выдают предупреждение о неиспользуемых переменных, будьте внимательны: это может быть признаком наличия других, более серьезных ошибок. Сокращайте код реального времени Код для обработки событий реального времени подвержен ошибкам, его трудно писать и еще труднее отлаживать. По возможности, выносите в отдельное зада БЕСПОЩАДНО УЛУЧШАЙТЕ ПРОГРАММЫ 89 ние или раздел программы те части кода, скорость работы которых очень важна. Если вся программа выполняется слишком долго, отладка каждого ее бита будет сильно затруднена. Сегодня мы разрабатываем все более крупные и сложные системы, чем когда бы то ни было, при этом возможности инструментальных средств отладки даже меньше, чем десятилетие назад. Еще до того как скоро сти процессоров возросли практически до бесконечности, а широкое распро странение компонентов для поверхностного монтажа ограничило возможности исследования ИС, предпочтительным средством отладки стал внутрисхемный эмулятор. Среди его функций трассировка состояний схемы в режиме реально го времени, таймер событий и даже анализатор производительности. Сегодня нам приходится использовать отладчики BDM и JTAG. Они весьма полезны для решения процедурных проблем, но практически не имеют никаких средств для повышения скорости работы. Запомните также два практических правила: при возрастании загрузки систе мы с 70 до 90% сроки разработки удваиваются. Увеличение загрузки системы до 95% утраивает этот срок. Разработка систем реального времени стоит довольно дорого, а проекты с высокой загрузкой еще дороже. Ход программы должен быть грациозным Избегайте изменения порядка операторов при выполнении программы. Старай continue, goto, break тесь не использовать операторы или несколько операторов return в одной функции. Это полезные конструкции, которые, однако, затруд няют понимание функций. Их чрезмерное использование приводит к превраще нию программы в «спагетти-код» . 1 Беспощадно улучшайте программы Экстремальное программирование и другие методы быстрого программирования особо подчеркивают важность рефакторинга, или переписывания заново плохого кода. Эта концепция не нова; как показали Каперс Джонс, Барри Бём и другие, плохо написанные модули на самом деле гораздо дороже прекрасно структу рированных, поскольку их трудно заставить работать и сложно поддерживать. Ярые сторонники рефакторинга требуют, чтобы мы переписывали любой фрагмент кода, который можно улучшить. На мой взгляд, это уж слишком. Наша задача – создать работающую продукцию и получить при этом прибыль; совер шенство никогда не будет доминирующим фактором. Хотя те функции, которые работают плохо, нужно переписывать в обязательном порядке. Если вы боитесь редактировать функцию, если она перестает работать после каждого изменения комментария, значит, она нуждается в рефакторинге. Когда профессиональный разработчик, в конце концов, делает вывод «нет уж, давайте мы лучше не будем трогать данный фрагмент кода, поскольку никто не решается 1 Так называют программу, состоящую из функций огромной длины и содержащую боль goto шое число операторов безусловного перехода . – Прим. пер. 90 СОВЕТЫ ПО УЛУЧШЕНИЮ ФУНКЦИЙ связываться с ним» – это сигнал, что нужно, бросив все дела, срочно переделы вать этот код, чтобы он стал понятным и управляемым. Второе начало термодинамики гласит, что любая замкнутая система стре мится к повышению энтропии, то есть к увеличению беспорядка. Программы тоже подчиняются этому печальному правилу. Даже при успешной поддержке неустойчивость ПО всегда возрастает, с каждым разом, существенно усложняя внесение изменений в программу. Как подчеркивал Рон Джеффрис, поддержка программы без рефакторинга повышает энтропию кода, добавляя фактор «бес порядка» (m) в каждую новую версию. Стоимость производства новых версий можно оценить по формуле: (1 + (1 + (1 + или (1 + , где – m) m) m)…, m) n n номер версии. Стоимость поддержки растет экспоненциально по мере того, как в программу вносится все большее число поспешных исправлений и небрежных заплаток. Так появился следующий образчик программистской мудрости, при водящий в ярость руководство: «в этой программе слишком много беспорядка, чтобы ее можно было поддерживать». Рефакторинг также вызывает увеличение стоимости программы, r. Но он устраняет фактор беспорядка, поэтому стоимость версий растет по закону 1 + r + + r + r.., который является линейным. Люк Хохманн пропагандирует «пострелизное сокращение энтропии». Он при шел к выводу, что все мы слишком часто вносим на скорую руку изменения в программу, чтобы побыстрее выпустить продукцию на рынок. Это приводит к удорожанию поддержки продукции, так что мы сполна расплачиваемся за не брежное отношение к программному обеспечению. Поддержка – это не только втискивание новых функций в программу, но и снижение возросшей энтропии. Реструктурируйте программу, чтобы сделать более понятной ее запутанную ло гику. Если код представляет собой беспорядочное нагромождение операторов или даже просто не полностью понятен, лучше перепишите его так, чтобы назначение программы прояснилось. Исключите слишком глубоко вложенные циклы или логические выражения – никто не сможет разобраться во всех «перепасовках» if, операторов имеющих пять уровней вложения. Ясность – сестра точности. Применяйте стандарты и экспертизу При написании программ пользуйтесь внутренним стандартом на микропро граммное обеспечение. Проводите формальную экспертизу кода, чтобы гаранти ровать строгое соблюдение этого стандарта и обнаружение ошибок. Тестируйте программу только после проведения экспертизы. Экспертиза примерно в 20 раз дешевле поиска ошибок традиционными спо собами отладки. При этом удается обнаружить целый класс проблем, которые никогда не были бы выявлены при обычном тестировании. Большинство иссле дований показывает, что традиционные средства отладки позволяют проверить лишь около половины программного кода! Без экспертизы вы с очень высокой вероятностью начнете выпуск продукции, содержащей ошибки. Интересно, что стандарты DO-178B на разработку ПО, используемого в системах, критически важных для обеспечения безопасности, в основном опираются на инструмен ТЩАТЕЛЬНО КОММЕНТИРУЙТЕ ПРОГРАММУ 91 тальные средства, позволяющие убедиться в том, что каждая строка программы исполняется. Эти замечательные средства анализа кода все-таки не могут заме нить экспертизу. Без стандартов и экспертиз обычно не удается создать высоко качественную микропрограмму. Тщательно комментируйте программу Даже если вы постоянно находитесь в герметично закрытой капсуле, никогда ни с кем не общаетесь, целыми днями прокручивая код, я все-таки призываю вас взять на себя обязательство сообщать свои мысли другим программистам ясно и грамматически правильно. В конечном счете программное обеспечение – это смесь компьютерного жаргона (на C или даже на C++) и комментариев (в Америке, по крайней мере, комментарии на английском языке предназначены для людей, а не для компьютеров). Написав программу на безупречном C, но с невнятными комментариями, мы сделаем плохую работу. Мне довелось прочитать очень много программ, созданных огромным числом разработчиков. Последовательные хорошо сформулированные комментарии встречаются редко. Иногда можно заметить энтузиазм группы разработки в на чале работы над проектом. Код инициализации реализован превосходно. Рабо main() та функции очевидна и тщательно документирована. По мере того как проект обрастает функциями, кодирование выполняется все менее тщательно. Начинают появляться комментарии типа /* ???? */ или мой любимый /* проверить потом */ Частота комментариев уменьшается; ясность уступает место кратким загадоч ным примечаниям; заглавные буквы используются хаотично. Первоначальное трепетное отношение к проекту, которым пронизаны тщательные информатив ные профессиональные комментарии, сделанные на раннем этапе разработки, резко меняется, когда, боясь сорвать сроки сдачи проекта, программисты отка зываются ото всего, что не является исполняемым кодом. Напряженные и постоянно корректирующиеся графики – суровая правда жизни в этой сфере бизнеса. Обычное дело, когда жертвуют всем, что сразу же не повлияет на работу продукции. Редкие руководители обращают внимание на качество исходного кода. Об этом вспоминают (если не забывают вообще) только в том случае, когда в разрабатываемой продукции возникают ошибки или постоянно проявляются дефекты, в результате чего срок завершения проекта отодвигается все дальше и дальше. Мой стандарт оформления комментариев заключается в описании функций продукции (не программы) – так, чтобы можно было проследить работу про граммы по комментариям, не заглядывая в сам код. Код обеспечивает реализа цию алгоритма; комментарии поясняют работу программы вам и другим про 92 СОВЕТЫ ПО УЛУЧШЕНИЮ ФУНКЦИЙ граммистам. Возможно, что к следующей версии данной программы вы при ступите через несколько лет. Пишите каждый бит документации на английском языке (если живете в США). Используйте существительные, глаголы и простые конструкции. Будь те кратки, не стоит писать «Войну и мир». Приводите точное и полное описа ние; представьте, что ваш читатель не имеет ни малейшего представления о том, как решается данная задача. В большинстве случаев я предпочитаю включать описание алгоритма в заголовок функции, даже для таких хорошо известных подходов, как метод Ньютона. Пояснения, в которых использованы имена ва ших переменных, имеют гораздо больше смысла, чем замечание «описание этого метода можно найти в любом учебнике по дифференциальному исчислению». И наконец, давайте взглянем правде в глаза: хорошо продуманные комментарии делают написание кода почти тривиальной задачей. Используйте заглавные буквы в соответствии с правилами грамматики. НЕ ИМЕЕТ СМЫСЛА ЗАПИСЫВАТЬ ВЕСЬ ТЕКСТ ТОЛЬКО В ВЕРХНЕМ РЕ ГИСТРЕ, ПОСКОЛЬКУ ТЕЛЕТАЙП ИСЧЕЗ ЛЕТ 25 НАЗАД. Обычай полно стью отказываться от заглавных букв также устарел. Еще хУжЕ поСтуПАюТ неКотОРыЕ ПроГраМмИсТы, сЛучАйНО пЕрЕклЮЧАющИе РеГисТрЫ. Воз можно, это звучит глупо, но я видел немало таких программ. А исчо пишыте фсе слава правелно. Избегайте длинных абзацев. Используйте простые предложения. «Запуск мотора с трехсекундной задержкой приводит в действие индукционное реле» лучше, чем «эта функция, будучи вызванной, запустит всю систему и приведет к переключению состояния внешнего контроллера, но не раньше, чем истечет время, которое указано в заголовочном файле HEADER.H». Размещайте в начале каждого модуля или функции заголовок стандартного формата. Форматы, используемые в разных организациях, могут значительно различаться, но должны быть согласованы внутри группы разработчиков. Все модули (исходные файлы) должны начинаться с общего описания содержимого файла, названия компании, сообщения о защите авторских прав (если это не обходимо) и даты. Перед каждой функцией должен находиться заголовок, со держащий описание ее назначения, входных и выходных значений (параметров), а также имя автора, дату, номер версии, протокол изменений с датами и фами лиями программистов, внесших изменения. В языке C для обозначения комментариев используются звездочки («*»), и это хорошо. Часто встречаются следующие комментарии: /****************** * комментарий * ******************/ и это плохо. Если, как в этом примере, ваш комментарий заканчивается звездоч кой, то при каждом его изменении приходится исправлять положение последней звездочки в строке. Лучше ее опустить совсем: /**************** РЕЗЮМЕ 93 * комментарий ****************/ Большинство современных компиляторов поддерживает оформление коммен тариев в стиле С++ – двумя косыми чертами («//», «двойной слэш»), это более /* */. удобно, чем требования языка C Начинайте каждую строку комментария двумя косыми чертами, чтобы четко разграничить комментарии и код. Некоторые программисты полагаются на свой любимый редактор, убирающий форматирование комментариев или добавляющий звездочку в конце строки. Не стоит. Редакторы подобны религии. Каждый предпочитает что-то свое, даже на стройки у всех разные. Иногда компиляторы принимают исходные файлы, соз данные в текстовом процессоре, позволяющем использовать разные стили фор матирования различных частей программы. Но до сих пор примитивный ASCII текст, отформатированный пробелами (не символами табуляции) – единствен ная гарантия переносимости и надежности. Пишите комментарии при описании блока и там, где необходимо пояснить отдельную строку. Не стоит комментировать каждую строку. Гораздо лучше ком ментировать группы операторов, совместно выполняющих одну макрофункцию. При описании каждой переменной поясняйте ее смысл и назначение. Длинные имена переменных – это только подсказка; сопровождайте информативное имя переменной подробным, выразительным описанием в прозе. Одна из «болезней» хороших комментариев – зачастую используемая для оправдания небрежной работы, – состоит в том, что со временем они перестают отражать истинное значение кода. Такой «дрейф» комментариев недопустим. Высшая степень квалификации означает согласование изменений в документа ции и в коде. Эти процессы должны идти параллельно. Никогда не откладывайте изменение комментариев на потом, потому что этого просто не случится. Лучше сначала исправляйте описание, а затем – код. Один из побочных эффектов бесславной 50-летней истории дрейфа коммен тариев: люди больше не доверяют комментариям. Это недоверие приводит к еще более небрежной работе. Очень трудно преодолеть это сползание к хаотичным комментариям. Опытные разработчики редактируют заголовки, отражая каждое исправление программы, однако еще лучше было бы добавить и примечание «также обновлены и комментарии», которое повысит доверие к документации. В заключение рассмотрим новый подход к написанию функции. Я выработал привычку: сначала писать все комментарии, в том числе заголовок и пояснения внутри кода. После этого очень просто, даже тривиально, дополнить их кодом на C или C++. Кто угодно сможет написать программное обеспечение, следуя имеющемуся алгоритму; разработка этого алгоритма и его отражение в четких комментариях – вот действительно творческая часть нашей работы. Резюме Когда я только начинал работать программистом, один старший товарищ пове дал мне о Фундаментальном законе инженерного искусства (так он его назвал): 94 СОВЕТЫ ПО УЛУЧШЕНИЮ ФУНКЦИЙ «Если эта чертова штуковина полностью работает, оставь ее в покое». За многие годы работы я слишком часто применял эту трогательную концепцию. Похоже, что она работает применительно к оборудованию, но горе тому, кто попытается пользоваться этим правилом при разработке микропрограммного обеспечения. Я думаю, что одна из причин кризиса ПО – вера в то, что понятие «практически работает» может служить мерилом успеха. Тем не менее профессионалы пони мают, что соблюдение требований к ПО важно не меньше, чем функциональные, а также рабочие характеристики продукции: она должна работать, она должна быть красивой, она должна быть удобной в обслуживании. Глава 6. ЭВОЛЮЦИОННАЯ РАЗРАБОТКА (Как обеспечить своевременное качество при разработке ПО и системном проектировании) Нильс Малотакс Нильс Малотакс – независимый консультант, преподающий практические методы обеспечения своевременного качества при организации исследований и разработки ПО. Термином «своевременное качество» обозначено безусловное достижение нужных результатов при соблюдении сроков и бюджета комфортным образом для всех участников проекта, включая разработчиков. Нильс не просто рассказывает истории успеха, он действительно наставляет группы разработчиков на путь обес печения своевременного качества и учит их не сходить с этого пути, а также представлять качественное ПО или системы в срок, без задержек и оправданий. Введение Разработчики ПО систематически не справляются с проектами, не укладываясь в рамки требуемой стоимости, сроков, функциональности и качества. Более по ловины пользователей информационно-коммуникационных технологий (ICT) не удовлетворено работой поставщиков ICT-решений [Эрнст и Юнг, 2001]. Эта проблема известна около 35 лет. Уже давно опубликованы подходы, позволя ющие получить впечатляющие результаты (например, Миллс, 1971 [1]; Брукс, 1987 [2]; Джилб, 1988 [3]). Но на практике мало что изменилось. При решении данной проблемы важно понять, если разработчики не смогут изменить свои привычки, несмотря на то, что уже созданы необходимые методы, значит все дело в психологическом барьере, мешающем им принять эти методы. Нужно разъяс нить практический смысл предлагаемых решений, чтобы справиться с проектом, не выходя за рамки стоимости, сроков, функциональности и качества, а также найти убедить разработчиков применять эти методы. способы Необходимость решения данной проблемы в основном экономическая: • • систематическое соблюдение стоимости, сроков, функциональности и ка чества разрабатываемого ПО снижает объем непродуктивного труда как разработчиков, так и пользователей (Кросби, 1996: «The Price of NonConformance» («Цена несогласованности») [4]); • • предотвращение непродуктивного труда сокращает нехватку IT-персонала; • • повышение качества программных разработок обеспечивает преимущества в конкурентной борьбе; • • успешная работа уменьшает психологическую нагрузку на IT-персонал, что положительно влияет на здоровье и повышает продуктивность. В этой главе мы продемонстрируем методы и технические приемы, названные нами «метод Эво» (от слова «эволюционный»), которые позволяют разработчи кам ПО и руководителям проектов обеспечивать «своевременное качество» (под этим термином понимается успешное завершение проекта в рамках требуемой стоимости и сроков, реализация необходимых функций и обеспечение заданно 96 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА го качества). Обучение этим методам и их применение в реальных проектах по разработке продукции давало поразительные результаты. Их содержание основано на практическом опыте и на исследованиях по совер шенствованию процесса разработки ПО, проводившихся главным образом под ру ководством Тома Гилба (1988 [3], более поздние публикации [5] и их обсуждение). 1. История Большинство описаний процесса разработки проектов основано на водопадной модели, где каждый этап разработки вытекает из предыдущего (рис. 6.1). Требо вания к проекту должны быть зафиксированы в начале работы, тогда в итоге мы получим «Большой взрыв» . В действительности практически никто не следует 1 этой модели, но в отчетах для руководства реальность подгоняется под эту мо дель. Обычно руководство ожидает реализации именно этой модели, и в боль шинстве процедур разработки она рассматривается как обязательная. В резуль тате – серьезное непонимание и большие потери сил. Анализ требований Проекти рование архитектуры Детальное проектирование тестиро вание Квалифика ционные испытания 6.1. Водопадная модель разработки Первые описания эволюционной разработки, в ту пору называвшейся инкре ментальной, опубликовали Харлан Миллс в 1971 году [1] и Ф. П. Брукс в своей знаменитой статье «No silver bullet» («Нет верного решения») в 1987 году [2]. Эволюционная разработка использовалась при проектировании ПО для чистой комнаты [6]. Практическое развитие теории эволюционной разработки предло жено Томом Гилбом в книге «Principles of Software Engineering Management» («Основы управления проектированием ПО»), опубликованной в 1988 году [3], и в более поздних работах, которые можно найти на его веб-сайте [16]. 1 Коренная рационализация работы Лондонской фондовой биржи, проведенная в 1986 го ду. – Прим. пер. 2. ПРОБЛЕМЫ, РЕШАЕМЫЕ МЕТОДОМ ЭВО 97 Инкрементальная разработка является частью метода экстремального про граммирования, или XP, [15, 17], однако даже если разработчики заявляют о своей приверженности подобному подходу, нам вряд ли удастся обнаружить элементы Эво, используемые описанным здесь способом. Мы предпочитаем использовать название «эволюционная разработка», или метод Эво, предложенное Томом Гилбом, поскольку не всякая инкременталь ная разработка является эволюционной. В инкрементальных методах разработ ки используются циклы, в каждом из которых выполняется часть работы по проектированию и реализации программы. Однако на практике это приводит к «Большому взрыву» лишь после долгой отладки в конце работы над проектом. Мы бы хотели использовать термин «эволюционная» для специального вида ин крементальной разработки, который позволяет решать следующие проблемы: • • разрешение парадокса требований; • • быстрое воздействие предварительной оценки на конечный результат; • • первоочередное решение важнейших проблем; • • первоочередное устранение самых высоких рисков; • • первоочередная реализация важнейших задач обучения и поддержки; • • синхронизация с другими разработками (например, с разработкой обору дования); • • специальные эксперименты для прояснения требований до начала работ; • • создание готовой полезной функциональной продукции в конце каждого цикла; • • к окончанию срока работы над проектом лучше, если 80% (важнейших) функций будут реализованы на 100%, чем 100% всех функций будут реали зованы на 80%. В первом случае заказчик может сделать выбор: выпустить товар на рынок или подождать еще немного. Во втором случае выбора у не го нет, остается только ждать и ворчать. При эволюционной разработке мы следуем водопадной модели (рис. 6.1) во время повторяющихся очень коротких циклов (рис. 6.2). Цикл Зав По Зав Во Во Во Во Во Во Во Во Во Во Во Во Во Во Во Во дго ерш ерш доп доп доп доп доп доп доп доп доп доп доп доп доп доп доп доп тов е ени ад ад ад ад ад ад ад ад ад ад ад ад ад ад ад ад ни к а е е Рис. 6.2. В эволюционной разработке используется множество водопадов 2. Проблемы, решаемые методом Эво A. Парадоксы требований Первый парадокс требований: • • Для достижения хороших результатов требования должны быть стабиль ными. • • Однако при работе над проектом требования всегда изменяются. 98 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА Даже если вы сделаете все возможное для принятия окончательной стабиль ной редакции требований, они все равно изменятся. Дело не только в том, что ваши заказчики меняют свое мнение, увидев появляющиеся результаты разрабо ток. Самим разработчикам также приходят в голову новые идеи, новые представ ления о том, какими на самом деле должны быть требования. Итак, возможное изменение требований в процессе работы над проектом – заранее известный риск. Вместо того чтобы игнорировать парадокс требований, используйте метод, призванный справиться с этим риском, – эволюционную разработку. Эво обеспечивает быструю и частую обратную связь, чтобы все заинтересо ванные стороны могли проверять и корректировать требования – и это действи тельно самая важная возможность. Между циклами предусмотрен небольшой временной интервал, когда заинтересованные стороны могут и должны пересмат ривать список первоочередных дел. Это необходимо для разрешения второго парадокса требований: • • Мы не хотим, чтобы требования изменялись. • • Однако, поскольку изменение требований – мы пытаемся известный риск, спровоцировать это изменение как можно раньше. Мы разрешаем парадоксы требований, создавая стабильные требования на время цикла разработки, в то время как подробный пересмотр требования про водится между циклами. B. Очень короткие циклы На самом деле мало кто воспринимает запланированные сроки со всей серьезно стью. До тех пор, пока дата окончания работы над проектом находится в далеком будущем (рис. 6.3), мы не чувствуем никакого давления сроков и работаем нето ропливо, обсуждаем интересные темы, встречаемся с друзьями, пьем кофе… (За сколько дней перед экзаменом вы реально начинали готовиться?..). Итак, в нача ле проекта мы работаем относительно медленно. Когда давление даты окончания проекта становится ощутимым, мы начинаем работать более напряженно, слегка нервничая, делая ошибки, что приводит к задержкам, вызывающим еще больший стресс. В результате мы не укладываемся в сроки. Мы знаем все причины, кото рые заставили нас опоздать. Но никогда не признаем свою вину. Данный подход не может быть правильным или неправильным. Такова человеческая психология. Просто мы функционируем таким образом. Это не стоит игнорировать. Примите это и затем подумайте, что с этим делать. Напряженность работы Начало Планируемый срок Рис. 6.3. Мы начинаем работать более напряженно лишь под давлением срока окончания проекта. Обычно мы опаздываем 2. ПРОБЛЕМЫ, РЕШАЕМЫЕ МЕТОДОМ ЭВО 99 Опытные руководители проектов сообщают своей группе разработчиков более раннюю дату (рис. 6.4). Если они делают это достаточно ловко, результат полу чается как раз к реальной дате. Проблема состоит в том, так это можно поступить лишь один или два раза. Вскоре сотрудники группы разработчиков обнаружива ют, что реальные сроки были не такими уж напряженными, и перестают верить в сроки завершения промежуточных этапов. А это даже хуже. Чтобы справиться с такой стороной человеческой психологии, нужно плани ровать очень короткие промежуточные этапы (инкременты) (рис. 6.5). Продол 1 жительность этих этапов должна быть такой, чтобы: • • давление даты окончания ощущалось с первого дня; • • имелось достаточно времени для завершения работы над реальным зада нием. Три недели – срок слишком длительный, чтобы давление ощущалось с перво го дня, а одной недели, как кажется, может не хватить для завершения реального задания. Обратите внимание, что давление в этой схеме гораздо менее опасно для здоровья, чем реальный стресс и срыв единственного срока представления готового результата в конце проекта. При работе над реальным проектом, когда у нас было всего шесть недель для полного завершения работ, нам пришлось использовать однонедельные циклы. В результате мы продолжаем использование однонедельных циклов во всех последующих проектах. Если же вы не сможете планировать работу даже на одну неделю, как тогда строить более долгосрочные планы?.. Напряженность работы Хитроумный Начало Планируемый (?) срок срок Рис. 6.4. Чтобы завершить проект вовремя, хитрые руководители сообщают своей группе разработчиков более ранний срок. Однако вскоре еще более хитрые разработчики догадываются об этом Напряженность работы Начало Планируемый срок Рис. 6.5. Решение проблемы: назначайте краткие, реалистичные «сроки сдачи». Результат: удовлетворение, мотивация, быстрая обратная связь Отсюда название этой технологии программирования – инкрементальная. – 1 Прим. пер. 100 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА C. Быстрая и частая обратная связь Если проблема абсолютно понятна, при разработке можно использовать водо падную модель. Для обозначения такого процесса вместо термина «разработка» мы говорим «производство». Однако в начале новой разработки существует мно жество неопределенностей, которые нужно изучить и превратить в определен ности. Поскольку разработка даже простейшего проекта слишком сложна, чтобы человек мог охватить этот процесс полностью (Е. Дийкстра, 1965 г.: «Компе тентный программист прекрасно осознает ограниченность размеров собственной головы» [12]), мы должны многократно изучать, что же на самом деле делаем и как сделать это лучше. Реакция Планирование Чему мы Что на самом деле 4 1 научились мы хотим узнать или сделать Проверка Исполнение 3 2 Анализ полученных Выполнение результатов плана Рис. 6.6. Цикл Шухарта, или цикл Деминга, или PDCA-цикл Для этого используется метод «сперва подумай, потом делай», поскольку стоимость размышлений ниже стоимости действий. Однако, поскольку мы не можем предвидеть все и должны принимать во внимание многое, нам прихо дится постоянно проверять верность наших суждений и предположений. Это называется обратной связью: мы планируем что-то, затем стараемся выполнить как можно лучше, после чего проверяем правильность полученных результатов. После проведения анализа мы можем скорректировать используемые методы и предположения. Шухарт описал этот метод еще в 1939 году [13]. Деминг [14] назвал его циклом Шухарта (рис. 6.6). Другие называют его циклом Деминга, или циклом PDCA («Plan-Do-Check-Act» – Планирование–Исполнение–Про верка–Реакция). На практике мы видим, что если разработчики что-либо делают (этап 2 этого цикла), они иногда планируют (этап 1), но почти никогда не задерживаются на этапах анализа и реакции. В методе Эво мы осознанно используем все этапы цикла в краткосрочных и частых петлях обратной связи (рис. 6.7): • • Цикл с недельным заданием. В этом цикле мы оптимизируем наши суж дения, планирование и возможности контроля результатов, чтобы точнее предсказывать будущее. Мы постоянно проверяем, ли мы пра выполняем вильные действия, в верном ли порядке и на соответствующем ли данному моменту уровне детализации. • • Короткий цикл представления промежуточного решения заказчику. В этом цикле мы оптимизируем требования и проверяем наши суждения. 2. ПРОБЛЕМЫ, РЕШАЕМЫЕ МЕТОДОМ ЭВО 101 Мы постоянно контролируем, представляем ли мы правильные решения в верном ли порядке и на соответствующем ли данному моменту уровне детализации. Циклы представления решения могут включать от одного до трех недельных циклов. Задание Завершение 6.7. Циклы метода Эво • • Цикл достижения стратегических целей. В этом цикле мы оцениваем на ши стратегические цели и проверяем, ведут ли наши действия к достиже нию этих целей. Такой цикл может занимать от одного до трех месяцев. • • Цикл планирования развития в масштабах организации. В этом цикле мы оцениваем наши планы развития и проверяем, отвечают ли наши страте гические цели нашему месту в этом мире. Такой цикл может длиться от трех до шести месяцев. В проектах по разработке продукции учитываются только циклы заданий и циклы работ. Задания в цикле выполняются в рамках работы над текущим решением, при этом некоторые другие задания могут выполняться для подго товки работы над последующими решениями (рис. 6.8). D. Фиксация сроков Организации, разрабатывающие проекты эволюционным методом, используют фиксацию сроков, а не фиксацию характеристик. Если предположить, что коли чество ресурсов, выделенных на данный проект, фиксировано, или, по крайней мере, ограничено, можно реализовать: 102 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА Завершение работы Задания Задания Завершение работы Задания Задания Задания Завершение работы Задания Задания Задания Задания Задания Рис. 6.8. Текущие задания позволяют завершить один цикл работ и подготовиться к следующим • • либо фиксированный набор характеристик за некоторое время. Это мы на зываем фиксацией характеристик; • • либо некоторое количество характеристик за фиксированное время. Это мы называем фиксацией сроков. Реализация фиксированного набора характеристик за фиксированное коли чество времени при данном комплекте ресурсов возможна только в том случае, если времени достаточно для реализации всех характеристик. На практике, од нако, всегда не хватает времени для реализации всех запрашиваемых характе ристик. Заказчик не может себе позволить то, что ему нужно. В этом случае мы просто обманываем себя, пытаясь достичь невозможного (рис. 6.9). Дело не в ленивых или не желающих работать программистах: если времени (или средств) недостаточно для реализации всех требуемых характеристик, они не Это очень просто. будут реализованы в полном объеме. Ресурсы Сроки Характеристики Рис. 6.9. Если ресурсы и сроки фиксированы, характеристики становятся переменной величиной Метод Эво гарантирует, что заказчик получит максимум, а реализация важней ших характеристик будет возможна в рамках определенного интервала времени при имеющихся ресурсах. Обращение к разработчикам с просьбой исполнить 2. ПРОБЛЕМЫ, РЕШАЕМЫЕ МЕТОДОМ ЭВО 103 невозможное – одна из главных причин неэффективной работы над проектом. Пустая трата сил всегда приводит к ухудшению итогового результата. На практике фиксация сроков означает, что: • • установлено количество часов, необходимое для выполнения задания; • • к концу этого временного интервала задание должно быть выполнено на 100%. Это значит, что оно должно быть действительно выполнено; • • перенос сроков внутри фиксированного интервала времени недопустим, поскольку это приведет к задержке в выполнении других заданий, а затем к неконтролируемому срыву сроков работы над всем проектом; • • перед окончанием временного интервала мы определяем, насколько далеки от завершения задания. Если мы видим, что не успеваем выполнить зада ние, следует определить, что нам уже известно, попытаться оценить, что нужно исследовать, поставить новые задачи и оценить необходимое для их выполнения время. Однако лучше, если мы, не вдаваясь в данный момент в излишние подробности, постараемся действительно завершить данное за дание на достаточном уровне детализации, уложившись в сроки. Список заданий (подробности см. в [8]) используется, чтобы определить: – цели задания; – стратегии выполнения задания; – методику проверки результата; – #7; с пособ, позволяющий определить, что задание действительно полностью завершено (т. е. в рамках этого задания не нужно больше ничего делать, и мы можем забыть о нем). E. Оценка, планирование и контроль Оценка, планирование и контроль – неразделимая троица. Если не выполнить выполнять другие. одну из этих операций, нет смысла • • Если вы не проведете предварительную оценку, то не сможете планировать и вам нечего будет контролировать. • • Если не провести планирование, оценка и контроль будут бесполезны. • • Если же вы не проводите контроль, зачем тогда занимались оценкой и пла нированием? Итак: • • Разработайте небольшие задания, исходя из требований, архитектуры и об щего плана работ. • • Оцените время, необходимое для каждого небольшого задания. • • Получите общее время, приняв во внимание: –  время, необходимое для выполнения всех заданий; –  имеющиеся в вашем распоряжении ресурсы; – #7; скорректированный промежуток времени, когда каждый ресурс будет доступен (никто не работает все 100% своего времени участия в проекте. Среднее статистическое значение составляет 55%. Непонимание этого – одна из важнейших причин, приводящих к запаздыванию в реализации проектов! [9]). • • Точно спланируйте следующий цикл. 104 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА • • Убедитесь в том, что работа в рамках каждого цикла выполнима. Это зна чит действительно выполнима. Получите подтверждение от тех, кто будет выполнять эту работу. • • Ориентировочно спланируйте следующие циклы (все равно планирование может измениться!). • • Контролируйте успехи и неудачи. Делайте выводы. Одновременно со вершенствуйте оценку и планирование. Предупреждайте все заинтересо ванные стороны как можно раньше, если конечные сроки представления решения изменяются по любой причине. • • В зависимости от наборов характеристик могут быть установлены разные конечные сроки представления решения. Если время и даты не имеют значения для вас (или для руководства), не стоит проводить ни оценку, ни планирование, ни контроль – они вам просто не нужны. Однако, если сроки важны, настаивайте на проведении оценки, пла нирования и контроля. К тому же все окажется не так сложно, как только вы этому научитесь. Если ваш заказчик (или руководитель) не хочет даже слышать о том, что вы не можете точно предсказать, какие характеристики будут реализованы к дате окончания работы над проектом, в то время как вы уверены, что не все характе ристики удастся реализовать (при фиксированном бюджете и фиксированных ресурсах), вы можете предложить ему на выбор два варианта: • • либо за день до окончания срока вы сообщите ему, что не преуспели в реа лизации всех функций; • • либо сообщите ему об этом сейчас (поскольку уже сейчас знаете об этом), что позволит вам каждую неделю вместе определять, какие функции наи более важны. Придется потратить некоторое время на убеждение, но уже через две недели вы будете сотрудничать, чтобы добиться наилучшего возможного результата. Вам необходимо пообещать только одно: используемый метод – самый эффективный из всех возможных. Во всех других случаях результат не будет лучше, возможно, будет даже хуже. Поэтому давайте работать вместе, чтобы добиться наилучшего результата. Или в самом начале работы примите решение о привлечении допол нительных ресурсов. Привлечение дополнительных трудовых ресурсов на более позднем этапе приводит к эффекту Брукса [9]: «Подключение дополнительных сотрудников к работе над запаздывающим проектом вызывает еще большую его задержку». Давайте перестанем вести страусиную политику, повернемся лицом к реальности и будем конструктивно решать реальные проблемы. F. Разница между напряженной работой и выполнением заказа Если попросить разработчиков оценить конкретное задание в рабочих днях, они обычно предложат оценку, которая будет временем выполнения заказа. Если же предложить им оценить задание в часах, будет предложена оценка времени напряженной работы. Руководители проектов знают, что разработчики переоценивают свои возможности, поэтому у каждого руководителя есть соб 2. ПРОБЛЕМЫ, РЕШАЕМЫЕ МЕТОДОМ ЭВО 105 √2, π) ственный коэффициент (2, e, для корректировки представленных оценок. Поскольку эти значения нужно ввести в инструментальное средство планиро вания проекта, например в MS Project, в качестве сроков выполнения заказа они указывают эти скорректированные даты. Проблема сроков выполнения заказа заключается в том, что здесь смешиваются два различных временных компонента: • • время напряженной работы – время, необходимое для выполнения работы; • • срок выполнения заказа – срок, к которому работа будет выполнена. Сформулируем это немного по-другому: срок выполнения заказа минус время напряженной работы – это время, необходимое для других дел, а не для выполнения работы. Примеры «других дел»: перерыв на чашечку ко фе, встречи, посещение туалета, дискуссии, помощь коллегам, телефон ные разговоры, электронная переписка, мечтание и т. п. На практике мы используем соотношение «Время напряженной работы/Срок выполнения заказа», составляющее обычно 50…70% для сотрудников, занятых полный рабочий день. Поскольку параметры, приводящие к изменению этих компонентов, различны, их нужно разделить и рассматривать отдельно. Если при планировании рассмат ривать только срок выполнения заказа, мы никогда не сможем корректировать наше планирование с учетом результатов контроля выполнения запланирован ных и ориентировочных сроков. Следовательно, мы никогда не научимся пред сказывать время разработки проекта. Если же эти элементы рассматриваются отдельно, можно очень быстро научиться корректировать свою оценку времени напряженной работы. По опыту прошлых проектов мы установили: в первую неделю выполняется 40% порученной работы, во вторую – 80%, начиная с треть ей – 100% и более. Теперь мы можем предсказывать! Кроме того, можно изучить управление временем для контроля собственно го соотношения «Время напряженной работы/Срок выполнения заказа». Еще в 1975 году Брукс отметил [9], что проекты по разработке программ занимают примерно вдвое больше запланированного времени. Исследования показывают, что примерно половина времени используется не для работы над проектом, а для дру гих видов деятельности. При работе над реальными проектами в настоящее время мы используем правило: сотрудники работают 2/3 цикла (26 часов из 39) для работы над за даниями проекта и резервируют 1/3 для других видов деятельности. Некоторые менеджеры жалуются, что если предоставить примерно трехдневную работу на пятидневный срок, сотрудники склоняются к мнению «этого времени должно хватить». Это называется законом Паркинсона [10]: «Любая работа полностью занимает все отведенное на нее время». Примерно также рассуждает начальство, предлагая выполнить шестидневную работу за пять рабочих дней и надеясь та ким образом повысить производительность. Поскольку работа, требующая шес ти дней напряженной работы, не может быть выполнена за пять рабочих дней, а сотрудники должны и будут заниматься другими делами в любом случае, они всегда с выполнением невозможного. Что еще хуже: это не будут справляться вызывает постоянное чувство неудачи, приводящее к разочарованию и отсут ствию мотивации. Если же дать им задание такого объема, с которым они могут 106 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА справиться, они справятся с ним. Это вызывает ощущение удовлетворенности и успеха, что значительно повышает мотивацию. Экспериментальный факт: пре доставление трехдневного объема работ на пять рабочих дней более продуктивно, чем шестидневного объема на тот же срок. G. Обязательства Если спросить любого разработчика, выполнено ли задание, он ответит: «Да». Если же после этого уточнить: «Действительно сделано?», он ответит: «Ну, поч ти». И здесь мы сталкиваемся с таким явлением: закончив работу над 90% за дания, программисты приступают к работе над остальными 90%. Это одна из важнейших причин срыва сроков. Поэтому крайне важно уметь определять, ког да работа действительно выполнена на 100%, кроме того, мы настаиваем на том, что любая работа должна быть выполнена на 100%. Если работа выполнена не на 100%, значит, что она не выполнена вообще. В циклах Эво необходимо, чтобы каждое задание было выполнено на 100%. Больше нет смысла об этом думать. При оценке и планировании заданий не обходимо оценить количество часов напряженной работы. Еженедельные прио ритеты уже определены. Поэтому каждую неделю, предлагая очередное задание каждому разработчику, руководитель проекта никогда не должен говорить: «Сде лайте это и это». Он должен всегда интересоваться: «Вы согласны с тем, что эти задания важнейшие в данный момент и вам нужно заниматься именно этим, а также с тем, что уложитесь в запланированные сроки?». Если разработчик колеблется при ответе хотя бы на один из этих вопросов, руководитель проекта должен поинтересоваться, почему и помочь устранить причину. После этого ему сотрудник сможет принять на себя полные обязательства, и справится с зада нием. Руководитель проекта может подсказать разработчику ответ намеками («В прошлом цикле вы не достигли цели, возможно, вы слегка переоценили свои возможности?»). Он не должен брать на себя ответственность за никогда решение, над какими заданиями должен работать сотрудник. Это единственный способ получить реальные обязательства разработчика. В конце цикла руково дителю нужно всего лишь воспользоваться зеркалом. Не справившись со свои ми обязательствами, разработчик заглянет в зеркало и увидит себя. Если же решение о том, что нужно делать, принял начальник, то даже сквозь зеркало разработчик увидит там руководителя своего проекта. Очень важно, чтобы руководитель проекта научил разработчиков правильно принимать на себя обязательства. Для объяснения важности полного выполне ния задания используйте предложение: «Пообещайте мне, что ничего не будете делать до тех пор, пока это не будет выполнено на 100%!» Только работая с ре альными обязательствами, программисты могут научиться правильно оценивать свои возможности и, соответственно, вовремя сдавать работу. Иначе они не на учатся этому Руководители проектов, которые боятся, что разработчики никогда. будут делать меньше, чем необходимо, и поэтому выдают им задания, превыша ющие возможности этих сотрудников, никогда не получат того, на что надеются, поскольку без реальных обязательств люди обычно делают меньше. 2. ПРОБЛЕМЫ, РЕШАЕМЫЕ МЕТОДОМ ЭВО 107 H. Риски Если вообще нет никаких рисков, используйте в разработке проекта водопадную модель. Если же риски есть – а так бывает при всякой новой разработке – при ходится постоянно думать об управлении ими. Значительная часть разработ ки – это снижение рисков. Когда разработка завершена, все возможные риски должны быть устранены. Если риск оборачивается худшим вариантом в конце разработки, просто не будет времени как-либо исправить ситуацию. Если же выявить риск заранее, у нас появится время для того, чтобы обдумать свои дей ствия на тот случай, если развитие проекта пойдет по наихудшему сценарию. Поскольку мы используем в работе над проектом еженедельное планирование, максимальная потеря времени, вызванная неверным предположением или иде ей, составляет одну неделю. Каждую неделю требования пересматриваются на основе полученной информации. Наши предположения о том, каким требованиям в итоге должна отвечать раз рабатываемая продукция, подвергаются рискам. В этом случае мы можем спро сить себя: • • Правильны ли наши идеи и правильно ли мы их разрабатываем? • • При каких условиях верны наши идеи? Многие риски связаны также с потерей времени и несинхронностью действий: • • Можем ли мы прогнозировать сроки достаточно точно? • • Какие задания мы забыли выполнить? • • Получим ли мы конечный результат от других (разработчиков оборудова ния, ПО, ответ другой заинтересованной стороны,…) вовремя? На самом деле самые важные вопросы, которые мы постоянно задаем себе при работе по методу Эво, следующие: что мы должны делать, в каком порядке и на каком уровне детализации в данный момент. Слишком высокая детализация на ранних этапах работы означает, что сложную работу придется переделывать снова и снова. Возможно, эта работа будет выполнена правильно. Но завершена она будет позже, чем это было возможно. I. Производственные совещания Обычно производственные совещания начинаются с всеобщих извинений, где каждый объясняет, почему не успел сделать то, что от него ожидали. Происхо дит подробное обсуждение работы, которую нужно было сделать, а когда вре мя совещания уже заканчивается, оказывается, что обсуждение новых заданий только началось. Это не такая уж большая проблема, поскольку большинству присутствующих в любом случае придется продолжить незавершенную работу. Руководитель проекта намечает новые сроки выполнения просроченных зада ний, и сотрудники продолжают работу. По завершении совещания руководите лю проекта остается подсчитать, сколько резервного времени («непродуктивного времени») осталось, а если резервы исчерпаны – насколько будет задержано выполнение проекта. При разработке многих проектов мы видели, что плановые (в MS Project) графики работы над проектом используются в основном в качест ве обоев. Как только они обновляются, реальные результаты работы каждую неделю все сильнее расходятся с запланированными. 108 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА При работе по методу Эво на еженедельных совещаниях мы обсуждаем толь ко новую работу и никогда – выполнявшуюся раньше. Мы не тратим время на извинения. То, что уже прошло – не изменишь. А из того, что действительно необходимо сделать, постоянно выделяется самое главное, поэтому мы всегда работаем над самым важным в данный момент. Мы не обсуждаем прошлые за дания, потому что они завершены. Если же обсуждаются новые задания, мы можем воспользоваться результатами завершаемой работы. Это может оказать ся полезным. Однако если в дискуссии участвует только несколько человек, ее можно завершить после совещания, чтобы не тратить понапрасну время осталь ных сотрудников. J. Волшебные слова Существует несколько «волшебных слов», которые можно использовать при ра боте по методу Эво. Они помогут нам выполнять правильные задания в правиль ном порядке на правильном для данного момента уровне детализации. • • Концентрация. Разработчики склонны отвлекаться на множество важных и интересных дел. Некоторые из них могут оказаться действительно важ ными, но не в данный момент. Сконцентрироваться на текущих приори тетных целях, не отвлекаясь ни на что другое, нелегко, но это позволяет сэкономить время. • • Приоритеты. Определение приоритетов и работа только над заданиями с высшим на данный момент времени приоритетом позволяет нам выпол нять важнейшие дела в первую очередь. • • Синхронизация. Каждый проект взаимодействует с внешним миром. Ак тивная синхронизация необходима для соблюдения сроков. • • Почему. Это слово заставляет нас определить причину, по которой мы де лаем что-либо, и, следовательно, проверить, нужно ли этим заниматься. Оно помогает нам не терять концентрацию. • • Сроки священны. В большинстве проектов сроки плавают. Священность сроков означает, что если вы обязались что-то выполнить к определенной дате, то сделаете это. Или очень скоро обнаружится, что вы не хозяин свое му слову. С помощью метода Эво вы быстро это поймете. • • Выполнено. Для того чтобы можно было делать оценки, строить планы и контролировать возможное, мы должны завершать задания полностью. Если задание закончено не на 100%, оно не выполнено. Это нужно понять, для того чтобы победить синдром: «90% работы выполнено, теперь мы ра ботаем над оставшимися 90%». • • «Баги», устранение «багов». «Баги» – это крошечные создания, ко торые самопроизвольно возникают в вашей продукции, вызывая проб лемы, а мы не можем ничего с этим поделать. Это неверно. Человеку свойственно ошибаться и, значит, делать что-то неправильно. Слова баг и ругательства, которые необходимо исключить из устранение багов – нашего словаря. Активно обучаясь на своих ошибках, мы можем научить ся избегать многих из них. В методе Эво мы активно вылавливаем свои ошибки на как можно более ранних этапах и боремся с ними. Поэтому 3. КАК МЫ ИСПОЛЬЗУЕМ МЕТОД ЭВО В РАБОТЕ НАД ПРОЕКТОМ 109 последствия ошибок, минимизируются и не распространяются на весь проект. Это позволяет оставить абсолютный минимум дефектов по всему проекту к концу работы над ним. Эво-проекты не нуждаются в специаль ной «фазе отладки». • • Дисциплина. Под дисциплиной мы понимаем не принудительное подчи нение правилам, а понимание того, как нужно поступать. Если за нами никто не следит, мы можем перейти дорогу в неположенном месте или сознательно нарушить какое-нибудь правило. Часто мы осознаем, что по ступаем неоптимальным образом, но нам трудно дисциплинировать себя. Если кто-нибудь стоит у нас за спиной – поступать должным образом зна чительно легче. Итак, соблюдать дисциплину трудно, но мы можем помочь друг другу. Метод Эво помогает соблюдать дисциплину. Зачем нам это? Мы хотим добиться успеха, поступая правильным образом. 3. Как мы используем метод Эво в работе над проектом По нашему опыту, начало многих проектов покрыто тайной. Обычно, когда про сят внедрить метод Эво в работу над проектом, оказывается, что один или боль шее число сотрудников уже изучают проект несколько недель или даже месяцев. Поэтому часто уже имеются некоторые требования и соображения по архитекту ре решения. Как правило, работники, знакомые с методами планирования, уже имеют представление о том, что следует сделать, и составили план, на основе которого проект был предложен и получил поддержку. A. День Эво Для того чтобы превратить обычный проект в Эво-проект, мы организуем «День Эво», в котором, как правило, принимают участие руководитель, архитектор, испытатель и все члены группы разработки. Присутствие заказчика может ока заться полезным, но не является абсолютно необходимым в первый день Эвопроекта, когда мы просто рассказываем группе разработки о том, как изменится методика их работы. В день Эво (и на всех последующих встречах) используется ноутбук и ЖК-проектор, чтобы все участники совещания могли проследить за тем, что мы пишем и о чем говорим. Лучше проводить день Эво за пределами компании. Вот типичное расписание этого мероприятия: Утро • • Презентация метода Эво [11]: почему и как. • • Презентация продукции системными архитекторами (люди, представляю щие продукцию, которую необходимо создать, обычно имеют различные точки зрения или даже не имеют никакой точки зрения вообще). День Днем мы учимся определять виды работ, которые нужно выполнить в течение предстоящей недели/цикла. Поэтому мы упражняемся по следующим темам: 110 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА • • Определение подзадач, на которые требуется не менее 26 рабочих часов. На практике детализировать удается только некоторые виды работ. Люди устают от такого занятия примерно за 20 минут, но, по крайней мере, вы полняют упражнение, тем более мы все равно не смогли бы детализировать все за один день. • • Оценка усилий, необходимых для выполнения подзадач, – в часах напря женной работы, не в рабочих днях, см. пункт «Разница между напряженной работой и выполнением заказа» выше. • • Определение приоритетов. • • Составление списка задач в порядке приоритетности. • • Выделение наиболее высокоприоритетных работ без конкретизации под задач. • • Оценка трудозатрат на выполнение высокоприоритетных подзадач (если еще не проведена). • • Коллективное распределение обязанностей по выполнению заданий, на чиная с самого первого. • • Определение каждым отдельным разработчиком конкретных заданий, ко торые он способен выполнить (реально выполнить) к концу цикла. Если распределение обязанностей не удается провести, необходимо определить меньшее число заданий, таким образом, чтобы все обязательства были рас пределены полностью. К концу дня каждый сотрудник определяет список своих заданий на предстоя щую неделю, при этом он берет на себя обязательство завершить эти задания полностью, а мы, в свою очередь, убеждаемся в том, что задания, над которыми работает коллектив, имеют наивысший приоритет. B. Последний день цикла Последний день цикла – особый день, разделенный на три части (рис. 6.10): • • Руководитель проекта посещает каждого разработчика отдельно и обсуж дает с ним результаты выполнения заданий. Если обязательства не вы полнены, проводится обсуждение причин. Возможно, была неправильно оценена сложность задания, возможно – проблема в неправильном исполь зовании рабочего времени? Разработчик должен проанализировать свои результаты, чтобы следующую работу он смог выполнить лучше. Посетив всех разработчиков, руководитель проекта получает общее представление о состоянии работ над проектом в целом. • • Состояние работ над проектом в целом обсуждается с заказчиком, руко водителем, ответственным за разработку конечной продукции или ответ ственным представителем заказчика. • • Здесь разрешается парадокс требований: в течение недели требования фик сированы, а на этом этапе образуется одно-двухчасовой интервал, когда за интересованные стороны могут трансформировать требования и приорите ты. По окончании собрания требования и приоритеты снова фиксируются. • • В заключение руководитель проекта определяет проекты заданий для раз работчиков и обсуждает эти проекты с каждым индивидуально. Разработ 3. КАК МЫ ИСПОЛЬЗУЕМ МЕТОД ЭВО В РАБОТЕ НАД ПРОЕКТОМ 111 чики подтверждают то, что задания имеют наивысший приоритет, и дают обязательство завершить эти задания к концу цикла. циклы 116 117 118 119 120 121 однонедельный цикл ср чт пт пн вт ср чт ка ий е й е й й й ер ни ни ни ни ни ни ие й й й ан ов ни ни ни ща да ща да да й да е й ан ов Пр ни ни ни да ва да за за за ве за ве ов еб да ва бо да за за я о о ие ие ир ие тр ес ни ро с за за тре ок ок ен ен ен ан е не ни о о с ка ка с лн нн лн лн Пл пи нн ка пи ол Пла ис ис по по по ве ер ве С С п сп сп вы Вы Вы ст Вы ст ов р р од од ка Пр зо зо зв ер зв Об Об ои ои ов Пр Пр Пр Последний день цикла ния о? о + тов кн ка ) ен я ут ва ий а ни о ов те лн вещ ин ст ан ое а ри ир по ад 0м тель зад ов со ио ен вы з нг (2 е Тр р ые яза я ти вы е п ци ни нн е ке Но Об ни са да ве ар ик не За ст М Ф ме од Из зв ои Пр Рис. 6.10. Структура еженедельного цикла C. Производственное совещание По завершении подготовки индивидуальных списков с рабочими заданиями на следующий цикл в конце последнего рабочего дня цикла или в начале перво го дня нового цикла на производственном совещании необходимо сделать сле дующее: • • Обсудить опыт работы над заданиями последнего цикла, если это будет полезно для последующей работы. • • Обсудить ход реализации проекта; возможно, потребуется (пере)опреде лить и (повторно) оценить сроки выполнения подзадач. 112 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА • • Провести формальную выдачу и принятие обязательств по исполнению за даний на следующий рабочий цикл. В этом случае все участники проекта будут знать, кто чем занимается, и смогут высказать свои соображения на этот счет. • • Провести обсуждение, если оно затрагивает большинство участников группы. • • Пересмотреть приоритеты решения задач, если в ходе дискуссий выяснит ся такая необходимость. Как правило, еженедельные производственные совещания длятся не более 20 минут. Обычная реакция в конце первого еженедельного собрания в рамках проекта Эво такова: «У нас еще никогда не было таких коротких совещаний». Однако если поинтересоваться: «Мы забыли обсудить что-то важное?», после дует ответ: «Нет, это было хорошее эффективное собрание». Вот один из наших способов экономии времени. 4. Памятки Чтобы правильно определять приоритеты и добиваться реального выполнения заданий, обычно используются различные памятки. В данный момент это: А.  Критерии назначения приоритетов заданиям. В.  Критерии назначения приоритетных сроков промежуточных отчетов. С.  Критерии завершения задания. А. Критерии назначения приоритетов заданиям Для облегчения процесса назначения приоритетов первоочередным заданиям, мы используем следующую памятку: • • в первую очередь – наиболее важные проблемы (на основе текущего и по следующих графиков завершения работы); • • в первую очередь – наиболее высокие риски (лучше раньше, чем позже); • • в первую очередь – большинство обучающих действий или действий по поддержке; • • синхронизация с действиями других разработчиков (например, для про верки оборудования необходимо тестовое ПО, для проверки ПО – соот ветствующее оборудование, будет ли оно готово к тому моменту, когда понадобится?); • • получение полезного, законченного, работоспособного и функционального результата в итоге. В. Критерии назначения приоритетных сроков завершения промежуточных этапов Чтобы помочь в назначении приоритетов заданиям, результаты которых нужно представить в первую очередь, мы используем следующую памятку: • • каждый промежуточный этап должен приводить к получению в кратчай шие сроки важнейших для заказчика результатов. Для принятия решения 4. ПАМЯТКИ 113 о том, какую работу следует выполнять в первую очередь, может исполь зоваться методика оценки важности [7]; • • промежуточные результаты должны быть симметричными. Это значит, что если в программе имеется точка входа, обязательно должна присутствовать и точка выхода. Если определена функция удаления, необходимо преду смотреть и какую-нибудь функцию добавления. Вообще говоря, набор свойств должен быть полезным в целом; • • каждый отдельный промежуточный этап должен иметь четкие отличия от предыдущих. Поскольку нам важно знать мнение заказчика, он дол жен видеть отличия, на которые можно было бы отреагировать. Если же заказчик не увидит ничего нового, у него сложится впечатление, что он попусту тратит свое время, и в будущем он не станет сообщать нам свое мнение; • • каждый промежуточный этап должен приводить к минимально возможному явному усовершенствованию. При планировании этапов постарайтесь оста вить только то, что абсолютно необходимо сделать до следующей проверки. Если для достижения этих результатов потребуется больше двух недель, попробуйте уточнить задачу. С. Критерии завершения задания Если спросить разных людей о содержании одного и того же задания, их мне ния в той или иной степени будут расходиться. Чтобы удостовериться в том, что разработчик работает над решением правильно, мы используем список задач (подробнее см. [8]). В зависимости от поставленных заданий списки задач могут немного разли чаться. В первую очередь разработчик записывает в список задач: • • требования к результатам выполнения задания; • • что необходимо сделать для выполнения задания; • • конструктивное решение: как реализовать намеченные функции; • • способ верификации: как на основе требований к решению убедиться, что система делает то, что должна делать, и не делает того, чего не должна; • • план (если для выполнения работы требуется больше одного рабочего дня). Если полный план составить сложно, нужно найти ответ на вопрос: «Что я должен сделать в первый день?»; • • все, что еще остается непонятным. После этого список заданий просматривается архитектором системы. На дан ном этапе сопоставляется то, что необходимо сделать по мнению разработчика, с тем, что необходимо сделать по мнению архитектора системы, – насколько ре зультаты этого этапа вписываются в общую картину работ над проектом? Обыч но существуют небольшие расхождения между этими точками зрения, поэтому лучше разрешить эти противоречия до начала реальной работы над заданием, чем Так экономится время. после. После согласования разработчик выполняет работу, проверяет, что достигнуты именно те результаты, которые требовались, не меньше, но и не больше. Замеча тельные усовершенствования недопустимы. Все, что не указано в требованиях, 114 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА не тестируется. Об этом никто ничего не знает, такое задание не должно вы полняться и поэтому является ненужным риском. В заключение разработчик использует критерии завершения задания в списке задач, для того чтобы определить, что в действительности выполнено. Эти кри терии могут быть адаптированы к определенным типам заданий. В практических проектах, связанных с созданием программного кода, мы используем следующий список: • • код компилируется и компонуется с использованием соответствующих версий файлов на уровне интеграции; • • код просто делает то, для чего он и предназначен: никаких ошибок в про грамме; • • нет «утечки» памяти ; 1 • • использована методика безопасного программирования. • • названия всех файлов выбраны в соответствии с утвержденными прави лами. • • сохранены предыдущие версии файлов. • • я совершенно уверен в том, что тестировщик не обнаружит никаких проблем. Данная памятка позволяет убедиться в том, что задание реально выполнено. Если все проверки прошли успешно, работу можно считать завершенной. Если впоследствии окажется, что работа была выполнена неполностью, необходимо отредактировать памятку. Когда мы решаем внедрить метод Эво, работы над многими проектами уже ведутся. Чтобы превратить обычный проект в Эво-про ект, мы организуем Эво-день. Поскольку в этот момент у разработчиков уже име ется более или менее ясное представление о том, что нужно сделать, несложно провести оценку, назначить приоритеты и выбрать задания. 5. Использование метода Эво в новых проектах Когда мы приступаем к работам над совершенно новым проектом, многие раз работчики еще не имеют ясного представления о том, что нужно сделать, не говоря уже о том, как это сделать. Если члены группы разработки раньше не использовали метод Эво, им будет сложно поставить задачи и, следовательно, оценка и планирование вряд ли возможны. Тем не менее цель первого Эво-дня состоит в том, чтобы в его конце группа разработки в общих чертах представ ляла, что предстоит сделать в ближайшие недели и совершенно определенно – чем заниматься на следующей неделе. Это может оказаться проблемой. Для ее решения необходимо определить: • • цель проекта; • • важнейшие факторы достижения успеха и то, чего ждут от реализации это го проекта основные заказчики; • • что нужно сделать в первую очередь. Как вы себе представляете, с чего нужно начать? Например: –  определение требований; 1 Перерасход памяти вследствие многократного размещения данных в куче (heap) с по следующим неаккуратным высвобождением памяти. – Прим. пер. 5. ИСПОЛЬЗОВАНИЕ МЕТОДА ЭВО В НОВЫХ ПРОЕКТАХ 115 –  проведение экспериментов; – #7; сбор информации о тех инструментальных средствах, языках програм мирования, средах, которые нужно использовать; – #7; знакомство с выбранными инструментальными средствами, языками программирования, средами; проверка, подходят ли они для решения данной задачи. Когда мы спрашиваем, как много времени потребуется разработчикам на реа лизацию этих действий, обычно следует ответ: «Ну, не знаю… Я не знаю, что нужно искать, что нужно изучать, какие будут приняты решения, поэтому я не могу оценить необходимое для этого время». Это возможно, но это не должно служить оправданием пустой траты времени. Определите важные задачи, кото рые должны быть решены. Задайте определенный временной интервал. Напри мер: «Даю вам 10 часов для выработки набора требований», или «в течение 8 часов вы должны составить список инструментальных средств». Затем запишите эти задания в список заданий-кандидатов, установите приоритеты и позвольте каждому сотруднику поработать в течение 26 часов с верхней частью списка, определить свои обязательства и понять, в чем они будут заключаться. Тогда на следующей неделе, благодаря предварительной работе, проведенной на первой неделе, команда разработчиков будет лучше представлять себе, что необходимо сделать. Нечетко поставленная задача обычно «съедает» огромную часть време ни, предназначенного на разработку проекта, поскольку разработчики не пред ставляют себе, что на самом деле нужно сделать для реализации проекта. Метод Эво помогает концентрировать внимание и быстро (с помощью эволюционных циклов) понять, чему на самом деле посвящен проект. Однако в некоторых случаях за отведенное время разработчикам не удается сформулировать свое отношение к не совсем ясно поставленным задачам. В этом случае, как послед нее средство, можно позволить им самостоятельно определять, что делать, при условии, что во время работы они будут фиксировать, что и как долго они дела ют. Эти записи можно будет использовать на собраниях группы в последующие недели. Обратите внимание, особенно в том случае, если задача поставлена не совсем четко, лучше сначала сделать задачу как можно яснее, а уже после этого затрачивать значительное время на ее решение. Этих проблем можно избежать, если разработчики уже имеют опыт исполь зования метода Эво. Тогда они знают, почему и как нужно ставить задачи, опре делять сроки, назначать приоритеты и заканчивать работу. Это позволяет им эффективно работать над проектом с самого начала, не спрашивая, почему надо поступать именно так. Они знают, почему и как. В начале работы по методу Эво над совершенно новым проектом существуют две дополнительных проблемы: необходимо понять, чему посвящен данный проект, и научиться использовать метод Эво. Проще начать знакомство с методом Эво в рамках разрабатываемо го проекта, поскольку в этом случае суть проекта уже ясна и осталось только применить к нему метод Эво. Однако даже если у вас нет опыта использования метода Эво, лучше начинать работы над проектом сразу по этому методу, просто потому, что вы быстрее получите более качественные результаты. В этом случае, когда метод Эво применяется впервые, особенно необходим хороший инструк тор, который поможет добиться успеха. 116 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА 6. Тестирование в методе Эво При обычном способе разработки тестирование выполняется в конце работ, по сле даты «Большого Взрыва». При этом тестировщики обычно обнаруживают сотни ошибок, исправление которых отнимает значительное время. Столь боль шое число ошибок приводит к их взаимному влиянию. Более того, исправление одних ошибок приводит к появлению других. Разработчики ПО обычно не используют средства математической статисти ки. И все же, так как при тестировании никогда не удается проверить все 100% программного кода, это означает, что проводятся лишь выборочные испытания. Из курса математики известно, что если мы делаем выборку, необходимо исполь зовать статистические методы для обработки результатов, чтобы можно было судить о поведении системы в целом. Поэтому мы должны проводить статисти ческую обработку результатов. Статистика свидетельствует, что эффективность тестирования в среднем рав на 50%. Возможно, по вашим данным, это значение выше, но мы должны при держиваться таких цифр. Это означает, что пользователь найдет в программе примерно столько же ошибок, сколько было обнаружено при тестировании. От сюда следует парадоксальный вывод: чем больше ошибок будет исправлено при тестировании, тем больше их останется в готовой программе. Или по-другому: для того чтобы пользователь не нашел ни одной ошибки, нужно, чтобы при тес тировании вообще не было обнаружено ошибок. Большинство программистов считает, что написать программу, полностью свободную от ошибок, невозмож но в принципе. Экстраполируя это заключение, например, на автомобильный транспорт, давайте спросим себя, это нормально, если автомобиль остановится, проехав всего несколько километров. Или, при попытке повернуть налево, ав томобиль будет время от времени поворачивать направо… Разве это нормально? При работе по методу Эво мы можем надеяться на то, что к моменту окон чательной проверки разработчик представит бездефектные результаты, поэтому тестировщикам останется только проверить, что все работает нормально в соот ветствии с требованиями. И хотя разработчики ПО обычно начинают смеяться при одной мысли об этом, мы говорим совершенно серьезно. Цель тестирова ния ранних промежуточных результатов, получаемых в циклах Эво, состоит не только в том, чтобы удостовериться: программа «работает». Тестирование нужно также не для того, чтобы усложнить жизнь разработчиков. При использовании метода Эво разработчики ПО спрашивают у тестировщиков, насколько они да леки от возможности создать бездефектную программу к моменту (или даже раньше) окончательной проверки (см. рис. 6.11). Эволюционная разработка Представление программы Завершение Завершение Завершение Завершение без ошибок работ работ работ работ Окончательная Оценка качества Оценка качества Оценка качества Оценка качества проверка Рис. 6.11. Тестирование первых предварительных результатов позволяет разработчику подготовить финальную версию программы, свободную от ошибок 8. ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА 117 7. Запросы об изменениях и отчеты о проблемах Запросы об изменениях (ЗИ) – это запрошенные изменения требований. От четы о проблемах (ОП) содержат информацию о найденных дефектах, которые должны быть исправлены в первую очередь. Новые выявленные задачи (НЗ) – это задачи, которые мы забыли поставить. Если такая задача обнаруживается, мы никогда не начинаем сразу же вносить изменения и поправки или выпол нять новое задание. Мы работаем только над поставленными задачами, для ко торых определены приоритеты и известна оценка времени их выполнения. Все задачи перечислены в списке задач-кандидатов в порядке важности. Сведения о любых ЗИ, ОП или НЗ сначала заносятся в базу данных. Это может быть что угодно – от реальной базы данных до записей в блокноте. База данных по стоянно анализируется группой контроля (ГК), управляющей внесением изме нений в техническую документацию. Состав этой группы может определяться как формально – специально назначенные сотрудники, которые могут и должны анализировать проблемы (ЗИ, ОП и НЗ), так и неформально – например, ру ководитель команды и представитель разработчиков, проверяющие базу данных и принимающие решения о том, что нужно делать. ГК может отложить решение некоторых проблем, проигнорировать их, а также поставить новую задачу не медленно или сначала поставить аналитическую задачу (рис. 6.12). При решении аналитической задачи сначала изучаются последствия возникшей проблемы, до кументируются рекомендации по ее решению и возможные последствия. Любые задачи, поставленные при таком анализе, заносятся в список задач-кандидатов, проводится оценка времени их решения и назначается уровень приоритета. Ра бота над поставленной или новой задачей начинается только в том случае, если она оказывается первой в списке задач-кандидатов. 8. Инструментальные средства После того как подобраны нужные методы и достигнуто понимание, как их ис пользовать, можно применять только определенные инструментальные средства. При работе над реальными проектами мы обычно заносим данные в электрон ную таблицу MS Excel, чтобы на интерактивных собраниях в режиме реального времени демонстрировать на экране ЖК-проектора ход работ. После постановки задач в качестве таблицы можно использовать MS Project, для контроля за за даниями, порученными каждому сотруднику и автоматической генерации оси времени на диаграмме Гантта (слева вверху на рис. 6.13). Эта ось времени, по сравнению с обычным планом, несет гораздо больше информации, в том числе и для руководства. Как оказывается, MS Project удобно настроить на использо вание 26-часовой рабочей недели с продолжительностью рабочего дня, равной 5,2 часа, чтобы при вводе в программу сроков, выраженных в реальных рабочих часах, на оси времени правильно отображалось количество рабочих дней, не обходимых для выполнения работы. 118 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА требования поставленные новые запросы отчеты задачи выявленные об изменениях о проблемах задачи база данных CCB задачи кандидаты часы приоритет задача 1 12 5 Отклонить задача 2 22 5 Отложить задача 3 13 5 Аналитическая задача 17 4 Новая задача 4 3 2 2 1 0 задача n 34 0 часы: оценка времени, необходимого для выполнения приоритет: 5 = наивысший, 1 = самый низкий, 0 = выполнение отложено Рис. 6.12. Все виды деятельности, включая запросы об изменениях требований, отчеты о проблемах и новые поставленные задачи оцениваются и получают приоритеты по одной и той же методике: с помощью списка задач-кандидатов Требования, свойства, заданные заказчиком, сроки сдачи промежуточных ре зультатов и задания связаны между собой (рис. 6.13). Очень удобно составить разные варианты списка заданий, например, список планируемых в рамках всего проекта заданий с назначенными приоритетами, а также списки заданий с на значенными приоритетами для каждого разработчика. Чтобы систематизировать соотношения между требованиями, свойствами, сроками сдачи и заданиями, а также представить эти отношения в различных формах нужно использовать реляционную базу данных. В настоящее время такая база данных еще не создана, поэтому руководитель проекта должен поддерживать целостность данных вруч ную. Это дополнительная работа. Однако такой подход помогает руководителю на первых этапах реализации проекта лучше разобраться в том, что происходит. После того как будет найден наилучший способ действий, а также выявлены действительно необходимые нам отношения и формы их представления – мы сможем сформулировать требования к создаваемой базе данных. Если бы мы 9. ВЫВОДЫ 119 ждали создания базы данных для поддержки всех этих отношений, вероятно, мы до сих пор не смогли бы начать использование метода Эво. Было бы интересно оценить, смогут ли существующие инструментальные средства, например, ком пании Rational, полностью решить подобную задачу. требования определены приоритеты Прошлые задания Джона Задание 1 Функция 1 Промежуточный результат 1 Задание Джона на текущую неделю Задание 2 Функция 2 Промежуточный результат 2 Что еще должен сделать Джон Задание 3 Функция 3 Промежуточный результат 3 определены приоритеты Прошлые задания Билла Задание n Функция n Промежуточный результат n Задание Билла на текущую неделю Задание n+1 Функция n+1 Промежуточный результат n+1 Что еще должен сделать Билл Задание n+2 Функция n+2 Промежуточный результат n+2 приоритеты определены определены приоритеты Прошлые задания Сью Задание m Функция m Задание Сью на текущую неделю Задание m+1 Функция m+1 Что еще должена сделать Сью Задание m+2 Функция m+2 приоритеты определены приоритеты определены Рис. 6.13. Связи между требованиями, функциями, определенными заказчиком, промежуточными результатами и различными формами представления списка заданий Однако прежде чем делать выбор таких средств, необходимо точно установить, чего мы хотим добиться, почему и как. Лишь после этого мы сможем сказать, поможет ли подобное средство сократить затраты времени и бюрократические процедуры или, наоборот, приведет к дополнительным затратам времени и уве личит бюрократизацию. 9. Выводы Мы описали проблемы, для решения которых предназначен метод Эво, а также способы организации работ над проектами Эво. Используя эти методы в реаль ных проектах, мы обеспечиваем: • • Более быстрое получение результатов. Проекты Эво позволяют доби ваться более качественных результатов при сокращении сроков разработки на 30% в сравнении с другими проектами. Обратите внимание: имеется в виду 30%-ное сокращение сроков по сравнению с работой над тем же проектом по традиционной методике. Этот срок может оказаться длиннее первоначально запланированного. И хотя 30% не являются научно дока 120 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА занным результатом, такая оценка выглядит вполне правдоподобно, если учесть, что мы постоянно проверяем, выполняем ли мы правильные задания в правильном порядке на правильном для данного этапа уровне детализации. Это означает, что любой другой процесс всегда будет менее эффективным. Большинство методов работы (даже если вы не знаете, по какому методу работаете, – в этом случае вы используете свой собственный подход) приво дит к тому, что значительный объем работы выполняется неверно, а затем переделывается, а кроме того, выполняется много необязательной работы. Большинство разработчиков признает, что более половины времени работы над проектом у них уходит на отладку программы. То есть на исправление того, что сначала было сделано неправильно. Метод Эво позволяет предот вратить появление большинства подобных «багов». • • Более высокое качество. Под качеством мы понимаем (согласно Кросби [4]) «соответствие требованиям» – а как иначе можно было бы добиться высокого качества и измерить это качество?). В методе Эво мы постоянно проверяем обоснованность требований и наших предположений, а также убеждаемся в том, что обеспечиваем удовлетворение важнейших требова ний в первую очередь. Следовательно, итоговый результат будет как ми нимум столь же хорошим, как и при использовании менее скрупулезных подходов, с которыми мы сталкиваемся в других случаях. • • Меньший стресс для разработчиков. В обычных проектах, где срыв сро ков выполнения заданий – нормальное явление, разработчики постоянно сталкиваются с ощущением неудачи. Это очень сильно снижает мотива цию. В проектах Эво разработчики регулярно добиваются успеха и видят результаты своей работы. Люди любят добиваться успеха. Это значительно повышает мотивацию. А так как мотивация – это двигатель продуктив ности, продуктивность резко возрастает. Это происходит в течение двух недель после начала использования метода Эво: сотрудники чувствуют себя свободными, счастливыми, веселыми и при этом выполняют больше по лезной работы. • • Удовлетворенность заказчиков. Заказчикам нравится получать предва рительные результаты и возможность регулярно сообщать свое мнение о ходе работ. Они понимают, как трудно составить спецификацию того, что им на самом деле нужно. Предоставляя предварительные результаты и откликаясь на изменения в требованиях, мы даем им почувствовать: мы понимаем, что делаем. При разработке по другой методике они постоянно беспокоятся о результате, который получат только в конце, при этом прак тический опыт подсказывает им, что обычно первые результаты не бывают безошибочными и предоставляются со значительным опозданием. Теперь же они получают реальные результаты, причем гораздо раньше. Они на чинают доверять нашим предсказаниям. Кроме того, у них появляется время для маневра на рынке, поскольку мы представляем завершенные, работающие результаты с постоянно растущим набором функций и улуч шающимся качеством задолго до истечения предельного срока. Раньше такого не происходило. ССЫЛКИ 121 • • Дополнительные прибыли. Затрачивая меньше времени на обеспечение более высокого качества предсказуемым способом, мы экономим значи тельные средства, при этом мы можем заработать больше денег на конеч ной продукции. В итоге получаем гораздо более высокую прибыль. Если говорить коротко, вопреки давнему предсказанию Брукса [2] об отсут ствии «верного решения», мы выяснили, что представленный метод, в основе которого лежат идеи, применявшиеся еще до написания статьи, и есть та самая «волшебная палочка», по мановению которой можно достичь столь замечатель ных результатов. Благодарности Многое (хотя и не все) из опыта практической реализации подхода, описанного в настоящей статье, является результатом разработки системы дистанционного контроля и управления компании Philips (Левен, Бельгия). Благодаря сотрудничеству с руководителем группы Бартом Ван-дер-беке данный подход был внедрен во все проекты его команды. Использование не продолжительных циклов «Планирование–Исполнение–Проверка–Реакция» на протяжении 8 месяцев позволило добиться заметного повышения уровня управ ляемости и комфортности работы – как для сотрудников, так и для руководи телей проекта. Мы хотели бы поблагодарить всех участников группы разработчиков и руко водителей проектов за их вклад в достижение этих результатов. Ссылки 1. H. D. Mills. Top-Down Programming in Large Systems // Debugging Techniques in Large Systems. Ed. R. Ruskin, Englewood Cliffs, N.-J.: Prentice Hall, 1971. 2. F. P. Brooks, Jr. No Silver Bullet: Essence and Accidents of Software Engineering // Computer. Vol. 20. 1987. № 4 (апрель). С. 10–19. 3. T. Gilb. Principles of Software Engineering Management. Addison-Wesley Pub Co, 1988. ISBN: 0201192462. 4. P. B. Crosby. Quality Is Still Free. McGraw-Hill, 1996. 4-е изд. ISBN 0070145326. 5. T. Gilb (рукопись). Evo: The Evolutionary Project Managers Handbook // http://www. gilb.com/pages/2ndLevel/gilbdownload.html, 1997. 6. S. J. Prowell, C. J. Trammell, R. C. Linger, J. H. Poore. Cleanroom Software Engineering, Technology and Process. Addison-Wesley, 1999. ISBN 0201854805. 7. T. Gilb (рукопись). Impact Estimation Tables: Understanding Complex Tech n o logy Quantatively // http://www.gilb.com/pages/2ndLevel/gilbdownload.html 1997. 8. N. R. Malotaux. TaskSheet // http://www.malotaux.nl/nrm/English/Forms.htm, 2000. 9. F. P. Brooks-младший. The Mythical Man-month. Addison-Wesley, 1975. ISBN 0201006502. Репринт 1995. ISBN 0201835959. 122 ЭВОЛЮЦИОННАЯ РАЗРАБОТКА 10. C. Northcote Parkinson. Parkinsons Law. Buccaneer Books, 1996. ISBN 1568490151. 11. N. R. Malotaux (слайды презентации Powerpoint). Evolutionary Delivery. 2001. // http://www.malotaux.nl/nrm/pdf/EvoIntro.pdf. 12. E. Dijkstra (статья). Programming Considered as a Human Activity, 1965. Re print in Classics in Software Engineering. Yourdon Press, 1979. ISBN 0917072146. 13. W. A. Shewhart. Statistical Method from the Viewpoint of Quality Control. Dover Publications, 1986. ISBN 0486652327. 14. W. E. Deming. Out of the Crisis. MIT, 1986. ISBN 0911379010. 15. Kent Beck. Extreme Programming Explained. Addison Wesley, 1999. ISBN 0201616416. 16. http://www.gilb.com. 17. http://www.extremeprogramming.org. Глава 7. РЕАЛИЗАЦИЯ ВСТРАИВАЕМОГО КОНЕЧНОГО АВТОМАТА Превратить конечный автомат в программу очень просто, если следуешь советам опытных практиков Мартин Гомез Мартин Гомез – специалист по программному обеспечению в лаборатории прикладной физики университета Джона Хопкинса, в настоящее время занимается разработкой летного ПО космических аппаратов, предназначенных для исследования Солнца. На протяжении 17 лет он разрабатывает встраиваемое ПО. Мартин имеет степень бакалавра по авиакосмической аппаратуре и степень магистра по электротехнике, полученные в Корнеллском университете. Ему можно написать по электронному адресу [email protected] Многие встраиваемые приложения являются первыми кандидатами на представ ление в виде конечных автоматов. Программу, которая должна выполнять опре деленную последовательность действий или по-разному реагировать на входные данные в зависимости от своего режима работы, зачастую лучше всего разраба тывать в виде конечного автомата. В настоящей статье представлен простой подход к реализации конечного авто мата для встраиваемых систем. На протяжении последних 15 лет я использовал его при разработке десятков систем, среди которых интерфейс пользователя, по строенный на основе программируемых клавиш, различные коммуникационные протоколы, транспортный механизм «кремний–подложка», система восстанов ления утраченного управления беспилотным летательным аппаратом, а также средства моделирования орбитального движения. Конечные автоматы В данной статье под термином «конечный автомат» мы понимаем систему, кото рая может находиться в одном из нескольких состояний. Состояние – это усло вие, которое определяет, какое из заранее заданных отношений между входными и выходными параметрами, а также входными параметрами для следующего со стояния будет реализовано. Опытный читатель легко узнает в этом определе нии конечный автомат Мили, в котором значения выходных параметров зависят как от текущего состояния, так и от значений входных параметров, в отличие от автомата Мура, где выходные параметры определяются только состоянием системы [1]. В обоих случаях следующее состояние автомата зависит как от те кущего состояния, так и от значений входных параметров. Прессман приводит несколько примеров диаграмм переходов, используемых для иллюстрации прин ципа работы программы. 124 РЕАЛИЗАЦИЯ ВСТРАИВАЕМОГО КОНЕЧНОГО АВТОМАТА На рис. 7.1 приведен конечный автомат. В этом примере первое появление символа «косая черта» не приводит печати выходных значений, однако пере водит конечный автомат во второе состояние. Если в этом состоянии на вход ‘/’, поступает символ, отличный от система возвращается в первое состояние, поскольку две косых черты должны следовать друг за другом. Обнаружив вто рую косую черту подряд, система генерирует выходное сообщение «Готово!». Пример конечного автомата для поиска в символьной строке последовательности «//» введен символ ‘/’ введен символ ‘/’ / вывод отсутствует / вывод сигнала об окончании Начало Поиск Поиск работы работы первого второго символа ‘/’ символа ‘/’ Готово! введен символ, отличный от ‘/’ / вывод отсутствует Рис. 7.1. Пример конечного автомата для поиска в символьной строке последовательности «//» При реализации конечного автомата я рекомендую использовать следующий алгоритм: • • Изучите, что нужно пользователю. • • Нарисуйте проект диаграммы переходов. • • Напишите основу программы конечного автомата, не вдаваясь в детали перехода из одного состояния в другое. • • Проверьте правильность осуществления переходов. • • Конкретизируйте детали переходов. • • Тестируйте. Пример Более наглядным примером может служить программа, управляющая опуска нием и подъемом шасси самолета. Хотя в большинстве самолетов эта операция осуществляется с помощью электрогидравлического механизма контроля (прос то потому, что они не оснащены бортовым компьютером), встречаются ситуа ции – как, например, в беспилотных летательных аппаратах, – когда необходимо реализовать механизм управления шасси с помощью программных средств. Давайте сначала опишем используемое в нашем примере оборудование, чтобы впоследствии можно было выбрать ПО для управления им. Шасси такого само лета состоит из передней стойки, левой главной стойки и правой главной стойки. Они оснащены гидравлическим приводом. Гидронасос с электроприводом обес печивает давление в гидравлическом приводе. ПО может включать и выключать этот насос. Направляющий гидрораспределитель устанавливается компьютером в положение «up» (убрать) или «down» (выпустить), что позволяет с помощью гидравлического давления убирать или выпускать шасси. Каждая стойка шасси ПРИМЕР 125 имеет два концевых выключателя, один из которых включается, когда шасси убраны, второй – когда они зафиксированы в выпущенном положении. Чтобы определить, находится ли самолет на земле, концевой выключатель на передней стойке шасси включается, только если вес самолета приложен к передней стойке шасси (обычно его называют «упорным выключателем»). Органы управления в кабине пилота состоят из рычага, убирающего/выпускающего шасси, и трех индикаторов (по одному на каждую стойку), которые могут отключаться либо светиться зеленым (шасси выпущены), либо светиться красным (когда шасси выпускаются/убираются). Теперь давайте разработаем конечный автомат. Первый шаг, самый сложный, состоит в том, чтобы выяснить, что на самом деле, по мнению пользователя, должна делать программа. Одно из преимуществ конечного автомата заключает ся в том, что он вынуждает программиста обдумывать все возможные варианты и для этого получать всю необходимую информацию у пользователя. Почему я считаю этот этап самым сложным? Сколько раз вам уже приходилось решать столь же простую задачу, буквально в одну строку: не убирать шасси, если само лет находится на земле? Очевидно (и это очень важно!), пользователь считает, что этого достаточно. Что вы думаете обо всех возможных вариантах? Разве нормально убирать шас си сразу же после того, как самолет оторвался от земли? А что, если он просто немного подпрыгнул при ударе о взлетную полосу при не очень аккуратной по садке? Что делать, если пилот во время стоянки самолета передвинул рычаг управления шасси в положение «up», а потом взлетел? Нужно ли в этом случае убирать шасси? Одно из преимуществ мышления в стиле конечного автомата состоит в том, что вы легко можете нарисовать диаграмму перехода между состояниями на дос ке и «пройтись» вместе с заказчиком по всем состояниям. В общепринятой нота ции переходы между состояниями конечного автомата обозначаются следующим образом: <событие, вызвавшее переход> / <вывод программы, являющийся ре зультатом этого перехода> [2]. Если мы решим просто нарисовать проект того, о чем нас попросил заказчик («не убирать шасси, когда самолет находится на земле»), он получит диаграмму вроде той, что представлена на рис. 7.2. Конеч ный автомат будет вести себя «плохо», как мы уже упоминали выше. Фрагмент конечного автомата, выполняющего только операции, затребованные заказчиком состояние шасси = up&& не на земле / включить насос, направление = up Начало работы Шасси Подъем выпущены шасси состояние шасси = down / включить насос, направление = down Рис. 7.2. Фрагмент конечного автомата, выполняющего только операции, затребов – 1 Прим. пер. РЕАЛИЗАЦИЯ 127 дание взлета», необходимо перезапустить таймер – самолет должен находиться в воздухе не менее двух секунд, прежде чем будут убраны шасси. Реализация Теперь самое время представить простую программу, реализующую конечный автомат. В листинге 7.1 приведена моя реализация конечного автомата, изобра женного на рис. 7.3. Листинг 7.1. Реализация управления авиационным шасси typedef enum {GEAR_DOWN = 0, WTG_FOR_TKOFF, RAISING_GEAR, GEAR_UP, LOWERING_GEAR} State_Type; /* В следующей таблице содержатся указатели для вызова функции для каждого состояния.*/ void (*state_table[] = {GearDown, WtgForTakeoff, RaisingGear, GearUp, LoweringGear}; State_Type curr_state; Main() { InitializeLdgGearSM(); /* Сердце конечного автомата – в этом цикле. Во время каждой итерации вызывается функция, соответствующая текущему состоянию. */ while (1) { state_table[curr_state](); DecrementTimer(); /* Выполняются другие функции, не связанные с этим конечным автоматом.*/ } }; void InitializeLdgGearSM() { curr_state = GEAR_DOWN; timer = 0,0; /* Остановить работу всей аппаратуры, выключить индикаторы и т. п. */ } void GearDown() { /* Убрать шасси по команде; не убирать, если самолет на земле.*/ if ((gear_lever == UP) && (prev_gear_lever == DOWN) && (squat_switch == UP)) { timer = 2.0; curr_state = WTG_FOR_TKOFF; }; prev_gear_lever = gear_lever; /* Запомнить для обнаружения движения штурвала вверх.*/ } void RaisingGear() { 128 РЕАЛИЗАЦИЯ ВСТРАИВАЕМОГО КОНЕЧНОГО АВТОМАТА /* Если все 3 стойки убраны, перейти в состояние GEAR_UP.*/ if ((nosegear_is_up == MADE) && (leftgear_is_up == MADE) && (rtgear_is_up == MADE)) { Curr_state = GEAR_UP; }; /* Если пилот изменил решение, начать выпуск шасси.*/ if (gear_lever == DOWN) { curr_state = LOWERING_GEAR; }; } void GearUp() { /* Если пилот переместил рычаг в положение DOWN, выпустить шасси.*/ if (gear_lever == DOWN) { curr_state = LOWERING_GEAR; }; } void WtgForTakeoff() { /* Если самолет находится в воздухе более 2 с, начать подъем шасси.*/ if (timer <=0,0) { curr_state = RAISING_GEAR; }; /*Если самолет снова коснулся земли, или пилот изменил решение, начать сначала.*/ if ((squat_switch ==DOWN) || (gear_lever == DOWN)) { timer = 2.0; curr_state = GEAR_DOWN; /* Не требуйте, чтобы пилот снова перемещал рычаг, это был просто отскок от взлетной полосы.*/ prev_gear_lever = DOWN; }; } void LoweringGear() { if (gear_lever == UP) { curr_state = RAISING_GEAR; }; if ((nosegear_is_down == MADE) && (Leftgear_is_down == MADE) && (rtgear_is_down == MADE)) { curr_state = _LOWERING; }; } 130 РЕАЛИЗАЦИЯ ВСТРАИВАЕМОГО КОНЕЧНОГО АВТОМАТА RaisingGear() Обратите внимание: код функции является попыткой отобра зить две строки таблицы переходов для состояния «Подъем шасси» (Raising Gear). В качестве упражнения можете попробовать расширить программу, реали зующую описанный нами конечный автомат, добавив блокировку по времени продолжительности цикла подъема шасси, поскольку наш инженер-механик потребовал, чтобы гидравлический насос работал не более 60 секунд подряд. При превышении продолжительности цикла необходимо известить пилота по переменным миганием зеленого и красного индикаторов и предоставить ему возможность повторить попытку убрать шасси. Еще одно упражнение для со вершенствования навыков. Давайте спросим нашего гипотетического инженера- механика, не испортится ли насос при смене направления потока во время его работы? Это может произойти в тех случаях, когда пилот меняет свое решение. Конечно же, он скажет «да». Как нужно модифицировать программу для конеч ного автомата, чтобы она быстро останавливала насос, когда направление потока принудительно изменяется на обратное? Тестирование Прелесть кодирования даже простых алгоритмов в форме конечных автома тов состоит в том, что в этих алгоритмах содержится практически написанный план тестирования. Нужно только проконтролировать все возможные переходы между состояниями. Я обычно делаю это с маркером в руке, зачеркивая стрелки переходов на диаграмме состояний по мере успешной проверки соответствую щих переходов. Это серьезная причина для того, чтобы избегать «скрытых со стояний» – их гораздо легче «забыть» при тестировании, чем явные состояния. Пока нет возможности использовать «реальное оборудование» для индикации смены состояний, можно делать это на уровне исходных кодов с помощью отлад чика либо написать утилиту («входной покер»), которая позволит моделировать любые входные значения для вашего приложения. Для такого тестирования потребуется немало кофе и терпения, поскольку да же в конечном автомате среднего размера может быть около 100 переходов меж ду различными состояниями. Однако количество переходов является отличным показателем сложности системы. Эта сложность зависит от требований заказчи ка: конечный автомат предельно наглядно демонстрирует, необходимые объемы тестирования. При использовании менее организованного подхода тестировать придется, как минимум, столько же – вы просто не будете знать об этом. Очень удобно включить в программу операторы печати, которые будут вы водить информацию о текущем состоянии системы, входные и выходные значе ния при каждом проходе цикла. Так вы облегчите проверку того, что является Золотым правилом тестировщика ПО: необходимо проверить, не только делает ли система то, что должна, но также и не делает ли она того, чего не должна. Или, другими словами, получаете ли вы только те значения выходных пере менных, которые ожидали получить? Значения выходных параметров проверить легко, но хотелось бы знать, что происходит «внутри» программы? Существуют ССЫЛКИ 131 ли «ошибочные» переходы между состояниями, то есть те, которые происхо дят случайно, лишь при одной из итераций в цикле? Меняются ли неожиданно какие-нибудь выходные параметры? В идеальном случае результаты тестовой печати должны в значительной степени напоминать таблицу переходов между состояниями. В заключение, и это относится ко всему встраиваемому ПО, не только создан ному с использованием конечных автоматов, призываю вас быть бдительными при первом подключении своего ПО к оборудованию. Очень просто перепутать полярность – «А я был уверен, что ‘1’ означает убрать шасси, а ‘0’ – выпустить». Мой напарник, специалист по оборудованию, часто использовал временный «вы ключатель труса», защищавший его прецизионные компоненты, на тот период, пока он проверял, не пытается ли моя программа перемещать объекты в непра вильном направлении. Запуск системы После того как все требования заказчика реализованы, для запуска конечного автомата, имеющего уровень сложности, аналогичный приведенному в примере, достаточно пары дней. Он почти всегда начинает работать так, как это и плани ровалось. Естественно, самая сложная проблема состоит в том, чтобы убедиться: я понимаю, чего хочет заказчик, и заказчик знает, чего он хочет – а для этого нужно значительно больше времени! Ссылки 1. Hurst S. L. The Logical Processing of Digital Signals. New York: Crane, Russak, 1978. 2. Pressman Roger A. Software Engineering: A Practitioner’s Approach. 3-е изд. New York: McGraw-Hill, 1992. 3. Shumate Kenneth C., Marilyn M. Keller. Software Specification and Design: A Disciplined Approach for Real-Time Systems. New York: John Wiley & Sons, 1992. Глава 8. ИЕРАРХИЧЕСКИЕ КОНЕЧНЫЕ АВТОМАТЫ Сандип Алувалия Сандип Алувалия – писатель и разработчик из компании EventHelix.com Inc., занимающейся созданием инструментальных средств и методик для систем реального времени и встраиваемых систем. Компания EventHelix разработала EventStudio – инструментальное средство автоматизированного проектирования и создания ПО для распределенного проектирования систем в объектно-ориентированном окружении, а также в окружении структурного проектирования. Эта компания расположена в Гейтсбурге, штат Мэриленд. Адрес веб-сайта: www.eventhelix.com. В настоящей главе мы остановимся на преимуществах иерархических конечных автоматов перед конечными автоматами обычной конструкции. В конечном автомате обычной конструкции все состояния считаются относя щимися к одному уровню. Такая структура не учитывает общие свойства имею щихся состояний. В реальной жизни многие состояния обрабатывают большин ство сообщений одинаковым образом; по-разному они реагируют лишь на не сколько важнейших сообщений. И даже в этом случае сохраняется некоторая общность свойств. Структура иерархического конечного автомата учитывает общ ность свойств, формируя иерархию состояний. Состояния, относящиеся к более высоким уровням иерархической структуры, выполняют обработку сообщений одинаковым образом, в то время как состояния более низких уровней иерархии, наследуя общие свойства состояний более высокого уровня, способны выполнять специфические для данного состояния функции. В приведенной ниже табл. 8.1 на примере типичного конечного автомата для обработки вызовов показано отобра жение множества обычных состояний на их иерархические эквиваленты. Таблица 8.1. Состояния типичного конечного автомата для обработки вызовов Обычные состояния Иерархические состояния Awaiting First Digit (Ожидание первой цифры) Setup.CollectingDigits.AwaitingFirstDigit Collecting Digits (Накопление цифр) Setup.CollectingDigits.AwaitingSubsequent Digits Routing Call (Маршрутизация вызова) Setup.RoutingCall Switching Path (Коммутация линии) Setup.SwitchingPath Conversation (Разговор) Conversation Awaiting Onhook (Ожидание подключения) Releasing.AwaitingOnhook Releasing Path (Освобождение линии) Releasing.ReleasingPath Традиционный конечный автомат можно представить как двухмерный массив, один из индексов которого определяет состояние, другой – обрабатываемое со общение. Конечный автомат с помощью индексов, задающих текущее состояние и полученное сообщение, определяет, какой обработчик сообщения будет вызван. В сценариях из реальной жизни система обычно характеризуется некоторым набором состояний и множеством входных сообщений различных типов. Это приводит к усложнению программного кода обработчика сообщений. Кроме то го, необходимо обрабатывать огромные двухмерные массивы. Система в виде ПРИМЕР ТРАДИЦИОННОГО КОНЕЧНОГО АВТОМАТА 133 иерархического конечного автомата позволяет исключить эту проблему, исполь зуя тот факт, что большинство состояний различаются своей реакцией лишь на несколько сообщений. При определении нового состояния нужно задавать только специфичные обработчики состояний. Пример традиционного конечного автомата На рис. 8.1 приведена диаграмма состояний для активной резервной двухпрово дной линии. В представленной здесь модели предполагается, что переход между активным и резервным режимом работы имеет внешнее управление. Активное Переключение Переключение Триггер ошибки Резервное Триггер ошибки Проверка Отказ Обслуживается при диагностике Диагностика оператором завершена успешно Отказ Рис. 8.1. Диаграмма состояний активной резервной двухпроводной линии Данный автомат может находиться в состояниях: Активное, Резервное, Про верка и Отказ. Необходимо предусмотреть обработку сообщений: Переключе ние, Триггер ошибки, Диагностика завершена успешно, Отказ при диагностике и Обслуживается оператором. Следовательно, обработчик сообщений должен управлять массивом из 4×5, то есть из 20 обработчиков. В листинге 8.1 приведены обработчики, которые необходимо определить. Для всех остальных ячеек двухмерной таблицы состояний нужно задать пустой («ни чего не делать») обработчик. Этот простой пример ясно иллюстрирует проблему традиционной модели конечного автомата. Имеется большое число повторений фрагментов кода в обработчиках сообщений. Это – причина головной боли раз работчиков конечных автоматов. В следующем разделе мы увидим, что в модели иерархического конечного автомата это сходство используется для реализации более элегантной структуры состояний. Листинг 8.1. Реализация традиционного конечного автомата /* == Обработчики для состояния Active == */ void ActiveStateFaultTriggerHandler(Msg *pMsg) { PerformSwitchover(); // Выполнить переключение в случае отказа // в состоянии Active NextState = SUSPECT; // Запустить диагностику SendDiagnosticsRequest(); // для подтверждения отказа 134 ИЕРАРХИЧЕСКИЕ КОНЕЧНЫЕ АВТОМАТЫ RaiseAlarm(LOSS_OF_REDUNDANCY); // Отослать оператору сообщение // о потере избыточности. } void ActiveStateSwitchoverHandler(Msg *pMsg) { PerformSwitchover(); // Выполнить переключение по команде // оператора CheckMateStatus(); // Проверить завершение переключения SendSwitchoverResponse(); // Проинформировать оператора // о переключении NextState = STANDBY; // Перейти в состояние Резервное } /* == Обработчики для состояния Standby == */ void StandbyStateFaultTriggerHandler(Msg *pMsg) { NextState = SUSPECT; // Запустить диагностику SendDiagnosticsRequest(); // для подтверждения отказа RaiseAlarm(LOSS_OF_REDUNDANCY); // Отослать оператору сообщение // о потере избыточности. } void StandbyStateSwitchoverHandler(Msg *pMsg) { PerformSwitchover(); // Выполнить переключение по команде // оператора CheckMateStatus(); // Проверить завершение переключения SendSwitchoverResponse(); // Проинформировать оператора // о переключении NextState = ACTIVE; // Перейти в состояние Active } /* == Обработчики для состояния Suspect == */ void SuspectStateDiagnosticsFailedHandler(Msg *pMsg) { SendDiagnosticsFailureReport(); // Проинформировать оператора // о результатах диагностики NextState = FAILED; // Перейти в состояние Failed } void SuspectStateDiagnosticsPassedHandler(Msg *pMsg) { SendDiagnosticsPassReport(); // Проинформировать оператора // о результатах диагностики ClearAlarm(LOSS_OF_REDUNDANCY); // Стереть оповещение о потере // избыточности NextState = STANDBY; // Перейти в состояние Standby } void SuspectStateOperatorInservice(Msg *pMsg) { // Оператор заменил карту, поэтому аннулировать текущие результаты // диагностики и перезапустить диагностику для новой карты. AbortDiagostics(); SendDiagnosticsRequest(); // Запустить диагностику для новой // карты. ПРИМЕР ИЕРАРХИЧЕСКОГО КОНЕЧНОГО АВТОМАТА 135 SendOperatorInserviceResponse(); // Проинформировать оператора // о запуске диагностики. } /* == Обработчики для состояния Failed == */ void FailedStateOperatorInservice(Msg *pMsg) { SendDiagnosticsRequest(); // Запустить диагностику для новой карты. SendOperatorInserviceResponse(); // Проинформировать оператора // о запуске диагностики. NextState = SUSPECT; // Перейти в состояние Suspect для диагностики. } Пример иерархического конечного автомата На следующей диаграмме состояний (рис. 8.2) представлен переработанный ко нечный автомат, в который добавлены два иерархических уровня. Inservice (Об служивается) и Out Of Service (Не обслуживается) – это высокоуровневые со стояния, которые обрабатывают обычные сообщения. Состояния более низкого уровня: Active (Активное) и Standby (Резервное) наследуют методы состояния Inservice. Состояния более низкого уровня: Suspect (Проверка) и Failed (Отказ) наследуют методы состояния OutOfService. Активное Тр и гге ро Переключение Переключение ши бк и Резервное Тригге р ошибк и Обслуживается Проверка Отказ при Обслуживается диагностике Диагностика оператором завершена успешно Отказ Не обслуживается Рис. 8.2. Диаграмма состояний иерархического конечного автомата На рис. 8.3 четко проиллюстрирована иерархия состояний. Даже состояния более высокого уровня – Inservice и Out Of Service – наследуют свойства со стояния Unit State, имеющего наивысший уровень в иерархии. В следующем фрагменте кода (листинг 8.2) объявлены все иерархические со стояния. В состоянии с наивысшим приоритетом определены все пустые («ни чего не делать») обработчики сообщений, таким образом, при определении про изводных состояний более низкого уровня не нужно заботиться о сообщениях, 136 ИЕРАРХИЧЕСКИЕ КОНЕЧНЫЕ АВТОМАТЫ которые они не обрабатывают. Все обработчики объявлены как виртуальные функции, поэтому они могут быть переопределены при описании производных состояний. Абстрактное состояние Обслуживается Не обслуживается Активное Резервное Проверка Отказ Рис. 8.3. Иерархия состояний конечного автомата Приведенный фрагмент кода содержит также реализацию класса Unit для ко static, нечного автомата. Состояния описаны как объекты типа принадлежащие классу Unit. Следовательно, они будут использоваться совместно всеми экзем плярами конечного автомата Unit. В конечном автомате также имеется указатель на текущее состояние, используемый для вызова соответствующего обработчика из метода OnMessage. Переходы между состояниями реализуются путем вызова метода NextState. NextState просто помечает указанное состояние как текущее. Листинг 8.2. Основная часть иерархического конечного автомата // Базовый класс для всех состояний конечного автомата Unit. // Определены все обработчики событий по умолчанию class UnitState { public: virtual void OnSwitchover(Unit &u, Msg *pMsg) {} virtual void OnFaultTrigger(Unit &u, Msg *pMsg) {} virtual void OnDiagnosticsFailed(Unit &u, Msg *pMsg) {} virtual void OnDiagnosticsPassed(Unit &u, Msg *pMsg) {} virtual void OnOperatorInservice(Unit &u, Msg *pMsg) {} }; // Базовый класс для всех состояний Inservice. Определена общая // обработка сообщений Переключение и Триггер ошибки. class Inservice : public UnitState { public: void OnSwitchover(Unit &u, Msg *pMsg); void OnFaultTrigger(Unit &u, Msg *pMsg); }; // Состояние Active наследует у состояния Inservice обработчики // событий Переключение и Триггер ошибки и детализирует их class Active : public Ins ice(u, pMsg); } Глава 9. РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ БЕЗОПАСНОСТИ Салах Обейд Салах Обейд является вице-президентом по инженерным разработкам в фирме Embedded Plus Engineering (Темпе, штат Аризона), которая создает системы и программное обеспечение. Он пользуется высоким авторитетом среди программистов и производителей систем как эксперт по применению методов объектно-ориентированного программирования и языков C++/UML (включая соответствующие методики проверки/верификации) в системах, критически важных для обеспечения безопасности. В Embedded Plus Engineering Салах руководит группами, сотрудничающими с компаниями авиакосмической, военной, телекоммуникационной отрасли и с предприятиями медицинского приборостроения. Его специализация – определение системных требований, проектирование систем, выработка стратегии имитации/ моделирования, формулировка требований к тестам и создание стандартов для разработки ПО. Кроме того, он занимается реализацией и интерпретацией стандарта DO-178B. Его кандидатура была предложена Федеральным авиационным агентством США (FAA) на пост сопредседателя отраслевой группы по проверке/ верификации объектно-ориентированных инструментальных средств. В настоящее время он является членом комитета RTCA SC-190 и комитета FAA/NASA по использованию объектно-ориентированных технологий в авиации (OOTiA), а также входит в состав группы по объектному управлению (OMG), работающей над определением спецификаций UML и CORBA. До прихода в компанию EmbeddedPlus Engineering Салах занимал руководящие посты в корпорации IBM, компаниях Allied Signal и Honeywell. Связаться с ним можно по электронной почте [email protected] com или через веб-сайт www.embeddedplus.com. Введение ПО имеет очень большое значение в приложениях, где обеспечение безопас ности является критически важным: от бортовых автомобильных компьютеров и органов управления беспилотными самолетами, а также круизными судами до управления работой медицинских приборов и электростанций. Программное обеспечение может отвечать различным уровням критичности. При определении уровня критичности и для управления процессом разработки ПО Федеральное авиационное агентство США (FAA) использует стандарт DO-178B, в котором изложены основные принципы разработки приложений, критически важных для обеспечения безопасности. В настоящее время документ DO-178B одобрен другими отраслями промышленности в качестве руководства по разработке при ложений, критически важных для обеспечения безопасности. В данной статье описано создание таких приложений и приведен обзор документа DO-178B. Кроме того, здесь содержится описание использования стандарта DO-178B при итеративной разработке объектно-ориентированного ПО. Отмечены также пре имущества итеративной разработки программ, критически важных для обеспе чения безопасности. ИСТОРИЯ ДОКУМЕНТА DO-178B 141 Надежность и безопасность Кто-то может подумать, что надежности и безопасность – это одно и то же, но это не так. Продукция может быть надежной, но небезопасной или безопасной, но ненадежной. Надежность заметно отличается от безопасности и не всегда явля ется обязательной в системах, требующих высочайшей безопасности. Например, сканер для проведения магнитно-резонансной томографии должен быть безопас ным, хотя и не обязательно надежным. Однако ясно, что если он сломается, его нельзя будет использовать или придется считать небезопасным. Большинство систем, требующих высочайшей безопасности, имеют безопасный режим работы в случае отказа; то есть они могут отказать, но их отказ должен быть безопасным. В нашем примере отказ магнитно-резонансного прибора допустим только в том случае, если он не нарушает безопасности. В тех случаях, где потеря функцио нальных возможностей приводит к катастрофическим последствиям, надеж ность является необходимым требованием, но не достаточным. Там, где потеря функциональности не оказывает влияния на уровень безопасности, обеспечение надежности не является обязательным, там же, где неправильные данные пред ставляют опасность, надежность будет обязательным признаком. На рис. 9.1 показана модель повышения надежности, в которой снижение (почти до нуля) частоты отказов приводит к повышению надежности системы. Надежность r Частота отказов f = 0 r, f Время t = 0 t Рис. 9.1. Модель повышения надежности История документа DO-178B Вследствие быстрого роста использования ПО в авиационных системах и обору довании, применяемом на самолетах, в начале 1980-х гг. появилась потребность в отраслевом руководстве по обеспечению соответствия требованиям подготов ки самолета к полету, установленным FAA. Был разработан документ DO-178A, предназначенный для определения приемлемого уровня надежности, который должны обеспечивать разработка ПО и его сертификация для соответствия тре бованиям подготовки самолета к полету. Несколькими годами позже появился документ DO-178B, призванный восполнить пробелы DO-178A. DO-178B ори ентирован на процедуры и уделяет дополнительное внимание верификации, а не 142 РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ тестированию. Особой внимание в этом стандарте уделяется проверке соблюде ния требований и структурному охвату. Стандарт DO-178B – один из наиболее строгих стандартов, применяемых в области разработки ПО. Это руководство для аэрокосмической отрасли ис пользовалось как образец при разработке сходных стандартов в других обла стях применения, например, в атомной энергетике, военной промышленности, железнодорожном/автомобильном транспорте и медицинской промышленности, где в процессе разработки программного обеспечения необходимо обеспечить на дежность, гарантоспособность и безопасность. FAA требует создания комиссии 1 из специально назначенных технических представителей для надзора за разра боткой ПО и связи с FAA. Обзор стандарта DO-178B «DO-178B – Software Considerations in Airborne Systems and Equipment Certifi cation» («DO-178B – анализ ПО для авиационных систем и сертификация обору дования») – это отраслевой стандарт, определяющий основные принципы произ водства ПО для авиационных систем, включая квалификацию инструментальных средств. Он публикуется аэрокосмической ассоциацией RTCA. Этот стандарт стал международным и используется для определения технологических требо ваний, призванных обеспечить необходимый уровень безопасности и готовности к полету ПО для авиационной радиоэлектроники. Данный стандарт также содер жит требования к процедуре квалификации инструментальных средств, исполь зуемых для автоматизации процессов разработки ПО, обычно выполняемых про граммистом. Руководство DO-178B описывает методику и методы, позволяю щ ие гарантировать, что целостность ПО и его надежность в конечном итоге будут сертифицированы и полностью одобрены FAA. Для каждого из шести уровней надежности программного обеспечения в руко водстве DO-178B описаны основные принципы разработки и верификации ПО. Чтобы определить уровень критичности отказа различных элементов системы, не обходимо выполнить процедуру назначения уровня безопасности системы. Обес печение безопасности является главной целью процедур, описанных в руковод стве DO-178B, однако этот документ может быть применен ко всем процедурам, использованным для других систем обеспечения безопасности. Уровень A имеет наивысшую важность для обеспечения безопасности и применяется в тех случаях, когда аномальное поведение системы может привести к катастрофическим послед ствиям. Самый низкий уровень E применяется в тех случаях, когда аномальное по ведение не оказывает влияния на работающее оборудование. Для каждого уровня безопасности, от A до E, данное руководство представляет требования к планиро ванию, разработке, верификации, управлению конфигурацией, гарантии качества, квалификации инструментальных средств, сертификации и эксплуатации. Стандарт DO-178B распределяет программное обеспечение по уровням со гласно степени серьезности последствий его отказа. В соответствии с основными принципами этого документа технологические требования и задания применимы Обеспечение достоверности результатов при возникновении неисправности. – 1 Прим. пер. КЛАССИФИКАЦИЯ НЕИСПРАВНЫХ СОСТОЯНИЙ 143 для всех случаев отказа. Например, тестирование на базе структурного охвата обязательно или необязательно в зависимости от требуемого уровня безопас ности конкретной программы. Программная ошибка может вызвать проблему, которая приведет к отказу оборудования; поэтому уровень безопасности ПО, необходимый для безопасной работы, связан с уровнем безопасности неисправ ных состояний системы. Классификация неисправных состояний Ниже перечислены категории неисправных состояний системы в соответствии со стандартом DO-178B: 1. #7; Катастрофические: неисправные состояния, приводящие к потере безопас ности системы. Например, не позволяющие продолжить полет и совершить посадку. 2. #7; Опасные/Очень серьезные: неисправные состояния, серьезно снижающие запас прочности или функциональные возможности системы, что может привести к травмам со смертельным исходом. 3.  Серьезные: неисправные состояния, снижающие запас прочности системы. 4. #7; Менее серьезные: неисправные состояния, способные значительно снизить безопасность системы (или самолета). 5. #7; Не оказывающие влияния на безопасность: неисправные состояния, кото рые не повлияют на работоспособность системы или самолета. Уровень безопасности программного обеспечения определяется при назначе нии уровня безопасности системы на основе вклада ПО в вероятность возникно вения неисправных состояний системы. В табл. 9.1 приведены уровни безопас ности ПО и их классификация по вероятности отказа: Таблица 9.1. Уровни безопасности ПО и их классификация Классификация Определение Вероятность Уровень ПО Катастрофиче- Самолет разрушен, значительное количество < 10 A –9 ский погибших Опасный Самолет поврежден, пассажиры пострадали, < 10 B –7 некоторые погибли Серьезный Пилот занят, требуется вмешательство, <10 C –5 возможность справиться с последствиями Менее серьез- Воздействие на пассажиров и функциональ- Не опреде- D ный ные возможности самолета малое или отсут- лена ствует Неопасный Никакого воздействия на пассажиров Не опреде- E и функциональные возможности самолета лена Для достижения более высокого уровня расчетной надежности необходимо следующее: • • спланированный, организованный, согласованный способ выполнения работ; • • тщательно проработанные приемы; • • соответствие стандартам. 144 РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ Стандарт DO-178B также поощряет использование итеративных методов в жизненном цикле системы и программного обеспечения. В процессе создания ПО и системы должна обеспечиваться обратная связь с другими процессами. На рис. 9.2 изображен такой итеративный процесс: Процессы жизненного цикла системы Процесс жизненного цикла системы Системные требования, обеспечиваемые Ограничение программно последствий неисправности Уровни безопасности ПО Идентификация/ Исключение Проектные источников ошибок ограничения Требования Определение и архитектура требований к аппаратуре программного обеспечения Процесс жизненного цикла программного обеспечения Рис. 9.2. Связь жизненного цикла ПО и системы Анализ архитектуры системы Использование некоторых архитектурных стратегий позволяет ограничить влия н ие программных ошибок и, следовательно, снизить требуемый сертифи кационный уровень ПО. Снижение критичности программного обеспечения и связанного с этим уровня сертификации позволяет минимизировать техноло гические требования в соответствии со стандартом DO-178B. Для достижения минимального уровня критичности ПО в аэрокосмической промышленности используются различные методы. Можно использовать самые разные архитек туры системы, однако для каждой из них характерна своя цена и затраты вре мени, необходимые для получения решения. Определение уровня критичности и связанного с ним уровня сертификации программного обеспечения должно проводиться в процессе присвоения уровня безопасности системы, при этом необходимо принять во внимание следующие методы, позволяющие снизить уровень критичности ПО. Разбиение на разделы Эта методика позволяет добиться изоляции отдельных компонентов программ ного обеспечения с независимыми функциональными возможностями. При ис пользовании разбиения на разделы уровень критичности ПО в целом может быть понижен, при этом каждому компоненту может потребоваться свой уровень сертификации в зависимости от уровня опасности отказа этого компонента. АНАЛИЗ АРХИТЕКТУРЫ СИСТЕМЫ 145 При создании ПО, требующего высочайшего уровня безопасности, разбие ние на разделы означает защиту; эта защита может обеспечиваться с исполь зованием различных аппаратных ресурсов, таких как процессоры, устройства памяти, драйверы ввода/вывода и таймеры. Комиссия по оценке уровня без опасности системы должна оценить, насколько хорошо проведено разбиение на разделы, а также каков уровень защищенности или незащищенности каж дого раздела. Несколько версий разнородного ПО Методика проектирования требует независимой разработки двух или большего числа версий программного обеспечения с одинаковыми функциональными воз можностями. Это обеспечит избыточность и позволит исключить повторяющие ся ошибки в ПО. Возьмите, к примеру, двухканальное устройство управления двигателем – это уже избыточная система, поскольку в работе используются два канала. Если один из них выйдет из строя, другой примет на себя управ ление двигателем и обеспечит безопасную работу. Программное обеспечение для обоих каналов может быть одинаковым, однако оно должно быть серти фицировано в соответствии с требованиями уровня А в силу его критической важности. Другой вариант состоит в том, чтобы разработать несколько версий разнородного ПО и попытаться снизить уровень критичности всего программ ного обеспечения. Мониторинг безопасности Мониторинг безопасности в основном реализуется программно с помощью дополнительного ПО, предназначенного для защиты от возникновения кон кретных неисправных состояний с помощью функции контроля отказов. Такая функция контроля может отображать предупреждения о возможных отказах или переключаться на использование избыточных функциональных возможно стей, если таковые имеются. Контролирующее ПО не обязательно должно иметь тот же уровень безопасности, что и функциональное ПО, этот уровень можно понизить, поскольку отказ контролирующего ПО не вызовет отказа системы в целом. На рис. 9.3 приведена базовая система, использующая контролирую щее ПО. Механизм Установка защиты Монитор Рис. 9.3. Базовая система мониторинга 146 РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ Документация по архитектуре системы После выбора архитектурной стратегии, ограничивающей влияние программных ошибок, и выяснения необходимого уровня сертификации ПО решения, при нятые с помощью процедуры оценки безопасности системы, документируются в Плане программного аспекта сертификации (PSAC). Документ PSAC, в ко тором представлен обзор программы и процесса разработки ПО, – это основа для первых контактов с сертификационными органами по проекту программного обеспечения. Назначаемые FAA технические представители (DER) действуют как посредники между FAA и группой, разрабатывающей программное обеспе чение. Эти представители сотрудничают с разработчиками на этапе принятия решений о выборе архитектуры и активно участвуют в процедуре оценки без опасности системы. Жизненный цикл программного обеспечения согласно стандарту DO-178B Основные принципы, определяемые стандартом DO-178B, устанавливают кри терии, которым должны соответствовать процессы в течение всего жизненного цикла ПО, чтобы гарантировать создание безопасной системы. Эти процессы можно разделить на две группы: разработка и интеграция. Интеграционные процессы, такие как квалификация инструментальных средств, верификация, управление конфигурацией и оценка качества позволяют в процессе разработки программного обеспечения гарантировать завершенность и качество всех видов деятельности при разработке ПО. Применение готовых программ, включая ком мерческое ПО (COTS), в рамках DO-178B считается допустимым, однако такое программное обеспечение должно пройти верификацию в соответствии с уров нем критичности системы, для которой оно предназначено. Документ DO-178B позволяет разрабатывать специальные руководства для процессов, используемых в вашей организации. Ниже приведен список видов деятельности и связанных с этим ожидаемых результатов, являющихся частью общей процедуры, описанной стандартом DO-178B. В DO-178B определены различные руководящие принципы для разных уров ней сертификации программного обеспечения, присвоенных при оценке тре буемой безопасности системы (см. табл. 9.1). Чтобы обеспечить соответствие требованиям стандарта DO-178B нужно представить необходимые документы и данные для всех уровней ПО. Ниже приведен список данных, которые согласно стандарту DO-178B требу ются на протяжении жизненного цикла программного обеспечения. Планирование • • План программного аспекта сертификации (PSAC). • • План разработки ПО. • • План верификации ПО. ЖИЗНЕННЫЙ ЦИКЛ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ СОГЛАСНО СТАНДАРТУ DO-178B 147 • • План управления конфигурацией ПО. • • План гарантии качества ПО. • • Стандарты требований к ПО. • • Стандарты проектирования ПО. • • Стандарты кодирования ПО. Определяются критерии перехода, взаимосвязь процессов и видов деятельности, а также их последовательность Определяются процессы разработки ПО (определение требований, проектирование, кодирование, тестирование и верификация) и интеграции (гарантия качества ПО, управление конфигурацией ПО) Определяется среда жизненного цикла ПО (инструментальные средства разработки, документация, инструментальные средства верификации и тестирования) Проводится дополнительный анализ (инструментальных средств, специальных требований к аппаратуре) Определяются стандарты разработки ПО (на требования высокого уровня, на требования низкого уровня, на кодирование, на документацию и т. п.) Рис. 9.4. Жизненный цикл ПО Разработка • • Требования к ПО (требования высокого уровня). • • Проектирование ПО (требования низкого уровня). • • Проектирование ПО (архитектура). • • Кодирование ПО. Процесс разработки Разработка программного обеспечения состоит из следующих процессов: • • определение требований к ПО; • • проектирование ПО; • • кодирование ПО; • • интеграция. Рисунок 9.5 иллюстрирует назначение и возможность оперативного контроля требований к ПО. 148 РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ Техническое Назначение требований описание системы Техническое Назначение требований описание компонента Оперативный Требования контроль Назначение требований к ПО (высокий уровень) Оперативный Требования контроль Создание к ПО (низкий уровень) Оперативный контроль Исходный код Оперативный контроль Рис. 9.5. Назначение требований к ПО и возможность оперативного контроля Виды деятельности при разработке ПО На рис. 9.6 показаны виды деятельности при разработке ПО. Определяются требования высокого Определяются уровня вторичные требования высокого уровня Проектируется архитектура ПО Определяются требования низкого уровня Определяются вторичные требования низкого уровня Создается исходный код программы Создается и интегрируется исполняемый объектный код Рис. 9.6. Виды деятельности при разработке ПО Верификация требований к ПО • • Требования к ПО высокого уровня согласуются с требованиями к системе. • • Требования к ПО высокого уровня пригодны для оперативной проверки на соответствие требованиям к системе. ЖИЗНЕННЫЙ ЦИКЛ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ СОГЛАСНО СТАНДАРТУ DO-178B 149 • • Требования к ПО высокого уровня точны и непротиворечивы. • • Требования к ПО высокого уровня совместимы с аппаратурой. • • Требования к ПО высокого уровня верифицируемы. Верификация проектирования ПО • • Требования к ПО низкого уровня согласуются с требованиями к ПО высоко го уровня. • • Требования к ПО низкого уровня пригодны для оперативной проверки на соответствие требованиям к ПО высокого уровня. • • Требования к ПО низкого уровня точны и непротиворечивы. • • Требования к ПО низкого уровня верифицируемы. • • Архитектура ПО согласуется с требованиями к ПО высокого уровня. • • Архитектура ПО пригодна для проверки на соответствие требованиям к ПО высокого уровня. • • Архитектура ПО точна и непротиворечива. • • Архитектура ПО совместима с аппаратурой. • • Архитектура ПО верифицируема. • • Архитектура ПО согласована со стандартами на ПО. Верификация программного кода • • Исходный код соответствует требованиям к ПО низкого уровня. • • Исходный код пригоден для оперативной проверки на соответствие требова ниям к ПО низкого уровня. • • Исходный код согласован с архитектурой ПО. • • Исходный код пригоден для проверки на соответствие архитектуре ПО. • • Исходный код точен и непротиворечив. • • Исходный код верифицируем. • • Исходный код согласован со стандартами на ПО. Верификация процесса интеграции • • Гарантировано использование методики тестирования по плану верификации ПО. • • Гарантировано точное соответствие совокупности тестовых данных всем тре бованиям и охват всех возможных режимов работы. • • Гарантирована правильность результатов верификации. • • Объектный код согласован с требованиями к ПО высокого уровня. • • Объектный код устойчив в отношении требований высокого уровня. • • Объектный код согласован с требованиями к ПО низкого уровня. • • Объектный код устойчив в отношении требований низкого уровня. • • Объектный код совместим с целевой аппаратурой. • • Объектный код согласуется со структурой ПО (если применимо). Верификация процесса верификации • • Тестовые процедуры правильны. • • Получаемые результаты верны. • • Соответствие плану верификации ПО. 150 РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ • • Полный охват тестами всех требований высокого уровня. • • Полный охват тестами всех требований низкого уровня. • • Полный охват тестами всего объектного кода. • • Полный охват тестами всех модифицированных условий/решений. • • Полный охват тестами всех решений. • • Полный охват тестами всех операторов. • • Полный охват тестами – сцепление модулей по данным и по управлению. Требования к ПО Требования к ПО высокого уровня низкого уровня Определение процедуры тестирования на основе требований к ПО Тесты Тестирование низкого уровня интеграции ПО Тестирование и аппаратуры интегрированного ПО Анализ охвата требований к ПО Анализ охвата структуры ПО Рис. 9.7. Тестирование на основе требований к ПО Управление конфигурацией • • Идентифицированы элементы конфигурации. • • Определен базис и обеспечена возможность оперативного контроля. • • Определены процедуры составления отчета о проблеме, контроля изменений, составление обзора изменений и отчета о текущей конфигурации. • • Определены процедуры архивации, восстановления и контроля версий. • • Определена процедура регулирования программной нагрузки. • • Определена процедура контроля за программным окружением на протяже нии всего цикла жизни ПО. ТЕХНОЛОГИЯ ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПРОГРАММИРОВАНИЯ И ПРОБЛЕМЫ 151 Обеспечение качества ПО (SQA) • • Обеспечение критериев перехода для процесса определения требований к ПО. • • Обеспечение критериев перехода для процесса проектирования ПО. • • Обеспечение критериев перехода для процесса кодирования ПО. • • Обеспечение критериев перехода для процесса интеграции ПО. • • Документация по гарантии качества ПО. Технология объектно-ориентированного программирования и проблемы приложений, критически важных для обеспечения безопасности Технология объектно-ориентированного программирования (ООП) по сравнению с традиционными методами разработки программного обеспечения имеет множе ство преимуществ. Вот некоторые из них: простота использования и повторного использования, работа и мышление на правильном уровне обобщения свойств и более сжатые сроки вывода продукции на рынок. Кроме того, отрасль пере ходит к использованию визуального моделирования – нового этапа в развитии технологии ООП. В визуальном моделировании используется унифицированный язык моделирования (UML). UML – графическая нотация (язык), позволяющая пользователям моделировать свои конструкции графически, это обеспечивает до полнительное преимущество: возможность увидеть их на правильном проектном уровне. Например, при использовании примеров и субъектов («актеров») пользо ватель занят разработкой системных требований и не должен на этом уровне вни кать в детали структуры системы. Это очень полезно, особенно при разработке приложений, критически важных для обеспечения безопасности, и оперативном контроле совместимости требований к элементам системы различных уровней. Кроме того, UML обеспечивает полезную возможность явного разграничения компонентов ПО. С помощью компонент-ориентированного подхода можно раз делить систему на множество компонентов, которые могут разрабатываться не зависимо. Приложения, критически важные для обеспечения безопасности, вообще, и авиационная электроника, в частности, – это наиболее консервативные об ласти, где принятие новых технологий происходит крайне осторожно в силу очевидных причин. Так как цена решения высока, а сроки реализации проектов с наивысшим уровнем безопасности обычно весьма продолжительны, часто из менять принятые процедуры неразумно. Стабильность процедур и инструмен тальных средств, используемых для создания ПО, обеспечивающего наивысший уровень безопасности, очень важна для успеха такого проекта. С другой стороны, сегодня инструментальные средства ООП развиты в достаточной мере, посколь ку применяются уже на протяжении многих лет. Объектно-ориентированные инструментальные средства используются при создании множества программ, предназначенных как для решения критически важных задач, так и для обеспечения высочайшего уровня безопасности. Однако использование объектно-ориентированных инструментальных средств до сих пор 152 РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ не получило широкого распространения в авиационной электронике, поскольку стандарт DO-178B был разработан еще до широкого признания технологии ООП. Далее мы обсудим некоторые из проблем, возникающих при использовании ООП для создания программного обеспечения, обеспечивающего высочайший уровень безопасности, в основном, ПО для авиационной электроники. Итеративный процесс Одно из главных преимуществ ООП – возможность его использования в ите ративном и инкрементном процессе разработки вместо водопадной модели жиз ненного цикла. Оно также стимулирует использование компонент-ориентиро ванных архитектур и визуального моделирования (язык UML) при разработке ПО. Итеративный процесс представляет собой альтернативу водопадной модели жизненного цикла, где все требования к системе должны быть определены за ранее, до начала создания какого бы то ни было кода. Итеративные процессы позволяют пользователям задавать требования, проектировать, создавать и тес тировать программный код, а затем повторять все сначала при появлении новых или изменении прежних требований. Важно отметить, что проектирование ПО должно базироваться на компонентах, а итерация должна выполняться только один раз для каждого фиксированного набора требований. После этого прово дятся интеграция и тестирование конечной продукции в целом, однако при каж дой итерации пользователи должны избегать перепроектирования или переко дирования программы, если только они не являются абсолютно необходимыми. На рис. 9.8 представлен итеративный процесс с использованием спирального метода разработки. Проблемы сертификации объектно-ориентированных приложений ООП отличается от других традиционных методов разработки программного обе спечения и в известном смысле имеет множество преимуществ перед ними. При разработке ПО, обеспечивающего наивысший уровень безопасности для авиации, необходимо выполнять все требования, указанные в руководстве DO-178B. Как уже подчеркивалось, для реализации этих принципов могут потребоваться зна чительное время и большие расходы; в некоторых случаях возникают сложности, как, например, при выполнении структурного охвата на объектном уровне. Еще одной серьезной проблемой может стать реализация возможности оперативного контроля связи между объектным и исходным кодом, необходимая для обеспе чения требуемого уровня безопасности ПО. Вследствие применения ООП или UML сегодня все пользователи работают на более высоком уровне абстракции и в некоторых проектах используются инструментальные средства, позволяю щие автоматически генерировать код и тесты для него. В таком случае при ис пользовании стандарта DO-178B возникают некоторые проблемы, о которых мы должны предупредить разработчиков. Далее обсуждаются проблемы, связанные с использованием ООП в проектах, разрабатываемых по стандарту DO-178B. ПРОБЛЕМЫ СЕРТИФИКАЦИИ ОБЪЕКТНО-ОРИЕНТИРОВАННЫХ ПРИЛОЖЕНИЙ 153 Определение требований ия ц Проектирование ика иф Рат Тестирование Кодирование Рис. 9.8. Итеративный процесс разработки ПО Автоматическая генерация кода Автоматическая генерация кода не является чем-то новым в разработке про граммного обеспечения; многие компании уже использовали автоматическую ге нерацию кода при создании ПО, обеспечивающего наивысший уровень безопас ности. Примерами систем, автоматически генерирующими код на предприя т иях авиационной электроники, является Software through Pictures, а также другие инструментальные средства на базе UML. Многие компании потратили сотни миллионов долларов, чтобы создать базовые инструментальные средства, позво ляющие автоматически генерировать код, и проводить связанный с этим комплекс обязательных сертификационных процедур на соответствие стандарту DO-178B. Использование UML или ООП дает множество преимуществ благодаря то му, что код генерируется автоматически; на рынке имеются инструментальные средства, обеспечивающие полную или частичную генерацию кода. Это стало возможным за счет того, что UML является стандартным формальным языком, а также благодаря поддержке исполняемых диаграмм состояний. Вот некото рые из преимуществ использования средств автоматической генерации кода: 1. #7; Сохранение связи кода с использованной моделью. Это очень важно, по скольку в большинстве случаев при ручной разработке об использованной модели забывают и при ее модернизации не обновляют должным образом программу. В известном смысле это сложная проблема, связанная с лиш ней работой, поскольку разработчику приходится сначала вносить изме нения в конструкцию системы, а затем делать то же самое с кодом про 154 РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ граммы. Например, чтобы добавить новую функцию на диаграмме UML, пользователь должен сначала нарисовать ее на диаграмме, а затем добавить в код программы. При использовании инструментария, автоматически ге нерирующего программный код, пользователь должен добавить функцию в конструкцию системы, а код будет создан автоматически в соответствии с обновленной конструкцией. Если разработчик использует диаграммы со стояний, можно определить и поведение функции. При наличии инстру ментального средства, способного генерировать код на основе диаграмм состояний, программа будет создана автоматически в соответствии с об новленной версией диаграммы состояний. 2. #7; Улучшенная возможность оперативного контроля. Так как код программы генерируется непосредственно при проектировании, это облегчает опера тивный контроль взаимосвязи структуры программы и ее кода. 3. #7; Автоматическая генерация кода улучшает продуктивность, исключая руч ные этапы создания кода в процессе разработки программного обес п ечения. При использовании автоматических генераторов кода руководителю проекта нужно следить за выполнением лишь немногих условий: • • Соответствует ли генератор кода общим принципам стандарта DO-178B или общим принципам вашего приложения? • • Поскольку автоматический генератор кода теоретически может создавать неверную программу или вносить ошибки в ваши приложения, он должен пройти сертификацию на соответствие требованиям стандарта DO-178B в области квалификации инструментальных средств того же уровня безопас ности, что и ваше приложение. • • Если в проекте используется генератор кода, создающий только каркас программы на базе диаграмм UML или объектно-ориентированных диа грамм, пользователь должен обеспечить проверку возможностей перекон струирования . В этом случае пользователь генерирует каркас программы, 1 а затем конкретизирует реализацию. При замене модели пользователь обязан генерировать каркас приложения повторно. Используемое инстру ментальное средство не должно вносить путаницу в реализацию, только генерировать изменения. • • Если применяется генератор кода, создающий программу полностью, нуж но позаботиться лишь о том: – #7; проведена ли сертификация в соответствии с требованиями стандарта DO-178B для квалификации инструментальных средств; – #7; сможет ли разработчик реализовать все необходимые функции, исполь зуя только генератор кода; – #7; будет ли выполнено автоматическое изменение модели в соответствии с внесенными пользователем изменениями в программу; – #7; контролирует ли разработчик каждый элемент конфигурации системы? Это важно с точки зрения эксплуатационной надежности. На более поздних этапах может потребоваться, чтобы вносимые изменения оказывали мини мальное влияние на остальную часть конструкции и программного кода. 1 То есть автоматического внесения изменений в конструкцию при изменении програм мы. – Прим. пер. ПРОБЛЕМЫ СЕРТИФИКАЦИИ ОБЪЕКТНО-ОРИЕНТИРОВАННЫХ ПРИЛОЖЕНИЙ 155 Это далеко не все вопросы, которые нужно принимать во внимание, однако их список слишком обширен, чтобы обсуждать его здесь. Существуют и другие проблемы использования средств автоматической генерации кода, связанные с наличием в программе фрагментов неисполняемого/деактивированного кода, а также с тестированием на основе требований. Автоматическая генерация тестов Некоторые из инструментальных средств на базе технологии ООП или языка UML могут также автоматически генерировать тестовые задания на основе диа граммы классов, диаграммы состояний, диаграммы операций и других диаграмм. Важно понять, что код, генерируемый автоматически – по модели, не обязатель но означает, что тестирование выполняется на основе требований. Генерация тестов на основе примеров использования, если они описаны кор ректно, допустима. Для приложений, обеспечивающих высочайшую безопас ность, важно наличие понятных требований, поддающихся контролю, и возмож ность использования этих требований как базы для проведения тестов, а также обеспечение возможности простого оперативного контроля. Возможность оперативного контроля Как правило, инструментальные средства на базе языка UML или инструмен тальных средств визуального моделирования не предоставляют механизма для присваивания меток и осуществления оперативной проверки соответствия тре бованиям. Это может стать сложной задачей, если вы не найдете способа автома тизации оперативного контроля и своевременного обновления требований при изменении диаграмм UML. Один из способов решения этой проблемы состоит в экспорте требований к программному обеспечению, включая вторичные тре бования, в инструментальное средство, поддерживающее возможность оператив ного контроля и осуществляющее его. Применяемый здесь прием состоит в поддержании связи между операциями, когда изменение одной приводит к соответствующим изменениям в другой, при этом все изменения будут своевременно обновлены. В ваших диаграммах UML нужно экспортировать далеко не все; особое вни мание следует уделить уровню обобщения. Исходный код должен быть отражен на низком уровне моделирования (функции внутри классов), а затем модель высокого уровня (диаграммы классов или пакеты) должна быть отражена в тре бованиях, которые следует задокументировать в виде примеров использования или в текстовом виде. Управление конфигурацией Применяя инструментальные средства визуального моделирования, разработчик должен контролировать и используемые модели, и сгенерированный исходный код, и, кроме того, все тестовые примеры и соответствующую документацию. Проект должен иметь среду управления конфигурацией, в которой разработчик мог бы в одном месте сохранить все, созданное им в рамках проекта. 156 РАЗРАБОТКА ПРИЛОЖЕНИЙ, КРИТИЧЕСКИ ВАЖНЫХ ДЛЯ ОБЕСПЕЧЕНИЯ Структурный охват Структурный охват важен, поскольку с его помощью можно увидеть, какие фрагменты кода не были протестированы, а к каким фрагментам нет доступа. В этом случае пользователь должен либо написать дополнительные тесты, либо обращаться с недоступными фрагментами кода как с неисполняемыми или де активированными. Структурный охват по стандарту DO-178B зависит от уров ня сертификации. Для ПО уровня безопасности A структурный охват должен выполняться для решений с модифицированными условиями, а объектный код должен коррелировать с исходным кодом. Невыполняемые/деактивированные участки программы Невыполняемые и деактивированные участки программы обнаруживаются пос л е выполнения всех требуемых тестов. Все участки кода, которые не были выпол нены при тестировании хотя бы один раз, классифицируются как невыполняе мые фрагменты и должны быть удалены из программы, если только их нельзя отнести к деактивированным, т. е. включенным в состав программы специально. В определенный момент может быть проведена активация деактивированного кода, и он начнет работать. Например, учитывая будущее развитие приложения, в нем может содержаться код для обработки будущих моделей. Деактивирован ный код должен удовлетворять соответствующим требованиям и должен быть зафиксирован при проектировании. Необходимо проведение тестирования деак тивированного кода на соответствие требованиям. В объектно-ориентированных языках программирования, таких как C++, компилятор и компоновщик для поддержки определенных функциональных возможностей, например, динамической диспетчеризации, могут добавлять свои фрагменты кода в ваш объектный код. Стандарт DO-178B не требует сертифи кации компиляторов, поскольку получаемый с их помощью код тес т ируется в соответствии с требованиями системы. При использовании технологии ООП компилятор может вставлять в программу дополнительный код, который невоз можно исполнить или протестировать – в этом случае он рассматривается как невыполняемый или деактивированный код в зависимости от ситуации. Наследование и множественное наследование Наследование свойств одного класса не представляет проблемы при разработке ПО, обеспечивающего наивысший уровень безопасности, и может дать некото рые преимущества. Например, совершенно предсказуемым является наследо вание интерфейса при конкретной реализации. Проблемы возникают при мно жественном наследовании, когда один класс наследует свойства двух или более классов. Это может привести к возникновению таких проблем, как совпадение сигнатур функций в обоих классах, что может вызвать проблемы и иметь непред сказуемые последствия. Отказ от множественного наследования поможет обес печить прозрачность структуры программы и упростит оперативный контроль и проведение тестирования на базе требований. ССЫЛКИ 157 Резюме Хотя в данном разделе мы лишь бегло затронули вопросы процедуры разра ботки ПО с наивысшим уровнем безопасности в соответствии с требованиями руководства DO-178B, нам удалось обсудить высокоуровневый подход к над зору за процессом разработки. Стандарт DO-178B содержит всесторонние реко мендации и основу для разработки безопасных программ. Сегодня существует несколько проектов предложений на тему использования ООП в программном обеспечении наивысшего уровня безопасности. Необходимо проделать много ра боты по определению дополнительных мер безопасности, необходимых при ис пользовании этой технологии в программном обеспечении для аэрокосмических и других критически важных задач. Если программному обеспечению требуется сертификат федерального авиа ционного агентства США (FAA), группа, разрабатывающая проект, должна осу ществлять все работы по планированию в самом тесном взаимодействии с сер тификационными органами через комиссию DER (специально назначенные технические представители). FAA требует разработки документа PSAC (План программного аспекта сертификации), чтобы гарантировать решение и согласо вание возможных проблем сертификации к началу работ над проектом. Еще одним требованием для успешной реализации проекта является нали чие неизменных требований, модели и стандартов кодирования. Стандарт коди рования должен соответствовать отраслевым нормативам для ПО наивысшего уровня безопасности, включая использование подмножества языков програм мирования, признанного отраслью безопасным. В настоящее время существуют хорошие подборки справочной информации по стандартам кодирования, напри мер, опуб л икованная Дэвидом Бинкли из национального института стандартов и технологий (NIST) – David Binkley «C++ in Safety Critical Systems» («Ис пользование языка C++ в системах наивысшего уровня безопасности»). В ру ководстве по проектированию должно определяться подмножество языка UML, которое будет использовано в работах над проектом. Например, в проекте долж но ограничиваться использование наследования и количество классов в пакете, поскольку это поможет обеспечить оперативный контроль, облегчит тестирова ние и структурный охват, необходимые по стандарту DO-178B. В целом, технология ООП (при условии ее правильного и разумного исполь зования) – это хороший выбор для разработки систем высшего уровня безопас ности, однако необходимо позаботиться о создании плана разработки ПО, кото рый будет отвечать требованиям руководства DO-178B. Ссылки 1. RTCA/EUROCAE. DO-178B Software Considerations in Airborne Systems and Equipment Certification. Глава 10. УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ Крис Кейдел и Олаф Мединг [email protected] Академия встраиваемых систем www.esacademy.com Введение Управление конфигурацией ПО (SCM) – это дисциплина, изучающая управле ние программным обеспечением и контроль его развития (с течением времени). Необходимо учитывать множество факторов и множество (различных) людей и сопутствующих этому процессов, политик, процедур и инструментальных средств. SCM – это краеугольный камень разработки программного обеспечения, который имеет очень широкое применение. Здесь мы уделим основное внимание рынку встраиваемых систем и разработчикам программного обеспечения, а не перспективам управления. Приведенные советы и концепции имеют в большей степени практическое, чем теоретическое значение. Тремя ключевыми концепциями SCM являются управление версиями, конт роль процессов и сравнение копий. В основе управление версиями лежит идея, что на любой стадии процесса разработки каждый файл проекта характеризу ется определенным номером редакции. Контроль процессов позволяет создать централизованную базу данных, предназначенную для управления отчетами об ошибках, запросах о расширении функциональных возможностей программы, идеями и отзывами пользователей или заказчиков. Контроль процессов необхо дим для поддержки текущей и последующих редакций программы, для улучше ния будущих версий программного обеспечения. И, наконец, сравнение копий позволяет разработчику легко идентифицировать различия между двумя любы ми редакциями файла или проекта. Многие из более развитых концепций SCM интегрируют, управляют и отслеживают выполнение этих ключевых операций в деятельности по разработке проекта. Улучшение качества программного кода и повышение продуктивности разра ботчиков не являются взаимоисключающими целями. Совсем наоборот. Можно существенно повысить и качество, и продуктивность, воспользовавшись инфор мацией и описанием способов использования инструментальных средств и кон цепций, приведенных ниже. Правильно подобранный инструментарий приятен в работе, в то же время он позволяет повысить уверенность специалиста в конечном успехе проекта. В данном разделе будет показано, как можно применять основные проверен ные инструментальные средства и процедуры для создания высококачественно го программного обеспечения. По собственному опыту и из бесед с коллегами я знаю, что при эксплуатации многих средств управления конфигурацией ПО их возможности до сих пор (через двадцать лет после появления на рынке) ис пользуются далеко не полностью. Особенно это относится к миру встраиваемых систем и персональных компьютеров (не использующих ОС Unix). Тому есть МОЩЬ И ЭЛЕГАНТНОСТЬ ПРОСТОТЫ 159 несколько причин: небольшие (зачастую состоящие только из одного человека) группы разработчиков проекта, широкий спектр платформ и операционных си стем, ограниченность бюджета, особенно с учетом стоимости коммерческих инст рументальных средств, отсутствие поддержки подразделений, разрабатываю щ их информационные системы, негативный опыт предыдущего применения средств SCM из-за их сложности, а также отсутствие поддержки со стороны руководства. Всеобщей тенденцией в области разработки встраиваемых систем становится все более широкое использование персональных компьютеров (ПК). Появляется и используется все больше и больше инструментальных средств разработки для ПК. Хорошая новость: сегодня доступны отличные, интуитивно понятные ин струментальные средства управления конфигурацией. В этом разделе предпри нята попытка обрисовать категории таких инструментальных средств, а также описать способы их применения и некоторые простые практические процедуры. Вполне вероятным допущением будет предположение о том, что большинство исходных кодов, в том числе микропрограммное обеспечение для встраиваемых систем и микроконтроллеров в наши дни редактируется и управляется с по мощью ПК. Поэтому все концепции, идеи и инструментальные средства, обсуж даемые ниже, в основном используются также именно в этой среде. В данном разделе описаны системы контроля версий, проблемы клиентов си стем контроля версий, концепции контроля версий, методы поиска ошибок, ин струментальные средства неконфигурационного управления, а также приведены советы и справочная информация. Будут кратко упомянуты и описаны другие инструментальные средства разработки ПО, именно потому что они также по вышают качество и продуктивность работы, хотя обычно не считаются средства ми управления конфигурацией. То, что многие разработчики ПО не только не применяют эти средства, но даже не подозревают об их существовании, и ста ло побудительным мотивом данного обсуждения. Среди таких средств ПО для зеркального отображения и резервного копирования информации, браузеры для Всемирной паутины и группы новостей в Интернете. Мощь и элегантность простоты Прежде чем подробно обсуждать системы контроля версий (VC), стоит отметить, что стандартные инструментальные средства контроля версий могут применять ся (и применяются) ко всем видам файлов (текстовым и двоичным) и докумен тов, включая интернет-страницы. Главным и наиболее известным преимуществом стандартного исходного кода над всеми другим видами документов является то, что они имеют простую текстовую (в виде ASCII-символов) структуру. Эта уни кальная «особенность» имеет два главных преимущества перед всеми другим ви дами документов (в том числе и перед документами на языке HMTL): сравнение копий и возможность слияния (будут подробно рассмотрены ниже). Сравнение копий позволяет обнаруживать различия в двух файлах с помощью инструмен тальных средств других компаний. Во-вторых (и не менее важно), с помощью стандартных или распространенных инструментальных средств можно присо единить ветвь с исправлениями обратно к главному «стволу» проекта (также 160 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ описано ниже). Неприятным, хотя и второстепенным исключением является раз личие принятых в главных операционных системах способов обозначения конца строки: для Windows, DOS это символы CR+LF, для Мас – CR, а в Unix – это LF. И наконец, многие системы контроля версий используют преимущества простой структуры стандартных текстовых файлов, записывая только небольшие фраг менты служебной информации между различными редакциями файлов, снижая тем самым требования к дисковому пространству. Контроль версий Важнейшим инструментальным средством обеспечения управления конфигура циями является средство контроля версий (VC). По мере развития программного обеспечения (исходного кода) VC фиксирует и хранит историю изменений. VC предоставляет пользователю простую возможность восстановить любую преды дущую редакцию любого файла в проекте при 100%-ной надежности и совмести мости. Широко распространено заблуждение, будто VC не нужно использовать в про ектах, разрабатываемых одним программистом. От его применения отдельный разработчик может получить такую же выгоду, как и целая группа. Все причи ны, по которым стоит применять VC, в равной степени верны и для отдельного разработчика. Многие системы VC просты в установке и использовании, кроме того, затраты времени на обучение работе с VC менее значительны в сравнении с любым побочным эффектом (см. ниже) вследствие отказа от системы VC. И последнее: насколько точным является допущение, что один и тот же разра ботчик будет поддерживать определенный программный проект на протяжении всего его жизненного цикла? И даже если это окажется верным, какова вероят ность того, что этот разработчик будет доступен и сможет вспомнить всю не обходимую информацию в случае экстренной необходимости? Также являются проблемой общая продуктивность и качество программного обеспечения. Типичные признаки отказа от использования (неполного использования) системы контроля версий Вот некоторые показательные признаки, свидетельствующие о том, что сред ства VC применяются лишь частично или, возможно, неправильно или не ис пользуются совсем. Среди этих признаков ручное копирование файлов, исполь зование номеров редакций в названиях файлов или каталогов, невозможность со 100%-ной уверенностью определить, какой код и сборочные файлы проекта (make-файлы) были использованы при компиляции конкретной редакции про граммного обеспечения, а также ошибки, считавшиеся исправленными, но снова проявившиеся у пользователей. Если сравнение исходных кодов происходит ре же нескольких раз в неделю, а разработчики создают собственные подкаталоги для «тестирования» – все это свидетельствует о серьезных проблемах при работе УСОВЕРШЕНСТВОВАННЫЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ 161 со средствами VC. И еще два признака – невозможность определить, когда (дата и редакция) конкретная функция появилась в программе и невозможность уз нать, кто внес изменения или написал конкретный (или вообще любой) фраг мент кода. Простые системы контроля версий Основные, рассчитанные на одного разработчика, системы VC существуют дав но. Одна из простейших, старейших и наиболее успешных систем VC называется «система контроля версий RCS» (Revision Control System). RCS включена в со став большинства дистрибутивов Unix, имеются ее версии для многих, если не для всех операционных систем. Многие современные полнофункциональные си стемы VC созданы на основе идей RCS и ее архивных файлов. Ее основная идея проста. Каждому исходному файлу соответствует архивный файл. Как исходный файл, так и его архив располагаются в одном и том же каталоге. При каждой регистрации изменений файла (см. ниже) они сохраняются в соответствующем архивном файле (также объясняется ниже). Система RCS следит за редакциями файла (которые называют также версиями) и обычно содержит инструменталь ные средства для сравнения копий файлов и их слияния. Однако первые си стемы RCS не были приспособлены для использования в составе группы из-за расположения архивных файлов и невозможности совместного доступа к ним группы разработчиков. Кроме того, тогда еще не была выработана концепция проектного файла, т. е. набора связанных файлов, представляющих проект по разработке программного обеспечения. Хорошую документацию и большинство реализаций этой системы можно легко найти и бесплатно загрузить с FTPсайтов в Интернете. Усовершенствованные системы контроля версий Усовершенствованные системы VC предоставляют широкий выбор функцио нальных возможностей. Они удовлетворяют потребности крупных групп, рабо тающих над многими тысячами проектов и файлов. При этом сотрудники мо гут быть географически удалены друг от друга. Усовершенствованные системы контроля версий предлагают поддержку разнообразных способов подключения удаленных пользователей и внутренний учет времени по Гринвичу или в фор мате всемирного времени (UTC) для поддержки разработчиков, находящихся в разных временных зонах. В них включены функции аудита и обеспечения безопасности, поэтому возможно ограничение доступа к важным файлам и под держка контрольного журнала выполняемых процессов. Для управления ПО на различных этапах – например, от создания прототипа до разработки завершаю щего тестового задания – используются модели продвижения файла. Модели па раллельной разработки позволяют всем программистам одновременно работать над независимыми ветвями, а полнофункциональные и автоматизированные средства слияния облегчают процесс регистрации изменений. В некоторых VC используются системы виртуальных файлов, явно указывающие положение фай 162 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ ла или перенаправляющие редактор или компилятор непосредственно к мощной SQL-базе данных. Еще одна полезная функция – возможность переименования или перемещения файлов внутри контролируемого дерева каталогов без утраты целостности предыдущих редакций этого файла. В состав таких систем часто включаются мощные средства, помогающие автоматизировать процесс сборки (компиляции) масштабных программных проектов. Триггеры событий оповеща ют группу разработчиков или руководителя о важнейших событиях, таких как регистрация изменений или успешное завершение ночной сборки проекта. Для масштабных проектов совершенно обычное дело – выделение специального ад министратора по конфигурации, работающего полное время. Для каких файлов нужно использовать контроль версий Об этом часто спорят. Многие статьи, посвященные управлению конфигурацией, содержат подробное обсуждение данной темы, поэтому нет смысла углубляться в эту проблему здесь. Если кратко, то существует соглашение, согласно кото рому в систему контроля версий нужно включать все файлы с исходным ко дом, необходимые для получения окончательной версии исполняемого файла. Естественно, это относится и к сборочным файлам проекта. Хорошая система VC должна обеспечивать очень простое повторное создание окончательной вер сии исполняемого файла, чтобы не было необходимости хранения в системе VC промежуточных двоичных файлов (объектные файлы, предварительно компи лированные файлы заголовков и т. п.) или даже окончательной версии самого исполняемого файла. В систему VC можно (и, вероятно, необходимо) включать библиотечные файлы, драйверы устройств, документацию к исходному коду, письменные процедуры любого рода, тестовые сценарии, результаты тестирова ния, стандарты кодирования или руководства по стилю оформления программ, специальные инструментальные средства и т. п. Совместная работа с файлами и клиенты системы контроля версий Многие системы VC являются полноценными приложениями с архитектурой «клиент/сервер». Очевидно, что при работе в групповом окружении все раз работчики каким-то образом должны иметь право как на чтение, так и на за пись или на изменение прав доступа к архивному файлу, расположенному на центральном файловом сервере. Поэтому необходимо задать себе вопрос, каким именно образом файлы будут передаваться с центрального файлового сервера на ваш локальный ПК. Производитель системы VC часто вместе с ней предостав ляет VC-клиента, обеспечивающего пользовательский интерфейс для обмена ис ходным кодом между ПК (рабочей станцией) и репозиторием (об этом ниже) на центральном файловом сервере. Однако этот VC-клиент может быть как доступ ным, так и недоступным с вашего ПК или из его операционной системы. Кроме СОВМЕСТНАЯ РАБОТА С ФАЙЛАМИ И КЛИЕНТЫ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ 163 того, ваш ПК может иметь прямой доступ к файловой системе сервера (NFS в Unix или образы дисков в сети Microsoft или Novell) или не иметь его. Фи зическое размещение клиентского ПК и сервера также ограничивает доступные варианты для выбора. Подведем итог: имеются две независимые переменные; первая – можно ли запустить клиента системы VC на вашем локальном ПК – и вторая – имеет ли ваш ПК доступ к файловой системе файлового сервера. Эти переменные образуют четыре разных набора значений, которые описаны ниже. Нет локального клиента, нет общей файловой системы Это наименее желательный сценарий. Примером такой системы может служить ПК, обращающийся к более старому мэйнфрейму. Или более вероятная ситуа ция – географически разделенная группа разработчиков с ограниченными сред ствами. Здесь остается единственный вариант – использовать терминал Telnet или другую оболочку Unix для удаленного запуска клиента непосредственно на центральном файловом сервере или на локальной рабочей станции (имеющей доступ к ресурсам файлового сервера), а затем вручную пересылать файлы по протоколу FTP между файловым сервером и вашим ПК. Например, начните сеанс работы с файловым сервером, выгрузите файл, перешлите его по FTP на свой ПК, отредактируйте, перешлите его обратно по FTP и, наконец, зареги стрируйте изменения. Нет локального клиента, но есть общая файловая система Это похоже на первый сценарий. Однако теперь ПК может получить доступ к файлам напрямую. Либо приложения на вашем ПК (редактор, компилятор и т. п.) могут получить прямой доступ к исходным файлам через локальную сеть, либо пользователь имеет возможность скопировать их вручную. Первый метод работает медленнее и увеличивает сетевой трафик. Второй требует руч ного выполнения дополнительных операций после выгрузки файла и перед ре гистрацией изменений. Есть локальный клиент, но нет общей файловой системы Здесь проблема состоит в том, что редкие системы VC обеспечивают поддержку доступа клиентов к серверу по локальной сети или через Интернет по такому сетевому протоколу, как TCP/IP. Еще меньшее число систем VC использует за щищенные методы коммуникаций (открытые ключи вместо незашифрованных паролей в начале сеанса и шифрование содержимого файла вместо его пере сылки в текстовом виде). Есть и локальный клиент, и общая файловая система Это наиболее распространенный и самый гибкий сценарий. Клиент часто ис пользует преимущество общей файловой системы для доступа к репозиторию на 164 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ файловом сервере; при этом он может даже «не знать» о том, что репозиторий расположен на отдельном файловом сервере. Поставщику системы VC гораздо проще реализовать VC-клиент, что отчасти и объясняет его популярность. Проблемы интегрированной среды разработки Интегрированные среды разработки (IDE) для создания программного обеспече ния предшествовали появлению графических (нетекстовых) окон и стали очень популярными в последнее десятилетие – во времена графического интерфейса пользователя (GUI). Большинство сред IDE предоставляют отличный интегри рованный редактор исходного кода с множеством замечательных функций, таких как автоматическое завершение конструкций исходного кода при редактировании и всплывающая во время набора синтаксическая подсказка. Кроме того, в них, как правило, включен встроенный отладчик, полнофункциональный, точно на страиваемый компилятор и компоновщик, а также всевозможные легкодоступные интерактивные справочные системы. В таких средах IDE часто не хватает интер фейса с системой VC, либо он включается в их состав с запозданием. Специфи кация SCC (Source Code Control – управление исходным кодом, см. ниже) – это одна из попыток подобной интеграции. Еще одной серьезной проблемой многих современных сред IDE является собственный, в некоторых случаях даже двоич ный, формат сборочного файла проекта. Такие нестандартные make-файлы го раздо труднее включить в систему контроля версий. Среди проблем, связанных с этими сборочными файлами проекта: слияние файлов, совместный доступ при полной блокировке этого файла (см. ниже) и тот факт, что каждая среда IDE обычно использует собственный формат, отличный от принятых в других средах. На самом деле даже у одного и того же производителя при переходе от одной версии IDE к другой форматы сборочных файлов проекта часто изменяются. Среды IDE – это замечательное и удобное инструментальное средство, которое, несомненно, повышает продуктивность разработчика. Однако они часто создают нестандартные файлы, содержащие информацию, необходимую для сборки про екта, сведения о конфигурации самой среды IDE, информацию для отладчика и браузера исходного кода и т. д. И не всегда легко определить, какую информа цию содержат эти файлы и нужно ли для них использовать систему VC. Проблемы графического интерфейса пользователя Некоторые производители систем VC предоставляют внешние VC-клиенты с графическим интерфейсом пользователя. Эти графические (нетекстовые) кли енты гораздо сложнее реализовать должным образом и поэтому они зачастую значительно удорожают систему. При их использовании легко выйти за рамки бюджета проекта по созданию встраиваемой системы. Иногда они оказываются слишком медлительными и лишь изредка поддерживают то же подмножество функций, что и эквивалентные им текстовые (на базе командной строки) систе мы VC. Еще одна проблема состоит в том, что к ним не всегда удается получить доступ из других операционных систем и с других аппаратных платформ. ИНТЕРФЕЙС ДЛЯ ВЕБ-БРАУЗЕРА ИЛИ КЛИЕНТ-JAVA-СИСТЕМ КОНТРОЛЯ ВЕРСИЙ 165 Спецификация SCC Программный интерфейс приложения (API) Microsoft Common Source Code Control (SCC) определяет способ взаимодействия между средой IDE и систе мой VC. Многие среды IDE для ОС Microsoft Windows взаимодействуют с си стемой VC в соответствии со спецификацией SCC. Система VC действует как поставщик сервиса SCC для среды IDE, поддерживающей спецификацию SCC. Это позволяет разработчикам получить доступ к основным функциям системы VC, таким как выгрузка файла и регистрация изменений, непосредственно с по мощью хост-окружения. После установки поставщика сервиса SCC изменяется интерфейс пользователя среды IDE. Появляются дополнительные пункты меню среды IDE для выполнения операций, предлагаемых поставщиком сервиса SCC. Расширяются также и свойства файлов – теперь они отражают статус файла в рамках управлениях исходным кодом. Проблема такого подхода в том, что часто с использованием интерфейса SCC предоставляется лишь подмножество функций VC. Поэтому по-прежнему необ ходим автономный VC-клиент для доступа к более развитым функциям, пред лагаемым большинством систем VC. Почему бы в таком случае не использовать автономный VC-клиент для доступа ко всем функциям? Спецификация SCC доступна только для пользователей ОС Microsoft Win dows, так как автором этой спецификации является корпорация Microsoft. Бо лее того, документация по интерфейсу SCC API не доступна для публичного использования. Чтобы получить ее копию, необходимо подписать соглашение о неразглашении. Стоит отметить, что это не единственный способ взаимодей ствия среды IDE с системой VC. Некоторые производители систем VC называют предоставляемые ими сервисы расширениями интерфейса, поскольку система VC распространяет свои функциональные возможности на среду IDE или на стан дартный браузер файлов, предлагаемый многими операционными системами. Интерфейс для веб-браузера или клиент-Javaсистем контроля версий Похоже, это прекрасная идея. Теоретически, хорошо написанный Java-код дол жен выполняться везде как автономное приложение либо в веб-браузере, в ка честве апплета, либо в качестве так называемого сменного модуля («плагина»). VC-сервер может быть реализован в виде выделенного веб-сервера, управляю щего VC-архивами, репозиторием или базой данных (объясняется ниже). Еще одним преимуществом использования технологии Java является встроенная под держка защиты информации. Однако в силу различных обстоятельств имеется очень ограниченное число Java-приложений разного рода, позволяющих реали зовать принцип «написал один раз – используй где угодно». Лишь отдельные поставщики систем VC предлагают продукцию на базе Java, однако их интерфейс пользователя оказывается слишком медлительным и в чем-то неуклюжим. Сле дует отметить, что веб-браузеры редко поддерживают новейшую версию Java, поэтому необходимо, чтобы плагин был написан с использованием более старой 166 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ версии Java. И все же, Java предлагает множество привлекательных возможно стей. В будущем с развитием Java и связанных с ней новых технологий, таких как Jini, можно ожидать появления большего количества систем VC на базе тех нологии Java. Основные положения концепции контроля версий Редакция, версия и выпуск Все три термина относятся к одной и той же идее, а именно: файл или про ект развиваются с течением времени путем внесения изменений и, тем самым, создания его редакций (revision), версий (version) и, в конечном счете, выпу сков (release). Понятия «редакция» и «версия» означают примерно одно и то же – «выпуск» означает программный код, поставленный (или выпущенный) 1 потребителю. Выгрузка, регистрация и фиксация «Выгрузка» (checkout) и «регистрация» (check-in) – основные и наиболее часто используемые процедуры. Выгрузка копирует новейшую (если иное не указано специально) версию файла из архива на локальный жесткий диск. Опе рация регистрации добавляет новую редакцию файла в соответствующий ему архив. Иногда эту процедуру называют «фиксацией изменений» (commit). По умолчанию, если иное не указано специально, новая версия становится либо главной редакцией, если мы работаем на «стволе» проекта, либо побочной ре дакцией, если мы работаем над ответвлением проекта (оба термина см. ниже). Если файл регистрируется как редакция, отличная от главной или побочной, создается новая ветвь проекта. Блокировка, снятие блокировки, замораживание и отмена замораживания Функция блокировки (lock) предоставляет разработчику исключительные права на запись (модификацию) конкретной редакции файла. В некоторых си стемах VC требуется (или строго рекомендуется) принудительное проведение политики полной блокировки. Преимуществом полной блокировки является предотвращение слияния исправленных файлов и возможного конфликта вер сий. Такие системы VC часто предоставляют также и административный мо дуль, который позволяет принудительно реализовывать определенную политику или проводить ее точную настройку. Примером такой политики может служить предоставление прав на изменение важнейших файлов только опытным разра ботчикам. Такой подход хорошо работает в небольших командах с развитыми средствами коммуникации. В этом случае группа (руководство) заранее опре деляет, кто и когда будет работать с данным файлом. Каждый сотрудник знает и может легко определить, кто в настоящий момент работает с конкретным фай лом. Единственная серьезная помеха при такой организации может возникнуть только в том случае, когда кто-то уже заблокировал файл, необходимый разра В литературе на русском языке все три понятия «редакция», «версия» и «выпуск» при 1 мерно эквивалентны; в данном разделе, чтобы избежать путаницы, для обозначения вер сии ПО, предоставляемого потребителю используется понятие «выпуск». – Прим. пер. ИНТЕРФЕЙС ДЛЯ ВЕБ-БРАУЗЕРА ИЛИ КЛИЕНТ-JAVA-СИСТЕМ КОНТРОЛЯ ВЕРСИЙ 167 ботчику, тогда нужно сообщить об этом коллеге и подождать, пока тот закончит внесение своих изменений. Замороженные (freeze) файлы нельзя заблокировать и поэтому их нельзя модифицировать до тех пор, пока не будет отменено за мораживание (thaw). Это может быть полезным инструментом управления, ко торый проинформирует разработчиков о том, что определенные файлы нельзя изменять, скажем, перед подготовкой основного выпуска программы. Сравнение копий Возможность найти различия между двумя редакциями одного и того же фай ла очень важна для любого разработчика программного обеспечения, даже в том случае, если по каким-либо причинам он вообще не использует систему VC. В общем случае инструментальное средство для сравнения копий (differencing) позволяет разработчику определить различия между двумя файлами и, более конкретно, между двумя редакциями одного и того же файла. В любой системе VC имеется встроенное средство сравнения файлов. Тем не менее существует множество внешних приложений для выполнения этой операции. Некоторые из них основаны на текстовом интерфейсе, другие – на графическом (визуальном) интерфейсе пользователя. Это неплохая идея – иметь в своем арсенале набор различных средств для сравнения копий, чтобы применять их в зависимости от решаемой задачи. Встроенных инструментальных средств обычно достаточ но для быстрых проверок; к ним можно получить удобный доступ через меню. Более мощные средства сравнения копий способны сопоставлять целые деревья каталогов и могут форматировать результаты, представляя их в удобной для чтения форме. Инструментальные средства сравнения копий позволяют устранить ненуж ные фрагменты программ, указывая на отладочный или экспериментальный код, который вы забыли удалить из программы. Часто приходится параллельно разрабатывать новую функцию и исправлять ошибки, недавно обнаруженные пользователями. Так может случиться, например, если вас попросят устранить серьезную ошибку в программе в тот момент, когда вы работаете над реали зацией новой функции. Использование инструментального средства сравнения копий перед каждой фиксацией изменений помогает своевременно удалить из программы код, присутствие которого в окончательном выпуске программы не нужно, например, вспомогательный вывод информации о значениях (отладоч ных) переменных во время работы программы. Еще одним важным применением инструментального средства сравнения ко пий является поиск всех изменений программного кода, внесенных между двумя указанными редакциями одного файла или целого набора файлов, в случае появ ления новой ошибки. Например, служба поддержки пользователей представила отчет об ошибке, содержащейся в выпуске 1.1, при этом база данных (см. ниже), отслеживающая появление ошибок, свидетельствует, что в выпуске 1.0 такой проблемы не было. Инструментальное средство сравнения копий покажет все разделы, в которых был изменен программный код – с большой долей вероят ности именно эти изменения и привели к возникновению ошибки. Возможность быстрой локализации ошибки важна для разработчиков встраиваемых систем, оборудование которых часто модернизиру пользовании такого сценария работы ре ИНТЕРФЕЙС ДЛЯ ВЕБ-БРАУЗЕРА ИЛИ КЛИЕНТ-JAVA-СИСТЕМ КОНТРОЛЯ ВЕРСИЙ 171 пликационное ПО каждые несколько часов повторяет синхронизацию архивов цент р ального файлового сервера и удаленного файлового сервера. Преимуще ство такого подхода – предоставление более быстрого доступа к файлам уда ленным участникам команды разработчиков. Среди его недостатков – сложность установки и обслуживания репликационного ПО и возможность возникновения конфликтов при повторной синхронизации файловых серверов. Рабочая копия и «песочница» Рабочая копия (working copy) содержит дубликат каждого файла проекта с определенным номером редакции, чаще всего последнюю редакцию файлов основного проекта или его ответвления. Рабочие копии – это способ предоста вить каждому программисту возможность независимой от других сотрудников работы на своем рабочем месте. Обычно рабочая копия располагается на локаль ном жестком диске разработчика и создается с помощью операции выгрузки. Ра бочую копию иногда называют «песочницей» (sandbox). Нет ничего необычного в наличии различных рабочих копий у каждого программиста в каждом проекте, при этом каждая рабочая копия относится к разным выпускам основного направ ления или ответвления проекта. Я часто создаю новую рабочую копию сразу же после определения контрольной точки главного выпуска проекта, чтобы обес печить двойную проверку и контроль всех редакций. Все файлы в новой рабо чей копии должны быть идентичны всем файлам рабочей копии, открывающей работу над новым выпуском программы (см. пункт «Советы» ниже). Триггеры событий Многие системы VC позволяют выполнять один или несколько операторов в случае наступления заранее заданного события. Это могут быть VC-операции или что-то другое. Например, отправка по электронной почте извещения руко водителю проекта при каждом фиксировании исправлений в файле. Ключевые слова Ключевое слово (keyword) – это специальная переменная, включаемая в текст исходного кода. Названия таких переменных обычно помещаются между двумя символами «$» (например, $Author$) и представляют текстовую информацию в рабочей копии. Ключевые слова могут опционально конкретизироваться, т. е. заменяться своими символьными значениями при проверке или просмотре ре дакции файла. Это очень полезная возможность, поскольку она позволяет си стеме VC размещать необходимую информацию прямо в исходном коде. В то же время использование ключевых слов позволяет разработчику выбрать, какую именно информацию системы VC внедрять в исходный код и где именно раз мещать ее, обычно ключевые слова располагаются в начале или в конце файла. Советы Структура дерева каталогов для файлов исходного кода Одним из ключевых аспектов любого крупного проекта по разработке ПО является реализация структуры каталогов и ее расположение. Дерево каталогов отражает отношения между файлами исходного кода, определяющими проект по 172 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ разработке ПО. Важнее всего, чтобы в исходном коде не было необходимости задания трудных для набора абсолютных путей доступа к файлам в директивах include import unit (C/C++), а также в операторах (Java) или (Паскаль). Вместо этого в операторах следует использовать относительные пути доступа к файлам, чтобы (многочисленные) рабочие копии файлов и проектов можно было созда вать в любом месте на локальном жестком диске разработчика. Размещение фай лов совместно используемого исходного кода по дереву каталогов – это своего рода искусство, поскольку каждый метод их расположения имеет свои преиму щества и недостатки и во многом зависит специфики архитектуры проекта. По этому довольно обычное явление – изменение структуры каталогов с исходными файлами по мере развития проекта. Однако не все системы VC правильно вос принимают переименование и перемещение файлов с исходным кодом. В статье под названием «The Version Control Process» («Процесс контроля версий», см. список рекомендованной литературы в конце раздела) проиллюстрирован один замечательный подход к размещению совместно используемых файлов исходно го кода и стилевых заголовочных C/C++ файлов. Дополнительные применения инструментальных средств сравнения копий Для обеспечения дополнительной безопасности и защиты исходного кода, а также его долговременного хранения я иногда выполняю резервное копирова ние своих архивов на центральном файловом сервере, а рабочих файлов со сво его ПК – на записываемый CD. Диски CD отлично подходят для этой цели, так как имеют наиболее длительный срок хранения по сравнению с другими сред ствами резервного копирования. Однако в силу различных причин программам для записи CD иногда не удается сделать точную копию файла. Именно здесь такие инструментальные средства, как Microsoft WinDiff (см. список ресурсов ниже) или другие дают гарантию выполнения резервного копирования, кото рая необходима при удалении старых версий файлов с вашего жесткого диска. WinDiff считывает (и сверяет с оригиналом) каждый отдельный байт на новом CD, чтобы подтвердить: все файлы были скопированы правильно. Уверенность при удалении старых версий кода эффективно экономит время разработчика и тем самым повышает продуктивность, а также помогает сконцентрировать ос новное внимание на главном проекте. Еще одно полезное применение утилиты WinDiff – проверка того, какие фай лы были скопированы при установке нового программного обеспечения (ин струментальных средств) на критически важный ПК. Это позволяет не толь ко лучше понять, как работает новое инструментальное средство, но и помочь разобраться в причинах несовместимости различных приложений, которая была и по-прежнему остается серьезной проблемой операционных систем корпорации Microsoft. Например, установка нового компилятора или другого инструмен тального средства разработки ПО может потребовать копирования множества файлов в определенный каталог операционной системы. Чтобы выяснить, ка кие именно файлы и где были установлены, используйте рекурсивный листинг каталогов и перенаправьте вывод в файл. Например, введите команду «dir /s/a c: > before.dir», установите новое и сположить эти окна на экране одно под 174 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ другим и прокручивать содержимое этих окон вперед и назад. Различающиеся фрагменты кода (если такие есть) сразу же бросятся в глаза. Полностью рабочие копии Неплохая идея – включить в систему VC все файлы – библиотеки, драйверы устройств, конфигурационные файлы (.ini) и т. д.,– необходимые для компиля ции, тестирования и запуска проекта в системе. Это гарантирует, что с помощью системы VC можно будет мгновенно подготовить к использованию полностью рабочую копию проекта. Множество рабочих копий Довольно распространенная практика – держать множество рабочих копий проекта на локальном ПК. Каждая рабочая копия содержит различные выпуски проекта. Если у вас под рукой имеются рабочие копии как предыдущего, так и нового выпуска программы – это облегчит подготовку списка внесенных в но вый выпуск изменений. Инструментальное средство сравнения копий укажет все фрагменты кода, в которые были внесены изменения между этими выпусками программного обеспечения. Это значительно упростит документирование изме нений для каждого нового выпуска. Множественные рабочие копии также очень удобны при локализации ошибок в предыдущих выпусках программы. Более то го, я часто создаю новую рабочую копию проекта сразу же по завершении работы над новым выпуском. Затем с помощью инструментального средства сравнения копий я проверяю идентичность рабочей копии нового выпуска и только что созданной рабочей копии. В идеале они должны совпадать на 100%. Неточное соответствие этих копий может служить признаком того, что вы добавили новый исходный код в файлы проекта, но забыли загрузить эти изменения в систему контроля версий. Руководство по стилю и соглашение о кодировании Оба названия относятся к одному из важнейших документов в управлении конфигурацией, который на обычном языке разъясняет требования к стилю кодирования программы, чтобы программисты, работающие в одной компании или над одним проектом, понимали исходный код, созданный их коллегами. Ру ководство помогает оформить всю программу в согласованном формате и тем самым повышает общее качество исходного кода. На эту тему написано мно жество статей и книг, и очень важно запомнить, что в каждом проекте должно быть принято соглашение о кодировании. Соглашение о кодировании нужно включить в систему VC, чтобы отслеживать его развитие. Стоит отметить, что при разработке исходного кода необходимо думать о человеке, а не о машине. И руководство по стилю программирования помогает достичь этой цели. Отслеживание ошибок Отслеживание ошибок (Bug tracking, BT) сопровождает проект на протяжении всего его жизненного цикла – как в прошлом и настоящем, так и в будущем. Возможность проследить историю проблемы помогает службе поддержки поль ОТСЛЕЖИВАНИЕ ОШИБОК 175 зователей определить, была ли, например, указанная ошибка и в той версии про граммы, с которой в настоящее время работает заказчик. Что касается настояще го, то это помогает руководителю установить, какие проблемы в данный момент устраняются или для каких проблем реализуются (разрабатываются) решения. Элементы будущего представлены запросами о разработке новых функциональ ных возможностей («перечень пожеланий») или идеями о новой продукции – и то, и другое формирует базу для будущих выпусков ПО, что, в свою очередь, обеспечит прибыль, необходимую для поддержки проекта по разработке про граммного обеспечения. BT также называют отслеживанием дефектов. Оба термина немного вводят в заблуждение, поскольку предполагают наличие проблем. Да, отслеживание проблем жизненно необходимо. Однако не менее важны и заслуживают внима ния заявки на расширение функциональных возможностей, пожелания заказчи ков, идеи программистов, возникшие в процессе разработки или тестирования, результаты тестирования, наблюдения торгового персонала и т. п. Одним словом, проблемы любого рода, описывающие поведение предшествующих версий и спо собные улучшить будущие выпуски программы. Отслеживание этих проблем – задание, предполагающее использование в основном базы данных с акцентом на мощные возможности запросов к ней. BT-приложения предоставляют центра лизованную базу данных для наблюдения за вышеупомянутыми проблемами. В идеальном случае она должна предоставлять простой доступ к информации любому участнику проекта по разработке ПО, т. е. разработчикам, специалистам по тестированию, руководителям, сотрудникам службы поддержки пользовате лей и торговому персоналу. И, конечно же, пользователь также должен иметь (ограниченный) доступ к такой базе данных. В последнее время были значительно усовершенствованы технология баз дан ных (серверы), локальных и глобальных сетей, а также (тонкие) клиенты, спо собные работать на любых настольных ПК. Итак, технологии имеются (уже на протяжении многих лет), а ПО, отслеживающее ошибки, все еще отстает от при ложений, осуществляющих контроль версий, и лишь отдельные программные пакеты обеспечивают тесную или полную интеграцию этих программ. Примером хорошей интеграции было бы единое клиентское ПО, предоставляющее доступ как к VC-архивам, так и к базе данных BT. Еще одним примером могла бы стать возможность простой локализации кода, связанного с определенной ошибкой. Одним из аргументов для этого служит тот факт, что система BT определена не так четко, как система VC. Эффективное отслеживание ошибок требует создания реальной базы данных с архитектурой клиент/сервер (против значительно более простого архива специального назначения или репозитория, обычно используе мого системами VC). Еще одной проблемой может стать различие требований рабочих групп к этой базе данных, например, какие поля следует включать в от чет об ошибке (дата, время, кто сообщил об ошибке, статус и т. д.), возможность управления типами отчетов, простота построения запросов, аппаратные требова ния к серверу базы данных и к работе администратора базы данных. Не менее важна возможность определить, какой конкретный дефект (характе ристика) или функция присутствует в указанной версии продукции. Так служ ба поддержки пользователей сможет быстро ответить на конкретные вопросы. 176 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ Я не очень много работал с инструментальными средствами BT, и мои проек ты и продуктивность сильно страдали от этого. Тот факт, что для установки и конфигурирования в вашей среде инструментальных средств BT требуются некоторые усилия, не может служить оправданием для отказа от использова ния этого важнейшего инструментария. В настоящее время я работаю над этой проблемой и планирую представить отчет об этом в следующих публикациях и презентациях. Неконфигурационные средства управления ПО для зеркального отображения информации Большинство редакторов при сохранении файла позволяет переименовывать те кущую версию документа, заменяя тип файла на .bak (сокращение от backup – резервная копия). Это, как минимум, позволяет восстановить предыдущую ко пию файла в том случае, если вы ошиблись, или ваш ПК завис во время редакти рования исходного кода. Дальнейшее развитие этой идеи – редакторы исходного кода (например, Borland BC5 IDE), которые автоматически сохраняют ваш теку щий файл в двух местах. Такая возможность позволяет восстановить файл как в случае отказа оборудования, так и при программном сбое. Я не могу понять, почему эта простая функциональная возможность (сохранение второй копии текущего файла в другом перенастраиваемом каталоге, желательно на другом физическом диске), которую к тому же легко реализовать, поддерживается не всеми редакторами исходного кода. Однако существуют автономные программы других производителей, автоматически сохраняющие зеркальную копию любого файла, в который внесены исправления. Одна из таких программ – AutoSave компании V Communications (см. список ресурсов ниже). Автоматизированное резервное копирование Разработчики ПО не должны беспокоиться о резервном копировании результа тов своей ежедневной работы. Резервное копирование информации на дискеты или другие съемные носители – не лучший выход, он может привести к воз никновению множества проблем. Совершенно необходимой функциональной возможностью является централизованное резервное копирование архивов ПО, репозиториев и баз данных. Существует множество приложений, выполняющих эту операцию. Если же регулярное резервное копирование этих критически важ ных данных не проводится, позаботьтесь о создании резервной копии на дискете. Возможно, она вам вскоре пригодится. Веб-браузер Веб-браузеры – обязательное программное средство, необходимое для доступа ко всем возможным видам информационной поддержки, в том числе поддержки продукции и всем видам технической поддержки. Это ПО упомянуто здесь по очевидной причине и для полноты описания. ЗАКЛЮЧИТЕЛЬНЫЕ КОММЕНТАРИИ 177 Группы новостей в Интернете Группы новостей появились еще на заре Интернета. Их более информативное название дискуссионные группы. Эти группы предназначены для обмена со общениями и используют сетевой протокол передачи новостей (NNTP). Сегод ня существует два типа серверов новостей: первый из них – это зависящие от поставщика автономные серверы, которые поддерживают одну или несколько групп новостей, посвященных продукции, предлагаемой данным производите лем. Все, что нужно для доступа к этим серверам новостей, – их адрес, информа ция о котором обычно размещается на веб-странице поддержки продукции (см. список ресурсов ниже). Подключившись к серверу, очень легко найти нужную группу новостей, поскольку названия этих групп очень информативны и число их обычно не превышает нескольких десятков. Традиционные серверы новостей, с другой стороны, связаны друг с другом через всемирную сеть. Зачастую они содержат десятки тысяч групп новостей и поддерживаются поставщиком услуг Интернет (Internet Service Provider, ISP). Типичной группой новостей является comp.lang.c, предназначенная для программистов, пишущих на языке C. Сущест вуют также модерируемые (цензурированные) группы новостей, в которых от фильтровывается весь спам (так на компьютерном сленге называется нежела тельная рекламная рассылка и другие, не имеющие отношения к теме, навяз чивые электронные сообщения). Группы новостей – отличный (и бесплатный!) источник справочной информации по любым вопросам или проблемам, которые могут возникнуть у вас. Ответ на свои утренние сообщения часто можно найти уже в обед, а ответы на вопросы, которые вы задали в конце рабочего дня, поч ти наверняка поступят в течение ночи. Вы обнаружите, что вам пишут из всех уголков мира (Россия, Германия, Новая Зеландия, Индия – перечень далеко не полный). Нередко, просматривая группу новостей, вы будете видеть заданные вопросы, на которые вы сами можете ответить и в свою очередь помочь кому-то улучшить программный код. Средства для чтения новостей доступны как авто номно, так и в составе большинства веб-браузеров. Весьма вероятно, что один из таких модулей уже установлен на вашем ПК и «ждет», когда вы начнете его использовать. Разработчики ПО для встраиваемых систем часто работают изолированно или в составе небольших групп. Средства для чтения новостей открывают им двери в мир взаимопомощи и поддержки и поэтому являются важнейшим инструментарием для любого профессионального разработчика ПО. Заключительные комментарии Напоследок – обзор основных, актуальных и сегодня инструментальных средств управления конфигурацией. Все вышеупомянутые инструментальные средства в равной степени применимы как в проектах по разработке встраиваемых систем, так и во всех других проектах по профессиональной разработке ПО. Если вы уже используете средства контроля конфигураций и отслеживания ошибок, то може те оценить их значение; в противном случае – скорее всего, вы уже обнаружили, что вам чего-то не хватает. Существует широкий выбор хороших коммерческих 178 УСТАНОВКА И ИСПОЛЬЗОВАНИЕ СИСТЕМЫ КОНТРОЛЯ ВЕРСИЙ и бесплатных инструментальных средств. Если они реализованы правильно, то приятны в использовании, поскольку интуитивно вы будете чувствовать, что делаете все правильно для улучшения своего исходного кода и повышения про дуктивности! И наконец, учтите, управление конфигурацией – это не тяжкая обязанность, а непрерывно совершенствующийся процесс. Я хотел бы поблагодарить Мэри Хиллстром за ее преданную поддержку и Билла Литтмана за его великодушные советы и чтение корректуры данной публикации. У вас есть замечания? Не стесняйтесь отправить их мне по элек тронной почте. Рекомендованная литература, ссылки и ресурсы Книга William J. Brown, Hays W. McCormick III, Scott W. Thomas. Anit Patterns and Patterns in Software Configuration Management. Wiley, 1999. Доступна в элек тронном виде по адресу: http://www.wiley.com/compbooks/catalog/32929-0.htm . Книга Karl Fogel. Open Source Development with CVS. Coriolis. 1999. Ноябрь. Выдающаяся книга, в которой описаны как разработка приложений с открытым исходным кодом, так и бесплатная программа Concurrent Version System (CVS), используемая многими крупными и географически разделенными командами разработчиков ПО. CVS является наследницей широко известной системы конт роля версий RCS VC. Карл убедительно доказывает, что они очень близко связа ны. Главы его книги, посвященные CVS, защищены открытой лицензией GNU, с ними можно ознакомиться по адресу http://cvsbook.redbean.com . Доступна также по адресу http://www.coriolis.com/bookstore (в строке поиска наберите «Fogel»). Книга Steve McConnell. Code Complete, A Practical Handbook of Software Construction. Microsoft Press, 1993. Эта книга, ставшая классикой, все еще в про даже, ее название («Кодирование завершено. Практическое руководство по про граммированию») говорит само за себя, тема освещена всесторонне. С книгой можно ознакомиться по адресу: http://mspress.microsoft.com/books/28.htm . Статья Aspi Havewala. The Version Control Process. Dr. Dobb’s Journal. 1999. Май. С. 100. В статье есть раздел под названием «Finding a Home for Shared Code» («Правильное размещение совместно используемого кода»), иллюстри рующий замечательный подход к упорядочению файлов, содержащих совместно используемый исходный код и C/C++ стилевые заголовки. Размещена по адресу http://www.ddj.com/articles/1999/9905/9905toc.htm . Статья Alan Radding. Join The Team. InformationWeek. 1999. 4 окт. С. 1a. Све жая публикация по проблемам управления конфигурацией и доступным сред ствам параллельной разработки для географически разделенных рабочих групп. Относится к редкому сорту газетных публикаций, из которых можно многое узнать. Размещена по адресу: http://www.informationweek.com/755/55adtea.htm . WinDiff. Программное инструментальное средство корпорации Microsoft. WinDiff входит в состав пакета «Windows NT 4.0 Resource Kit Support Tools», который можно загрузить бесплатно. За более подробной информацией о фай лах для загрузки обращайтесь к базе знаний Microsoft Knowledge Base по адресу http://support.microsoft.com/support (статья Q206848). РЕКОМЕНДОВАННАЯ ЛИТЕРАТУРА, ССЫЛКИ И РЕСУРСЫ 179 AutoSave. Программное инструментальное средство компании Innovative Software. Для получения дополнительной информации об этой недорогой ути лите посетите ее веб-страничку http://www.innovativesoftware.com/ , сведения о рас пространителях можно найти по адресу http://www.v-com.com/ . comp.software.config-mgmt. Группа новостей, поддерживаемая всеми тради ционными серверами новостей. Участники этой группы очень активны и посто янно обновляют раздел «Часто задаваемые вопросы» (FAQ). Это форум для об суждения тем, связанных с управлением конфигурацией, а также с выполнени ем бюрократических процедур и инструментальных средств, используемых для реализации стратегии управления конфигурацией. Если ваш поставщик услуг Интернета не поддерживает серверы новостей, или если вы не имеете доступа к программе для чтения новостей, ответы на часто задаваемые вопросы можно найти по адресу http://www.faqs.org/ . microsoft.public.visual.sourcesafe. Группа новостей, поддерживаемая только поставщиком специального сервера новостей «msnews.microsoft.com». Она по священа пакету Microsoft Visual Source Safe. Как оказалось, в этой группе но востей не ведется раздел FAQ и нет активных MVP. Коротко говоря, MVP – это те, кого корпорация отметила за их готовность делиться своими знаниями в личных контактах. Кажется, MVP никогда не устают отвечать на вопросы по электронной почте. В большинстве случаев в течение нескольких часов вы полу чите множество ответов на любой вопрос. borland.public.teamsource. Группа новостей, поддерживаемая только постав щиком специального сервера новостей «forums.inprise.com». Она посвящена про граммному пакету компании Borland (или Inprise) TeamSource. В этой группе также не поддерживается раздел FAQ. Она очень активна и управляется пер соналом компании Borland и участниками группы TeamB. Участники группы TeamB – это неоплачиваемые профессионалы-добровольцы, выбранные компа нией Borland, они не являются сотрудниками Borland и высказывают свое мне ние практически по всем аспектам, связанным с присутствием продукции компа нии Borland на рынке, включая в числе прочего: разработку программ, маркетинг и поддержку пользователей. Участники группы TeamB неутомимо отвечают на вопросы по электронной почте. РАЗДЕЛ СТРАНИЦА I Основы оборудования 18 II Проектирование 72 III Математика IV Системы реального времени 232 V Ошибки и исправления 312 185 Глава 11. Введение в машинные вычисления 208 Глава 12. Аппроксимации для вычислений с плавающей запятой 227 Глава 13. Математические функции 229 Глава 14. Стандарт IEEE 754 для чисел с плавающей запятой Введение Джек Ганссл В этом разделе содержится полезная информация для тех, кто пишет программ a = 3 + b. ный код, вроде Другими словами – для всех. Очень важна глава Грега Массея «Введение в машинные вычисления» опи сывает идеи, которые должен понимать каждый программист, разрабатывающий встраиваемое ПО. Мы используем наши компиляторы как черные ящики, на деясь: они знают, что нам нужно… хотя обычно это не так. Удивительный язык: результатом операции 20 000 плюс 20 000 оказывается отрицательное значение int)! (для переменных типа Математика, действующая за кулисами вычислений, очень коварна: переполнения, потери значащих разрядов и другие эффекты мо гут значительно исказить ожидаемые вами результаты. В главах, написанных вашим покорным слугой, предложен альтернативный взгляд на некоторые операции над числами с плавающей запятой и целыми числами. Не стоит думать, что единственный способ решить проблему лежит на пути использования стандартных библиотек компилятора. Рассмотрим сле дующий график: На нем представлено время, затраченное на вычисления косинуса по алго ритму, используемому коммерческим компилятором. По горизонтальной оси отложено время. Обратите внимание: затраты времени постоянно изменяются! При создании системы реального времени важно обеспечить не только своевре менность вычислений, но и предсказуемость ее работы. Применяя функцию, по добную описанной выше, мы должны учитывать наихудшую по времени оценку времени ее работы. Существуют и другие алгоритмы, обеспечивающие иное соотношение ско рость/точность вычислений. Большинство из них ведет себя более предсказуемо. Тщательно подбирайте свои алгоритмы, не падайте духом, если предлагаемая поставщиком компилятора библиотечная функция не соответствует вашим тре бованиям. Существует множество альтернативных вариантов. Глава 11. ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ Грегори У. Массей Грег Массей – разработчик встраиваемого ПО в подразделении Cable Networks компании Acterna. Профессионально занимается компьютерами более 15 лет – его деятельность связана с тестовыми, измерительными, коммуникационными приложениями, а также приложениями для автомобильной и военной промышленности, для обеспечения безопасности и автоматизации производства на предприятии. Он познакомился с компьютерами в Клемсонском университете, где получил степень магистра математики. Среди его нецифровых увлечений – семья, церковь, классическая музыка (игра на саксофоне и скрипке). Электронный адрес Грега: greg. [email protected] Введение Совершенствование языков программирования, компиляторов, оборудования, а также стандартов все больше упрощает задачу выполнения встраиваемыми системами математических расчетов. Но даже с учетом этих улучшений расчеты далеко не всегда проводятся так, как мы того ожидаем. В этой главе сравниваются разные типы машинных вычислений – с целыми числами, с фиксированной запятой и с плавающей запятой – в аспекте универ сальности, точности и скорости. Уделяется внимание источникам возникновения ошибок при каждом типе вычислений и способам их исправления. Рассматри ваются преобразование типов, эффекты переполнения, приемы, используемые при реализации, размеры определяемых пользователем целых переменных и за висимость реализации от оборудования. Показано, как реализовать вычисления с фиксированной запятой при помощи целых чисел и как приспособить их для своих потребностей. Основной акцент сделан на простоте и практичности. При меры приводятся на языке C, хотя изложенные идеи в равной степени справед ливы и для других языков программирования. Целочисленная арифметика Двоичная арифметика целых чисел так же стара и так же известна, как и сами компьютеры. Однако до сих пор здесь таятся некоторые сюрпризы, способные вызвать затруднения у разработчиков встраиваемого ПО. Деление и отрицательные числа Рассмотрим работу следующего простого цикла: int i; for (i = –8; i < 8; ++i) { ДЕЛЕНИЕ И ОТРИЦАТЕЛЬНЫЕ ЧИСЛА 183 printf(«%3d,», i / 4); } Считается, что при целочисленном делении дроби усекаются. Мы знаем, что в целых числах 7/4 – это не 1 / , а 1. Дробная часть отбрасывается. В операторе 3 4 печати все целые числа делятся на 4, поэтому можно было бы ожидать появле ния на печати четверок для каждого возможного целого значения: –2, –2, –2, –2, –1, –1, –1, –1, 0, 0, 0, 0, 1, 1, 1, 1. Однако вместо этого в результатах печати мы увидим одну двойку и семь нулей: –2, –1, –1, –1, –1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1. Отличие результатов обусловлено правилом, используемым при целочислен ном делении для целых отрицательных частных. Если в результате деления по лучается –7/4, частное не округляется до –2, а усекается по направлению к нулю, давая в результате – 1. Почему это так важно? Предположим, что операция деления – это часть опе рации масштабирования в цифровом термометре. Информация, поступающая с аналогово-цифрового преобразователя, должна быть преобразована в значения, подходящие для отображения либо в шкале Цельсия, либо в шкале Фаренгейта. Отсчеты аналогово-цифрового преобразователя не соответствуют целым значе ниям числа градусов, а результаты измерений более точны, чем требуется для отображения на дисплее. После пересчета масштаба все выходные значения должны иметь равный вес, однако, как иллюстрирует приведенный ниже рису нок, это не так: Идеальное масштабирование вывода Сигнал аналогово–цифрового преобразователя Масштабированный сигнал для дисплея Операция пересчета масштаба преобразует значение, соответствующее каж дому отсчету, к ближайшему целому числу для отображения на экране. Иногда в одно и то же отображаемое значение преобразуются три отсчета, иногда – че тыре. Если алгоритм пересчета масштаба использует целочисленное деление, усекающее дробь по направлению к нулю, значению 0 будет соответствовать в два раза большее число отсчетов по сравнению с другими значениями. Такой уклон в сторону 0 может оказаться серьезной проблемой для любого измерительного прибора, выводящего как положительные, так и отрицательные значения. Ситуация станет еще хуже, если мы захотим использовать деление с округлением вместо усечения. Допустим, что результаты измерений представ лены в милливольтах, мы решили разделить их на 1000, чтобы получить значе ние, выраженное в вольтах. В табл. 11.1 показано, что мы ожидаем увидеть и что получ зон –10 000…10 000. Для хранения данных ДЕЛЕНИЕ И ОТРИЦАТЕЛЬНЫЕ ЧИСЛА 185 в этом случае достаточно двухбайтовой переменной с областью допустимых зна чений –32 768…32 767. После прибавления смещения наименьшим возможным значением станет 0, а наибольшим 20 000. Та же самая двухбайтовая переменная целого типа подойдет и для этого дополнительного диапазона, однако в некото рых случаях для получения результата может потребоваться более вместитель ный целый тип. На втором шаге мы добавили половину делителя. Этот шаг позволяет провес ти округление. Он работает правильно, даже если делитель является нечетным числом. Результат этой операции не превысит 20 500, так что мы по-прежнему сможем использовать двухбайтовую целую переменную со знаком. На шаге три мы выполнили обычное целочисленное деление. Оно не сможет произвести усечение отрицательного числа по направлению к нулю, поскольку смещения первых двух шагов гарантируют, что мы всегда будем иметь дело с по ложительными числами. На четвертом шаге мы удалили смещение. Поскольку введенное значение было разделено на 1000, смещение, которое мы должны вычесть, также должно составить 1/1000 от первоначального смещения. Смещение, использованное на первом и четвертом шаге, не обязательно долж но равняться наибольшему ожидаемому значению, оно может превышать его, если это не приведет к переполнению использованной переменной целого типа. При таком подходе можно написать одну функцию деления, подходящую во многих случаях. Усечение по направлению к нулю выполняется также при преобразовании переменной, имеющей тип с плавающей запятой, к целому типу. В языках C float и C++ можно безопасно округлять значения с плавающей запятой (типа double) или до ближайшего целого с помощью этого преобразования: int IntVal = (int) floor(FloatVal + 0,5); Добавляем 0,5, чтобы значения с дробной частью, равной / или большей, 1 2 округлялись до следующего целого числа (в сторону увеличения). Функция floor double, возвращает значение типа которым будет наибольшее целое число, не превышающее входного значения. Целые типы и их размер В табл. 11.2 приведены типичные размеры различных целочисленных типов, поддерживаемые большинством компиляторов C и C++ для микропроцессоров: Таблица 11.2. Типичные размеры целочисленных типов Диапазон значений Диапазон значений Размер, знакового типа беззнакового типа Тип данных бит Min Max Min Max Char 8 –128 127 0 255 Short 16 –32 768 32 767 0 65 535 Long 32 –2 147 483 648 2 147 483 647 0 4 294 967 295 Определяется пользователем n –2 2 –1 0 2 –1 n–1 n–1 n 186 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ int Тип должен иметь размер не менее 16 битов. Обычно его размер составляет 16 битов для 8-разрядных и 16-разрядных процессоров и 32 бита для 32-разрядных процессоров. Чаще всего это наилучший тип для переменных, где размер не явля int ется критически важным параметром, поскольку для типа компилятор исполь зует такой размер, который сможет реализовать наиболее эффективным образом. Последняя строка табл. 11.2 позволяет определить точное количество битов, необходимое в особых ситуациях. Например, представим, что вам необходимо пересылать большие массивы целых чисел по каналам передачи данных. Вы мо жете значительно повысить пропускную способность системы, определив поль зовательский тип размера, который будет достаточным для того, чтобы в нем можно было хранить значения именно того диапазона, который требуется. По добный тип можно реализовать с помощью битовых полей на языке C и C++ или с помощью операций сдвига разряда и маскирования. И еще об одном аспекте целочисленного типа – о порядке байтов. Когда мик ропроцессоры только разрабатывались, одни компании решили сначала разме щать в памяти младший байт целого числа, а другие – старший байт. Эти форма ты получили название (little-endian) и обратный прямой порядок байтов порядок (big-endian), соответственно. байтов Порядок байтов в целых переменных может порождать проблемы, если дан ные пересылаются между процессорами с различным порядком байтов либо по переменно интерпретируются одним и тем же процессором как значения разных типов, среди которых есть целый. Копирование, проверка на равенство и по битовые операции работают с обоими форматами правильно, если только не производится преобразование типов (short в long и т. п.). При выполнении дру гих операций необходимо восстановить поддерживаемый процессором порядок байтов в целой переменной. Переполнение или исчезновение значащих разрядов При выполнении операций с целыми числами переполнение или исчезновение значащих порядков происходит, если результат вычислений превышает мак симально допустимое для данного типа значение или же оказывается меньше минимально допустимого. На большинстве платформ это не приводит к возник новению исключительных ситуаций или выдаче предупреждений. Вместо этого число «оборачивается». Самый старший бит или биты результата отбрасывают ся, остаются лишь биты, умещающиеся в формате данного типа. Все сохранив шиеся биты имеют верное значение. Математически «обернутый» результат W можно получить из ожидаемого с помощью уравнения E × W = E – 2 k, n где n – размер данного типа в битах, k – целое число, необходимое для того, чтобы W попало в допустимый для данного типа диапазон значений. В табл. 11.3 продемонстрировано поведение однобайтовых целых переменных при перепол нении или исчезновении значащих разрядов: ПЕРЕПОЛНЕНИЕ ИЛИ ИСЧЕЗНОВЕНИЕ ЗНАЧАЩИХ РАЗРЯДОВ 187 Таблица 11.3. Переполнение и исчезновение значащих разрядов в однобайтовых переменных Операция Поведение переменной типа Поведение переменной типа unsigned signed char Инкремент … 254, 255, 0, 1, … … 126, 127, –128, –127, … Декремент … 1, 0, 255, 254, … … –127, –128, 127, 126, … Увеличение на 0, 100, 200, 44, 144, … 0, 100, –56, 44, –112, … 100 Умножение на 10 1, 10, 100, 232, 16, 160, … 1, 10, 100, –24, 16, –96, … Иногда программисты сознательно используют эффект «обертывания» целых чисел в своих приложениях. Рассмотрим систему планирования событий для их последующей обработки. В ней имеется таймер, периодически увеличивающий значение целой переменной на единицу. Внесенному в расписание событию при сваивается метка, соответствующая времени его предполагаемой обработки. По скольку речь идет о встраиваемой системе, она должна правильно обрабатывать переполнение таймера. Следующий замысел позволяет с выгодой использовать переполнение целой переменной и срабатывает для любых значений задержки события, которые меньше половины максимально допустимого значения таймера. Показания таймера хранятся в беззнаковой целой переменной CurrentTime. Ее начальное значение 0 периодически инкрементируется и, поскольку речь идет о на дежной встраиваемой системе, работающей всегда без каких бы то ни было проб лем, значение таймера в конце концов переполнится и «обернется» вокруг нуля. Когда системе потребуется запланировать событие, которое наступит некото рое время спустя, она вычисляет время: EventTime = CurrentTime + EventDelay; используя беззнаковые целые переменные. Иногда при сложении текущего вре мени с временем задержки будет происходить переполнение и «обертывание» таймера, в результате метка будет указывать на время наступления события, меньшее текущего времени. Система записывает новое событие в список запланированных событий, ожи дающих обработки. Ей нужно поместить новое событие после запланированных событий, которые произойдут раньше данного, и перед теми, которые наступят позже. Единственная проблема заключается в том, что время наступления со бытия может «обернуться». Алгоритм вставки должен просмотреть список с по мощью следующего простого сравнения: unsigned int Difference = NewEventTime – CurrentEventTime; if ((int) Difference > 0) { . . . // Перейти к следующему событию в списке. } else { . . . // Вставить новое со 00 100 100 3 33 000 33 001 –1 65 535 –1 МАТЕМАТИЧЕСКИЕ ОПЕРАЦИИ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ 189 Наш алгоритм приведет к вставке нового элемента в список после второго int события. Преобразование разности к знаковому типу позволяет системе пра вильно определить, в какую точку расписания необходимо вставить событие. Система может периодически выполнять проверку, чтобы узнать, не наступи ло ли время для начала обработки первого события в списке. В данном списке одному времени могут соответствовать несколько событий, кроме того, система могла пропустить точное время начала обработки назначенного события, по этому для обработки всех событий, запланированное время которых не меньше значения текущего времени, система использует следующий алгоритм: unsigned int Difference = CurrentTime – FirstEventTime; while ((int) Difference >= 0) { . . . // Удалить и обработать первый элемент списка Difference = CurrentTime – FirstEventTime; } При таком подходе даже нет необходимости переходить от знакового к без знаковому типу и обратно. Можно обрабатывать все времена и разности как знаковые целые величины. Хотя, если считать время беззнаковой величиной, все выглядит понятнее. Математические операции с плавающей запятой Неожиданный результат Математические операции с плавающей запятой – это очень мощный инстру мент, некоторые его возможности даже невозможно себе представить в цело численных операциях или операциях с фиксированной точкой, однако и здесь есть некоторые проблемы. Если разобраться в тонкостях, с этими проблемами можно справиться. Рассмотрим следующий фрагмент кода: float x = 0,0; float dx = 0,1; int i = 0; while (x != 1.0) { x += dx; i += 1; } Он выглядит как цикл, который должен выполниться 10 раз и завершиться при x = 1,0 и i = 10. К сожалению, этот цикл будет выполняться вечно. Если про верить значение переменной x после 10 итераций, мы получим 1,00000011920. Условие завершения цикла требует продолжать итерации до тех пор, пока зна чение переменной не станет в точности равным 1,00000000000. Этим и объ x ясняется бесконечность цикла. 190 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ float Похоже, проблема в недостаточной точности. Переменные типа занима ют 4 байта. Сможем ли мы решить проблему, изменив тип переменных x и dx на double, который резервирует 8 байтов для хранения переменной? К сожалению, нет. И в этом случае программа будет выполняться вечно. После 10 итераций x имеет значение 0,999999999999999890. Оно намного точнее и содержит 15 вер ных десятичных разрядов вместо 6. Но этого все еще недостаточно. float, Программист, использующий тип может заменить в условии окончания цикла сравнение != (не равно) на < (меньше), и проблема будет решена. Однако double это решение непригодно в общем случае – с переменными типа цикл будет выполняться неверное число раз. При других значениях переменной dx такой подход также не будет работать. Лучшим решением этой проблемы будет изменение условия окончания цикла на Это сработает для любых типов: x < 0,95. float, double. и и Мы ожидаем, что после 9-й итерации x будет иметь значение 0,9, а после 10-й – 1,0, так что такой подход работает при любых погрешностях в значении переменной x, меньших 0,05. В наших примерах погрешности были значительно ниже этой величины. Проблема, с которой мы столкнулись в этом примере, решается легко, однако при этом возникает ряд вопросов: • • Откуда берутся погрешности? • • Какой может быть величина этих погрешностей? • • Как предсказать появление подобных погрешностей? • • Как разработать решение для учета этих погрешностей? Форматы с плавающей запятой Чтобы ответить на первый вопрос, нам понадобится разобраться в том, как представляются числа с плавающей запятой в компьютере. Большинство со временных реализаций чисел с плавающей запятой удовлетворяет требованиям документа IEEE 754 – стандарта для двоичных вычислений с плавающей запя той. В этом стандарте определены два размера форматов с плавающей запятой и минимальные требования для двух других дополнительных размеров. Число с плавающей запятой состоит из трех частей: знакового разряда, ман тиссы и порядка. Вот стандартные форматы (согласно документу IEEE 754): Таблица 11.7. Стандартные форматы представления чисел с плавающей запятой Знак Порядок Мантисса float 1 разряд 8 разрядов 23 разряда double 1 разряд 11 разрядов 52 разряда Знаковый разряд равен 0 для положительных чисел и 1 для отрицательных. (Ноль – это особый случай; +0 и –0 представлены по-разному, однако должны обрабатываться как равные значения.) Мантисса и порядок имеют примерно тот же смысл, что и в стандартном (экс поненциальном) представлении числа. Мантисса записывается в двоичном виде, а порядок показывает, на сколько разрядов вправо или влево сдвинута мантисса. Однако обе эти величины не являются точной копией стандартных мантиссы МАТЕМАТИЧЕСКИЕ ОПЕРАЦИИ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ 191 и порядка. Во-первых, они записаны в двоичной, а не в десятичной системе счисления, поэтому каждая цифра занимает двоичный, а не десятичный разряд. Вместо десятичной запятой используется двоичная запятая, разделяющая це лую и дробную части числа. Во-вторых, значения, записанные в поле порядка и в поле мантиссы, не являются точным представлением стандартных порядка и мантиссы. Стандартная мантисса имеет две формы: нормализованную и ненормализо ванную. Нормализованная форма используется для всех чисел, за исключением очень маленьких. Показатель выбирается таким, чтобы целая часть числа рав нялась единице. (Сравните с экспоненциальной записью чисел, в которой перед десятичной запятой стоит одна цифра, отличная от нуля.) Поскольку целая часть числа всегда равна единице, нет необходимости хранить этот разряд в памяти. Поэтому в поле мантиссы записывается только ее дробная часть. Стандартный порядок может иметь как положительное, так и отрицатель ное значение. Вместо того чтобы записывать в поле порядка дополнение до двух (как представляют целые знаковые отрицательные числа), сюда всегда заносится беззнаковое целое значение. Стандарт предписывает использование смещения, которое должно быть вычтено из беззнакового значения, чтобы полу чить знаковое значение порядка. (Смещение позволяет проектировщикам рас ширить диапазон в сторону положительных порядков. Диапазон отрицательных порядков уменьшен, однако эта потеря компенсируется изменением формата мантиссы.) Итак, мы получили систему для представления положительных и отрица тельных чисел в широком диапазоне – с большим и малым модулем. Однако для полноты этой системы необходимо нулевое значение. Требуется также пред ставление для сигнализации о переполнении и о различных ошибках. Порядок, состоящий только из нулей или только из единиц, используется как признак того, что мантисса находится в одном из специальных состояний. В табл. 11.8 приведены специальные значения и форматы, определенные стандартом: Таблица 11.8. Представление специальных значений Знак Порядок Мантисса Значение 0, 1 00…0 00…0 Ноль (+0 или –0) 0, 1 00…0 от 00…1 до 11…1 Ненормализованные числа для представления значений очень малой величины. Предполагается, что целая часть мантиссы равна 0 0, 1 от 00…1 до от 00…0 до 11…1 Нормализованные числа для представления 11…0 подавляющего большинства значений с плавающей запятой. Предполагается, что целая часть мантиссы равна 1 0, 1 11…1 00…0 ± бесконечность в зависимости от значения знакового разряда 1 11…1 10…0 Неопределенное (+∞ + –∞ или ±∞ × 0) 0 11…1 любая NaN (not a number – не число). Может представлять неинициализированные данные и т. п. 1 11…1 Любая, кроме 10…0 192 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ В табл. 11.9 приведена дополнительная информация о форматах по стандарту IEEE 754: Таблица 11.9. Дополнительная информация о представлении чисел в форматах с плавающей запятой Свойство float double Размер 4 байта 8 байтов Размер нормализованной 24 разряда 53 разряда мантиссы (с учетом подразумеваемой «1») Диапазон значений от 1 до (2 – 2 ) от 1 до (2 – 2 ) –23 –52 нормализованной мантиссы Эквивалентная десятичная более 7 разрядов более 15 разрядов точность Размер порядка 8 разрядов 11 разрядов Смещение порядка 127 1023 Диапазон значений порядка от –126 до 127 от –1022 до 1023 Числовой диапазон 0, от ±2 до ≈2 0, от ±2 до ≈2 –126 128 –1022 1024 при максимальной точности Эквивалентный десятичный 0, от ± ≈1,2×10 до ≈3,4×10 0, от ± ≈2,2×10 до ≈1,8×10 –38 38 –308 308 диапазон А теперь давайте рассмотрим представление числа 11 при использовании ти float. па Его значение положительно, поэтому знаковый разряд равен 0, Целая часть должна равняться 1, подберем порядок. Поскольку 11 = 1,375×2 , мантисса 3 равна 1,375, порядок 3. Чтобы записать мантиссу, начнем с искомого значения 1,375. Вычтем под разумеваемую 1 и получим 0,375. Этот результат меньше, чем 2 , поэтому за –1 пишем 0 в первый двоичный разряд. Наш результат не меньше, чем 2 , поэтому –2 запишем 1 в следующий разряд и вычтем 2 из 0,375, получим новое значение –2 0,125. Оно не меньше, чем 2 , поэтому запишем 1 в третий разряд и вычтем 2 . –3 –3 Полученный результат теперь равен 0, поэтому мы можем заполнить оставшиеся биты нулями. Чтобы получить порядок, добавим смещение 127 к искомому значению по рядка 3. Переведем результат 130 в двоичную систему счисления и получим 10000010. float Итак, число 11 в формате представляется следующим образом (табл. 11.10): Таблица 11.10. Представление числа 11 в формате float Знак Порядок Мантисса 11 float 0 10000010 01100000000000000000000 Погрешности округления А теперь, давайте получим представление числа 0,1. Нормализовав его, получим 0,1 = 1,6×2 . Добавим смещение к порядку: 123. Вычтем подразумеваемую 1 из –4 мантиссы: 0,6. Вычтем из этого числа 2 и получим 0,1. После вычитания 2 –1 –4 МАТЕМАТИЧЕСКИЕ ОПЕРАЦИИ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ 193 останется 0,0375, затем вычтем 2 и получим 0,00625 и т. д. После вычитания –5 2 значение разности будет достаточно большим, чтобы из него можно было –23 вычесть 2 . И здесь возникает проблема. У нас закончилось место в мантиссе. –24 Согласно стандарту IEEE мы должны округлить мантиссу до ближайшего зна чения; в данном случае получаем (табл. 11.11): Таблица 11.11. Представление числа 0,1 в формате float Знак Порядок Мантисса 0,10000000149 float 0 01111011 10011001100110011001101 Теперь понятно, почему возникла ошибка в цикле. Все очень просто – мы не можем точно представить в двоичном виде 0,1 в формате с плавающей запятой. Нужная нам мантисса является бесконечной периодической дробью, при любом размере представления с плавающей запятой оно будет усечено, и в итоге мы получим результат, слегка отличающийся от 0,1. Как только что было продемонстрировано, существуют числа, которые нельзя представить точно в формате с плавающей запятой. В двоичном представлении может возникнуть периодическая дробь, даже если в десятичном ее не было. Обобщим то, что мы только что наблюдали: при преобразовании в двоичную дробь любого числа, дробная часть которого не представима в виде слагаемых, являющихся степенями двойки, нельзя получить точное представление в фор мате с плавающей запятой. Это один из общих источников погрешностей, воз никающих при вычислениях с плавающей запятой. Подобный тип погрешности можно обнаружить при делении 2 на 5. И 2, и 5 можно точно представить в формате с плавающей запятой, а их частное 0,4 точ float ного представления не имеет. Результат для типа будет 0,40000000596. Разность обусловлена погрешностью округления: вычисленный результат, не имеющий точного представления в формате с плавающей запятой, округляет ся до ближайшего числа в этом формате. Стандарт IEEE 754 требует, чтобы вычисленный результат операций сложения, вычитания, умножения, деления и извлечения квадратного корня в формате с плавающей запятой был как можно ближе к теоретическому, поэтому результирующая ошибка не будет превышать / разряда. (До введения стандарта многие реализации операций 1 2 с плавающей запятой приводили к погрешностям величиной в один разряд или больше. Для того чтобы соответствовать этому требованию, процессор, выполняющий операции с плавающей запятой, или библиотека должны в дей ствительности проводить расчеты с использованием нескольких дополнитель ных разрядов.) Деление, описанное выше, имело погрешность 5,96×10 . Насколько плох этот –9 результат? Максимальная возможная погрешность для значений такого поряд float) ка (т. е. имеющая тот же порядок в представлении переменной типа со ставляет ± / от 23-го разряда. Это все равно, что ±1 в 24-м разряде. Порядок, 1 2 используемый для записи чисел от 0,25 до 0,5, равен –2 (до того, как к нему прибавят смещение), таким образом, максимальная погрешность составит ±2 –26 или около ±1,5×10 . –8 194 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ Погрешность ±1,5×10 будет слишком большой для вычислений, в которых –8 в результате получается 10 . А для больших чисел, например 10 , она будет –7 23 пренебрежимо мала. Другими словами, численное значение погрешности не дает нам достаточной информации. Определим как отношение абсолютной ошибки относительную погрешность к ожидаемому результату. Теперь относительная погрешность в нашей задаче вычисления частного 2 : 5 равна(1,5×10 ) / 0,4, или 3,75×10 . Относительная –8 –8 погрешность представления числа 0,1 имеет именно такое значение. Относитель ная погрешность избавляет нас от необходимости знать модуль ожидаемого ре зультата. При арифметических расчетах в самом худшем случае относительная погреш ность округления составит 6×10 при расчетах с одинарной точностью и около –8 1,1×10 при двойной точности вычислений. Это не так уж и плохо. Немногие –16 приборы способны измерять физические величины с точностью до 7-го знака, не говоря уже о 16 точных разрядах! Если бы погрешности вычислений с плавающей запятой не превышали этих величин, жизнь в мире машинных вычислений была бы просто замечательной. Однако погрешности могут быть значительно выше. Сначала мы рассмотрим кумулятивные эффекты при последовательном выполнении операций умноже ния и деления. Затем обратим внимание на гораздо более серьезную проблему, которая может возникнуть при сложении и вычитании. Ошибки при умножении и делении Несколько дополнительных замечаний помогут лучше понять следующий раз дел. Математики и специалисты по вычислительной технике определяют по ε грешность машинных вычислений («машинную эпсилон») как максимальное значение относительной погрешности, которая может возникнуть при инверти ровании младшего значащего разряда мантиссы. Таким образом, выполнение одиночной операции умножения или деления может привести к погрешности округления порядка ±ε/2. Последовательное выполнение умножений и деле n ний, каждое из которых использует результат предыдущей операции, может при вести к возникновению суммарной погрешности ±nε/2. Обычно суммарная по грешность значительно меньше этой оценки, поскольку различные погрешности могут иметь разные знаки и не все достигают максимально возможного значения. Используя полученную выше оценку суммарной погрешности, мы можем по лучить возможное количество разрядов, вычисленных неточно. Количество неточных разрядов: b = ceil(log n), S 2 × где n – число последовательных операций или /, а функция ceil(x) округляет в сторону увеличения нецелое значение x до ближайшего целого. Теперь опре делим Количество верных разрядов: b = b – b , G M S где b – количество разрядов в мантиссе, включая разряд с подразумеваемым M float, double. значением: 24 для типа 53 для типа МАТЕМАТИЧЕСКИЕ ОПЕРАЦИИ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ 195 Количество верных десятичных разрядов связано с количеством верных дво ичных разрядов в мантиссе соотношением × Количество верных десятичных разрядов: d = floor(b lg 2), G G где floor(x) – целая часть числа Немного алгебры – и в результате получим x. максимальное количество верных разрядов (n ) при последовательном выпол max × нении и /: n = 2 . (b –ceil(d /lg2) M G max Ниже приведена функция на языке С, выполняющая эти расчеты: int MaxMultDiv(int GoodDigits, int MantissaBits) { double Power = MantissaBits; Power –= ceil(GoodDigits / 0,30103); return (int) (pow(2.0, Power) + 0,5); } В табл. 11.12 приведены минимальные значения точности для мантисс двух распространенных размеров: Таблица 11.12. Минимальные значения точности Max допустимое количество операций × и / Количество точных разрядов float double 4 1024 5,5E+11 5 128 6,87E+10 6 16 8,59E+09 12 8192 13 512 14 64 15 8 Приведенные данные относятся к наиболее неблагоприятному случаю после довательного выполнения операций умножения и деления. Ваши результаты, вероятно, будут лучше. Ошибки при сложении и вычитании Рассмотрим следующий код: float pi = 3.14159265359; float k = 1000,0; float sum = pi + k; printf(«pi = %15.7fn», pi); printf(«sum = %15.7fn», sum); В результате его выполнения на печати появится: 196 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ pi = 3.1415927 sum = 1003.1416016 Второе значение явно неточное. Относительная погрешность мала. Как и при умножении и делении, точность результата гарантированно будет не хуже, чем ±ε/2. Тем не менее такая точность не может нас удовлетворить. Возможно, по тому, что мы можем сложить эти значения в уме вообще без погрешности. Этот простой пример показывает: если складываются или вычитаются значения с пла вающей запятой, сильно различающиеся по модулю, то число с меньшим модулем теряет свою точность. Продолжим рассмотрение этого примера. Давайте посмотрим, что получится π. при попытке восстановить значение числа Выполнив вычисления: float pi2 = sum – k; printf(«pi2 = %15.7fn», pi2); в результате получим: pi2 = 3.1416016 Ничего удивительного, если принять во внимание значение суммы – таким способом мы просто привлекли внимание к проблеме. Теперь вычисленное нами значение имеет только 5 верных значащих разрядов из-за неточности промежу точного результата вычислений. Давайте рассмотрим операции сложения и вычитания более детально. Ниже приведены мантиссы двух слагаемых, представленные в двоичном виде: × 3,1415927 = 1,100 1001 0000 1111 1101 1011 2 ; 1 × 1000 = 1,111 1010 0000 0000 0000 0000 2 . 9 При сложении показатели порядка чисел должны совпадать. Если для ман тиссы выполнить операцию сдвига вправо, то можно будет увеличить порядок на 1. При сдвиге на 8 разрядов вправо получим: × 3,1415927 = 0,000 0000 1100 1001 0000 1111 1101 1011 2 . 9 Теперь давайте сложим эти значения, в результате получим: × 1003,1415927 = 1,111 1010 1100 1001 0000 1111 1101 1011 2 . 9 В мантиссе содержится слишком много двоичных разрядов. Последние 8 цифр, набранные курсивом, должны быть отброшены. Согласно стандарту IEEE 754 результат должен быть округлен, а не усечен, поэтому получаем: × 1003,1416016 = 1,111 1010 1100 1001 0001 0000 2 . 9 Вычитая 1000, получим в итоге: × 3,1416016 = 0,000 0000 1100 1001 0001 0000 2 . 9 Мы должны сдвигать мантиссу влево до тех пор, пока в первом разряде не появится 1 (нормализация). При каждой операции сдвига порядок уменьшается МАТЕМАТИЧЕСКИЕ ОПЕРАЦИИ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ 197 на 1. У нас нет данных для сдвига в крайние справа разряды, поэтому мы запол ним их нулями. Результат, полученный при вычислении, приведен ниже вместе с правильным результатом: × 3,1416016 = 1,100 1001 0001 0000 0000 0000 2 ; 1 × 3,1415927 = 1,100 1001 0000 1111 1101 1011 2 . 1 Вычитание близких значений приводит к потере точности. Если и уменьшае мое, и вычитаемое имеют точное значение, результатом будет «мягкая» потеря точности. Если же, как в нашем примере, хотя бы одно из чисел имеет при ближенное значение, результатом будет катастрофическая потеря точности. Это правило применимо как к положительным, так и к отрицательным чис лам с плавающей запятой. Если два числа имеют близкие значения модулей, но различаются по знаку, их сложение приведет к потере точности. Если одно из слагаемых является приближенным значением, в результате возникнет катастро фическая потеря точности. Подведем итог. Сложение и вычитание могут приводить к возникновению ошибок. Степень серьезности ошибок зависит от знаков и модулей чисел, кото рые складываются или вычитаются, а также от того, являются ли они точными или приближенными значениями. В табл. 11.13 приведены ситуации, которые надо учитывать при сложении и вычитании: Таблица 11.13. Возможные ошибки при выполнении операций сложения и вычитания Модули Сложение Близки Различны Знаки Безопасно; ошибки не превышают Возможна потеря точности Одинаковы ±ε/2 значения, меньшего по модулю Противоположны Возможна потеря значащих разрядов Модули Вычитание Близки Различны Знаки Возможна потеря значащих Возможна потеря точности Одинаковы разрядов значения, меньшего по модулю Безопасно; ошибки не превышают Противоположны ±ε/2 Обработка ошибок при вычислениях с плавающей запятой Сравнение значений с плавающей запятой При необходимости сравнить вычисленное значение x с константой c запиши те условие так, чтобы выполнялась проверка на принадлежность этого значения к малой окрестности ожидаемого значения. Задайте допуск eps на основании float ожидаемой точности значения x. Для переменных типа это может быть × 0,00001. (Конечно, если равно нулю, использовать умножение для вычис c c ления eps нельзя.) При необходимости сравнить два вычисленных значения x и y допуск следует задать в виде доли от значения одного из этих чисел. Ис 198 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ пользуйте для этого коэффициент относительной погрешности rel, зависящий от точности используемого вами типа с плавающей запятой. Таблица 11.14. Предпочтительные операции сравнения значений с плавающей запятой Вместо Лучше использовать Комментарии if (x == c) if (fabs(x – c) < eps) if (x <= c) if (x < c + eps) «True», если условие выполнено if (x < c) if (x < c – eps) «False», если условие выполнено if (x == y) if (fabs(x – y)< x * rel) Для вычисления допустимой погрешности можно использовать как x, так и y Суммирование числовых последовательностей Во многих расчетах требуется вычислить сумму последовательности чисел. Часто члены с наибольшим модулем суммируются вначале, а наименьшие сла гаемые прибавляются последними. Если последовательность чисел заранее из вестна, можно составить программу так, чтобы слагаемые суммировались от наи меньших по модулю к наибольшим. Наилучшим подходом, особенно в том случае, если данные действительно от сортированы, будет суммирование по алгоритму Кахана: double KahanSum(double Term[], int NumTerms) { double Sum = Term[0]; double Adjustment = 0; double AdjustedTerm; double NewSum; for (int i = 1; i < NumTerms; ++i) { AdjustedTerm = Term[i] – Adjustment; NewSum = Sum + AdjustedTerm; Adjustment = (NewSum – Sum) – AdjustedTerm; Sum = NewSum; } return Sum; } Вычисление значений многочленов Вместо вычисления значений такого многочлена, как f(x) = 5x + 3x – 7x + 2x – 12, 4 3 2 с помощью возведения в степень лучше использовать эквивалентную функцию f(x) = ((5x + 3)x – 7)x + 2)x – 12, в которой степени числа вычисляются с помощью повторяющейся операции x умножения. Как правило, такой алгоритм не только работает быстрее, но и дает более точный результат. Эта небольшая уловка известна как схема Горнера. МАТЕМАТИЧЕСКИЕ ОПЕРАЦИИ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ 199 Альтернативные числовые форматы Представление в двоичной форме с плавающей запятой – не лучший выбор для некоторых приложений. Если необходимо точно представить такие числа, как 0,1, можно использовать десятичную запись с плавающей запятой. В этом случае для хранения каждой десятичной цифры мантиссы используется четыре двоичных разряда. Такое представление называется двоично-десятичным (BCD), формат, в котором каждый байт содержит две десятичных цифры, называется упакованным двоично-десятичным представлением (упакованный BCD). Од нако даже в том случае, когда в упакованном BCD формате использованы все разряды, память используется не так эффективно, как в двоичном виде с пла вающей запятой. float Например, в типе используется 23 разряда для хранения мантиссы и обеспечивается точность, превышающая 7 десятичных разрядов. Для хранения мантиссы с эквивалентной точностью в упакованном BCD формате требуется, по крайней мере, 28 разрядов. Еще в одной альтернативной системе записи, рациональной арифметике, ис пользуются два целых числа для хранения числителя и знаменателя. При та ком подходе удается представить точно любое рациональное число – в пределах, ограниченных допустимыми значениями числителя и знаменателя. Это пред ставление удобно для решения задач с использованием дробей, но не подходит для вычисления тригонометрических или логарифмических функций. К сожале нию, в этом случае реализация даже основных арифметических операций очень сложна и медленна из-за необходимости вычислять наибольший общий дели тель. Поэтому рациональная арифметика используется редко. Использование эквивалентных выражений для устранения катастрофической потери точности Так ли ужасна катастрофическая потеря точности? В худшем случае она может сократить количество верных значащих цифр результата до нуля! Предположим, нам нужно найти значение выражения y = 1 – cos(x) при малых x. Косинус 0 равен 1, а косинус малых значений угла очень бли зок к 1. При непосредственном вычислении y потеря значащих разрядов про изойдет при вычитании из 1. К какому виду ее можно отнести, к «мягкой» или к катастрофической? Математическая функция косинус имеет иррациональные значения – их нельзя представить точно ни в двоичном, ни в десятичном виде. Поэтому все вычисленные значения косинуса будут приближенными. Результат вычитания будет катастрофическим. Для очень малых значений x переменная y не будет иметь ни одного верного разряда. Такое выражение называется численно неустойчивым при малых значениях переменной x. Можем ли мы заменить это выражение каким-нибудь эквивалентным ему, но не требующим катастрофического вычитания? Воспользуемся тождеством cos a + sin a = 1, 2 2 200 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ чтобы преобразовать формулу к эквивалентному виду: Теперь нам удалось избавиться от катастрофической потери точности при ма лых значениях x. Так как значение косинуса близко к 1, складываются (но не вычитаются!) почти равные числа. Однако это уравнение создало другие проблемы. Сложность вычислений воз росла. Для вычисления значений тригонометрических функций нужно больше времени, чем для выполнения арифметических операций, а у нас теперь две та ких функции. Более того, при значениях x, близких к ±π, ±3π, ±5π, … вычислен ные значения косинуса будут близки к –1. При сложении таких почти близких по модулю значений снова произойдет катастрофическая потеря точности. А не которые значения х приводят к делению на 0. Если ситуация допускает затрату небольшого дополнительного времени на вычисления, можно использовать одно уравнение для одних значений x и дру гое – для других. Но есть способ лучше. Потратив некоторое время на поиск информации в математическом справоч нике, можно найти следующее тождество: Теперь мы можем преобразовать наше уравнение к виду y = 2sin (x/2), 2 в котором нет ни сложения или вычитания, ни деления на малые числа (а значит, нет вероятности деления на 0), кроме того, здесь только одна тригонометри ческая функция. Теперь мы добились необходимой точности, практически без падения производительности. На рис. 11.1 представлены результаты вычислений по обеим формулам: На рис. 11.1 использована логарифмическая шкала, поэтому график функ ции не похож на синусоиду. Значения рассчитаны с двойной точностью, со гласно стандарту IEEE 754. Модифицированная формула работает для всех значений x, представленных на рисунке. (Она была протестирована для всех x вплоть до 10 , никаких проблем обнаружено не было.) Оригинальная –100 формула становится неточной уже при меньших 10 . В этой точке отно x, –3 сительная погрешность, отложенная по правой оси, начинает увеличиваться. С уменьшением x относительная погрешность возрастает и при x, меньших 2×10 , она в конце концов достигает 1. Здесь оригинальная формула полно –10 стью неприменима и дает в результате 0. Модифицированная формула дает ≈ результаты с точностью до 14-го знака для всех значений x. При x 7×10 –7 относительная погрешность значения, вычисленного по оригинальной фор муле, составляет 10 , таким образом, верными являются только 7 значащих –7 разрядов результата. Этот пример приведен здесь не для того, чтобы преувеличить преимущества устранения катастрофической потери значащих разрядов. Это типичное повы АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ С ФИКСИРОВАННОЙ ЗАПЯТОЙ 201 шение точности расчетов, которого можно добиться, применив математические тождества для преобразования численно неустойчивых формул в численно устойчивые. Значения выражения 1 – cosx, вычисленные по оригинальной и модифицированной формуле погрешность формуле вычислениях y Значения оригинальной Относительная при по Значения x Модифицированная Оригинальная Относительная погрешность Рис. 11.1. Значения выражения 1 – cos x, вычисленные по оригинальной и модифицированной формуле Не все численно устойчивые эквивалентные формулы являются простыми или очевидными. Вот формула, предложенная компанией Hewlett Packard, по которой можно точно вычислить = ln(1 + при малых y x) x: Символ обозначает машинное сложение с ошибкой округления. Арифметические операции с фиксированной запятой Область применимости Для решения некоторых задач нужны дробные числа, однако нет реальной по требности в значениях с плавающей запятой. Такие задачи можно решить в чис лах с фиксированной запятой, которые на самом деле подчиняются правилам целочисленной арифметики с некоторыми оговорками и допущениями. Вот некоторые критерии, указывающие на то, что в данной задаче лучше ис пользовать числа с фиксированной запятой: 202 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ • • используемые значения принадлежат фиксированному диапазону; • • для чисел, близких к 0, не требуется более высокая абсолютная точность, чем для чисел с большим модулем; • • производятся линейные расчеты (умножение и деление на константы, сло жение, вычитание и интерполяция); • • имеются ограничения на скорость работы программы или на используемую память; • • данная платформа аппаратно не поддерживает числа с плавающей запятой. Чтобы отдать предпочтение числам с фиксированной запятой, не обязательно выполнение всех этих условий. Степень важности приведенных критериев, по нашим оценкам, постепенно убывает к концу списка. Иногда в каком-то кон кретном приложении лучше использовать числа с фиксированной запятой, даже если сопроцессор поддерживает операции с плавающей запятой. Представление чисел с фиксированной запятой и операции над ними Арифметические операции с фиксированной запятой реализуются в целых чис лах с использованием масштабного множителя. В этом случае самый младший разряд представляет не единицу, а величину, обратную масштабному множителю. Например, для термометра с ценой деления 0,1 градуса масштабный множитель равен 10, таким образом, в самом младшем разряде числа будут храниться де сятые доли градуса. Для представления действительного числа в формате с фиксированной за x пятой с помощью масштабного множителя s используется ближайшее целое значение: × i = floor(s x + 0,5). x Масштабный множитель обычно имеет значение, большее единицы, хотя это s требование не является обязательным. В табл. 11.15 представлены реализации обычных арифметических операций. Для каждой операции приведены примеры. Условные обозначения, использован ные в этих примерах, показаны в табл. 11.16. Таблица 11.15. Реализации арифметических операций Примеры значений Операция Определение Реализация (см. ниже) Истинное Целое Представление Сложение 112,5 1125 112,5 x + y n + n x y Вычитание 82,3 823 82,3 x – y n – n x y Умножение 1470,74 14 707 1470,7 x · y (n · n + s/2) x y s Деление 6,45033 65 6,5 x/y (s · n + n /2) x y n y Интерполя31,56 316 31,6 (a · x + b · y) (a · n + b · n + (a + b)/2) x y ция (a + b) (a + b) АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ С ФИКСИРОВАННОЙ ЗАПЯТОЙ 203 Примечание: последнее деление в трех нижних строчках таблицы, должно вы полняться c усечением вниз, а не с усечением к нулю, чтобы для отрицательных чисел получались правильные результаты. В колонке «Истинное» табл. 11.15 в представлен идеальный результат, кото рый должен получиться при вычислениях с неограниченной точностью. В ко лонке «Целое» приведено целое значение, полученное при вычислениях по формуле. В колонке «Представление» содержится значение с фиксированной запятой, которому соответствует целое число. Таблица 11.16. Условные обозначения Переменная Значение Описание 10 Масштабный коэффициент представления с фиксированной заs значения, использованные для демонстрации выполнения каждой операции 15,1 y 1 a Коэффициенты, использованные для интерполяции 4 b Реализация операций сложения и вычитания в числах с фиксированной за пятой абсолютно точна. Что касается умножения и деления, то при реализации необходимо округлять полученный результат до ближайшего целого. Приведен ные формулы позволяют провести округление результата корректно. В них не включена проверка на переполнение или исчезновение значащих разрядов. Там, где возможно, следует выбирать представление в целых числах, в этом случае в таких проверках нет необходимости. Обработка ошибок при выполнении операций с фиксированной запятой При проектировании системы на основе операций с фиксированной запятой важно тщательно подбирать масштабный множитель. Особенно опасно смеши вать системы с фиксированной запятой, в которых используются различные мас штабные множители, что демонстрирует следующий пример (рис. 11.2). У входных значений на рис. 11.2 один масштабный множитель, у промежу точных результатов – другой, а у выходных значений – третий. Проследив ход вычислений для каждого возможного входного значения, можно увидеть, что некоторые выходные значения соответствуют только одному входному значе нию, в то время как другие – трем различным входным значениям. Линейные изменения входного параметра не приводят к линейному отклику на выходе. Чтобы устранить эту проблему, в том случае, когда один масштабный мно житель зафиксирован системными требованиями, все последующие масштабные множители, вводимые при проектировании, должны быть кратными ему. Если зафиксированы два масштабных множителя (например, входной и выходной), любой промежуточный масштабный коэффициент должен быть их общим крат ным. Это означает, что наименьший приемлемый масштабный множитель – это наименьшее общее кратное двух масштабных коэффициентов. 204 ВВЕДЕНИЕ В МАШИННЫЕ ВЫЧИСЛЕНИЯ Входное значение с фиксированной запятой = 8 s Промежуточный результат с фиксированной запятой = 10 s Выходной результат с фиксированной запятой = 4 s Количество аналогово-цифровых входных значений, отвечающих каждому выходному значению Рис. 11.2. Количество аналогово-цифровых входных значений, отвечающих каждому выходному значению Сложение и вычитание могут быть выполнены точно, однако это невозможно сделать для умножения и деления. Одним из способов минимизации суммарной погрешности является использование для промежуточного результата такого масштабного множителя, который содержал бы несколько дополнительных де сятичных знаков. Для хранения значений, соответствующих большему масштаб ному множителю могут потребоваться более длинные целые типы. Заключение Каждая из распространенных форм машинной арифметики – целая, с фиксиро ванной запятой и с плавающей запятой – имеет свои преимущества и недостат ки. Разработчикам программного обеспечения необходим практический опыт использования каждой из этих форм для выбора оптимального представления чисел в каждом конкретном приложении и для устранения проблем, связанных с этим представлением. В этой главе представлен только обзор проблемы численного анализа. При не обходимости проведения всестороннего анализа специализированных расчетов, например, операций с матрицами, более подробную информацию можно найти в руководствах по численному анализу. Библиография David Goldberg. What Every Computer Scientist Should Know About Floating Point Arithmetic. Computing Surveys, March 1991. IEEE Computer Society (1985). IEEE Standard for Binary Floating–Point Arithmetic. IEEE Std 754–1985. Peter A. Stark. Introduction to Numerical Methods. Macmillan Publishing Co., 1970. Josef Stoer. Introduction to Numerical Analysis. Springer Verlag, 1980. Глава 12. АППРОКСИМАЦИИ ДЛЯ ВЫЧИСЛЕНИЙ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ Джек Ганссл Большинство встраиваемых процессоров «не умеет» вычислять тригонометри ческие и другие комплексные функции. При программировании на языке C мы с удовольствием вызываем библиотечные функции, выполняющие за нас всю работу. К сожалению, столь оптимистичный подход зачастую не подходит для систем реального времени, где очень важно одновременно решить проблемы раз мера и скорости работы программы, а также точности вычислений. Компилятор использует библиотеки времени исполнения – это своеобразное «решение на все случаи жизни». Оно обеспечивает разумный компромисс меж ду скоростью и точностью. Однако все встраиваемые системы различны, к ним предъявляются разные требования. В некоторых случаях лучше написать соб ственные подпрограммы для приближенных вычислений. Почему? Скорость – библиотеки времени исполнения многих компиляторов работают очень медленно. Остроумная аппроксимация может избавить от необходимости применения более быстрого процессора. время работы функций, предлагаемых компилятором, мо Предсказуемость – жет серьезно изменяться в зависимости от значений входных аргументов. Систе мы реального времени должны иметь предсказуемое время работы. Альтернатив ный вариант – всегда использовать наихудшую оценку времени выполнения, что с другой стороны может означать: ваш процессор работает слишком медленно или слишком загружен для использования в данном приложении. – внимательно читайте руководство по использованию компилято Точность ра! Некоторые компиляторы не поддерживают в явном виде стандарт ASNI C, требующий вычисления всех тригонометрических функций с двойной точностью (этим печально знамениты компиляторы 8051). С другой стороны, зачем платить (тратить дополнительное время) за использование выражений двойной точно сти, если нужна точность до пятого знака? Размер – в случае нехватки памяти использование одной из этих аппроксима ций может сэкономить значительное пространство для размещения кода. Если вам нужна лишь простая функция для вычисления косинуса, зачем включать целую библиотеку тригонометрических функций с плавающей запятой? Представленный набор не является энциклопедией всех возможных аппрок симаций; в него включены лишь аппроксимации, имеющие наибольшее практи ческое значение, из авторитетного руководства по этой теме – книги Computer Джона Харта (ISBN 0-88275-642-7). К сожалению, сегодня тираж Approximations этой книги уже полностью разошелся. Кроме того, аппроксимации очень сложно использовать без строгого математического аппарата. Все представленные здесь аппроксимации являются либо полиномами, ли бо отношениями полиномов. Во всех случаях использованы малоизвестные коэффициенты, полученные с помощью рядов Чебышева и функций Бесселя. 206 АППРОКСИМАЦИИ ДЛЯ ВЫЧИСЛЕНИЙ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ Они гарантируют минимальные ошибки в указанных интервалах. Для каждой аппроксимации (за редкими исключениями) приведен график ошибок, чтобы легче было оценить, на каком интервале они проявляются. В некоторых слу чаях, если используется ограниченный интервал входных данных, точность результатов может значительно превышать приведенные значения. Например, функция cos_73 имеет точность 7,3 десятичного разряда в диапазоне от 0 до 360 градусов. Однако, как видно по рис. 12.4, в диапазоне от 0 до 30 градусов можно до биться улучшения точности почти на порядок. На самом деле нужно очень осторожно относиться к точности, обеспечивае мой вашим компилятором при операциях над числами с плавающей запятой. double float. Иногда значения типа обрабатываются как В других случаях (осо бенно это относится к таким крошечным процессорам, как PIC), компилято ры «жульничают» и обеспечивают точность вычислений с плавающей запятой, меньшую 32 разрядов. Все программные коды приведенных ниже аппроксимаций компилировались с помощью пакета Microsoft Visual C++ 6.0. Исходный код можно найти по адре су www.ganssle.com/approx/sincos.cpp. В его состав входит тестовый код, записы вающий в текстовый файл полученные результаты и погрешности вычислений; импортировав эти результаты в электронную таблицу вы сможете оценить их точность. Общие замечания о тригонометрических функциях Обычно аргументы задаются в радианах, а не в градусах. 360 градусов, состав ляющие полный оборот вокруг оси, эквивалентны 2π радианов; таким образом, один радиан равен 360/(2π), или примерно 57,3 градуса. Это может показаться странным, если не вспомнить о длине окружности, которая равна 2πr; при r (ра диус окружности), равном единице, ее длина действительно будет 2π. Правила перехода от радианов к градусам и обратно выглядят так: × Угол в радианах = угол в градусах 2π/360; × Угол в градусах = угол в радианах 360/(2π). Таблица 12.1. Значения тригонометрических функций Градусы Радианы sin cos tg 0 0 0 1 0 45 π/4 √2/2 √2/2 1 90 π/2 1 0 бесконечность 135 3π/4 √2/2 –√2/2 –1 180 π 0 –1 бесконечность 225 5π/4 –√2/2 –√2/2 1 270 3π/2 –1 0 бесконечность 315 7π/4 –√2/2 √2/2 –1 360 2π 0 1 0 ОБЩИЕ ЗАМЕЧАНИЯ О ТРИГОНОМЕТРИЧЕСКИХ ФУНКЦИЯХ 207 Косинус и синус Во всех приведенных ниже примерах аппроксимируется функция cos; аппрок симация для sin выводится через соотношение: sin(x) = cos(π/2 – x). Таким образом, sin и cos на самом деле являются одной и той же функцией, просто смещенной по фазе на 90°. Программный код для функции sin (в пред положении, что мы вызываем функцию cos_32, аппроксимацию с наименьшей точностью) выглядит так: // Синус – это просто косинус, смещенный на половину пи, поэтому // мы преобразуем аргумент и вызовем аппроксимацию косинуса. // float sin_32(float x){ return cos_32(halfpi–x); } Все аппроксимации косинуса в данной главе вычисляют функцию cos точ π/2 но в пределах диапазона значений аргумента от 0 до (0…90°). Это серьезно сужает область допустимых значений аргумента! Вообще, все аппроксимации наилучшим образом работают в ограниченных интервалах; а уже от нас зави сит, сможем ли мы сузить область входных значений так, чтобы аппроксимация работала точно. Поэтому, прежде чем вызывать любую из приведенных ниже аппроксимаций косинуса, необходимо преобразовать значение его аргумента к интервалу от 0 π/2 до с помощью следующего кода: // Математические константы double const pi=3.1415926535897932384626433;// пи double const twopi=2.0*pi; // два пи double const halfpi=pi/2.0; // пи пополам // // Это главный «драйвер» аппроксимации косинуса // Он преобразует аргумент к диапазону [0, pi/2], // после чего вызывает аппроксиматор. // float cos_32(float x){ int quad; // в каком квадранте мы находимся? x=fmod(x, twopi); // избавляемся от аргументов > 2*pi if(x<0)x=–x; // cos(–x) = cos(x) quad=int(x/halfpi); // вычисляем номер квадранта (от 0 до 3) switch (quad){ case 0: return cos_32s(x); case 1: return –cos_32s(pi–x); case 2: return –cos_32s(x–pi); case 3: return cos_32s(twopi–x); } } 208 АППРОКСИМАЦИИ ДЛЯ ВЫЧИСЛЕНИЙ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ cos_32s, Данный код настроен на вызов функции являющейся аппроксимаци ей косинуса с точностью 3,2 десятичного разряда (отсюда – и название функ ции). Для всех других аппроксимаций косинуса используйте аналогичный код, cos_32s cos_52s, cos_73s cos_121s, в котором нужно заменить на или в зависимо сти от необходимого уровня точности. Смотрите полный листинг с подробным описанием примера. Следует разумно подходить к объявлению переменных и констант. Очевидно, cos_32 double. что при работе с аппроксимацией не нужны значения типа Для float. повышения эффективности кода используйте тип Читая полный листинг, cos_32 cos_52 обратите внимание, что для функций и мы везде использовали float, double. значения типа а в более точных аппроксимациях – Один из приемов, ускоряющий расчеты при аппроксимации, состоит в вычис лении x путем приращения порядка в представлении переменной x с плавающей 2 запятой. Этот метод требует точных знаний о том, как числа хранятся в памяти, зато позволяет сэкономить сотни микросекунд по сравнению с применением го x*x. раздо более очевидной операции Как выполняются преобразования аргумента? Обратите внимание: в приве денном фрагменте область значений аргумента разбита на четыре «квадранта» – те самые квадранты единичного круга (рис. 12.1): π/2 1 0 π 0 2 3 3π/2 Рис. 12.1. Квадранты круга π/2) • • для квадранта 0 (значения от 0 до преобразований аргумента делать не нужно, так как аппроксимация косинуса рассчитана именно на эту область. • • в квадранте 1 можно использовать формулу cos(x) = –cos(π – x), чтобы заменить значения аргумента значениями из квадранта 0. π). • • в квадранте 2 применяем формулу cos(x) = –cos(x – • • и наконец, в квадранте 3 косинус снова становится положительным; если π/2. вычесть аргумент из 2π, получим значение от 0 до Предлагаемые аппроксимации действительно преобразуют базовые полиномы в более простую форму и, как описано в комментариях, позволяют значитель но сократить объем вычислений. Все операции с плавающей запятой требуют существенных затрат времени, поэ ит за пределы допустимого интервала (от БОЛЕЕ ТОЧНОЕ ВЫЧИСЛЕНИЕ КОСИНУСА 213 π/2), 0 до используйте преобразование области значений аргумента (приведено double, выше). Кроме того, переменные должны иметь тип чтобы избежать по тери точности. На рис. 12.5 приведены абсолютные (а не относительные) по грешности. Более точное вычисление косинуса При наличии полинома достаточно высокой степени можно добиться любой требуемой точности. Ряд дополнительных алгоритмов представлен ниже. Все π/2, они справедливы в диапазоне от 0 до и во всех используется описанный выше алгоритм преобразования, позволяющий заменить любой угол значени ем, принадлежащим к указанному диапазону. Во всех алгоритмах угол задается в радианах. Графики погрешности вычислений не приводятся, поскольку точность этих алгоритмов превышает точность типичной встроенной в компилятор реализации функции cos, поэтому полученные результаты просто не с чем сравнивать. double Обратите внимание, тип языка C на большинстве компьютеров содер жит около 15 верных разрядов. Поэтому для реализации данных алгоритмов, особенно версий с точностью 20,2 или 23,1 разряда, необходимы типы данных с еще большим числом разрядов. Некоторые реализации языка C поддержива long double. ют тип Однако нужно внимательно читать руководство к данному компилятору! Так, например, компилятор Microsoft Visual C++, хотя и поддер long double, живает ключевое слово на самом деле преобразует все значения double. этого типа к типу π/2]: Точность около 14,7 десятичного разряда в интервале [0, c1= 0,99999999999999806767 c2=–0,4999999999998996568 c3= 0,04166666666581174292 c4=–0,001388888886113613522 c5= 0,000024801582876042427 c6=–0,0000002755693576863181 c7= 0,0000000020858327958707 c8=–0,000000000011080716368 cos(x)= c + x (c + x (c + x (c + x (c + 1 2 2 2 3 2 4 2 5 x (c + x (c + x *c )))))). 2 6 2 7 2 8 π/2]: Точность около 20,2 десятичного разряда в интервале [0, c1 = 0,9999999999999999999936329 c2 =–0,49999999999999999948362843 c3 = 0,04166666666666665975670054 c4 =–0,00138888888888885302082298 c5 = 0,000024801587301492746422297 c6 =–0,00000027557319209666748555 c7 = 0,0000000020876755667423458605 c8 =–0,0000000000114706701991777771 214 АППРОКСИМАЦИИ ДЛЯ ВЫЧИСЛЕНИЙ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ c9 = 0,0000000000000477687298095717 c10=–0,00000000000000015119893746887 cos(x)= c + x (c + x (c + x (c + x (c + x (c + 1 2 2 2 3 2 4 2 5 2 6 x (c + x (c + x (c + x *c )))))))). 2 7 2 8 2 9 2 10 π/2]: Точность около 23,1 десятичного разряда в интервале [0, c1 = 0,9999999999999999999999914771 c2 =–0,4999999999999999999991637437 c3 = 0,04166666666666666665319411988 c4 =–0,00138888888888888880310186415 c5 = 0,00002480158730158702330045157 c6 =–0,000000275573192239332256421489 c7 = 0,000000002087675698165412591559 c8 =–0,0000000000114707451267755432394 c9 = 0,0000000000000477945439406649917 c10=–0,00000000000000015612263428827781 c11= 0,00000000000000000039912654507924 cos(x)= c + x (c + x (c + x (c + x (c + x (c + 1 2 2 2 3 2 4 2 5 2 6 x (c + x (c + x (c + x (c + x *c ))))))))). 2 7 2 8 2 9 2 10 2 11 Тангенс Тангенс определяется как отношение tg(x)=sin(x)/cos(x). Тем не менее при вы боре аппроксимации такой подход, к сожалению, далеко не самый лучший. Когда значения функции cos(x) приближаются к нулю, очень быстро возрастает по π/4 грешность. Более того, в некоторых точках, например при x = (см. преды дущие графики погрешностей вычисления синуса и косинуса – рис. 12.2–12.5) погрешности вычисления синуса и косинуса «усиливают» друг друга – обе они велики и имеют одинаковый знак. Поэтому для тангенса лучше всего использовать отдельную аппроксимацию. Все приведенные нами аппроксимации дают верное значение тангенса для углов π/4 в диапазоне от 0 до (от 0 до 45 градусов), поэтому приведем еще одну фук цию для приведения углов к значениям в указанном диапазоне. // // Это основной «драйвер» аппроксимации тангенса // Он преобразует значение аргумента к диапазону [0, pi/4], // после чего вызывает аппроксиматор. // Вводите только положительные значения угла. // // ПРЕДУПРЕЖДЕНИЕ: Мы не тестировали поведение аппроксимации // в окрестностях значений x=pi/2 и x=3*pi/2, где тангенс равен // бесконечности. Если это нужно учесть в вашем приложении, примите // соответствующие меры. // float tan_32(float x){ int octant; // в каком октанте мы находимся? ТАНГЕНС 215 x=fmod(x, twopi); // избавляемся от значений >2*pi octant=int(x/qtrpi); // получаем номер октанта (от 0 до 7) switch (octant){ case 0: return tan_32s(x *four_over_pi); case 1: return 1.0/tan_32s((halfpi–x) *four_over_pi); case 2: return –1.0/tan_32s((x–halfpi) *four_over_pi); case 3: return –tan_32s((pi–x) *four_over_pi); case 4: return tan_32s((x–pi) *four_over_pi); case 5: return 1.0/tan_32s((threehalfpi–x) *four_over_pi); case 6: return –1.0/tan_32s((x–threehalfpi) *four_over_pi); case 7: return –tan_32s((twopi–x) *four_over_pi); } } Приведенный выше код сначала осуществляет преобразование аргумента, tan_32. затем вызывает функцию При использовании аппроксимаций с более высокой точностью подставьте название соответствующей функции вместо tan_32. Преобразование аргумента производится примерно так же, как для косинуса, за исключением того, что теперь круг разделен на октанты. Одна из особенностей four_over_pi). этого алгоритма в том, что аргумент умножается на 4/π (константа Это происходит потому, что сами алгоритмы в действительности находят значе ние выражения tg((π/4)x). Необходимые алгоритмы приведены на следующем листинге. Напомним, что и tg(90°), и tg(270°) равны бесконечности. По мере того как значение аргумента приближается к 90° или 270°, значение тангенса резко воз растает, что видно из графика погрешностей (рис. 12.6). Никогда не вычисляйте тангенс вблизи 90 или 270 градусов! погрешность tan(х) Относительная Градусы tan(х) tan_32 отн. погрешность Рис. 12.6. тносительные погрешности функции tan_14 БОЛЕЕ ТОЧНОЕ ВЫЧИСЛЕНИЕ ТАНГЕНСА 219 // ********************************************************* // *** // *** Подпрограммы для вычисления тангенса с точностью до 14 // *** разрядов. // *** // ********************************************************* // // tan_14s вычисляет tg(pi*x/4) // // Точность вычислений около 14 десятичных разрядов в области [0, pi/4]. // Аргумент задается в радианах. Внимание: функция вычисляет // tg(pi*x/4), А НЕ tg(x); это следствие использованного алгоритма // преобразования аргумента, нужное для правильного масштабирования. // // Алгоритм: // tan(x)= x(c1 + c2*x**2 + c3*x**4)/(c4 + c5*x**2 + c6*x**4 + x**6) // double tan_14s(double x) { const double c1= –34287,4662577359568109624; const double c2= 2566,7175462315050423295; const double c3= –26,5366371951731325438; const double c4= –43656,1579281292375769579; const double c5= 12244,4839556747426927793; const double c6= –336,611376245464339493; double x2; // находим квадрат аргумента x2=x * x; return (x*(c1 + x2*(c2 + x2*c3))/(c4 + x2*(c5 + x2*(c6 + x2)))); } Функция tan_14 вычисляет tg((π/4)x) с точностью около 14,1 десятичного разряда. Используйте код для преобразования области значений аргумента (при веден выше), если значение аргумента выходит за пределы допустимого интер π/4 вала от 0 до и, конечно же, учитывайте своеобразное «масштабирование» «π/4», применяемое данной функцией. Обратите внимание, переменные описаны double. как Отложенные на рис. 12.9 погрешности являются относительными, а не абсолютными. Более точное вычисление тангенса При наличии полинома достаточно высокой степени можно добиться любой требуемой точности. Ниже приведен ряд дополнительных алгоритмов. Все они π/4, справедливы в диапазоне от 0 до и во всех используется описанное выше преобразование, позволяющее заменить любой угол значением, принадлежащим к указанному диапазону. Во всех алгоритмах угол задается в радианах, вычис π/4. ления проводятся с использованием значения, умноженного на Описанный выше алгоритм преобразования угла в этом случае остается справедливым. 220 АППРОКСИМАЦИИ ДЛЯ ВЫЧИСЛЕНИЙ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ Графики погрешности вычислений не приводятся, поскольку точность этих алгоритмов превышает точность типичной встроенной в компилятор реализации функции tan, поэтому полученные результаты просто не с чем сравнивать. double Обратите внимание, тип языка C на большинстве компьютеров содержит около 15 верных разрядов. Поэтому для реализации данных алгоритмов, особенно версий с точностью 20,2 или 23,1 разряда, необходимы типы данных с еще большим long double. числом разрядов. Некоторые реализации языка C поддерживают тип Однако нужно внимательно читать руководство к данному компилятору! Так, на пример, компилятор Microsoft Visual C++, хотя и поддерживает ключевое слово long double, double. на самом деле преобразует все значения этого типа к типу π/4: Точность порядка 20,3 разряда в интервале от 0 до c1= 10881241,46289544215469695742 c2= –895306,0870564145957447087575 c2= 14181,99563014366386894487566 c3= –45,63638305432707847378129653 c4= 13854426,92637036839270054048 c5= –3988641,468163077300701338784 c6= 135299,4744550023680867559195 c7= –1014,19757617656429288596025 tg(xπ/4)=x(c1 + x2(c2 + x2(c3 + x2*c4))) /(c5 + x2(c6 + x2(c7 + x2))) π/4: Точность порядка 23,6 разряда в интервале от 0 до c1= 4130240,558996024013440146267 c2=– 349781,8562517381616631012487 c3= 6170,317758142494245331944348 c4=– 27,94920941480194872760036319 c5= 0,0175143807040383602666563058 c6= 5258785,647179987798541780825 c7=– 1526650,549072940686776259893 c8= 54962,51616062905361152230566 c9=– 497,495460280917265024506937 tg(xπ/4)=x(c1 + x2(c2 + x2(c3 + x2(c4 + x2*c5)))) /(c6 + x2(c7 + x2(c8 + x2(c9 + x2)))) Арктангенс, арксинус и арккосинус Арктангенс – это функция, обратная тангенсу, поэтому arctg(tg(x)) = Амери x. канское обозначение этой функции: «atan(x)» или «tan (x)». –1 На практике аппроксимация для функций, обратных синусу и косинусу, ис пользуется редко; в большинстве случаев мы вычисляем эти функции через арк тангенс по следующим формулам: arcsin(x) = arctg(x/√(1 – x )); 2 arccos(x) = p/2 – arcsin(x) = = p/2 – arctg(x/√(1 – x )). 2 АРКТАНГЕНС, АРКСИНУС И АРККОСИНУС 221 π/12. Аппроксимации действительны в интервале от 0 до Следующий код, на базе алгоритма, приведенного Джеком Креншоу в книге Math Toolkit for Real-Time Programming, позволяет выполнить соответствующее преобразование аргумента: // // Это основной «драйвер» аппроксимации арктангенса // Он преобразовывает значение аргумента к диапазону [0, pi/12], // после чего вызывает аппроксиматор. // // double atan_66(double x){ double y; // возвращается функцией atan__s int complement= FALSE; // true, если x>1 int region= FALSE; // зависит от области, к которой принадлежит х int sign= FALSE; // true, если х<0 if (x <0 ){ x=–x; sign=TRUE; // arctan(–x)=–arctan(x) } if (x > 1.0){ x=1.0/x; // х должен быть в интервале от 0 до 1 complement=TRUE; } if (x > tantwelfthpi){ x = (x–tansixthpi)/(1+tansixthpi*x); // преобразует х, чтобы он был меньше tg(pi/12) region=TRUE; } y=atan_66s(x); // запуск аппроксимации if (region) y+=sixthpi; // коррекция для области, которой // принадлежит х if (complement)y=halfpi–y; // коррекция, если мы используем 1/x if (sign)y=–y; // коррекция для отрицательных х return (y); } Погрешность atan(tan(x)) x aТan atan_66 погрешность мента используйте приведенный выше код. Глава 13. МАТЕМАТИЧЕСКИЕ ФУНКЦИИ Джек Ганссл Не всегда удается воспользоваться библиотекой времени исполнения, чтобы реализовать все математические операции, необходимые встраиваемой системе. В библиотеке может отсутствовать нужная функция, либо библиотечная реали зация оказывается слишком громоздкой или медленной. Поэтому полезно иметь в запасе набор альтернативных формул. Код Грея Для преобразования числа G, представленного в 8-разрядном коде Грея, в дво ичный вид B: // вначале: присвоить значение 1 всем битам от B0 до B6 B7 = G7 if (B6 = G5) then B5 = 0 if (B5 = G4) then B4 = 0 if (B4 = G3) then B3 = 0 if (B3 = G2) then B2 = 0 if (B2 = G1) then B1 = 0 if (B1 = G0) then B0 = 0 Для получения представления G двоичного числа B в коде Грея: G = B xor (B >>2) Умножение целого на константу Во многих процессорах отсутствует специальная инструкция для умножения. Если скорость вычисления важна, попытайтесь переформулировать уравнение. Например, мы знаем, что умножение на 2 выполняется медленно, гораздо быст р ее выполнить операцию сдвига. Почему бы не использовать тот же прием и для умножения на константы? Вот несколько формул, распространение их на другие случаи – тривиальная задача: A × 3 = A × 2 + A A × 5 = A × 4 + A A × 10 = (A × 4 + A) × 2 Вычисление исключающего ИЛИ Операцию XOR для чисел A и B можно выполнить так: A XOR B = A + B – 2 (A AND B) ВАЖНЕЙШИЕ МАТЕМАТИЧЕСКИЕ ФУНКЦИИ 225 Извлечение квадратного корня в целых числах Один из подходов состоит в суммировании всех нечетных чисел, начиная с 1 до тех пор, пока сумма остается не больше числа, стоящего под знаком корня. Число слагаемых и будет квадратным корнем. Например, чтобы вычислить квадратный корень из 31, находим 1 + 3 + 5 + 7 + 9 = 25; при следующем слагаемом сумма станет 36, что больше 31. Другой подход к вычислению квадратного корня из 32-разрядного числа, по зволяет быстро получить 16-разрядный результат (не более чем за 16 итераций): typedef unsigned int UInt16; typedef unsigned long int UInt32; static UInt16 isqrt (UInt32 x) { UInt16 bit = 16; UInt16 mask = 0x8000; UInt16 root = 0x0000; do { UInt32 acc = root | mask; if (acc * acc <= x) root |= mask; mask >>= 1; } while (–bit); return root; } Важнейшие математические функции Вот основные соотношения между функциями, которые помогут упростить ваш программный код. arcsin(x) = arctg(x/sqr(–x + 2)) 2 arccos(x) = –arctg(x/sqr(–x + 1)) + π/2 2 arcsec(x) = arctg(x/sqr(x – 1)) 2 arccosec(x) = arctg(x/sqr(x – 1)) + (sgn(x) – 1) × π/2 2 arcctg(x) = arctg(x) + π/2 sh(x) = (exp(x) – exp(–x))/2 ch(x) = (exp(x) + exp(–x))/2 th(x) = exp(–x)/(exp(x) + exp(–x)) × 2 + 1 arsh(x) = ln(x + sqr(x + 1)) 2 arch(x) = ln(x + sqr(x – 1)) 2 arth(x) = ln(1 + x)(1 – x))/2 Глава 14. СТАНДАРТ IEEE 754 ДЛЯ ЧИСЕЛ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ Джек Ганссл Представление чисел с плавающей запятой согласно стандарту IEEE 754 сегод ня является наиболее распространенным представлением действительных чисел в компьютерах. В представлении с плавающей запятой используется основание системы счис ления и показатель степени. Например, число 123,456 можно представить в виде × 1,23456 10 . В шестнадцатеричной системе число 123,ABC может быть пред 2 × ставлено как 1,23ABC 16 . 2 Число с плавающей запятой по стандарту IEEE имеет три компонента: знак, показатель степени (его по-другому называют порядком) и мантиссу. Мантисса состоит из дробной части и неявной первой цифры (будет объяснено ниже). По казатель степени всегда относится к подразумеваемой двойке, поэтому на самом деле означает 2 . показатель Размещение чисел в памяти представлено в табл. 14.1: Таблица 14.1. Размещение чисел в памяти Знак Порядок Дробная часть Смещение Одинарная точ- 1 бит, самый стар- 8 битов с номера- 23 бита с номера- 127 ность (32 разряда) ший разряд (бит 31) ми 30–23 ми 22–00 Двойная точность 1 бит, самый стар- 11 битов с номера- 52 бита с номера- 1023 (64 разряда) ший разряд (бит 63) ми 62–52 ми 51–00 0 в знаковом разряде обозначает положительное число, 1 – отрицательное. Чтобы обеспечить поддержку как положительных, так и отрицательных по казателей степени к реальному порядку прибавляется – для чисел смещение с плавающей запятой одинарной точности это 127. Если реальный показатель степени (использующийся в математических операциях) равен нулю, в поле по рядка записывается 127. Хранящееся значение 200 означает (200 – 127), или 73. По причинам, обсуждающимся ниже, значения порядка –127 (одни нули) и +128 (только единицы) зарезервированы для специальных значений. В числах с двойной точностью используется смещение 1023, поле для хра нения порядка содержит 11 двоичных разрядов, поэтому можно представлять числа и с большим модулем, и с маленьким. Мантисса характеризует число без порядка. Она состоит из подразумеваемой первой цифры и дробных разрядов. Значение с одинарной точностью представляется следующим образом: (–1) 2 (1,M), S E – 127 а с двойной точностью – так: (–1) 2 (1,M), S E – 1023 где S – знак, E – порядок, хранящийся в памяти, M – мантисса. СПЕЦИАЛЬНЫЕ ЗНАЧЕНИЯ 227 Специальные значения Стандарт IEEE 754 поддерживает некоторые специальные значения (табл. 14.2): Таблица 14.2. Специальные значения согласно стандарту IEEE 754 Название Порядок Дробная Знак Значения разрядов Значения разрядов часть порядка мантиссы +0 min – 1 =0 + все нули все нули –0 min – 1 =0 – все нули все нули число min ≤ e ≤ max любая любой любые любые +∞ max + 1 =0 + все единицы все нули –∞ max + 1 =0 – все единицы все нули NaN max + 1 ≠0 любой все единицы любые Ноль представляется как все нули в полях мантиссы и порядка с нулем или единицей в знаковом разряде. Оба значения являются допустимыми. Согласно требованиям стандарта при сравнении чисел с +0 и с –0 должны возвращаться одинаковые результаты. √[(–1)]) Некоторые вычислительные операции (например, деление на ноль или приводят к неопределенному результату, который называется нечисловым (NaN – Not a Number). При выполнении любой операции с NaN в итоге также получится NaN. Ре зультатом выполнения всех операций сравнения (=, <, ≤, >, ≥), исключая про false, верку на неравенство, будет значение если NaN является одним из опе рандов. Таблица 14.3. Источники возникновения NaN Операция Причина возникновения NaN + ∞ + (–∞) × 0 × ∞ / 0/0, ∞/∞ MOD x MOD 0, MOD y ∞ (если x < 0) √[] √x Таблица 14.4. Операции с бесконечностью Операция Результат n / ±бесконечность 0 ±бесконечность × ±бесконечност ±бесконечность ±не ноль / 0 ±бесконечность бесконечность + бесконечность бесконечность ±0 / ±0 NaN бесконечность – бесконечность NaN ±бесконечность / ±бесконечность NaN ±бесконечность × 0 NaN 228 СТАНДАРТ IEEE 754 ДЛЯ ЧИСЕЛ С ПЛАВАЮЩЕЙ ЗАПЯТОЙ Таблица 14.5. Некоторые параметры представлений Параметр Одинарная точность 24 (точность, двоичных разрядов) p Точность, десятичных разрядов 7,22 Старший бит мантиссы Скрытый Реальный размер мантиссы, бит 23 +127 E max –126 E min Смещение порядка +127 Размер порядка, бит 8 Размер знака, бит 1 Размер формата, бит 32 Максимальное значение модуля 3,4028E+38 (2 ) +1 E max 1,1754E–38 Минимальное значение модуля (2 ) E min Двойная точность 53 15,95 Скрытый 52 +1023 –1022 +1023 11 1 64 1,7976E+308 2,2250E–308 РАЗДЕЛ СТРАНИЦА I Основы оборудования 18 II Проектирование 72 III Математика 183 IV Системы реального времени V Ошибки и исправления 312 234 Глава 15. Ядра реального времени 254 Глава 16. Реентерабельность 271 Глава 17. Латентность прерываний 277 Глава 18. Как работает ваш компилятор языка C: минимизация размеров программы 296 Глава 19. Оптимизация кода на языках C и C++ 304 Глава 20. Макросы assert в системах реального времени Введение Джек Ганссл При знакомстве с литературой по проектированию программного обеспечения, можно обратить внимание на интересную особенность: ученые часто говорят о «встраиваемых» системах (когда имеют в виду вообще все подобные систе мы) и системах «реального времени» как о двух разных областях. Удивительный факт: Барри Бом в своей основополагающей работе, в которой была предло жена конструктивная стоимостная модель (COCOMO) для оценки затрат на разработку ПО, впервые назвал системы резервирования авиабилетов, которые должны очень быстро реагировать на действия оператора, системами «реального времени». И до сих пор встраиваемые приложения обычно относятся к миру систем реаль н ого времени. Когда происходит прерывание, обычно остается мало вре мени для его обработки. Внешние устройства требуют внимания… прямо сейчас. В этом разделе вы найдете советы по выбору операционных систем реального времени, которые дает Джин Лабросс, возможно, один из наиболее авторитетных авторов в этой области. Созданная им ОС (uC/OS) входит в состав сотен ви дов продукции. Она сертифицирована по уровню безопасности на соответствие жесткому стандарту DO–178B. Это правильная… и красивая ОС. Познакомьтесь с книгой Дж. Лабросса и просмотрите исходный код этой ОС реального време ни – она просто великолепна. Четко структурирована, прекрасно прокомменти рована, удовлетворяет требованиям жесткого стандарта. Совместимы ли красота и надежность? Наш опыт подсказывает: да. Реентерабельность и латентность – важные, но недооцениваемые концеп ции – рассмотрены мною в двух главах этого раздела. Еще один заслуживаю щий внимания источник – работа Дэвида Симона An Embedded Software Primer, представляющая хорошее введение в некоторые из этих проблем. Якоб Энгблом и Сандип Алувалия написали главы об оптимизации про граммного кода. Якоб имеет богатый опыт работы в компании, разрабатываю щей компиляторы, благодаря чему прекрасно разбирается в тонкостях работы компилятора и знает его возможности. Сандип излагает свои соображения об оптимизации приложений с точки зрения пользователя. Прежде всего, при разработке собственного кода реального времени следу ет думать как о времени, так и о выполняемых функциях. Время – это товар, столь же ценный как и ПЗУ или ОЗУ. Мы должны дорожить каждым мгнове нием, каждой секундой, для завершения наших неотложных задач. Потеря даже одной микросекунды может иметь для вашего пользователя катастрофические последствия. Глава 15. ЯДРА РЕАЛЬНОГО ВРЕМЕНИ Джин Дж. Лабросс Джин Дж. Лабросс – президент компании Micrium, Inc., которая является поставщиком высококачественных встраиваемых программных решений. Он получил степень магистра электротехники в Шербрукском университете (Шербрук, Канада) и уже почти 20 лет занимается разработкой встраиваемых систем. Дж. Дж. Лабросс – автор еще двух монографий, посвященных этим вопросам: MicroC/OS-II, The Real-Time Kernel (ISBN 1-57820-103-9) [MicroC/OS-II. Ядро реального времени] и Embedded Systems Building Blocks, Complete and Ready-to-Use Modules in C (ISBN 0-87930-604-1) [Компоновочные блоки встраиваемых систем. Полный набор готовых к использованию модулей на языке С]. Дж. Дж. Лабросс опубликовал множество статей в научных журналах, регулярно выступает с докладами на Конференции по встраиваемым системам и входит в состав оргкомитета этой конференции. Введение В этой главе я расскажу о том, что такое ядро реального времени и немного о том, как оно используется. Затем я рассмотрю некоторые критерии выбора ядра реального времени – возможно, вам когда-нибудь придется решать подоб ную проблему. В качестве примера я буду использовать реально существующее ядро под названием µC/OS-II (читается: микроси ОС два). µC/OS-II – это лег ко переносимое на другую платформу, пригодное для записи в ПЗУ, масштаби руемое, многозадачное ядро с приоритетными прерываниями, специально раз работанное для использования во встраиваемых приложениях. Ядро µC/OS-II написано на языке ANSI C; его структура и принципы работы описаны в книге (ISBN 1-57820-103-9). В составе различного MicroC/OS-II, The Real-Time Kernel ПО для авиационного электронного оборудования ядро µC/OS-II было серти фицировано Федеральным управлением гражданской авиации США (FAA) для применения в коммерческой авиации и отвечает требованиям стандарта RTCA DO-178B, предъявляемым к программному обеспечению для авиационной радио электроники. К упомянутой выше книге прилагается CD, содержащий ВЕСЬ исходный код µC/OS-II. Ядро µC/OS-II, выпущенное еще в 1992 году, исполь зуется уже в сотнях решений. µC/OS-II перенесена более чем на 100 платформ, соответствующие файлы можно БЕСПЛАТНО загрузить с веб-сайта компании Micriµm: www.Micrium.com . Что такое ядро реального времени? Ядро реального времени (далее ядро) – это ПО, распределяющее время мик ропроцессора так, чтобы гарантировать максимально возможную эффектив ность обработки событий, для которых время является критически важным параметром. Использование ядра упрощает разработку ПО, поскольку допус кает разделение системы на множество независимых элементов, называемых задачами. 232 ЯДРА РЕАЛЬНОГО ВРЕМЕНИ Что такое задача? Задача – это простая программа, полагающая, что микропроцессор находится в ее полном распоряжении. Каждая задача имеет собственный стек и предна значена для реализации определенной функции ПО. Ядро следит за значени ем указателя стека для каждой задачи. При проектировании ПО, содержащего ядро, каждой задаче присваивается приоритет в соответствии с вашей оценкой ее важности. Таким образом, при проектировании системы реального времени вся работа, которая должна ею выполняться, разбивается на отдельные задачи, решающие свою часть проблемы. Например, каждая из следующих операций может обслуживаться одной или несколькими задачами: • • считывание показаний датчиков (температура, давление, состояние выклю чателя…); • • вычисления; • • управляющие циклы; • • обновление выводимой информации (приводы, реле, индикаторы…); • • мониторинг; • • стеки протокола; • • ожидание ввода с клавиатуры; • • интерфейс оператора; • • управление выводом на дисплей (текстовый или графический); • • часы/календарь; • • последовательный обмен информацией; • • регистрация данных • • и т. д. Задача представляет собой бесконечный цикл и выглядит следующим образом: void MyTask (void) { while (1) { // Какие-либо операции (Ваш код) // Ожидание события, либо: // Задержка на ‘n’ тактовых интервалов таймера // ожидание изменения значения семафора // ожидание сообщения // Другое // Какие-либо операции (ваш код) } } Разрабатывая приложение, вы должны предоставить ядру информацию о сво ей задаче. Это можно сделать, вызвав поддерживаемую ядром службу создания задачи. А именно вы должны сообщить ядру адрес вашей задачи – в приведен MyTask(), ном выше примере адрес функции а также уровень приоритета, кото рый вы присваиваете задаче, размер стека и памяти, который, по вашему мнению, ей необходим. Вообще говоря, приоритет задачи определяется ее важностью. Для каждой задачи ядро создает специальную структуру данных под названием Task ЧТО ТАКОЕ ЗАДАЧА? 233 Control Block (TCB – блок управления задачей). TCB содержит сведения о при оритете задачи, ее состоянии («готова к работе» или находится «в состоянии ожидания»), текущем значении указателя стека и другую информацию. В теле кода задачи, внутри бесконечного цикла, следует поместить вызов функций ядра, чтобы ваша задача ожидала наступления какого-либо события. Одна задача может сообщить ядру: «Меня нужно запускать каждые 100 милли секунд», другая: «Я ожидаю получения пакета от Ethernet-контроллера», а третья: «Я жду завершения аналогово-цифрового преобразования» и т. д. Обычно собы тия генерируются либо вашим приложением с помощью ISR (Interrupt Service Routine – подпрограмма обработки прерывания), либо другими задачами. В об щем, ISR может передать задаче, чтобы вывести ее из сообщение состояния ожи В свою очередь, задача сама может передавать сообщения другой задаче. дания. Благодаря такому механизму обработки событий ядро может гарантировать, что ни одна из задач не будет занимать время центрального процессора целиком. То есть если вы не сообщите ядру о необходимости ожидания определенных событий, задача действительно будет бесконечным циклом и, следовательно, ее выполнение займет все время процессора. Большинство ядер поддерживает Это означает, приоритетные прерывания. что ядро всегда стремится выполнять задачу с наивысшим приоритетом, нахо дящуюся в состоянии «готова к работе». Рабочий профиль системы, созданной на базе ядра с приоритетными прерываниями, приведен на (4) (3) Подпрограмма обработки прерываний (ISR) ISR (5) (2) (6) Задача с высоким приоритетом (7) Задача с низким приоритетом (1) (8) Время Рис. 15.1. Рабочий профиль ядра с приоритетными прерываниями Р1–(1)  Выполняется задача с низким приоритетом. Р1–(2) #7; Происходит событие, наступления которого ожидала задача с высо ким приоритетом; это вызывает прерывание работы микропроцессора. Р1–(3) #7; Микропроцессор сохраняет в стеке выполняющейся задачи ее кон текст и передает управление ISR, обрабатывающей это событие. Кон текст задачи обычно содержит значения регистров процессора (более подробно мы обсудим это позже). Р1–(4) #7; ISR вызывает службу ядра, которая переводит задачу с высоким прио ритетом из сос оздаете решения, использующие автономные источники питания, ТАКТОВЫЙ ИНТЕРВАЛ ТАЙМЕРА 235 а процессор поддерживает спящие режимы с пониженным энергопотреблением, при обработке пустой задачи можно перевести CPU в один из этих режимов. Тогда код пустой задачи будет выглядеть следующим образом: void OSTaskIdle (void) { while (1) { // Перевод CPU в спящий режим с ПОНИЖЕННЫМ ЭНЕРГОПОТРЕБЛЕНИЕМ; } } При возникновении прерывания (т. е. события, ожидаемого одной из задач) CPU выводится из спящего режима и обслуживается программой ISR. По всей вероят ности, ISR переведет задачу в состояние готовности, следовательно, ядро «переклю чится» с пустой задачи на задачу, обрабатывающую данное событие. По окончании обработки события, если нет необходимости выполнять другие задачи, ядро снова «переключит» CPU на выполнение пустой задачи и немедленно перейдет к ис полнению инструкций бесконечного цикла (т. е. снова вернется в начало цикла). Тактовый интервал таймера Практически каждому ядру необходим эталон времени для отслеживания задер жек и простоев в работе программ. Такой эталон времени называется тактовым (clock tick). Обычно в этой роли выступает аппаратный интервалом таймера таймер, который прерывает работу CPU каждые 10–100 миллисекунд. Довольно часто в качестве генератора тактовых интервалов используется электросеть, от которой питается устройство, исполняющее ваше приложение. Сеть позволяет получить частоту 50 Гц (в Европе) или 60 Гц (в Северной Америке). Получив уведомление о возникновении прерывания таймера, ядро выясняет, не ожидает ли какая-нибудь задача истечения определенного интервала времени, чтобы пе рейти в состояние «готова к работе». Например, если необходимо приостановить выполнение задачи на 10 тактовых интервалов таймера, то в состояние «готова к работе» ее нужно перевести при возникновении 10-го прерывания таймера. В этот момент ядро определит, является ли готовая к работе задача самой важ ной, и, в случае выполнения этого условия, просто приостановит работу прерван ной таймером задачи и возобновит исполнение новой задачи. Приведенная ниже программа иллюстрирует задержку выполнения задачи на 10 тактовых интерва OSTimeDly(), лов таймера с помощью вызова функции входящей в ядро µC/OS-II. void MyTask (void) { while (1) { OSTimeDly(10); // Приостанавливает выполнение текущей // задачи на 10 тактовых интервалов! // Код задачи (т. е. ваш код) } } 236 ЯДРА РЕАЛЬНОГО ВРЕМЕНИ Как упоминалось выше, прерывание таймера используется для перевода за дач, ожидающих наступления события, в состояние «готова к работе», если это событие не наступает по истечении указанного пользователем времени ожида ния. Например, задача, описанная ниже, ожидает поступления сообщения от OSQPend() любой другой задачи или от ISR. – еще одна функция µC/OS-II, позволяющая задачам получать сообщения, имеет три аргумента. Первый аргу мент – указатель на объект, называющийся очередью сообщений и используе мый для хранения пересылаемых сообщений, второй аргумент – длительность интервала (в тактовых интервалах таймера), в течение которого задача должна ожидать получения сообщения. Последний аргумент – указатель на код ошиб ки, который возвращается ядром как сообщение о результате вызова функции OSQPend(). OSQPend(), Получив управление обратно после вызова функции ваша программа должна просто проверить код ошибки, чтобы узнать, поступило ли вашей задаче сообщение или она была активизирована по окончании интервала ожидания. void MyTask (void) { void *pmsg; OS_ERR err; while (1) { pmsg = OSQPend(MyMsgQ, 10, &err); if (err == OS_ERR_TIMEOUT) { // За 10 тактовых интервалов таймера сообщение не поступило } else { // Сообщение получено, обработка сообщения, на которое // указывает переменная pmsg. } } } Планирование задач Планирование задач – функция, выполняемая ядром для определения необхо димости запуска наиболее важных задач. Планирование задач происходит при выполнении одного из следующих условий: 1. #7; ISR (подпрограмма обработки прерывания) с помощью служб ядра посыла ет задаче сообщение. Если задача, получающая сообщение, более важна, чем прерванная, то по окончании выполнения всех вложенных ISR, возобновит ся выполнение задачи, получившей сообщение, а выполнение прерванной задачи по-прежнему будет приостановлено (см. рис. 15.3А). Результатом планировки задач в этом случае будет переключение контекстов (подробно описано ниже). Если же задача, получающая сообщение менее важна, чем прерванная, то по окончании выполнения всех вложенных ISR, будет воз обновлено выполнение прерванной задачи (см. рис. 15.3Б). Другими сло вами, переключение контекста не выполняется. ПЛАНИРОВАНИЕ ЗАДАЧ 237 ISR отправляет сообщение для HPT Подпрограмма обработки прерываний (ISR) Переключение контекста Задача с высоким A приоритетом (HPT) Задача ожидает Задача с низким поступления сообщения приоритетом (LPT) Время ISR отправляет сообщение для LPT Подпрограмма обработки прерываний (ISR) Переключение контекста Б НЕ ВЫПОЛНЯЕТСЯ Задача с высоким приоритетом (HPT) Задача ожидает поступления сообщения Время Рис. 15.3. Планирование задач и переключение контекстов по инициативе ISR 2. #7; Задача посылает сообщение другой задаче, используя службы ядра. Если задача, принимающая сообщение более важна, чем передавшая его, ядро переключится на принимающую задачу (см. рис. 15.4), в противном случае продолжается выполнение задачи, отправившей сообщение. Задача ожидает поступления сообщения Задача с высоким приоритетом (HPT) Задача с низким приоритетом (HPT) Переключение контекста Время LPT отправляет сообщение для HPT Рис. 15.4. Планирование задач и переключение контекстов по инициативе задачи 3. #7; Задача переходит в состояние ожидания на определенное время (например, OSTimeDly()). вызвав функцию В этом случае выполнение данной задачи приостанавливается, и ядро выбирает и выполняет следующую наиболее важную задачу, находящуюся в состоянии «готова к работе». Чтобы ядро запустило задачу, она должна находиться в состоянии готова (Ready-To-Run). То есть если задача ожидала событие, и оно произо к работе шло, ядро подготовит задачу к работе. Планировщик запускает только те задачи, которые находятся в состоянии «готова к работе». 238 ЯДРА РЕАЛЬНОГО ВРЕМЕНИ Переключение контекстов Как уже говорилось, контекст задачи, вообще говоря, представляет собой копию содержимого всех регистров процессора. Для приостановки выполнения задачи ядро должно просто сохранить значения всех регистров CPU. Аналогично для возобновления работы задачи ядру достаточно просто восстановить содержимое регистров процессора из сохраненного контекста. На рис. 15.5 продемонстриро вано переключение контекстов для процессора Motorola 68HC11. Текущий TCB Новый TCB Приоритет Приоритет Не готов Готов Рис. 15.5. Переключение контекстов процессора Motorola 68HC11 Р5(1) #7; Ядро сохраняет указатель на TCB (блок управления задачей) текущей задачи. Р5(2) #7; Когда планировщик решает переключиться на другую задачу, он об новляет значение указателя так, чтобы тот содержал ссылку на TCB новой задачи. Р5(3)  Указатель стека SP содержит адрес стека задачи. Р5(4) #7; Для переключения контекстов ядро сначала сохраняет значения всех регистров CPU в стеке текущей задачи. Для процессора 68HC11 ядру SWI достаточно просто вызвать команду (программное прерывание). SWI Инструкция помещает в стек значения всех регистров CPU, как показано на рис. 15.5. SP Р5(5) #7; После этого текущее значение регистра (указатель стека) сохраня ется ядром в блоке TCB выполняемой задачи. Р5(6) #7; Затем ядро загружает в регистр значение нового указателя на вершину стека из блока TCB новой задачи. СЛУЖБЫ ЯДРА 239 SP Р5(7)  Регистр содержит указатель на вершину стека новой задачи. RTI, Р5(8) #7; После этого ядро выполняет команду которая приводит к авто матическому восстановлению из стека значений всех регистров CPU. В этой точке процессор исполняет код новой задачи. В итоге этот процесс можно отобразить в следующем псевдокоде. Планирование задач и переключение контекстов процессора 68HC11: { Найти HPT, находящуюся в состоянии «готова к работе» (указатель на ее TCB); Сохранить значения регистров CPU в стеке выполняемой задачи; Сохранить значение регистра SP в TCB выполняемой задачи; Загрузить в регистр SP указатель на вершину стека новой задачи из ее TCB; Выполнить выход из инструкции команды прерывания; } Для переключения контекстов на процессоре 68HC11 в μC/OS-II требуется меньше 10 строк на языке ассемблера! Службы ядра Итак, мы узнали, что: 1.  Ядро позволяет разбивать приложение на несколько задач. 2. #7; Ядру необходим какой-либо эталон времени (тактовый интервал таймера), который позволит задачам самостоятельно приостанавливать свою работу на определенный промежуток времени или для обеспечения тайм-аута при получении сообщений. 3.  Задача или ISR могут посылать сообщения другим задачам. 4. #7; Ядро с приоритетными прерываниями всегда пытается выполнять наи более важные задачи, находящиеся в состоянии «готова к работе». При наступлении события активизируется планировщик задач, если имеется более важная задача, готовая к работе, которая требует обслуживания про цессором. 5. #7; Переключение контекста используется для сохранения текущего состояния задачи и восстановления более важной задачи. Большинство коммерческих ядер предоставляют в наше распоряжение го раздо больше служб. В этой главе мы опишем лишь некоторые из основных служб. Службы ядра. Семафоры Это одна из важнейших служб, призванная гарантировать исключительный до ступ к общим ресурсам. А именно ядра предоставляют механизм, называющий ся семафором, который ваша задача должна использовать для доступа к общим переменным, массивам, структурам данных, устройствам ввода/вывода и т. д. В приведенном ниже примере показаны две задачи, которые должны получать доступ (для чтения или модификации) к данным. 240 ЯДРА РЕАЛЬНОГО ВРЕМЕНИ OS_EVENT *MyDataSem; void Task1 (void) { INT8U err; while (1) { 0, &err); OSSemPend(MyDataSem, // Доступ к совместно используемым данным! OSSemPost(MyDataSem); : : } } void Task2 (void) { INT8U err; while (1) { 0, &err); OSSemPend(MyDataSem, // Доступ к совместно используемым данным! OSSemPost(MyDataSem); : : } } Чтобы доступ к данным был возможен, каждая задача предварительно долж на «получить» семафор. В μC/OS-II это осуществляется путем вызова функ OSSemPend(). ции Если семафор имеет значение «доступен», вызов функции OSSemPend()успешно завершается и задача получает доступ к ресурсу. Если же семафор «открыт» для другой задачи, то задача, запросившая доступ, будет «бло кирована» и помещена в список задач, ожидающих «освобождения» семафора. Когда задача, владеющая семафором, завершит доступ к ресурсу, она вызовет OSSemPost(), функцию которая освобождает семафор. На этом этапе ядро про веряет наличие задач, ожидающих семафора, и если таковые имеются «передает» семафор заданию с наиболее высоким приоритетом. Затем ядро определяет, не является ли задача, ожидающая освобождения семафора, более важной, и в слу чае необходимости переключает контекст на нее. И наоборот, если задача, ос вободившая семафор имеет более высокий приоритет по сравнению с задачей, переведенной в состояние готовности, то ядро возвращается к задаче, освободив OSSemPost(). шей семафор, и немедленно выполняет код, обратившись к функции Существует три типа семафоров: двоичные, счетные и мьютексные. Двоичные семафоры используются при доступе к единственному ресурсу. Например, мож но использовать двоичный семафор для доступа к дисплею – здесь я предпола гаю, что ваши задания совместно используют один дисплей (ЭЛТ, ЖК и т. д.). Счетные семафоры используются в том случае, если необходимо предоставить доступ к любому из нескольких идентичных ресурсов. Например, можно ис пользовать вычислительный семафор для доступа к одному из буферов буфер ного пула. Начальным значением такого семафора будет число бу

О книге «Руководство по микропрограммному обеспечению»

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

На нашем сайте можно скачать книгу «Руководство по микропрограммному обеспечению» в формате pdf или читать онлайн. Здесь так же можно перед прочтением обратиться к отзывам читателей, уже знакомых с книгой, и узнать их мнение. В интернет-магазине нашего партнера вы можете купить и прочитать книгу в бумажном варианте.


Pirate Books

  1. Руководство по микропрограммному обеспечению

    [​IMG]

    Издательство: ДМК Пресс
    Жанр: Разработка и тестирование программного обеспечения

    Качество: Хорошее
    Страниц: 408
    Формат: pdf, fb2, epub

    Книга адресована разработчикам микрокода, пишущим те самые программы, на которых работают технологии XXI века. Она заполняет важнейший пробел в литературе по встраиваемому программному обеспечению. Существует настоятельная потребность в сборнике идей и концепций, справочнике, настольной книге инженеров, куда они заглядывали бы, чтобы найти решение своих задач и освежить в памяти забытый материал. Главной темой этой книги является микрокод, однако суровая реальность мира встраиваемого ПО такова, что код и аппаратура взаимозависимы. Они не могут существовать в изоляции; ни в одной другой области программирования нет такой глубокой связи между реальным и виртуальным. Аналоговые инженеры постоянно твердят, что у них прекрасная профессия. Конечно, очень здорово ворочать операционными усилителями. Но бедняги не ведают, как это увлекательно — сделать так, чтобы все двигалось, огоньки мигали, газ тек. Это мы, разработчики встраиваемого ПО, управляем работой моторов, перекачиваем кровь, приводим в действие автомобильные тормоза, и выдвигаем компакт-диски из дисководов. Что может сравниться по притягательности с этой размытой границей между микрокодом и реальным миром? В книге описываются инструментальные средства и методы улучшения качества программного кода, эволюционная разработка ПО, встраиваемые конечные автоматы, системы реального времени, обработка и управление ошибками. Примеры сопровождаются многочисленными листингами на языках С и С++. Издание предназначено инженерам и программистам, использующих встраиваемое ПО в своей работе, а также будет полезно студентам вузов и всем читателям, интересующимся микропрограммным обеспечением. На сайте издательства ДМК-Пресс выложены исходные коды всех примеров программ из книги.

    Вложения:

Поделиться этой страницей

Понравилась статья? Поделить с друзьями:
  • B kurunga коралловый клуб инструкция по применению
  • Инженер отдела профилактики пожаров должностная инструкция
  • Технология мокрого фасада по пенопласту инструкция
  • Витрум пронаталь инструкция по применению цена отзывы
  • Препарат инспра инструкция по применению цена отзывы