Глава 12 Знакомство с микроконтроллером
Примерно в середине 70-х один из сотрудников предложил мне идею того, что, по сути дела, являлось персональным компьютером. Смысл идеи сводился к оснащению процессора 8080 монитором и клавиатурой и последующей продаже его в качестве прибора для дома. Я спросил: «И что же с ним делать?» Он ответил только, что домохозяйка, например, смогла бы хранить там кулинарные рецепты. Я не увидел в этом никакой пользы, и мы к данному вопросу больше не возвращались.
Из воспоминаний Гордона Мура, основателя Fairchild и Intel
Общее число существующих семейств микроконтроллеров оценивается приблизительно в 100 с лишним, причем ежегодно появляются все новые и новые. Каждое из этих семейств может включать десятки разных моделей. В 2002–2003 гг. в мире выпускалось ежегодно 3,2 млрд штук микроконтроллеров. Сравните — объем выпуска микропроцессоров для ПК в 2005–2006 гг. можно оценить в 200 млн единиц в год, т. е. всего около 6 % рынка. В то время как в финансовом исчислении, по данным Ассоциации полупроводниковой промышленности США, мировой объем рынка процессоров для ПК в 2006 году равнялся 33 млрд долларов, а микроконтроллеров — всего 12 млрд. Типичная цена рядового МК — порядка 2–5 долл., отдельные их представители могут стоить как существенно меньше, так и больше, но в любом случае их цена не достигает сотен долларов, как для отдельных моделей микропроцессоров от Intel и AMD.
Если говорить о ведущих компаниях, выпускающих микроконтроллеры, то первое место среди производителей 8-разрядных чипов традиционно принадлежит Motorola. Компания Microchip с очень популярным среди радиолюбителей семейством PIC занимает третье место, a Atmel, о продукции которой мы будем говорить далее — лишь шестое. Тем не менее эта формальная статистика еще ни о чем не говорит. Так, среди МК со встроенной flash-памятью Atrfiel принадлежит треть мирового рынка (и в 1995 году она была первой, кто вообще выпустил МК такой категории на рынок), при этом надо учитывать, что среди лидеров рассматриваемое семейство AVR-контроллеров самое молодое — первый Atmel AVR был выпущен в 1997 году. Так как рынок МК весьма консервативен (в рекламу на ТВ не вставишь что-нибудь вроде «в данном пылесосе используется последняя модель RISC-микроконтроллера с 32-разрядной шиной данных», поэтому мода тут играет далеко не ведущую роль), и шестое место в мировом масштабе можно рассматривать, как огромный успех.
Кроме 8-разрядных МК AVR, Atmel выпускает еще несколько их разновидностей, в том числе относящихся к таким популярным семействам, как ARM-процессоры и заметно модифицированные наследники старинного 8051, для которого в мире накоплен огромный объем программного обеспечения. Мы здесь ограничимся лишь 8-разрядными AVR, как одними из самых удобных в радиолюбительской и полупрофессиональной практике (например, для изготовления научного, производственного и другого спецоборудования в единичных экземплярах) — на этой почве они конкурируют лишь с упомянутыми PIC, однако для начального освоения опытные конструкторы рекомендуют именно AVR.
По вычислительной мощности ядро AVR-контроллеров, выполненное по RISC-архитектуре (Reduced Instruction System Command — «система с сокращенным набором команд»), заметно превышает 8-разрядные процессоры первых персональных компьютеров 80-х годов (i8086 в первых моделях IBM PC и 6502 в персоналках Apple), и сравнимо с производительностью 16-разрядного процессора i286, поскольку большинство инструкций выполняются за один такт, а рабочие частоты более высокие (обычно до 16 МГц, за небольшими исключениями, а у некоторых моделей — до 20 МГц). В AVR имеется 32 регистра общего назначения (часть из которых может также выполнять специализированные функции). Это позволяет в простых программах вообще не обращаться к памяти, что особенно удобно для начинающих.
Classic, Mega и Tuny
Линейка AVR делится на три семейства: Classic, Mega и Tuny. МК семейства Classic (они именовались, как AT90S<MapKa контроллера>) ныне уже не производятся, однако все еще распространены, т. к. их еще много на складах торгующих фирм и для них наработано значительное количество программ. Чтобы все это ПО пользователям не пришлось переписывать, фирма Atmel позаботилась о преемственности — все МК семейства Classic (за исключением разве что самого первого и не очень удачного AT90S1200) имеют функциональные аналоги в семействе Mega, например, AT90S8515 — ATmega8515, AT90S8535— ATmega8535 и т. п. (только AT90S2313 имеет аналог в семействе Tuny— ATtuny2313). На рис. 12.1 приведены варианты корпусов микроконтроллеров Atmel AVR и панельки для них.
Рис. 12.1. Различные корпуса микроконтроллеров Atmel AVR и панельки для них
Полная совместимость обеспечивается специальным установочным битом (из набора т. н. Fuse-битов), при программировании которого Mega-процессор начинает функционировать как Classic (подробнее об этом — в главе 13). Для вновь разрабатываемых устройств обычно никакого смысла в режиме совместимости нет, однако такой прием в ряде случаев может оказаться полезным для начинающих, т. к. МК Classic устроены проще и не заставляют пользователя отвлекаться на ненужные подробности, не имеющие отношения к делу. Поэтому часть примеров в этой книге, особенно начального уровня, будут ориентированы на семейство Classic.
Семейство Tuny (что в буквальном переводе означает «легко запоминающийся») предназначено для наиболее простых устройств, часть таких МК не имеет возможности программирования по последовательному интерфейсу (а АТ-tuny10 даже является однократно программируемым), и потому мы их не будем рассматривать в этой книге (за исключением ATtuny2313, точнее его «классического» аналога AT90S2313, оба они очень удобны для проектирования небольших, но функциональных устройств, и к тому же могут работать с частотой до 20 МГц). Это не значит, что Tuny следует избегать, среди них есть очень удобные и функциональные микросхемы. Но нельзя объять необъятное — здесь в основном мы будем рассматривать Mega.
Перечислим отличительные особенности Mega.
• Flash-пэмять программ от 8 до 128 кбайт (у семейства Classic 2–8 кбайт).
• Статическое ОЗУ (SRAM) от 512 байт до 4 кбайт (для Classic 128–512 байт).
• EEPROM данных от 512 байт до 4 кбайт (для Classic 128–512 байт).
• Различные способы тактирования: от встроенного RC-генератора, внешней RC-цепочки, внешнего кварцевого резонатора, внешнего сигнала (у Classic — только от кварцевого резонатора или внешнего сигнала). Удобная возможность для удешевления и упрощения схем, хотя и усложняет начальное программирование кристалла, причем у некоторых старших моделей имеется возможность программного снижения частоты.
• Расширенные режимы пониженного энергопотребления.
• Наличие встроенного детектора снижения напряжения питания (Brown-Out Detector, BOD).
• Усовершенствованный полнодуплексный последовательный синхронноасинхронный порт USART (на практике автором использовался исключительно в режиме обычного UART).
• Последовательный двухпроводной интерфейс TWI (по другому, I2С — на практике автор никогда не мог его заставить работать лучше, чем программный имитатор I2С, пригодный практически для всех моделей AVR).
• Инструкции аппаратного умножения 8-разрядных чисел (в семействе Classic отсутствуют).
Структура МК AVR
Для ознакомления с тем, как устроены МК AVR, возьмем «классический» AT90S8515. Он включает в себя все существенные узлы моделей МК AVR из середины линейки, т. е. как младших Mega, так и старших Tuny, за исключением имеющегося в некоторых моделях АЦП (как, например, в его близком родственнике AT90S8535/ATmega8535, который мы будем широко использовать). Выбор именно Classic обусловлен тем, что блок-схема AYR громоздкая и без того, а в Mega присутствует еще много компонентов, которые для нас останутся второстепенными. Как и АЦП, эти компоненты (Brown-Out Detector, Fuse-биты, USART, дополнительные таймеры и т. п.) мы рассмотрим по ходу дела в дальнейшем.
На рис. 12.2 показана внутренняя структура МК AT90S8515. Нумерация выводов приведена для корпуса DIP-40, кроме этого, процессор выпускается в 44-выводных корпусах PLCC и TQFP (см. рис. 12.1). Даже беглого взгляда на рисунок достаточно, чтобы понять, что для детального рассмотрения структуры этого МК здесь просто не хватит места. Поэтому мы не будем переписывать фирменное описание (с некоторыми подробностями мы познакомимся по ходу дальнейшего изложения), а рассмотрим только некоторые ключевые узлы этой структуры и особенности их функционирования.
Рис. 12.2. Структура AT90S8515
Параллельные порты ввода/вывода
Начнем с внешних портов. В этой модели их четыре, и если подсчитать необходимые выводы (8x4 = 32), прибавить к ним обязательные выводы питания (контакты 20 и 40), тактового генератора (контакты 18 и 19) и вывод Reset (контакт 9), также присутствующий во всех моделях МК без исключения, то получится, что на все остальное остается три вывода. Это, конечно, недостаточно, поэтому почти все выводы портов, кроме своей основной функции (двунаправленного ввода/вывода) несут также и дополнительную. А как они (функции) разбираются между собой? А никак. Никакого специального переключения выводов портов не требуется, просто, если вы, к примеру, в своей программе инициализируете последовательный порт UART, то соответствующие выводы порта D (PD0 и PD1, выводы 10 и 11 микросхемы) будут работать именно в альтернативной функции, как ввод и вывод UART. При этом в промежутках между этим режимом выводов они могут выполнять функцию обычных двунаправленных выводов (хотя на практике это неудобно, потому что приходится применять схемотехнические меры для изоляции функций друг от друга, но иногда к этому прибегают). Аналогичная ситуация со всеми остальными альтернативными функциями — они начинают работать, когда в программе инициализированы соответствующие устройства МК.
По умолчанию все дополнительные устройства отключены, а порты работают на вход, причем находятся в состоянии с высоким импедансом (т. е. высоким входным сопротивлением). Работа на выход требует специального указания, для чего в программе нужно установить соответствующий нужному выводу бит в регистре направления данных (обозначается DDRx, где х — буква, обозначающая конкретный порт, например для порта А это будет DDRA). Если бит сброшен (т. е. равен логическому нулю), то вывод работает на вход (установка по умолчанию), если установлен (т. е. равен логической единице) — то на выход. Причем для установки выхода в состояние «1» нужно отдельно установить соответствующий бит в регистре данных порта (обозначается PORTx), а для установки в «0»— сбросить этот бит. Направление работы вывода (вход-выход, регистр DDRх), и его состояние (0–1, PORTх) путать не следует.
Регистр данных PORTх фактически есть просто выходной буфер, все, что в него записывается, тут же оказывается на выходе. Но если установить вывод порта на вход (т. е. записать в регистр направления логический ноль), как это сделано по умолчанию, то регистр данных DDRх будет играть несколько иную роль — установка его в «0» (так по умолчанию) означает, что вход находится в третьем состоянии с высоким сопротивлением, а установка в «1» подключит к выводу «подтягивающий» (pull-up) резистор сопротивлением около 35 кОм (подобно рис. 11.3, а; вернитесь к описанию работы подобного выходного каскада на «общую шину» в главе 11 — и вы поймете, зачем он нужен).
Сразу отметим, что встроенный pull-up-резистор лучше употреблять при работе на «общую шину» в пределах одной платы, но в большинстве случаев, когда требуется такой резистор (например, если вы подключаете ко входу выносную кнопку с двумя выводами, которая коммутируется на «землю», или при работе на «общую шину» с удаленными устройствами), лучше устанавливать дополнительный внешний резистор параллельно этому внутреннему, с сопротивлением от 1 до 5 кОм (в критичных для потребления случаях его величину можно увеличить до 20–30 кОм). В ответственных устройствах такой резистор следует устанавливать на выводе 9 (Reset) и на выводах 6, 7 и 8, которые служат для программирования и подключены к программирующему разъему ISP (см. главу 13), поскольку их также следует «подтягивать» к напряжению питания (тем более что довольно часто они также используются в качестве обычных входных/выходных линий, что процессу программирования, как правило, не мешает).
Заметки на полях
Установка дополнительного резистора к питанию (как и конденсатора — к «земле») по входу Reset для более надежного сброса рекомендовалась для самых первых моделей AVR, однако в описаниях современных типов вы такого не встретите. Но даже для старых моделей не оговаривалась установка внешних резисторов по другим выводам. Однако для более надежной работы устройства в условиях помех автор настоятельно советует следовать изложенным рекомендациям — хуже от этого не будет. Сопротивление «родного» резистора (который на самом деле представляет собой, разумеется, полевой транзистор) слишком велико для того, чтобы электромагнитные помехи («наводки») на нем эффективно «садились», и у вас могут происходить ложные срабатывания, перезапуски системы, а при очень мощных помехах— даже порча программы в памяти программ. Это, конечно, не касается ситуации, когда порт в режиме входа подсоединен к низкоомному выходу другой микросхемы или, скажем, транзисторного ключа (см. главу 12), т. к. у них на выходе всегда имеется какой-то сигнал, и резистор тогда не потребуется вообще, лучше всего ставить вывод микросхемы в третье состояние. Не забывайте только об этих резисторах при работе в режимах экономии питания — нужно тщательно проанализировать схему на предмет того, чтобы исключить ситуации, при котором через эти резисторы протекает ток.
Добавим еще, что, как вы, очевидно, уже поняли из изложенного, выводы портов в достаточной степени автономны, и их режим может устанавливаться независимо друг от друга. Кстати, а как прочесть уровень на выводе порта, если он находится в состоянии работы на вход? Возникает искушение прочесть данные из регистра данных PORTх, но это ничего не даст — вы прочтете только то, что там записано вами же. А для чтения того, что действительно имеется на входе (непосредственно на выводе микросхемы), предусмотрена другая возможность. Чтение происходит из буферного элемента, который в первом приближении соответствует элементу В на схемах по рис. 11.3, т. е. для чтения нужно обратиться к некоторому массиву, который обозначается PINх. Обращение осуществляется так же, как и к отдельным битам обычных регистров (см. главу 13), но PINх не есть регистр, это просто некий диапазон адресов, чтение по которым предоставляет доступ к информации из буферных элементов на входе порта. Записывать что-то по адресам PINx, естественно, нельзя.
Прерывания
Как и в ПК, прерывания (interrupts) в микроконтроллерах бывают двух видов. Но если в ПК прерывания делятся на аппаратные (например, от таймера или клавиатуры) и программные (фактически не прерывания, а подпрограммы, записанные в BIOS — с распространением Windows это понятие почти исчезло из программистской практики), то в МК, естественно, все прерывания являются аппаратными, а делятся они на внутренние и внешние. Любое прерывание, а также вообще возможность их возникновения требует отдельно предварительного специального разрешения. Учтите, что для инициализации прерываний в программе необходимо сделать два действия: разрешить соответствующее прерывание (предполагаем, все прерывания вообще уже разрешены) и установить для него один из доступных режимов. И, конечно, написать подпрограмму-обработчик, иначе все это будет происходить вхолостую (подробнее см. главу 13).
Внутренние прерывания могут возникать от любого устройства, которое является дополнительным по отношению к ядру системы: от таймеров, от аналогового компаратора, от последовательного порта и т. д. Внутреннее прерывание— это событие, которое возникает в системе и прерывает выполнение основной программы. Система внутренних прерываний в AVR довольно раз ветвленная и представляет собой основной механизм взаимодействия устройств с ядром системы, и мы еще к этому вопросу будем неоднократно возвращаться.
На внешних прерываниях мы остановимся здесь подробнее. Внешних прерываний у МК типа AT90S8515 два, INTO и INT1 (а вот в ATmega128 — целых восемь!), естественно, они могут возникать независимо друг от друга. Внешнее прерывание — событие, которое возникает при появлении сигнала на одном из входов, специально предназначенных для этого (в данном случае контакт 12 или 13). Различаются три вида событий, вызывающих прерывание, и их можно устанавливать в программе: это может быть низкий уровень напряжения, а также положительный или отрицательный фронт на соответствующем выводе. Любопытно, что прерывания по всем этим событиям выполняются, даже если соответствующий вывод порта сконфигурирован на выход.
Кратко рассмотрим особенности этих режимов. Прерывание по низкому уровню (режим установлен по умолчанию, для его инициализации достаточно разрешить соответствующее прерывание) возникает всякий раз, когда на соответствующем входе присутствует низкий уровень. «Всякий раз» — это значит, что действительно всякий, т. е. если отрицательный импульс длится какое-то время, то прерывание, закончившись (т. е. когда выполнится соответствующая процедура), повторится снова и снова, не давая основной программе работать. Поэтому обычно сразу же по возникновении такого внешнего прерывания его следует запретить (процедура обработки при этом, раз уж началась, выполнится до конца), и разрешить опять только тогда, когда внешнее воздействие должно уже закончиться (например, если это нажатие кнопки, то его стоит опять разрешить по таймеру через одну-две секунды).
В отличие от этого, прерывания по фронту или спаду выполняются один раз на импульс. Конечно, от дребезга контактов там никакой защиты нет и быть не может, потому что МК не способен отличить дребезг от серии коротких импульсов. Если это критично, нужно либо принимать внешние меры по защите от дребезга, либо использовать тот же способ, что и для прерывания по уровню— внутри процедуры обработчика прерывания первой же командой запретить само прерывание, а через некоторое время в другой процедуре (по таймеру, например, или по иному событию) опять его разрешить (способ «антидребезга», фактически идентичный применению одновибратора, см. главу 9). Но если по нажатию кнопки просто что-то устанавливается в некое состояние, то ничего страшного не случится, если это произойдет несколько раз подряд, только следует учесть, что окончание этого процесса совпадет с отпусканием кнопки.
Подробности
У внимательного читателя возникает законный вопрос— а зачем вообще нужен режим внешнего прерывания по уровню? Дело в том, что оно во всех моделях выполняется асинхронно, т. е. в тот момент, когда низкий уровень появился на выводе МК. Конечно, обнаружение прерывания может произойти только по окончании текущей команды, так что очень короткие импульсы могут «пропасть». Но прерывания INT0 и INT1 в режиме управления по фронту у большинства моделей определяются наоборот, только синхронно, т. е. в момент перепада уровней тактового сигнала контроллера, поэтому их длительность не должна быть короче одного периода тактового сигнала. Но это не самое главное: по большому счету разницы в этих режимах никакой бы не было, если бы не то обстоятельство, что синхронный режим требует непременно наличия этого самого тактового сигнала. И асинхронное внешнее прерывание, соответственно, может «разбудить» контроллер, находящийся в одном из режимов глубокого энергосбережения, когда тактовый генератор не работает, а синхронное— нет. И обычные МК, вроде разбираемого AT90S8515 семейства Classic (но не его Меда-аналога!), выводиться из глубокого «сна» могут только внешним прерыванием по уровню, которое не всегда удобно использовать. У большинства же моделей семейства Меда (из младших моделей — кроме АТmega8), имеется еще одно прерывание INT2, которое происходит только по фронтам (а не по уровню), и, в отличие от INT0 и INT1, только асинхронно. Это значительно повышает удобство работы с семейством Меда в режиме энергосбережения (на эту тему см. главу 17).
Таймеры-счетчики
В МК 8515 два таймера-счетчика: один 8-разрядный (Timer 0), второй — 16-разрядный (Timer 1). Оба счетчика представляют собой счетчики с предзагрузкой (вроде 561ИЕ11/14) и могут работать от тактовой частоты процессора непосредственно, или поделенной на 8, 64, 256 или 1024, представляя в таком режиме собой именно таймеры, т. е. устройства для отсчета времени.
Могут они работать и как обычные счетчики внешних импульсов с выводов Т0 (вывод 1) для Timer 0 и Т1 (вывод 2) для Timer 1 (по спаду или по фронту). Частота подсчитываемых импульсов не должна превышать половины частоты тактового генератора МК (причем при несимметричном меандре инструкция рекомендует и еще меньшее значение предельной частоты — 0,4 от тактовой), иначе счетчик вам посчитает «погоду на Марсе» — это сильное ограничение, поэтому, например, использовать МК для создания универсального частотомера неудобно. Поэтому все быстродействующие логические схемы конструируют не на микроконтроллерах, а на комбинационной логике — на ПЛИС.
При наступлении переполнения счетчика возникает событие, которое может вызывать соответствующее прерывание. Счетчик Timer 0 фактически этим и ограничивается. 16-разрядный счетчик Timer 1 — более «продвинутая» штука, и может вызывать прерывания по совпадению с определенным заранее заданным числом (точнее, даже два отдельных прерывания с двумя разными числами А и В), при этом счетчик может обнуляться или продолжать счет, и на специальных выводах OSC1A (вывод 15) или OSC1B (вывод 29) при этом могут генерироваться импульсы (аппаратно, без участия программы). Этот режим нам понадобится, чтобы задавать определенную частоту прерываний — например, в часах для отсчета секунд (см. главу 14).
Также возможно прерывание по внешнему событию на специальном выводе ICP (вывод 31), при этом содержимое счетчика помещается в некий регистр ICR1, а счетчик может обнуляться и начинать счет заново или просто продолжать счет (режим измерения периода внешнего сигнала). Источником таких событий может быть встроенный аналоговый компаратор— это удобно для того, чтобы построить на основе МК частотомер, но, как мы видели ранее— только низкочастотный, не более 5–7 МГц. Некоторые подробности о прерываниях и таймерах вы узнаете также из главы 17, когда мы будем разбирать режимы энергосбережения.
В AT90S8535 и во всех Mega (кроме Mega8515) есть как минимум еще один, третий таймер, который также будучи, как и Timer0, 8-разрядным, может выполнять более интересные вещи (например, работать автономно от остальной системы, когда весь процессор находится в режиме экономии, что позволяет этот таймер использовать в качестве часов реального времени, RTC). Но и это не все: описанные таймеры могут работать в т. н. PWM-режиме, специально предназначенном для их работы в качестве широтно-импульсных модуляторов (ШИМ). Этот режим мы кратко рассмотрим в главе 19 в связи с голосовой сигнализацией.
Кроме таймеров-счетчиков в любом AVR-контроллере есть сторожевой (Wathcdog) таймер. Он предназначен в основном для вывода МК из режима энергосбережения через определенный интервал времени, но может выполнять и простой перезапуск МК при включении питания, например, если работа программы зависит от прихода внешних сигналов, то при их потере (например, из-за сбоев на линии) МК может просто «повиснуть», а Wathcdog-таймер выведет его из этого состояния.
Остальные узлы МК семейства AVR мы рассмотрим по ходу изложения конкретных схем — так будет нагляднее. А тому, как состыковать последовательный интерфейс UART с компьютером, будет посвящена даже отдельная глава 18. Здесь же мы закончим краткое знакомство с микроконтроллером и перейдем к вопросу о том, как его программировать.