Целевая платформа

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

История встраиваемых систем

Как ни странно, одной из причин появления микроконтроллеров является холодная война и космическая гонка. Конечно, и до 60-х годов существовали процессоры и компьютеры, однако они представляли собой стеллажи и наборы плат, соединенных проводами. В инструментальной лаборатории МТИ (англ. MIT Instrumentation Laboratory) группа инженеров под руководством Чарльза Старка Драпера (англ. Charles Stark Draper) специально для программы «Аполлон» разработала Apollo Guidance Computer (сокр. AGC), процессор которого был выполнен в виде интегральной микросхемы. По сути это и была первая «встраиваемая система» (англ. embedded system) с весьма смешными по сегодняшним меркам характеристиками. Процессор состоял из 4100 вентилей на резисторно-транзисторной логике; имел 4 килобита оперативной и 32 килобита постоянной памяти; работая на частоте 2,048 МГц, был способен выполнять всего 12 инструкций (элементарных операций: сложение, вычитание и т. д.) Таких параметров хватило для осуществления самого безумного и опасного предприятия за всю историю человечества — высадки человека на Луну.

Бортовой компьютер AGC (такие были установлены в командном и лунном модуле) работал под управлением операционной системы реального времени (кооперативная многозадачность, планировщик на прерываниях), написанной на языке ассемблера, и был в состоянии выполнять до 8 задач одновременно. К слову, программный код миссии Apollo 11 выложен в публичный доступ на GitHub. Изучать его нет особого смысла, так как это анахронизм, потерявший актуальность, однако это довольно интересное культурное событие — во время холодной войны за такие действия могли посадить или даже приговорить к смертной казни.

После программы «Аполлон», в начале 70-х, независимо друг от друга над микропроцессорной техникой начали работу довольно известные на сегодня компании — Intel и Texas Instruments, пути которых разошлись в самом начале. Intel в ноябре 1971 года представила первый коммерческий 4-битный микропроцессор i4004, предназначенный для калькуляторов. (Впоследствии данная компания превратилась в монополиста на рынке универсальных процессоров.) А вторая, Texas Instruments, решая ту же самую задачу — создавая микропроцессоры для калькуляторов, — разработала семейство микросхем TMS1000, с одним большим отличием — на одном кристалле с ним была расположена оперативная и постоянная память. Патент на данное изделие получил Гари Бун (англ. Gary Boone) в 1973-м, и именно эту дату принято считать датой рождения микроконтроллеров как класса устройств.

При таком подходе не требуются дополнительные микросхемы памяти, что позволяет создавать миниатюрные устройства. Название «микроконтроллер» (англ. micro + controller, микро + регулятор), скорее всего, происходит от специфики применения подобных микросхем — устройств автоматизации и управления.

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

Со временем на рынке появились и другие компании, предлагающие микроконтроллеры (сокр. МК) с разной разрядностью и архитектурами. Сейчас среди них можно выделить Renesas Electronics, Atmel, Microchip, Freescale Semiconductor, Texas Instruments, NXP Semiconductor, Fujitsu, ST Microelectronics и многие другие.

Микроконтроллер и ядро ARM Cortex-M3

Как уже говорилось выше, микроконтроллер (англ. microcontroller или MCU — MicroController Unit), в отличие от компьютерного процессора, включает в себя не только цепочки для выполнения математических операций (АЛУ), но и оперативную и постоянную память, различные контроллеры (например NVIC), модули преобразователей (ADC, DAC) и аппаратные реализации различного рода интерфейсов передачи данных (SPI, USART, I2C, CAN и т. д.).

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

Сердцем любого МК является ядро (англ. core). Некоторые компании занимаются разработкой и продвижением собственных архитектур (так, Atmel продвигает AVR, а Texas Instruments — MSP430), другие же выпускают микроконтроллеры с лицензируемой архитектурой ARM, разрабатываемой британской компанией ARM Limited. На данный момент ARM представляется наиболее эффективной, предлагая превосходную производительность с относительно низкой ценой. Тем не менее, простые 8- и 16-битные микроконтроллеры до сих пор находят применение там, где нужна минимальная цена за кристалл.

В начале мы заявили, что приводить примеры кода будем для микроконтроллера от компании ST Microelectronics — stm32f103с8, построенного на ядре ARM Cortex-M3. Как должно быть понятно из названия, данный микроконтроллер является 32-битным, т.е. элементарная ячейка данных представляет собой 32 бита, или 4 байта.

Устоявшейся классификации не существует, однако все МК можно разделить по трем классам параметров: набору инструкций, разрядности (размер обрабатываемых данных — 2n бит) и назначению.

Классификация по набору инструкций

Нашей целью не является разбор архитектур и описание их преимуществ и недостатков, заметим лишь, что в RISC, исходя из названия, набор команд сокращенный. Все инструкции фиксированной длины и выполняются за один цикл. Такой подход позволяет упростить реализацию в железе, но повышает сложность компилятора. ARM-ядро (от англ. Advanced RISC Machine — усовершенствованная RISC-машина) имеет RISC-архитектуру, но не в чистом виде, так как не все инструкции ARM выполняются за один цикл.

Классификация МК по разрядности шины

Классификация по назначению

Так как ARM ядро унифицировано, т.е. у разных производителей оно построено одинаково, то и программный код должен исполняться одинаково для МК любого производителя. Для упрощения разработки ARM Limited предоставляет библиотеку CMSIS (от англ. Cortex Microcontroller Software Interface Standard), позволяющую писать почти кросс-вендорный код. Слово «почти» здесь написано по той причине, что помимо ядра в микроконтроллере присутствуют и периферийные блоки, которые уже являются вендор-зависимыми, т.е. разрабатываются самими производителями микроконтроллеров. Так, в дополнение к CMSIS для семейства МК stm32f10x от ST Microelectronics предоставляется заголовочный файл stm32f10x.h, который по сути является драйвером МК — в нем описаны все адреса регистров для работы с периферией, макроопределения и т.д. Ниже приведена диаграмма устройства данной линейки.

Периферийные блоки могут сильно отличаться от микроконтроллера к микроконтроллеру, в зависимости от задач, которые они должны решать. Как правило, в любом МК можно встретить:

Отличаться может и само ядро. В stm32f103c8 располагается ARM Cortex-M3 (ARMv7-M), пожалуй, наиболее распространенная архитектура на сегодня. Сами Cortex'ы бывают трех семейств:

Cortex-M также подразделяется на несколько типов, которые отличаются по производительности:

К ключевым особенностям Cortex M3 относятся: 32-битное ядро / шина данных; гарвардская архитектура (англ. Harvard architecture) — раздельная шина данных и инструкций; трехступенчатый конвейер (англ. pipeline): этап выборки (англ. fetch), дешифровки (англ. decode), и исполнения (англ. execute); блок векторов прерываний (англ. nested vectored interrupt controller), позволяющий обрабатывать исключительные события; поддержка интерфейса отладки JTAG или SWD (англ. serial wire debug).

Любое устройство воспринимается микроконтроллером как модуль памяти, хотя физически таковым может и не являться. Память программы, оперативная память, регистры устройства ввода-вывода — все они находятся в едином адресном пространстве. Структура адресного пространства Cortex-M3 закреплена стандартом и не изменяется от производителя к производителю. Так как ядро 32-битное, то размер адресуемого пространства численно равен 232 = 4 гигабайтам2.

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

За более подробным описанием карты памяти следует обратиться к документации.

В дальнейшем мы раскроем подробнее некоторые понятия, такие как «конвейер», а сейчас перейдем к понятию «прерывание» (англ. interrupt) и модулю NVIC в целом.

Мало в каком устройстве нет кнопок, состояние которых необходимо отслеживать. Обычно подобные элементы управления подключаются к одному из входов МК таким образом, что при нажатии на нем изменяется напряжение. Например, кнопка отжата — на входе 0 вольт, кнопка нажата — на входе 3,3 вольта. Если отслеживание уровня напряжения происходит простым считыванием входного регистра, то существует вероятность пропустить сам факт нажатия. Допустим, время выполнения некоторого участка кода занимает 1 секунду, а время кнопки в нажатом состоянии всего 200 миллисекунд. При таком раскладе можно нажать кнопку раза четыре и не получить ответной реакции. Для обработки подобных асинхронных, по отношению к самой программе, событий (англ. event), необходимо использовать механизм прерываний. Он позволяет реагировать на их появление моментально3.

Для пояснения данного понятия прибегнем к аналогии из жизни. Представьте, что вы попросили своего друга объяснить, что же такое прерывание. И спустя каких-то пять секунд после этого звонит ваша возлюбленная, что заставляет вас прервать беседу и со словами: «Прости, мне надо ответить...» — взять трубку. Закончив разговор, вы возвращаетесь к понятию прерывания и ждете, когда ваш друг даст определение. Всё, что ему нужно сказать, — «Собственно, это оно и было». Другими словами, программа останавливается (при этом ее текущее состояние сохраняется на стек), и начинает работать другой участок кода, называемый обработчиком (англ. handler) прерывания. По завершении выполнения обработчика программа возвращается на то место, где была прервана, и продолжает свою работу.

Каждое прерывание вызывается событием, но не каждое событие вызывает прерывание.

Это два пересекающихся множества.

В зависимости от источника, прерывания можно разделить на три типа.

Все имена существующих векторов прерываний описаны в файле startup_<mcu>.s.

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

Возможны разнообразные прерывания по самым разным причинам. Поэтому каждому прерыванию ставят в соответствие число — так называемый номер прерывания (англ. position). Чтобы связать адрес обработчика с номером, используется таблица векторов прерываний (англ. vector table).

Таблица прерываний в микроконтроллерах с ядром ARM является векторной. Каждый элемент в ней — это 32-битный адрес, указывающий на определенный обработчик: вектор с адресом 0x08 указывает на NMI-прерывание, а 0x0C соответствует HardFault.

Первые 15 элементов строго закреплены стандартом ядра, т.е. одинаковы для всех микроконтроллеров на данной архитектуре. Все последующие прерывания называются вендор-зависимыми (англ. vendor specific), т.е. зависят от производителя (прерывания от блоков RTC, USB, UART и т.д.). Таблицу со стандартной частью можно найти в Cortex-M3 Devices Generic User Guide.

Номер исключенияIRQПриоритетСмещение адреса
1-30x00000004
2-14-20x00000008
3-13-10x0000000C
4-12Настраиваемый0x00000010
5-11Настраиваемый0x00000014
6-10Настраиваемый0x00000018
7-10
11-5Настраиваемый0x0000002C
13
14-2Настраиваемый0x00000038
15-1Настраиваемый0x0000003C
160Настраиваемый0x00000040

В таблице можно заметить такую колонку, как «приоритет» (англ. priority). Это контринтуитивно, но чем меньше число, описывающее его, тем более важным является прерывание. Первые три прерывания (Reset, NMI и HardFault) описываются отрицательным числом. Приоритеты всех остальных прерываний можно настраивать (по умолчанию они имеют нулевой приоритет).

Но зачем нужны приоритеты? Буква N в названии модуля NVIC происходит от слова nested, т.е. «вложенный». Если во время работы обработчика некоторого прерывания произойдет другое, приоритет которого больше, чем того, что обрабатывается сейчас, то произойдет то же самое, что и с основной программой, — обработчик будет остановлен, управление перехватит более приоритетное прерывание4.

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

Для понимания работы некоторых вещей, описанных далее, понадобятся три системных (т.е. в любом ARM) прерывания: SysTick_Handler, SVC_Handler и PendSV_Handler, поэтому приведем их краткое описание.

Последнее, о чём следует упомянуть в данном разделе, это специализированный тип памяти, называемый регистром (англ. register). Регистры бывают двух типов:

В Cortex-M3 насчитывается 21 регистр ядра. Первые 13 называют регистрами общего назначения и разбивают на две группы: нижние R0-R7 и верхние R8-R12. К нижним возможно применять как 16-битные инструкции Thumb, так и 32-битные Thumb-2, а к верхним применимы только 16-битные, и то не все. Впрочем, такие тонкости вряд ли нужны разработчикам на Си, так как обращаться к этим регистрам можно только через язык ассемблера.

Регистры общего назначения — это ячейки памяти, расположенные непосредственно в ядре и предназначенные для выполнения инструкций. Именно в них подгружаются значения переменных и затем совершаются такие операции, как сложение или вычитание. Отсюда вытекают некоторые особенности: поскольку в Cortex-M3 нет инструкций для работы с числами с плавающей запятой, данные операции раскладываются на ряд элементарных доступных инструкций. Следовательно, обычное сложение таких чисел займет больше одного цикла. Другая особенность — желательно, чтобы количество используемых переменных в области видимости (в функции) не превышало количество регистров общего назначения. В противном случае «лишние» переменные будут храниться в оперативной памяти, обращение к которой — довольно медленная операция.

Регистр R13 отводится под указатель стека (англ. stack pointer, SP). На самом деле их два, но в любой момент времени доступен только один из них. Первый называется системным (англ. main stack pointer, MSP), а второй пользовательским (англ. process stack pointer, PSP). Подробное описание архитектуры не входит в наши задачи, но в грубом приближении такое разделение необходимо для разделения программы привилегированного уровня выполнения (прерывания или операционной системы) и пользовательского приложения (т.е. нашей основной программы)5.

Регистр связи (англ. link register) R14 используется для запоминания адреса возврата при вызове подпрограммы (функции), что позволяет вернуться к выполнению прерванного кода.

Регистр R15, счетчик команд (англ. program counter), отводится для хранения адреса текущей команды.

Все последующие регистры именуются специальными (англ. special registers). Первый из них называется PSP (от англ. program status register) и состоит из трех частей:

В регистре PRIMASK (англ. priority mask) используется только один бит (из 32), который по умолчанию установлен в 0, запрещая все прерывания с настраиваемым приоритетом (т.е. все прерывания, кроме системных). Если записать туда 1, прерывания разрешаются.

Следующий регистр, FAULTMASK, управляет маскируемыми (переключаемыми) прерываниями, глобально разрешая или запрещая их, кроме NMI (англ. non-maskable interrupt). По умолчанию нулевой бит сброшен в ноль, т.е. такие прерывания запрещены.

Регистр BASEPRI использует первые 8 бит и применяется для запрета прерываний, приоритет которых меньше или равен записанному в него значению. Чем меньше значение, тем выше уровень приоритета. Всего получается 128 уровней6.

Последний регистр, CONTROL, отвечает за режим работы процессора и используемого стека.

Режимов работы у ядра может быть два: привилегированный (англ. privileged) и непривилегированный (англ. unprivileged). Нулевой бит регистра, nPRIV, задает режим, а первый, SPSEL, — используемый стек. В привилегированном режиме доступны все области памяти и инструкции. При попытке обращения к запрещенным областям памяти или вызова некоторых инструкций в непривилегированном режиме последует исключение, и выполнение программы прекратится, т. е. выполнение перейдет к одному из обработчиков исключительных ситуаций: Hard Fault, MemManage Fault, Usage Fault или Bus Fault.

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

По умолчанию тактирование всей периферии отключено для экономии энергии. Следовательно, если разработчик желает использовать тот или иной модуль, ему придется вручную включать его. Если в некоторых целях используется порт ввода-вывода A, то первое, что необходимо сделать, — подать на него питание и тактирующий сигнал. У выбранного нами в начале МК за данную функциональность отвечает один из регистров блока сброса и тактирования (англ. reset and clock control):

Используя драйвер stm32f10x.h, тактирование можно включить следующим образом:

Данной строчкой кода мы обращаемся к структуре RCC, поля которой не что иное, как регистры. Каждый регистр, например APB2ENR, имеет свой адрес и задан макросом в драйвере.

Т.е. RCC ссылается на байт по адресу 0x40021000 в пространстве памяти, который приводится к типу структуры RCC_TypeDef, которая, в свою очередь, инкапсулирует регистры данного модуля. Сверим данный адрес с документацией на МК:

Маска RCC_APB2ENR_IOPBEN заменяется на число 8, т.е. 23, или 1 на четвертой позиции в регистре APB2ENR. Данная ячейка в памяти является триггером и управляет тактированием порта A. Строчку кода выше можно с тем же успехом записать по-другому:

Библиотека CMSIS позволяет писать более читаемый код.

Последующие уровни абстракции (англ. hardware abstraction layer, HAL) и вовсе избавляют от необходимости работать с регистрами напрямую. Подобные библиотеки сводят приведенную выше строчку к вызову функции с соответствующими аргументами.

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

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

Особенность встраиваемых систем

Ограниченность ресурсов — вот ключевая особенность встраиваемых систем. В вашем телефоне спокойно может быть 2 или даже 4 Гб оперативной памяти, 32 Гб постоянной и восьмиядерный процессор с частотой 1,6 ГГц. В микроконтроллере stm32f103c8 доступно всего 20 Кб оперативной и 64 Кб постоянной памяти, а максимальная частота ядра составляет жалкие 72 МГц. Когда-то компьютера с худшими характеристиками хватило для миссии Apollo, а сейчас мой телефон то и дело зависает, а производительность падает после каждого обновления...

Теперь, когда мы понимаем, что есть микроконтроллер, можно перейти к вопросу о его программировании. Какой язык выбрать?

Прогулка по уровням абстракции

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

В начале компьютерной эры игры создавались на «жесткой логике». Яркий пример — игра Breakout от компании Atari: она была создана на дискретных компонентах, без применения микропроцессора. Задача, прямо сказать, не из простых — однако Стиву Возняку7 она оказалась по силам. Каково же было его изумление, когда вместо месяцев работы над подобным проектом он мог потратить всего одну ночь на создание того же самого, используя микропроцессор и язык программирования.

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

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

Если не вдаваться глубоко, транзисторы состоит из трех частей, из двух типов материала, сложенных в виде сэндвича. Отличительной характеристикой одного вещества (N, англ. negative) является то, что в кристаллической решетке имеется избыток электронов, а во втором веществе (P, англ. positive), наоборот, их недостаток (образовавшееся вакантное место называют «дыркой», т.е. эдаким виртуальным положительным зарядом). В зависимости от «укладки» слоев бывают NPN- и PNP-транзисторы.

Электрод, подключенный к середине, называют базой (англ. base), другие два — коллектором (англ. collector) и эмиттером (англ. emitter). Стрелка на эмиттере указывает направление тока.

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

В итоге при подаче тока на базу транзистор открывается (резистор ограничивает ток базы). Если тока нет, т. е. напряжение между базой и эмиттером равно 0 В, то транзистор закрыт, и ток через К-Э не бежит.

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

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

Операция «НЕ»

Видоизменив схему — заменив реле на сопротивление — легко получить инвертирование сигнала.

Операция НЕ унарная, т.е. требует всего одно значение. Если мы подадим на базу низкое напряжение, то транзистор будет закрыт. Снимая напряжение на коллекторе, мы получим высокий уровень. И наоборот, открыв транзистор (высокое напряжение на базе), мы замкнем цепь на землю, т.е. напряжение на коллекторе будет низким.

Для описания логических операций удобно использовать так называемую таблицу истинности:

AA
01
10

Операция «И»

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

ABAB
000
010
100
111

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

Операция «ИЛИ»

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

ABAB
000
011
101
111

Физически такую операцию легко реализовать, соединив транзисторы параллельно, а не последовательно, как в случае с операцией И.

Часто для построения схем используют «совмещенные операции», такие как NAND (NOT + AND) или NOR (NOT + OR). В случае, когда нужно переключить состояние из 0 в 1 или из 1 в 0, удобно использовать исключающее ИЛИ (XOR).

Такое построение называется транзисторно-транзисторной логикой, или ТТЛ.

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

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

Предположим, что в регистре уже записано 0b1001, а нам необходимо значение 0b1101. Изменить состояние одного-единственного бита можно при помощи логических операций.

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

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

Затереть единицу в определенной позиции можно, использовав две операции. Сначала инвертируется маска, а затем производится логическое умножение:

Таким незамысловатым образом программы управляют микроконтроллером.

Самопроверка

Вопрос 1. Что такое «встраиваемая система» и чем она отличается от обычного компьютера?

Вопрос 2. Какие архитектуры вы знаете?

Вопрос 3. Что такое прерывание и зачем оно нужно?

Вопрос 4. Чем прерывание отличается от события?

Вопрос 5. Что такое регистр?

Вопрос 6. При построении схем «И», «ИЛИ» мы использовали ТТЛ; попробуйте составить такие же схемы, но только на диодной логике. Помните, что диод проводит ток только в одном направлении.

Вопрос 7. Попробуйте составить схемы следующих элементов:

Вопрос 8. Составьте таблицу истинности для следующих выражений:

Вопрос 9. Запишите в регистр reg единицу на 6-ю позицию и ноль в 7-м бите.


Назад | Оглавление | Дальше


1 Встраиваемой системой называют особый вид компьютерной системы, которая решает одну специализированную задачу, чаще всего в режиме реального времени, т.е. время обработки сигналов имеет критическое значение.
2 Не стоит путать адресное пространство с реальным объёмом памяти. 4 гигабайта — это то количество элементарных ячеек памяти (байтов), которое способна адресовать шина. В реальности у микроконтроллера на борту может быть всего 16 килобайт flash-памяти и 6 килобайт ОЗУ.
3 В действительности имеется небольшая задержка (англ. latency), откуда она берётся, вы поймёте чуть позже.
4 Между началом выполнения кода в обработчике и моментом вызова проходит 12 тактов. Если во время прерывания происходит другое (менее приоритетное), то оно встаёт в очередь, при этом между завершением текущего и запуском следующего прерывания тратится всего 6 тактов.
5 При написании обычной прошивки стек MSP всегда используется для обработки исключительных ситуаций (прерываний), а PSP — только для исполнения обычной программы. В случае ОС компания ARM рекомендует использовать MSP для ядра системы и прерываний, а стек PSP — для выполнения задач.
6 В stm32 используются только первые 4 бита, т.е. уровней прерываний всего 16.
7 Сооснователь Apple Inc., один из создателей персональных компьютеров, выдающийся инженер-электронщик. Ознакомиться с его биографией можно в книге «iWoz: Computer Geek to Cult Icon: How I Invented the Personal Computer, Co-Founded Apple, and Had Fun Doing It» (на русском «Стив Джобс и я: подлинная история Apple»)
8 Хорошее описание того, как устроен процессор и как осуществляются различные операции в нём, можно найти в книге «Цифровая схемотехника и архитектура компьютера», Дэвид М. Хэррис, Сара Л. Хэррис.