- •Медицинские микропроцессорные системы
- •Анисимов а.А.
- •Isbn © сПбГэту «лэти», 2019 введение
- •1. Общая структура микроконтроллеров avr
- •2. Программирование микроконтроллеров на языке ассемблер
- •3. Работа с отладочной платой attiny104-xnano
- •4. Устройство портов ввода-вывода
- •5. Таймеры-счётчики
- •6. Широтно-импульсная модуляция
- •7. Использование аналого-цифрового преобразователя
- •8. Передача данных по uart
- •9. Последовательный интерфейс spi
- •Приложение 1. Основные команды языка assembler для микроконтроллера attiny104
- •Список литературы
- •Оглавление
- •Медицинские микропроцессорные системы
- •197376, С.-Петербург, ул. Проф. Попова, 5
МИНОБРНАУКИ РОССИИ
__________________________________________
Санкт-Петербургский государственный электротехнический
университет «ЛЭТИ» им. В. И. Ульянова (Ленина)
___________________________________________
А. А. АНИСИМОВ
Медицинские микропроцессорные системы
Учебное пособие
Санкт-Петербург
Издательство СПбГЭТУ «ЛЭТИ»
2019
УДК 616-71 (07)
ББК З-5я7 + 3973.23-018.2я7
С30
Анисимов а.А.
С30 Медицинские микропроцессорные системы: учеб. пособие.
СПб.: Изд-во СПбГЭТУ «ЛЭТИ», 2019. 83 с.
ISBN
В данном учебном пособии рассматриваются теоретические и практические аспекты программирования микроконтроллеров семейства AVR с использованием специализированных отладочных средств.
Предназначено для бакалавров, обучающихся по направлению 12.03.04 «Биотехнические системы и технологии», также может быть полезно магистрантам, обучающимся оп направлению 12.04.04 «Биотехнические системы и технологии», и аспирантам, обучающимся по направлению подготовки кадров высшей квалификации 12.06.01 «Фотоника, приборостроение, оптические и биотехнические системы и технологии».
УДК 616-71 (07)
ББК З-5я7 + 3973.23-018.2я7
Рецензенты: кафедра медицинской радиоэлектроники ГУАП (д-р техн. наук, проф. К. В. Зайченко); д-р биол. наук, проф. Н. Б. Суворов (ФГБНУ ИЭМ СЗО РАМН).
Утверждено
редакционно-издательским советом университета
в качестве учебного пособия
Isbn © сПбГэту «лэти», 2019 введение
Микропроцессорные системы последнее десятилетие стали неотъемлемой частью любого медицинского оборудования сложнее градусника (хотя даже они изрядно усложнились). Поэтому понимание основных принципов работы подобных устройств становится насущной необходимостью для любого специалиста, занимающегося не только разработкой, но и обслуживанием медицинской техники.
В данном учебном пособии сделана попытка описать структуру и общие принципы работы стандартных микроконтроллерных устройств на примере распространённых микроконтроллеров семейства AVR, производимых компанией Atmel (ныне входящей в состав Microchip, производителя легендарных микроконтроллеров семейства PIC). Данный тип микроконтроллеров был выбран как по соображениям преемственности (AVR контроллеры стали очень популярны в России с самого своего появления), так и ввиду большого разнообразия различных отладочных средств и бесплатного программного обеспечения, обладающего тем не менее весьма широким функционалом.
Теоретические сведения по каждому виду периферии, входящей в состав микроконтроллера AtTiny104, подкреплены практическими заданиями по написанию программного кода на двух различных языках программирования: ассемблере, позволяющим получить код, максимально приближенный к «железному» уровню, и на языке Си, позволяющем значительно упростить написание программ, и облегчающим переход к программированию микроконтроллеров более высокого уровня.
Изучение базовых принципов работы микроконтроллеров позволит в дальнейшем без особых проблем перейти к освоению более сложных систем, в том числе 32-битных микроконтроллеров на базе ядра ARM.
1. Общая структура микроконтроллеров avr
В рамках единой базовой архитектуры восьмибитные микроконтроллеры AVR подразделяются на четыре основных семейства:
Classic AVR
Tiny AVR
Mega AVR
XMega AVR
Микроконтроллеры семейства Classic в настоящее время являются устаревшими и их рассмотрение не представляется целесообразным. Микроконтроллеры семейства Tiny имеют небольшой объем памяти программ (1-2 Кбайта) и весьма ограниченную периферию. Микроконтроллеры семейства Mega, напротив, имеют развитую периферию, расширенный объем памяти программ и данных (до 256 Кб). Семейство XMega, появившееся на рынке относительно недавно (в 2008 году), относится к разряду 16-битных микроконтроллеров, имеет самую развитую периферию (например, встроенный 12-битный ЦАП, блок прямого доступа к памяти), наибольший объём памяти и повышенную тактовую частоту (до 120 МГц).
Структура микроконтроллеров семейства Tiny.
Ядро микроконтроллеров AVR семейства Tiny, как и ядро микроконтроллеров семейств Classic и Mega, выполнено по усовершенствованной RISC-архитектуре (Enchanced RISC), его упрощенная схема представлена на рисунке 1. Арифметико-логическое устройство (АЛУ), выполняющее все вычисления (то есть предназначенное для выполнения арифметических и логических преобразований над данными – вычитание, сложение, умножение, сравнение, сдвиг данных) подключено непосредственно к 32 рабочим регистрам, объединенным в регистровый файл – это так называемые оперативные регистры общего назначения (РОН). Доступ к этим ячейкам самый быстрый, а число операций с их содержимым наиболее разнообразное.
Благодаря этому АЛУ выполняет одну операцию (чтение содержимого регистров, выполнение операции и запись результата обратно в регистровый файл) за один машинный цикл. Практически каждая из команд (за исключением команд, у которых одним из операндов является 16-разрядный адрес) занимает одну ячейку памяти программ. В микроконтроллерах AVR реализована Гарвардская архитектура, которая характеризуется раздельной памятью программ и данных, каждая из которых имеет собственные шины доступа к ним. Такая организация позволяет одновременно работать как с памятью программ, так и с памятью данных.
Рис. 1.1. Упрощенная схема микроконтроллерного ядра
Разделение шин доступа позволяет использовать для каждого типа памяти шины различной разрядности, причем способы адресации и доступа к каждому типу памяти также различны. Еще одним решением, направленным на повышение быстродействия, является использование технологии конвейеризации. Конвейеризация заключается в том, что во время исполнения текущей команды производится выборка из памяти и дешифрация кода следующей команды. Причем, поскольку длительность машинного цикла микроконтроллеров AVR составляет всего один период тактового генератора, они могут обеспечивать ту же производительность, что и RISC-микроконтроллеры других фирм, но при более низкой тактовой частоте.
Счетчик команд (program counter)
Счетчик команд представляет собой регистр, в котором содержится адрес следующей исполняемой команды, при этом напрямую из исполняемой программы он недоступен. Размер счетчика команд зависит от объема имеющейся памяти программ и составляет от 2 до 16 разрядов. При нормальном выполнении программы содержимое счетчика команд автоматически увеличивается на 1 или на 2 (в зависимости от выполняемой команды) в каждом машинном цикле. Этот порядок нарушается при выполнении команд перехода, вызова и возврата из подпрограмм, а также при возникновении прерываний.
После включения питания, а также после сброса микроконтроллера в счетчик программ автоматически загружается нулевой стартовый адрес (0x00 в шестнадцатеричной системе) или начальный адрес сектора загрузчика. Как правило, по этому адресу располагается команда безусловного перехода к части программы, предназначенной для инициализации используемой периферии, откуда начинается выполнение программы. При возникновении прерывания в счетчик команд загружается адрес соответствующего вектора прерывания. Если прерывания используются в программе, по адресам векторов прерываний должны размещаться команды перехода к подпрограммам обработки прерываний.
Функционирование конвейера
Как и во всех микроконтроллерах AVR, в микроконтроллерах семейства Tiny используется конвейерная обработка команд. Функционирование конвейера показано в схематичном виде на рисунке 1.2. Во время первого машинного цикла происходит выборка команды из памяти программ и ее декодирование. Во время второго цикла эта команда выполняется, а параллельно происходит выборка и декодирование второй команды и так далее. В результате фактическое время выполнения каждой команды получается равным одному машинному циклу. Однако в действительности при отработке ряда команд происходит нарушение нормального функционирования конвейера. Наиболее ярким примером команд, вызывающих подобное нарушение, являются команды условного перехода, а также команды типа Test & Skip (проверка и пропуск следующей команды, если результат проверки положительный). В случае истинности условия, проверяемого командой условного перехода, выполнение программы должно будет продолжиться с некоторого адреса. А поскольку в конвейере уже произошла выборка команды, расположенной за командой перехода, время выполнения команды перехода увеличивается на один машинный цикл, во время которого происходит выборка команды, расположенной по требуемому адресу. При выполнении команд типа Test & Skip, следующая команда не выполняется в случае истинности проверяемого условия. Однако выборка пропускаемой команды уже произошла. Вследствие того, что команда не выполняется, в конвейере образуется «дырка», которая заключается в пропуске одного или двух (в зависимости от пропускаемой команды) машинных циклов. Таким образом команды типа Test & Skip выполняются за один машинный цикл, если результат проверки условия отрицателен, и за два или три цикла, если он положителен.
Рис.1.2. Функционирование конвейера
Очевидно, что в результате выполнения любой команды, изменяющей содержимое счетчика команд (команды перехода, вызова и возврата из подпрограмм), также происходит «разрыв» в работе конвейера, вследствие чего происходит задержка выполнения программы на несколько машинных циклов. Длительность задержки составляет от двух до четырех машинных циклов в зависимости от команды.
Тактирование микроконтроллера
С микроконтроллерами семейства Mega и Xmega могут использоваться различные источники тактового сигнала (в семействе Tiny их количество ограничено). Прежде всего, это встроенный кварцевый генератор с подключаемым внешним резонатором. Также в качестве тактового может использоваться простейший RC-генератор – как внутренний (калибруемый), так и с внешней RC-цепочкой. Кроме того, в качестве тактового может использоваться внешний сигнал синхронизации с генератора тактовых импульсов. Многие микроконтроллеры имеют несколько (до 6) режимов пониженного энергопотребления, так называемые «спящие» режимы. Каждый из этих режимов позволяет сократить энергопотребление микроконтроллера в периоды его бездействия. Вход в любой из этих режимов выполняется по команде SLEEP. При выходе микроконтроллера из спящего режима производится его сброс, который происходит также при появлении на выводе RESET сигнала низкого уровня (логический ноль), включении напряжения питания, снижение напряжения питания ниже минимально допустимого уровня, срабатывании сторожевого таймера, а также получении команды сброса по интерфейсу для программирования и отладки JTAG.
Организация памяти
В микроконтроллерах семейства AVR реализована Гарвардская архитектура, в соответствии с которой разделены не только адресные пространства памяти программ и памяти данных, но также и шины доступа к ним. Способы адресации и доступа к этим областям памяти также различны. Такая структура позволяет центральному процессору работать одновременно как с памятью программ, так и с памятью данных, что существенно увеличивает производительность. Каждая из областей памяти данных (ОЗУ и энергонезависимая EEPROM) также расположена в своем адресном пространстве.
Память программ предназначена для хранения команд, управляющих функционированием микроконтроллера. Память программ также часто используется для хранения таблиц констант, не меняющихся во время работы программы. Память программ представляет собой электрически стираемое программируемое постоянное запоминающее устройство (ППЗУ, FLASH ПЗУ). В связи с тем, что длина всех команд кратна одному слову (16 бит), память программ имеет 16-разрядную организацию. Логически память программ разделена на две неравные части – область прикладной программы и область загрузчика. В последней может располагаться специальная программа (тот самый загрузчик), позволяющая микроконтроллеру самостоятельно управлять загрузкой и выгрузкой прикладных программ. Если же возможность самопрограммирования микроконтроллера не используется, прикладная программа может располагаться и в области загрузчика. Для адресации памяти программ используется счетчик команд. Размер счетчика команд составляет 12…16 разрядов, в зависимости от объема адресуемой памяти. Обобщенная карта памяти AVR микроконтроллеров приведена на рисунке 1.3.
Рис. 1.3. Структура памяти AVR микроконтроллеров
По адресу 0x0000 памяти программ находится вектор сброса. После инициализации (сброса) микроконтроллера выполнение программы начинается с этого адреса. Начиная с адреса 0x0001 или 0x0002 памяти программ располагается таблица векторов прерываний. Размер этой области зависит от модели микроконтроллера. При возникновении прерывания, после сохранения в стеке текущего значения счетчика команд, происходит выполнение команды, расположенной по адресу соответствующего вектора. Поэтому по этим адресам располагаются команды перехода к подпрограммам обработки прерываний. В моделях с объемом памяти менее 8 Кбайт в качестве этих команд используются команды относительного перехода (RJMP), а в остальных моделях – команды абсолютного перехода (JMP).
В качестве промежуточных операндов используются 32 ячейки – оперативные регистры общего назначения (РОН). Доступ к этим ячейкам самый быстрый, а число операций с их содержимым наиболее разнообразное. При написании программ на Ассемблере эти регистры обозначаются как R0, R1, R2 … R31, и делятся на три группы:
Младшие R0 – R15 – обычные регистры общего назначения, но в некотором смысле неполноценные. С ними не работают многие команды, например, загрузка непосредственного числа.
Старшие R16 – R31 – полноценные регистры, работающие со всеми командами без исключения.
Индексные R26…R31 – шесть последних регистров из старшей группы отличаются от остальных. В принципе, их можно использовать и как обычные регистры общего назначения. Но, кроме этого, они могут образовывать регистровые пары X(R26:R27), Y(R28:R29), Z(R30:R31) которые используются как указатели при работе с памятью.
Память данных
Память данных AVR микроконтроллеров разделена на три части: регистровая память, оперативная память (статическое ОЗУ) и энергонезависимое ЭСППЗУ (EEPROM). Регистровая память включает 32 регистра общего назначения (РОН), объединенных в файл, и служебные регистры ввода/вывода (РВВ). В старших моделях микроконтроллеров имеется также область дополнительных (Extended) регистров ввода/вывода (ДРВВ). Под РВВ в памяти микроконтроллера отводятся 64 байта, а под ДРВВ — 160 байт. Введение дополнительных РВВ связано с тем, что для поддержки всех периферийных устройств этих моделей обычных 64 регистров недостаточно. В обеих областях регистров ввода/вывода располагаются различные служебные регистры (регистры управления микроконтроллером, регистры состояния), а также регистры управления периферийными устройствами, входящими в состав микроконтроллера. Распределение адресов пространства ввода/вывода (как основного, так и дополнительного) зависит от конкретной модели микроконтроллера и входящих в его структуру периферийных устройств.
Кроме 32 регистров общего назначения, в структуру микроконтроллеров обычно включена оперативная память (ОЗУ), предназначенная для временного хранения переменных. Есть она не везде – в самых младших микроконтроллерах семейства Tiny оперативной памяти нет вовсе, в её качестве выступают 32 регистра общего назначения. Оперативная память представляет собой несколько сотен ячеек для временного хранения данных, от 64 байт до 4 килобайт, в зависимости от модели. В этих ячейках могут храниться любые данные, а доступ к ним осуществляется через команды Load и Store.
Для долговременного хранения различной информации, которая может изменяться в процессе функционирования готовой системы (калибровочные константы, серийные номера, ключи), в микроконтроллерах может использоваться энергонезависимая EEPROM-память. Ее объем составляет для различных моделей от 512 байт до 4 Кбайт. Эта память расположена в отдельном адресном пространстве, а доступ к ней осуществляется с помощью определенных РВВ.
Стек
Стек представляет собой область памяти, которую микроконтроллерное ядро использует для сохранения и восстановления адресов возврата из подпрограмм и прерываний. Практически у всех микроконтроллеров AVR стек размещается в оперативной памяти. Для адресации текущего элемента (вершины стека) используется указатель стека SP (Stack Pointer). Это однобайтовый регистр ввода-вывода SPL у моделей с объемом памяти данных до 256 байт, или двухбайтовый SPH:SPL (SPH – старший байт, SPL – младший байт) у старших моделей с большим объёмом памяти.
Так как после подачи напряжения питания (или после сброса) в регистрах содержится нулевое значение, в самом начале программы указатель стека необходимо проинициализировать, записав в него значение конечного адреса памяти данных. При вызове подпрограмм адрес команды, расположенной за командой вызова, сохраняется в стеке. Значение указателя стека при этом уменьшается на 2, т. к. для хранения счетчика команд требуется 2 байта.
При возврате из подпрограммы этот адрес извлекается из стека и загружается в счетчик команд. Значение указателя стека соответственно увеличивается на 2. То же происходит и во время вызова прерываний. Схематичное расположение стека в памяти данных представлено на рисунке 1.4.
Рис
1.4.
Расположение стека в памяти данных
Во всех моделях AVR микроконтроллеров стек доступен со стороны пользовательской программы и может быть использован в процессе выполнения программы. Для работы со стеком существует всего две команды: занесения в стек (PUSH) и извлечения из стека (POP).
При старте контроллера, обычно первым делом проводят инициализацию стека, записывая в 16-битный регистр SP адрес, откуда он будет увеличиваться. Делается это следующим образом:
LDI R16, Low(RAMEND)
OUT SPL, R16
LDI R16, High(RAMEND)
OUT SPH, R16
Где RAMEND - это макроопределение, указывающее на конец ОЗУ в конкретном микроконтроллере. При написании программ на языках более высокого уровня (C, C++) компилятор проводит эту операцию за пользователя.
Прерывания – это аппаратные события, которые прекращают нормальный ход программы для выполнения какой-либо приоритетной задачи. Причём это событие может быть как внутренним (от встроенной периферии самого микроконтроллера – таймеров, портов ввода-вывода, АЦП и других), так и внешним – например, появление на входе импульса от нажатой кнопки. Возникает вопрос, можно ли обрабатывать эти события без использования прерываний?
В наиболее простых случаях так и происходит: основная программа представляет собой бесконечный цикл, внутри которого тем или иным способом отслеживаются возникновения событий, при наступлении которых устанавливается определённое значение переменной, называемой обычно флагом (бит в специализированном регистре или ячейке памяти). Основная программа проверяет в цикле значения используемых флагов, и при их изменении переходит к обработке соответствующего события. Чем неудобен подобный подход? Во-первых, подобный цикл ожидания полностью загружает микроконтроллер, который в это время мог бы делать что-нибудь полезное. Во-вторых, некоторые события в принципе не могут долго ждать, например, обработка приёма данных по USART – если пропустить хоть один байт, логика работы программы будет нарушена, а повторная пересылки данных может быть не предусмотрена. Именно поэтому для организации более эффективного использования ресурсов микроконтроллера и используют прерывания.
Как работают прерывания.
При возникновении прерывания микроконтроллер завершает текущую команду, сохраняет в стеке содержимое счетчика команд и совершает переход на адрес соответствующего вектора прерывания. По этому адресу, как правило, находится команда безусловного (JMP или RJMP) перехода к подпрограмме обработки прерывания. За каждым аппаратным прерыванием микроконтроллера закреплен свой адрес, и все вместе они образуют таблицу векторов прерываний, которая расположена в самом начале памяти программ. Поскольку у каждого микроконтроллера набор периферии разный, вектор прерываний также будет отличаться. Ниже приведена таблица векторов прерываний микроконтроллера ATTiny104, который мы будем использовать в дальнейшей работе.
Контроллер стартует с адреса 0x00 (нулевого адреса памяти программ). Далее мы делаем безусловный переход на метку RESET. Если этого не сделать, то контроллер начнёт выполнять команды из таблицы векторов прерываний, что нам совершенно не нужно. После перехода по метке первым делом необходимо проинициализировать стек. Потом, используя команду SEI, разрешаем глобальные прерывания. За разрешение конкретных прерываний для каждого вида периферии отвечают соответствующие регистры управления локальными прерываниями.
Таблица 1.1. Вектора прерываний микроконтроллера ATTiny104
.ORG 0x000 RJMP RESET // Reset Handler |
.ORG 0x001 RETI // IRQ0 Handler |
.ORG 0x002 RETI // PCINT0 Handler |
.ORG 0x003 RETI // PCINT1 Handler |
.ORG 0x004 RETI // Timer/Counter0 Capture Handler |
.ORG 0x005 RETI // Timer/Counter0 Overflow Handler |
.ORG 0x006 RETI // Timer/Counter0 Compare Match A Handler |
.ORG 0x007 RETI // Timer/Counter0 Compare Match B Handler |
.ORG 0x008 RETI // Analog Comparator Handler |
.ORG 0x009 RETI // Watchdog Timer Handler |
.ORG 0x00A RETI // Voltage Level Monitor Handler |
.ORG 0x00B RETI // ADC Conversion Handler |
.ORG 0x00C RETI // USART0 Rx Start Handler |
.ORG 0x00D RETI // USART0 Rx Complete Handler |
.ORG 0x00E RETI // USART0 Data Register Empty Handler |
.ORG 0x00F RETI // USART0 Tx Complete Handler |
.ORG INT_VECTORS_SIZE // Конец таблицы прерываний |
Когда возникает прерывание, выполнение текущих операций приостанавливается, и микроконтроллер переходит по соответствующей метке на подпрограмму обработки прерывания. Последней командой подпрограммы обработки прерывания должна быть команда RETI, которая обеспечивает возврат в основную программу и восстановление предварительно сохраненного счетчика команд и данных, заблаговременно перенесённых в стек.
Что происходит в том случае, если одновременно возникает не одно прерывание, а несколько? Тогда в регистре состояния устанавливаются соответствующие флаги, и прерывания обрабатываются одно за другим, в порядке очерёдности. Положение вектора в таблице определяет приоритет соответствующего прерывания, при этом чем меньше адрес, тем выше приоритет прерывания. Если прерывания в работе микроконтроллера не используются, то на месте таблицы векторов прерываний может быть размещена часть основной программы
Обработка прерываний
Для глобального разрешения или запрещения прерываний предназначен флаг I регистра состояния SREG. Для разрешения работы прерываний он должен быть установлен в единицу (это делается с помощью ассемблерной команды SEI), а для запрещения сброшен (командой CLI). По умолчанию (после сброса микроконтроллера) этот флаг сброшен, и все прерывания микроконтроллера запрещены. Также возможно индивидуальное разрешение или запрещение (маскирование) прерываний, которое производится установкой или сбросом соответствующих разрядов регистров масок прерываний. Для каждого блока периферии существует собственный регистр для разрешения локальных прерываний. При возникновении прерывания флаг I регистра SREG сбрасывается на аппаратном уровне, запрещая тем самым обработку следующих прерываний. При возврате из подпрограммы обработки прерывания (при выполнении команды RETI) флаг I устанавливается обратно.
Все доступные для работы прерывания можно разделить на два типа. Прерывания первого типа генерируются при наступлении некоторого события, в результате которого устанавливается флаг прерывания. Затем, если прерывание разрешено, в счетчик команд загружается адрес вектора соответствующего прерывания. При этом флаг прерывания сбрасывается на аппаратном уровне. Он также может быть сброшен программным образом, путем записи единицы в разряд регистра, соответствующий флагу.
Прерывания второго типа не имеют флагов прерываний и генерируются в течение всего времени, пока присутствуют условия, необходимые для генерации прерывания. Соответственно, если условия, вызывающие прерывание, исчезнут до разрешения прерывания, генерации прерывания не произойдет.
Наименьшее время отклика для любого прерывания составляет 4 машинных цикла, в течение которых происходит сохранение счетчика команд в стеке. В течение последующих двух или трех циклов выполняется команда перехода к подпрограмме обработки прерывания. Если прерывание произойдет во время выполнения команды, длящейся несколько циклов, то генерация прерывания произойдет только после выполнения этой команды. Если же прерывание произойдет во время нахождения микроконтроллера в «спящем» режиме, время отклика увеличивается еще на 4 машинных цикла. Возврат в основную программу занимает 4 машинных цикла, в течение которых происходит восстановление счетчика команд из стека. После выхода из прерывания процессор всегда выполняет одну команду основной программы, прежде чем обслужить любое отложенное прерывание.
Поскольку прерывание нарушает стандартный ход выполнения программы и может возникнуть в любой момент времени, необходимо сохранить текущие данные. Для этого необходимо использовать стек, туда нужно переместить все регистры, используемые в обработчике прерывания, чтобы не потерять хранящиеся там данные. Также необходимо сохранять регистр флагов SREG, в котором хранится результат логических операций:
TIM0_OVF:
PUSH R16 // Сохраняем регистр R16
IN R16, SREG // Перемещаем содержимое SREG в R16
PUSH R16 // Сохраняем всё в стек
PUSH R17 // R17 сохраняем туда же
…………… // Выполнение кода обработчика прерывания
POP R17 // Перед выходом из прерывания извлекаем
POP R16 // сохранённые данные
OUT SREG, R16 // Действуем при этом в обратном порядке
POP R16
RETI // Выходим из прерывания
Также существует ряд операций, которые должны выполняться неразрывно, например, чтение 16-разрядного счетного регистра таймера. Поскольку ядро микроконтроллеров семейства Tiny 8-разрядное, то 16-разрядный регистр таймера считывается (или записывается) в два приема – причём сначала считывается младший байт, а потом старший (это подробно рассматривалось в главе, посвящённой таймерам). Между двумя этими операциями не должно возникать никаких прерываний, поэтому перед чтением такого регистра необходимо их запретить, а после окончания операции чтения разрешить обратно.
