Глава 3 Обработка хранимой программы

В предыдущей главе мы с вами разработали простейший процессор, состоящий из арифметико-логического устройства (АЛУ) и регистра с параллельным вводом/выводом данных. Собственно АЛУ выступает в роли «числодробилки», а рабочий регистр используется для хранения операндов, а также результатов всех операций. В нашем примере, описанном на стр. 33, мы складывали вместе два числа, накапливая результат в рабочем регистре. Если задавать код режима работы АЛУ перед каждым шагом, то мы в принципе можем заставить наше вычислительное устройство выполнить любую задачу, которая может быть описана последовательностью арифметических и логических операций. Эта совокупность кодов команд (например, «сложить», «вычесть», «логическое И»…) может храниться во внешней памяти. Там же могут находиться различные операнды, передаваемые в АЛУ, а также результаты выполнения команд. Таким образом, эти коды включают в себя как собственно программу программируемого устройства, так и различные операнды, или данные. Извлекая (fetch) эти команды по очереди, мы можем выполнять заданную программу. Такая структура вместе с соответствующими каналами передачи данных, дешифраторами и логическими схемами обычно называется цифровым компьютером или цифровой вычислительной машиной.

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

Прочитав эту главу, вы:

• Познакомитесь с фон-неймановской архитектурой и узнаете ее недостатки.

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

• Поймете, какая взаимосвязь существует между цифровым компьютером, микропроцессором и микроконтроллером.

• Познакомитесь со структурой памяти программ, а также ее взаимодействием со счетчиком команд и конвейером.

• Узнаете формат типичных команд.

• Познакомитесь с назначением и структурой памяти данных.

С исторической точки зрения электронные цифровые вычислительные машины в том виде, в котором мы их сегодня знаем, являются косвенным результатом Второй мировой войны. В то время были созданы различные опытные образцы компьютеров, причем некоторые из них действительно работали[43]. Как правило, эти вычислительные машины представляли собой специализированные устройства, предназначенные для выполнения какой-либо конкретной задачи при различных входных данных. Алгоритм функционирования некоторых из таких машин можно было менять, но при этом требовалась их частичная переделка.

Поскольку принципиальный вопрос возможности создания таких вычислительных систем был уже решен, основным достижением группы инженеров, работавших с Джоном фон Нейманом[44], было осознание того факта, что программа может храниться в памяти вместе с данными. Основным преимуществом такого подхода является его гибкость, так как для изменения программы достаточно просто загрузить новый код в соответствующую область памяти. По существу, фон-неймановская[45] архитектура, показанная на Рис. 3.1, состоит из центрального процессора (ЦПУ), памяти и общей шины (называемой также магистралью), по которой в обоих направлениях пересылаются данные. На практике ЦПУ также должен взаимодействовать и с окружающим миром. При этом данные к/от соответствующих интерфейсных портов передаются по одной общей шине данных.

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

Рис. 3.1. Элементарная фон-неймановская вычислительная машина (шина адреса не показана)

В первое послевоенное десятилетие в Гарвардском университете было создано несколько компьютеров семейства «Марк», от «Марк 1» до «Марк 4», в которых память программ была полностью отделена от памяти данных (в первых машинах «Марк 1» и «Марк 2» программа считывалась с бумажной перфоленты). Такая концепция была более эффективной, чем фон-неймановская (или, как ее иногда называют, принстонская[46] архитектура, поскольку код программы мог считываться из памяти программ одновременно с обменом между ЦПУ и памятью данных или с операциями ввода/вывода. Однако такие машины были намного сложнее и дороже в изготовлении. А с учетом уровня технического развития 50-х годов, да еще и после проигрыша в конкурсе на создание компьютера для контроля сети континентальных радиолокационных станций, устроенного Министерством обороны США, они и вовсе не получили широкого распространения. Однако с развитием сложных интегральных схем эта гарвардская архитектура снова оказалась в центре внимания.

На Рис. 3.2 показаны две физически разделенные шины, используемые для передачи информации между ЦПУ и этими неперекрывающимися областями памяти. Каждая память имеет собственную шину адреса, поэтому адрес ячейки памяти программ никоим образом не связан с адресом ячейки памяти данных. В таком случае говорят, что обе области памяти находятся в различных адресных пространствах. Память данных иногда называют файловой памятью, в этом случае n-я ячейка обозначается как файл n.

Рис. 3.2. Элементарная гарвардская вычислительная машина (шины адреса не показаны)

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

Центральный процессор

Центральный процессор состоит из связки АЛУ/рабочий регистр и соответствующей управляющей логики. По сигналам схемы управления команды программы выбираются из памяти, дешифруются и исполняются. Данные, которые получаются или используются во время выполнения программы, также располагаются в памяти. Этот цикл «выборка — исполнение» образует рабочий ритм вычислительной машины и повторяется непрерывно в течение всего времени, когда система находится в активном состоянии.

Память

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

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

Память программ

В памяти программ хранится двоичный код, составляющий программу, или программное обеспечение (software). Это слово созвучно термину hardware (аппаратные средства) и отражает тот факт, что данный код не связан с каким-либо физическим изменением схемы устройства. В идеале память, в которой находится программа, должна быть такой же быстрой, как и ЦПУ, поэтому для данных целей обычно используется полупроводниковая память, созданная при помощи технологий, подобных рассмотренным в предыдущей главе[47].

Память данных

В памяти данных хранятся данные, используемые во время работы программы. И опять же быстродействие этой памяти обычно сравнимо с быстродействием ЦПУ. Также в адресном пространстве памяти данных могут располагаться специальные регистры, например порты ввода/вывода.

Интерфейсные порты

Независимо от своего назначения компьютер должен иметь возможность взаимодействовать с окружающим миром. Хотя обычно вспоминаются такие устройства, как клавиатура и монитор, можно считывать и изменять состояние практически любого физического устройства. Так, данные об объеме топлива, впрыскиваемого в цилиндр двигателя, в совокупности со значением скорости вращения вала могут использоваться для управления моментом зажигания искры в камере сгорания бензинового двигателя.

Шина данных

Все элементы фон-неймановского компьютера соединяются между собой одной общей магистралью передачи данных, или шиной (понятие шины было введено во 2-й главе, см. Рис. 2.4 на стр. 34). Вся информация передается по этим общим линиям в обоих направлениях, при этом ЦПУ играет роль главного контроллера. В компьютере с гарвардской архитектурой память программ имеет отдельную шину данных, что позволяет осуществлять выборку команд одновременно с действиями на шине данных памяти программ. Другие шины используются для передачи адресов различным областям памяти, а также управляющей информации и информации о состоянии (см. Рис. 3.4).

* * *

Микроконтроллеры, которым посвящена эта книга, имеют гарвардскую архитектуру, поэтому дальше мы будем рассматривать только ее. Взяв за основу ЦПУ, показанный на Рис. 2.20 (стр. 49), и добавив к нему память программ, память данных, а также схемы управления и дешифрации, мы получим примитивный компьютер с гарвардской архитектурой (Рис. 3.3). Серым цветом на рисунке выделены элементы исходной схемы с Рис. 2.21, приведенного на стр. 50.

Благодаря подключению шины данных АЛУ к памяти данных, мы получаем возможность считывать из памяти первый операнд, а также при необходимости помещать в нее результат операции. Адрес этого операнда является частью кода команды, считанного из памяти программ и дешифрованного устройством управления. Это же устройство управления формирует сигналы выбора режима АЛУ, который зависит от текущей команды. Результат, получаемый на выходе АЛУ, может быть загружен либо в рабочий регистр (устройство управления формирует импульс на линии W), либо обратно в ту же ячейку памяти, откуда был считан операнд (устройство управления формирует импульс на линии F). Информация об адресате результата операции также содержится в коде команды.

Команды (в виде кодовых слов) обычно располагаются в памяти программ последовательно. Для поочередной адресации каждой команды используется двоичный суммирующий счетчик (см. Рис. 2.24 на стр. 53). Если, предположим, при сбросе компьютера счетчик команд (Program Counter — PC) обнуляется, то первая команда будет расположена по адресу h’000’ памяти программ, вторая — по адресу h’001’ и т. д. (см. Рис. 3.4). Устройство управления просто инкрементирует счетчик после выборки каждой команды. Непосредственно загружая новый адрес в счетчик команд, можно осуществить переход к другому участку кода.

Рис. 3.3. Структура элементарного гарвардского компьютера на системном уровне

Последовательность операций «выборка команды/ее дешифровка/исполнение», т. е. так называемый цикл выборки — исполнения команды, является фундаментальным понятием, необходимым для понимания работы компьютера. Чтобы проиллюстрировать этот рабочий ритм, рассмотрим простую программу, которая считывает переменную NUM_1, прибавляет к ней число 4 и записывает результат в переменную NUM_2. На языке высокого уровня Си эту операцию можно записать следующим образом[48]:

NUM_2 = NUM_1 + 4;

Несколько более подробно структура нашего компьютера, который я назвал BASIC (аббревиатура от Basic All-purpose Stored Instruction Computer — базовый универсальный компьютер с хранимой программой), изображена на Рис. 3.4. На этом рисунке показаны ЦПУ и обе области памяти со своими шинами данных и соответствующими шинами адреса.

Рис. 3.4. Состояние ЦПУ в момент выполнения первой команды при одновременной выборке второй команды. Все адреса/данные представлены в шестнадцатеричной системе

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

Сначала разберемся с процессом выборки команд.

Счетчик команд

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

Поскольку счетчик команд подключен через внутреннюю шину данных к исполнительному блоку, мы можем использовать АЛУ для управления этим регистром и изменения предопределенной последовательности исполнения команд. Таким образом, можно реализовать различные команды перехода к другим частям программы, а также команды пропуска.

Конвейер

В двух регистрах команд содержатся коды команд, считанные из памяти программ. В начало конвейера (в первый регистр команд, IR1) загружается код n-й команды и хранится там для обработки в следующем цикле. Это позволяет исполнять команду n - 1, находящуюся в конце конвейера (во втором регистре команд, IR2) одновременно с выборкой n-й команды и загрузкой ее в конвейер. Работа конвейера показана на Рис. 3.7.

Дешифратор команд

Дешифратор команд ID является «мозгами» ЦПУ — он дешифрует код команды, находящийся в регистре IR2, и формирует в определенной последовательности сигналы для исполнительного блока, необходимые последнему для определения местоположения операнда (если таковой имеется) в памяти данных и для переключения АЛУ в заданный режим. На Рис. 3.4 показано выполнение команды movf h’25’,w (копирование содержимого регистра данных с адресом h’25’ в рабочий регистр).

* * *

Исполнительный блок осуществляет обращения к памяти данных и конфигурирование АЛУ. Работой исполнительного блока управляет дешифратор команд, функционирование которого, в свою очередь, зависит от значения кода команды n — 1, находящегося в регистре команд IR2.

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

Регистр адреса

Когда ЦПУ собирается обратиться к ячейке (регистру) памяти данных, он помещает адрес этой ячейки в регистр адреса FAR. При этом производится непосредственная адресация памяти данных по ее шине адреса. Как показано на Рис. 3.4, из памяти данных считывается регистр с адресом h’25’, и его содержимое защелкивается во внутреннем регистре данных FDR процессора.

Регистр данных

Этот «двунаправленный» регистр выполняет две функции:

• Хранит содержимое адресованного регистра данных, если ЦПУ осуществляет цикл чтения. Именно это происходит при выполнении 1-й команды (movf h’25’,w), которая пересылает (копирует) содержимое регистра с адресом h’25’ в рабочий регистр.

• Хранит данные, которые ЦПУ собирается записать в адресованный регистр данных. Такой цикл записи, в частности, имеет место при выполнении команды movwf h’26’, которая пересылает (копирует) содержимое рабочего регистра в регистр с адресом h’26’.

Арифметико-логическое устройство

АЛУ выполняет арифметические и логические операции, определяемые значением кода режима (см. Рис. 2.10 на стр. 39), который извлекается из кода команды дешифратором команд.

Регистр состояния

Этот регистр содержит флаги нуля Z и переноса С, которые устанавливаются соответственно, если результат операции равен нулю и если в результате сложения возник перенос.

Рабочий регистр

В рабочем регистре АЛУ (W) обычно находится один из операндов команды — либо источник, либо адресат. Например, команда addwf h’20’,w складывает содержимое рабочего регистра с содержимым регистра h’20’ и помещает сумму обратно в рабочий регистр W. В некоторых компьютерах этот регистр называется также аккумулятором.

* * *

Помимо ЦПУ, в нашем компьютере имеется две области памяти, предназначенные для хранения кода программы и данных.

Память программ

Каждая позиция (или ячейка) памяти программ может содержать одну команду, которая кодируется 14-битным словом. Из Рис. 3.4 видно, что каждая из этих ячеек имеет свой адрес, выставляемый счетчиком команд на шину адреса памяти программ. На этом рисунке содержимое PC равно h’001’ (или Ь’0000000000000’), что приводит к выдаче содержимого ячейки h’001’ на шину данных памяти программ и, следовательно, загрузке его в начало конвейера. В рассматриваемом примере считанное значение равно h’3E04’ (или b’11111000000100’), что является машинным кодом команды addlw 04. В конечном счете дешифратор команд интерпретирует этот код как операцию сложения константы «4» с рабочим регистром.

Память данных

Каждая ячейка (или регистр) памяти данных содержит один байт (восемь битов) данных. Адрес регистра формируется исполнительным блоком в регистре адреса FAR и выставляется на шину адреса памяти данных. Содержимое адресованного регистра либо считывается в регистр данных FDR, либо перезаписывается находящимся в нем значением.

Шины адреса и данных памяти данных совершенно независимы от одноименных шин памяти программ, что позволяет одновременно обращаться к обеим областям памяти. Таким образом, адреса памяти программ и памяти данных имеют различный смысл, т. е. адрес h’25’ в памяти программ совсем не то же самое, что адрес h’25’ в памяти данных, который соответствует регистру h’25’.

* * *

Теперь, когда у нашего ЦПУ появилась память программ и память данных, рассмотрим более подробно саму программу. Наша иллюстративная программа состоит всего из трех команд и, как уже упоминалось, предназначена для копирования увеличенного на 4 значения однобайтной переменной, расположенной по адресу NUM_1, в ячейку с адресом NUM_2. Из Рис. 3.4 видно, что переменная NUM_1 представляет собой псевдоним для обозначения содержимого регистра данных h’25’. Аналогично, имя NUM_2 является символическим выражением для указания содержимого регистра данных h’26’.

А теперь рассмотрим используемые в программе команды.

∙ movf

Эта команда (MOVe File) копирует содержимое заданного регистра данных в рабочий регистр (как правило) или же обратно в тот же регистр данных (см. стр. 141). Таким образом, команда movf num_1,w загружает байт, расположенный по адресу h’25’ памяти данных, в рабочий регистр. Если содержимое указанного регистра равно нулю, то при выполнении команды устанавливается флаг Z, в противном случае этот флаг будет сброшен.

∙ addlw

Эта команда (ADD Literal to Working register) прибавляет однобайтную константу к содержимому рабочего регистра. Таким образом, команда addlw 04 прибавляет число 4 к содержимому рабочего регистра и записывает результат обратно в этот же регистр. Если возникает переполнение, то устанавливается флаг С, а если результат равен нулю — флаг Z.

∙ movwf

Эта команда (MOVe Working register to File) копирует содержимое рабочего регистра в заданный регистр данных. Таким образом, команда movwf NUM_2 сохраняет содержимое рабочего регистра по адресу h’26’ памяти данных. На состояние флагов данная команда не влияет.

Описывая команды, мы использовали мнемонические обозначения, такие как addlw. Разумеется, реальные логические схемы, декодирующие эти команды, работают исключительно с двоичными кодами. Мнемонические обозначения просто играют роль своеобразных «памяток» для программиста. Хотя крайне маловероятно, что кто-либо станет писать программы в машинных кодах, двоичный формат всех команд имеет логическую основу, и его знание будет полезно для понимания недостатков и ограничений набора команд и реальных аппаратных средств, которые мы будем обсуждать в следующих двух главах.

Пока мы рассмотрим две категории команд.

Прямая адресация регистра данных

Данный способ адресации используют команды, в которых указывается адрес регистра данных, являющийся их операндом. Например, в команде movf h’25’,w операндом является регистр h’25’.

Из Рис. 3.5 видно, что 14-битный код команды состоит из трех частей:

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

• Седьмой бит кода команды, обозначенный символом «d», определяет адресата результата операции. Например, команда addwf h’30’,w означает «сложить содержимое рабочего регистра с регистром h’30’ и поместить результат обратно в рабочий регистр», тогда как команда addwf h’30’,f означает «сложить содержимое рабочего регистра с регистром данных h’30’ и поместить результат обратно в регистр h’30’». В первом случае адресатом операции является рабочий регистр W и бит d равен 0, а во втором случае адресатом является регистр данных и бит d равен 1. Мы еще вернемся к этой команде в пятой главе. В символической записи команды символы «,w» соответствуют сброшенному биту адресата d, а символы «,f» соответствуют установленному биту d.

• Младшие семь битов (6…0) определяют адрес регистра данных. Так, в нашем примере используется регистр h’25’, поэтому в указанном поле содержится значение Ь’0100101’. Так как размер поля адреса равен семи битам, то посредством прямой адресации можно адресовать только один банк памяти, вмещающий в себя 27 = 128 регистров, т. е. с регистра h’00’ по регистр h’7F’ (см. Рис. 4.7 на стр. 97).

Рис. 3.5. Формат кода команд, использующих прямую адресацию

Операции с константами

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

Рис. 3.6. Формат слова команд операций с константами

Код операции команды из нашего примера (addlw 04) равен Ь’111110’, а константа равна Ь’00000100’. Значение константы должно лежать в диапазоне Ь’00000000’…Ь’11111111’ (h’00’…h’FF’ или, в десятичной системе, 0…255), что вполне логично, поскольку рабочий регистр, как и все внутренние регистры исполнительного блока, является восьмибитным[49].

* * *

Не только команды могут иметь мнемонические обозначения. Как мы видели, символические имена можно присваивать и ячейкам памяти данных. Так, на Рис. 3.4 идентификатор NUM_1 используется для указания содержимого регистра данных h’25’, a NUM_2 — регистра данных h’26’. Таким образом, нашу программу можно символически записать следующим образом:

NUM_2 = NUM_1 + 4;

Возвращаясь к собственно компьютеру, мы видим, что, начиная с адреса h’000’, наша программа имеет вид

00100000100101

11111000000100

00000010100110

Если только вы не киборг, то чтение такой программы — весьма сомнительное удовольствие[50].

Если мы воспользуемся шестнадцатеричной системой[51], то будет уже удобнее:

0825

ЗЕ04

00А6

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

Раз уж мы все равно собираемся использовать компьютер для перевода нашей программы, называемой также исходным кодом, в двоичный машинный код, называемый объектным кодом, то имеет смысл не мелочиться и записать ее полностью в символическом виде. При этом различные команды будут представлены их мнемоническими обозначениями, а адреса переменных — своими именами. В результате наша программа примет вид:

movf NUM_1,w; Копируем содержимое NUM_1 в W

addlw 4; Прибавляем к нему число 4

movwf NUM_2; Копируем NUM_1 + 4 в NUM_2

Текст после символов «;» называется комментариями, которые используются для облегчения понимания программы.

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

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

* * *

В основе работы любого вычислительного устройства лежит периодическое выполнение цикла выборкаисполнение. При этом каждая команда поочередно выбирается из памяти программ, интерпретируется и исполняется. Поскольку память, к которой обращается программа в процессе выполнения, является памятью данных, а каждое устройство памяти имеет собственные шины, операции выборки и исполнения могут осуществляться параллельно. Таким образом, во время выборки n-й команды исполняется команда n — 1. На Рис. 3.4 показано, что коды обеих команд, как следующей, так и текущей, хранятся в двух внутренних регистрах команд — IR1 и IR2 соответственно. Команды, считанные из памяти программ, загружаются в начало этого конвейера и «выталкиваются» в дешифратор команд с конца конвейера. На Рис. 3.7 изображен развернутый во времени процесс выполнения нашей команды, разбитый на машинные циклы. Во время каждого цикла, за исключением самого первого, выборка новой команды и исполнение предыдущей осуществляются одновременно.

Рис. 3.7. Параллельные потоки выборки и исполнения команд

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

* * *

Выборка (Рис. 3.4)……Цикл 2

• Инкрементируется счетчик команд, чтобы указать на 2-ю команду.

• Одновременно код 1-й команды перемещается по конвейеру (из регистра IR1 в регистр IR2).

• Содержимое счетчика команд (h’001’) выставляется на шину адреса памяти программ.

• После этого на шине данных памяти программ появляется код 2-й команды, который загружается в регистр IR1.

Исполнение (Рис. 3.4)…..Цикл 2

• Адрес операнда h’25’ (т. е. NUM_1) заносится в регистр адреса FAR и выставляется на шину адреса памяти данных.

• Искомое значение, находящееся по адресу NUM_1, выставляется на шину данных памяти данных, после чего загружается в регистр FDR.

• АЛУ переключается в режим пропуска, в котором аргумент с входа АЛУ без изменений копируется в рабочий регистр.

* * *

Выборка….. Цикл 3

• Инкрементируется счетчик команд, чтобы указать на 3-ю команду.

• Одновременно код 2-й команды перемещается по конвейеру (из регистра IR1 в регистр IR2).

• Содержимое счетчика команд (h’002’) выставляется на шину адреса памяти программ.

• После этого на шине данных памяти программ появляется код 3-й команды, который загружается в регистр IR1.

Исполнение ….. Цикл 3

• АЛУ переключается в режим сложения, в котором константа, содержащаяся в коде 2-й команды, прибавляется к содержимому рабочего регистра.

• Результат операции NUM_1 + 4 с выхода АЛУ помещается обратно в рабочий регистр.

* * *

Выборка ….. Цикл 4

• Инкрементируется счетчик команд, чтобы указать на 4-ю команду.

• Одновременно код 3-й команды перемешается по конвейеру (из регистра IR1 в регистр IR2).

• Содержимое счетчика команд (h’003’) выставляется на шину адреса памяти программ.

• После этого на шине данных памяти программ появляется код 4-й команды, который загружается в регистр IR1.

Исполнение ….. Цикл 4

• Адрес операнда h’26’ (т. е. NUM_2) заносится в регистр адреса FAR и выставляется на шину адреса памяти данных.

• АЛУ переключается в режим пропуска, в котором содержимое рабочего регистра без изменений копируется в регистр FDR и выставляется на шину данных памяти данных.

• Содержимое регистра FDR заносится в память данных по адресу, выставленному на шину адреса, т. е. в регистр NUM_2.

* * *

Обратите внимание на автоматическое изменение счетчика команд на этапе выборки каждого цикла. Такой последовательный характер изменения его содержимого будет сохраняться до тех пор, пока не встретится команда, напрямую модифицирующая этот счетчик, например команда goto h’200’. При выполнении этой команды адрес h’200’ помещается в счетчик команд, нарушая обычный процесс инкрементирования, в результате чего ЦПУ перейдет к команде, расположенной по адресу h’200’. Далее изменение счетчика команд снова примет линейный характер.

Хотя наша программа делает, прямо скажем, немного, на выполнение каждой команды затрачивается всего около 1 мкс. Миллион простейших операций в секунду — это сила! По существу, все компьютеры, какими бы «умными» они ни казались, просто выполняют с очень большой скоростью множество относительно простых операций. Поэтому основной задачей программиста является принятие решения о том, в какой последовательности необходимо расположить команды и структуры данных для выполнения соответствующей задачи.

* * *

До настоящего момента мы рассматривали одни компьютероподобные структуры. Для логического завершения главы нам осталось только провести связь между предметом обсуждения и собственно микроконтроллерами.

Так что же это такое — микроконтроллер? Кратко говоря, микроконтроллер — это микропроцессор, который объединен с памятью и различными устройствами ввода/вывода в одной интегральной микросхеме. То есть по сути дела это микропроцессор со встроенными вспомогательными узлами. Так что нам придется совершить небольшое путешествие во времени к моменту рождения микропроцессора. Вся эта история началась в 1968 году, когда Роберт Нойс (один из изобретателей интегральных микросхем), Гордон Мур[52] и Эндрю Грув уволились из компании Fairchild Corporation и основали свою собственную компанию, назвав ее Intel[53]. В течение трех лет новая компания освоила выпуск полупроводниковой памяти всех основных типов, используемых в настоящее время, — динамического и статического ОЗУ, а также микросхем EEPROM.

Одним из неосновных направлений деятельности компании была разработка интегральных микросхем большой степени интеграции (БИС) по спецификациям заказчика. В 1970 году к Intel обратились представители японской корпорации Busicom с предложением изготовить подходящий набор микросхем (так называемый чипсет) для линейки калькуляторов. В то время рынок калькуляторов развивался очень динамично, поэтому любые микросхемы пришлось бы менять каждые несколько лет. Естественно, при этом снижалась рентабельность производства БИС и увеличивалась их стоимость. И вот инженеру Тэду Хоффу[54] пришла в голову революционная идея: а почему бы не создать простой ЦПУ на кристалле? Его можно было бы запрограммировать на реализацию функций калькулятора, а для расширения функциональности устройства по мере появления новых требований достаточно будет просто усовершенствовать его программное обеспечение. Все это значительно увеличивало срок жизни такой микросхемы и ее рентабельность. Кроме того, не следует забывать, что основной сферой деятельности компании Intel было производство микросхем памяти, а компьютероподобные архитектуры требуют ее очень много! Это была поистине блестящая мысль. Разумеется, в конце 1969 года японские заказчики одобрили предложение компании Intel, поскольку оно было простым и гораздо более гибким, нежели традиционные решения.

Весной 1970 года в Intel появился Федерико Фаггин[55], а уже к концу года были изготовлены рабочие образцы первого в мире чипсета. Эксклюзивными правами на его приобретение обладала компания Busicom. Однако к середине 1971 года у нее возникли серьезные финансовые затруднения, и компания Intel, возместив затраты на разработку этого чипсета в размере 65 000 долл., получила права на его продажу всем желающим. В то время рыночные перспективы этого изделия были достаточно туманны, но Intel все же решила рискнуть и опубликовала в ноябрьском номере журнала «Electronic News» за 1971 год рекламу своего «микропрограммируемого компьютера на кристалле», получившего обозначение 4004 (термин микропроцессор вошел в обиход только после 1972 года). Появление процессора 4004 вызвало бурный интерес, поскольку он позволял внедрить «интеллект» в электронную технику.

Микропроцессор 4004 имел фон-неймановскую архитектуру с 4-битной шиной данных и позволял напрямую адресовать до 512 байт памяти. Он работал на частоте 108 кГц и содержал 2300 транзисторов[56]. Годом позже был выпущен 8-битный микропроцессор 8008, работавший на частоте 200 кГц и позволявший адресовать 16 Кбайт памяти. Эта микросхема состояла уже из 3500 транзисторов. Если четырех битов было вполне достаточно для работы с BCD-числами, использующимися в калькуляторах, то 8-битная архитектура уже годилась для создания интеллектуальных терминалов (наподобие кассовых аппаратов), в которых требовалась поддержка разнообразных алфавитно-цифровых символов. В 1974 году на смену 8008 пришел микропроцессор 8080[57], а в 1976 году появился слегка модифицированный вариант последнего — 8085. Нужно сказать, что 8-битный микропроцессор 8085 до сих пор выпускается компанией Intel.

Идея микропроцессора оказалась настолько удачной, что множество других производителей электронных компонентов тоже поспешили застолбить место на этом рынке. Более того, многие бывшие разработчики открывали собственные компании, взять, к примеру, ту же Zilog. К 1976 году было выпущено или хотя бы анонсировано 54 различных моделей микропроцессоров. Так, родоначальником одного из семейств, имевших наибольший успех на рынке, был микропроцессор 6800, разработанный компанией Motorola[58]. Этот микропроцессор имел ясную и гибкую фон-неймановскую архитектуру, мог работать на частоте 2 МГц и адресовать до 64 Кбайт памяти. В модели 6802 (1977) была даже встроенная память объемом 128 байт и внутренний тактовый генератор. В 1979 году была выпущена усовершенствованная модель 6809, ставшая последним представителем этого семейства 8-битных микропроцессоров. Основными ее конкурентами были такие микропроцессоры, как 8085 компании Intel, Z80 компании Zilog и 6502 компании MOS Technology.

Вообще говоря, изначально микропроцессоры не предназначались для использования в обычных компьютерах. Но в 1975 году небольшая компания — производитель калькуляторов MITS[59], оказавшись на грани банкротства, совершила рискованный ход и переориентировалась на изготовление и продажу компьютеров. Примитивная вычислительная машина, разработанная инженером Эдом Робертсом (Ed Roberts), была построена на базе микропроцессора 8080 компании Intel. Взаимодействие с оператором осуществлялось посредством переключателей и лампочек, располагавшихся на передней панели, — никакой клавиатуры и монитора. В течение нескольких недель после начала рекламной акции компания получила около 650 предварительных заказов на этот компьютер, названный «Альтаир»[60] (сумма каждого заказа составляла около 400 долл.). В результате вместо долга на сумму 400 000 долл. компания получила прибыль в размере 250 000 долл.

Этот первый персональный компьютер (ПК) породил целое поколение компьютерных фанатов. Так, однажды, в декабре 1975 года, никому доселе не известный 19-летний студент факультета вычислительной техники Гарвардского университета Билл Гейтс (Bill Gates) и зашедший к нему в гости приятель Пол Аллен (Paul Allen) увидели фотографию «Альтаира»[61] на обложке журнала «Popular Electronics» и решили заняться написанием программного обеспечения для этого ПК. Они связались по телефону с Эдом Робертсом и сообщили ему, что у них есть уже почти завершенный транслятор языка Бейсик для «Альтаира» (вообще-то это была, мягко говоря, неправда). Так на свет появилась корпорация Microsoft.

Примерно двумя месяцами позже насколько десятков человек основали в Сан-Франциско своеобразный компьютерный клуб, приобретя в складчину один «Альтаир» на всех. В числе членов этого клуба были Стив Джобс (Steve Jobs) и Стив Возняк (Steve Wozniak). В качестве демонстрации работы клуба они собрали собственный ПК, назвав его «Apple»[62]. К 1978 году объем продаж компьютеров «Apple II» составил 700 000 долл.; в течение 1979 года этих компьютеров было продано на сумму 7 млн долл., в следующем году — на сумму 48 млн долл…

Компьютер «Apple II» был построен на базе недорогого микропроцессора 6502 производства компании MOS Technology. Разработчиком этого процессора (и одним из основателей компании) был Чак Педцл (Chuck Peddle), ранее служивший в компании Motorola и отвечавший там за разработку процессора 6800. Неудивительно, что микропроцессор 6502 до боли напоминал это предыдущее детище Чака. Компания Motorola даже подала в суд с требованием запретить продажу микропроцессора 6501, тем более что его цоколевка полностью совпадала с цоколевкой их процессора 6800. Вплоть до конца 70-х годов микропроцессор 6502 оставался одним из основных игроков на рынке ПК, будучи, помимо всего прочего, «сердцем» таких известных в то время компьютеров, как «ВВС Micro»[63] и «Commodore PET»[64].

Основным фактором, реально повлиявшим на популярность компьютера «Apple II», было наличие у последнего пакета программ «VisiCalc» для работы с электронными таблицами. Когда бизнес-сообщество осознало, что ПК — это не просто игрушка и что с его помощью можно решать «реальные» задачи, объем продаж этих компьютеров резко подскочил. То же самое произошло и с компьютерами IBM PC. Этот ПК, представленный компанией IBM в 1981 году, был построен на базе микропроцессора 8088, работавшего на частоте 4.77 МГц. В компьютере имелось ОЗУ объемом 128 Кбайт, два дисковода для дискет объемом 360 Кбайт и монохромный дисплей, работавший в текстовом режиме. В качестве операционной системы в нем использовалась ОС PC/MS-DOS версии 1.0 компании Microsoft. В комплекте с ней поставлялся пакет программ для обработки электронных таблиц «Lotus 1-2-3».

Уровень развития технологии изготовления кремниевых СБИС, достигнутый к концу 70-х, сделал возможным размещение на одном кристалле нескольких десятков и даже сотен тысяч транзисторов. И сразу же перед разработчиками микропроцессоров встал вопрос: каким образом использовать эту возможность? Наиболее очевидным и, соответственно, наиболее популярным направлением совершенствования микроконтроллеров было увеличение разрядности АЛУ и емкости шин/памяти. По этому пути, в частности, пошла компания Intel, выпустив в 1978 году микропроцессор 8086 (16-битный вариант микропроцессора 8085[65]), имевший в своем составе 29 000 транзисторов.

При его разработке особое внимание было уделено программной и аппаратной совместимости с его 8-битным предшественником. С коммерческой точки зрения это было очень мудрым решением, поскольку позволяло удержать многочисленных потребителей процессора 8085 от перехода к изделиям конкурентов. В то же время это решение было весьма неоднозначным с технической точки зрения. Так или иначе, но выпуск этого микропроцессора оказался несколько преждевременным, поэтому в оригинальных компьютерах IBM PC компании IBM использовалась модифицированная версия 8086 — процессор 8088, имевший урезанную 8-битную шину данных и 20-битную шину адреса[66].

В 1979 году компания Motorola представила свой вариант 16-битного микропроцессора, получившего название 68000, а также его модификацию 68008 с 8-битной шиной данных. Однако внутренняя организация всех этих микропроцессоров была 32-битной, за счет чего удалось обеспечить их совместимость с более поздними моделями, вплоть до выпущенного в 1995 году микропроцессора 68060, а также RISC-процессора ColdFire, появившегося в 1997 году. Микропроцессоры семейства 68000 представляли собой совершенно новую разработку и технически были более прогрессивными по сравнению со своими конкурентами семейства 80x86.

Компания Apple решила использовать процессор 68000 в своих новых ПК «Macintosh». Однако, несмотря на все преимущества этого процессора, объем продаж компьютеров Apple Mac составил менее 5 % от объема продаж IBM PC. Гораздо больших успехов компания Motorola добилась на рынке микропроцессоров для встраиваемых систем — начиная от яйцеварок и заканчивая системами управления самолетов. Конечно же, микропроцессоры изначально были разработаны именно для этой области, поэтому количество микропроцессоров, проданных для использования во встраиваемых системах, более чем на порядок превысило количество, проданное для нужд компьютерного рынка.

В таких устройствах микропроцессор «спрятан» в недрах системы вместе с памятью и различными интерфейсными схемами ввода/вывода. То есть он выступает в роли центрального контроллера, управляя системой в соответствии с программой, зашитой в его памяти программ. Ежегодно для использования во встраиваемых системах продается свыше 3.5 млрд микропроцессоров и сопутствующих микросхем, что составляет более 95 % всего рынка микропроцессоров.

Другое направление совершенствования микроконтроллеров, ставшее возможным в конце 70-х, заключалось в сохранении относительно простого ЦПУ и использовании оставшихся ресурсов кристалла для реализации встроенной памяти и интерфейсов ввода/вывода. Это дало возможность создавать простые встраиваемые системы управления на одной-единственной микросхеме, значительно уменьшая таким образом общее число микросхем, необходимое для реализации заданной функции. Для реализации подавляющего большинства задач управления большой вычислительной мощности не требуется, а вот уменьшение размера готовых устройств и, соответственно, их стоимости крайне желательно. В качестве простого примера можно привести смарт-карту с интегрированным процессором. Такие микропроцессорные устройства получили название микроконтроллеров[67]. Например, в каждом доме, незаметно для нас, обитает несколько сот микроконтроллеров. Они есть повсюду — в бытовой технике, аудио- и видеоаппаратуре, персональных компьютерах, телекоммуникационных устройствах, смарт-картах и, в том числе, в автомобилях.

Если микропроцессор с точки зрения архитектуры (см. Рис. 3.1 и Рис. 3.2) представляет собой только блок центрального процессора, то микроконтроллер уже является законченной самодостаточной компьютероподобной системой. Рассмотрим в качестве примера электронную часть системы контроля автомобильного одометра, которая отображает общий пробег автомобиля с момента изготовления, а также дальность последней поездки (так называемый путевой одометр). Основным входным сигналом системы является сигнал от автомобильного тахометра, который формирует импульсы при каждом обороте маховика двигателя. Подсчитав суммарное количество этих импульсов, можно определить количество оборотов двигателя, а по интервалу между импульсами можно вычислить скорость движения автомобиля. Разумеется, реальный путь, проходимый автомобилем, зависит от передаточного числа коробки передач, поэтому нам необходимо знать о том, какая из пяти передач была включена водителем в каждый момент времени. Эта информация поступает из коробки передач по линиям G5, …, G1 (обычно обозначаемым как G[5:1]). Включенной передаче соответствует напряжение ВЫСОКОГО уровня на соответствующей линии (передача заднего хода не учитывается). Два дополнительных входа предназначены для задания единицы измерения отображаемых значений (мили или километры) и для обнуления путевого одометра.

Собственно дисплей одометра представляет собой семиразрядный 7-сегментный индикатор (см. Рис. 6.8 на стр. 183), который может отображать значения до

. Поскольку общее число сегментов довольно велико (целых 49), то для управления индикатором используется сдвиговый регистр (см. Рис. 2.22 на стр. 51), данные в который передаются по одной линии (Рис. 3.8). По второй лини передаются тактовые импульсы — для полного обновления содержимого дисплея необходимо 49 импульсов[68].

Рис. 3.8. Пример микроконтроллерной системы

Дисплей путевого одометра является 4-разрядным и позволяет отображать значения до

. Сдвиговый регистр этого дисплея тоже управляется по двум линиям, только в данном случае для вывода нового 4-разрядного значения необходимо 28 тактовых импульсов.

Для реализации этой системы нам потребуются следующие ресурсы (так называемый бюджет ресурсов):

• Вход, срабатывающий по фронту и подключенный к счетчику/таймеру для подсчета числа оборотов вала двигателя (на этот вход поступают импульсы от тахометра).

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

• Четыре цифровых выхода для тактирования двух сдвиговых регистров и передачи информации о сегментах.

• Микропроцессор для выполнения вычислений, считывания входных сигналов и формирования выходных.

• • Память программ, обычно ПЗУ какого-либо типа.

• Память данных для хранения рабочих переменных программы, обычно статическое ОЗУ.

• Энергонезависимая память для долговременного хранения информации, такой как суммарный путь, пройденный автомобилем, и расстояние, пройденное с момента последнего сброса путевого одометра.

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

• Модули приема/передачи данных по последовательным каналам с использованием разнообразных синхронных и асинхронных протоколов.

• Модули счетчиков/таймеров для подсчета числа внешних событий и формирования цифровых сигналов с точными временными параметрами.

• Модули аналого-цифрового преобразователя для считывания и оцифровки входных аналоговых сигналов.

• Модули цифро-аналогового преобразователя для формирования выходных аналоговых сигналов.

Модули специализированного интерфейса для управления многоразрядными жидкокристаллическими индикаторами (ЖКИ).

Такое использование дополнительных ресурсов кристалла привело к появлению в конце 70-х годов первых микроконтроллеров. К примеру, микроконтроллер Motorola 6801 (35 000 транзисторов), разработанный специально для использования в автомобилях, был построен на базе существующего микропроцессора 6800. Этот микроконтроллер имел ПЗУ программ объемом 2048 байт, ОЗУ данных объемом 128 байт, 29 линий ввода/вывода и 16-битный таймер. После того как микроконтроллеры доказали свою жизнеспособность, все ведущие производители микропроцессоров выпустили на рынок различные семейства микроконтроллеров. Каждое из этих семейств базировалось на определенном ядре, при этом различные представители одного и того же семейства отличались набором периферийных устройств. Например, в семействе 68НС11 компании Motorola (дальнейшее развитие микроконтроллера 6801) было использовано слегка модернизированное ядро 6800. Семейства 68НС12 и 68НС16 имели уже 16-битные ядра, которые, однако, обеспечивали совместимость с предыдущим 8-битным семейством 68НС11. Вскоре выяснилось, что во многих встраиваемых приложениях вовсе не требуются все вычислительные возможности древнего ядра 6800, поэтому было выпущено новое семейство 68НС05[69], представители которого имели значительно урезанное ядро и, соответственно, меньшую стоимость. Как это ни удивительно, но 4-битные микроконтроллеры, такие как TMS1000 компании Texas Instruments, лидировали по объему продаж среди всех остальных разновидностей процессоров вплоть до начала 90-х (и до сих пор продолжают пользоваться устойчивым спросом). Похоже, что и 8-битным микроконтроллерам, ставшим в последнее время наиболее популярными, в обозримом будущем уготована та же судьба. Кстати говоря, процессор 14500 компании Motorola вообще был однобитным!

В основе всех этих микропроцессоров и микроконтроллеров лежала фон-неймановская архитектура, используемая в универсальных ЭВМ. Альтернативная гарвардская архитектура впервые возродилась в микропроцессоре 8X300 компании Signetics, который в середине 70-х был приспособлен компанией General Instruments для работы в качестве периферийного интерфейсного контроллера (Peripheral Interface Controller — PIC). Компания собиралась использовать этот контроллер как программируемый порт ввода/вывода для своего 16-битного микропроцессора СР1600. После того как в 1988 году компания General Instruments продала свое подразделение интегральных микросхем молодой компании, названной Arizona Microchip Technology, это устройство вновь появилось на свет, но уже в виде самостоятельного микроконтроллера. Именно данному семейству микроконтроллеров и посвящена оставшаяся часть книги.

Примеры

Пример 3.1

Контроллер теплицы должен контролировать аналоговый сигнал от датчика влажности почвы и, если его величина ниже некоторого порогового значения, открывать водяной клапан на пять секунд с последующей 5-секундной паузой. В резервуаре с водой имеется поплавковый датчик, который замыкает контакты при снижении уровня воды ниже порогового значения. В этом случае должен включаться звуковой сигнализатор для индикации тревоги.

Можете ли вы придумать систему на базе микроконтроллера, реализующую указанные функции?

Решение

В решении, приведенном на Рис. 3.9, используется автомобильный одометр с Рис. 3.8. Единственным новым периферийным устройством является аналоговый порт, используемый для считывания и оцифровки аналогового сигнала отдатчика влажности почвы. В основе работы этого датчика лежит зависимость сопротивления почвы от ее влажности. Электроды датчика, включенные последовательно с постоянным резистором, образуют делитель напряжения, выходное напряжение которого будет меняться в зависимости от влажности почвы. Микроконтроллер может преобразовать это аналоговое напряжение в соответствующий цифровой код, который затем будет сравниваться в программе с предустановленным значением. Также порт ввода может представлять собой обыкновенный аналоговый компаратор, формирующий на выходе лог. 1 или лог. 0, если входное напряжение превышает определенное значение, которое может задаваться программно.

Рис. 3.9. Климатический контроллер теплицы

Глядя на Рис. 3.9, мы можем оценить требуемые ресурсы:

• Вход для внешнего генератора, подключенный к счетчику/таймеру. Это необходимо для того, чтобы микроконтроллер мог отсчитывать временные интервалы. На практике такие таймеры очень часто работают от внутреннего тактового сигнала микроконтроллера.

• Один аналоговый вход для измерения уровня аналогового сигнала от датчика влажности.

• Один цифровой вход для контроля уровня воды в резервуаре.

• Один цифровой выход для открытия и закрытия водяного клапана.

• Один цифровой выход для управления звуковым сигнализатором.

• Микропроцессор для вычислений, считывания входных и формирования выходных сигналов.

• • Память программ, обычно ПЗУ какого-либо типа.

• Память данных для хранения рабочих переменных программы, обычно статическое ОЗУ.

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

Пример 3.2

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

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

Решение

1. Подойти к переходу и остановиться.

2. Посмотреть на светофор.

3. Принять решение — не горит ли в нашем направлении зеленый сигнал?

4. ЕСЛИ сигнал красный, ТО перейти к шагу 2, ИНАЧЕ продолжить.

5. Посмотреть налево.

6. Едут ли машины?

7. ЕСЛИ да, ТО перейти к шагу 5, ИНАЧЕ продолжить.

8. Посмотреть направо.

9. Едут ли машины (вообще-то все машины уже должны были остановиться, но кто знает!)?

10. ЕСЛИ да, ТО перейти к шагу 5, ИНАЧЕ продолжить.

11. Перейти через дорогу — задача решена!

На Рис. 3.10 описанный алгоритм представлен в графическом виде. В этой блок-схеме прямоугольники используются для обозначения действий, ромбы — для обозначения условий, а прямоугольники со скругленными углами — для обозначения точек входа и выхода. Линии со стрелками указывают последовательность выполнения действий и дополнительно помечаются в точках принятия решений. В принципе в данном конкретном случае графическое представление алгоритма не имеет больших преимуществ по сравнению с текстовым. Однако в более сложных задачах, со множеством условий и вариантов выполнения, графическое представление может оказаться гораздо удобнее для документирования поведения системы. А когда система становится очень сложной, то и простой перечень задач, и блок-схема становятся одинаково бесполезными. В этом случае описание системы необходимо строить по иерархическому принципу, начиная с самых общих вопросов и постепенно продвигаясь к более конкретным задачам.

Рис. 3.10. Блок-схема алгоритма перехода через дорогу

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

Разумеется, робот не будет иметь ни малейшего понятия о том, что ему делать после перехода на другую сторону, если только мы не сообщим ему об этом. Что же касается человека, то он уже, образно говоря, «запрограммирован» — у него есть опыт!

Заметьте, что этапы пронумерованы в том порядке, в котором они должны выполняться. Счетчик команд, в данном случае читатель, начинает выполнение с 1-й команды (состояние сброса) и заканчивает выполнением 11-й команды. В микроконтроллере после выполнения действий, предписываемых текущим этапом, счетчик команд автоматически инкрементируется, указывая на следующий этап, если только текущая команда не была командой пропуска или перехода. При выполнении команды пропуска счетчик команд «перепрыгивает» через следующую команду, обычно при определенном условии или результате. А при выполнении команды перехода счетчик команд просто переходит к заданному этапу. Если бы таких команд не было, в программе нельзя было бы реализовать ветвления и циклы. Под циклом в данном случае понимается многократное повторение одних и тех же действий, например периодическая проверка наличия зеленого сигнала светофора до тех пор, пока он не включится.

Вопросы для самопроверки

3.1. Можете ли вы предложить вариант инкрементирования и декрементирования содержимого рабочего регистра, показанного на Рис. 3.4, с использованием трех команд, рассмотренных в этой главе?

3.2. Разработайте программу, которая позволит роботу с микроконтроллерным управлением из Примера 3.2 наполнить стакан водой из крана.

3.3 Компьютер BASIC, структура которого изображена на Рис. 3.4, может одновременно осуществлять выборку одной команды и исполнять другую команду. Объясните, за счет чего он может выполнять эти операции параллельно.

3.4 Составьте перечень задач, в соответствии с которым робот сможет пройти к ближайшему банкомату, снять со счета заданную сумму наличных, запросить баланс и вернуться на исходную позицию. Не забудьте про обработку запроса на печать баланса, а также продумайте действия робота при отсутствии на счете достаточной суммы денег!

3.5. Для подключения коробки передач к микроконтроллерной системе, показанной на Рис. 3.8, требуется пять выводов микросхемы. Многие микроконтроллеры выпускаются в корпусах с малым числом выводов (см., например, Рис. 10.2 на стр. 304). Подумайте, как можно уменьшить требуемое число выводов, а также будет ли ваше решение экономически оправданным? Подсказка: взгляните на Рис. 2.6 (стр. 36).

3.6. Подумайте, каким образом можно уменьшить на единицу количество выходов микроконтроллера, требуемых для управления дисплеями обоих одометров, и насколько это будет удобно?