Подключение avr. Микроконтроллеры Atmega8. Программирование Atmega8 для начинающих. Тут у нас возникает два противоречия

Способы тактирования

Каноническим способом тактирования МК является подключение кварцевого резонатора к соответствующим выводам (рис. 18.11, а). Емкость конденсато­ров С1 и С2 в типовом случае должна составлять 22-36 пФ (о включении кварцев см. главу 15). В большинстве моделей Tiny и Mega имеется специ­альный конфигурационный бит скрот, который позволяет регулировать по­требление. При установленном в единицу (незапрограммированном) этом бите размах колебаний уменьшается, однако при этом сужается возможный диапазон частот и общая помехоустойчивость, поэтому использовать этот режим не рекомендуется (см. далее). Может быть также использован низко­частотный кварцевый резонатор (например, «часовой» 32 768 Гц), при этом конденсаторы С1 и С2 можно не устанавливать, так как при установке скрот в значение О подключаются имеющиеся в составе МК внутренние конденса­торы 36 пФ.

Вместо кварцевого может быть использован керамический резонатор. Автору этих строк удавалось запускать МК на нестандартных частотах, используя вместо кварца в том же подключении миниатюрную индуктивность (при ее значении в 4,7 мкГ и емкостях конденсаторов 91 пФ частота получается око­ло 10 МГц).

Рис. 18.11. Способы тактирования МК AVR с использованием: а - кварцевого резонатора; б - внешнего генератора; в - RC-цепочки

Естественно, тактировать МК можно и от внешнего генератора (рис. 18.11, б). Особенно это удобно, когда требуется либо синхронизировать МК с внешними компонентами, либо иметь очень точную частоту тактирова­ния при использовании соответствующих генераторов (например, серии SG-8002 фирмы Epson).

Наоборот, когда точность не требуется, можно использовать внешнюю ЛС-цепочку (рис. 18.11, в). В этой схеме емкость С1 должна быть не менее 22 пФ, а резистор R1 выбирается из диапазона 3,3-ЮОкОм. Частота при этом определяется по формуле F= 2/3 RC, CI можно не устанавливать вооб­ще, если записать логический ноль в конфигурационную ячейку скрот, под­ключив тем самым внутренний конденсатор 36 пФ.

Наконец, можно обойтись вообще без каких-то внешних компонентов - ис­пользовать встроенный /гС-генератор, который может работать на четырех частотах, приблизительно равных 1, 2, 4 и 8 МГц. Эту возможность наиболее целесообразно использовать в младших моде.(1ях Tiny, выпускающихся в 8-контактном корпусе- тогда выводы, предназначенные для подключения резонатора или внешнего генератора, можно использовать для других целей, как обычные порты ввода-вывода. Семейство Classic встроенного RC-генератора не имело.

По умолчанию МК семейств Tiny и Mega установлены в состояние для рабо­ты со встроенным генератором на частоте 1 МГц (cksel = oooi), поэтому для работы в других режимах нужно соответствующим образом установить конфигурационные ячейки cksel (см. табл. 18.1). Как это осуществить на практике, будет рассказано в главе 19, Рекомендуемое значение этих ячеек для обычных резонаторов от 1 МГц и более - все единицы в ячейках cksel, и ноль в скрот.

Подробности

При установке ячеек следует учитывать, что состояние cksel = оооо (зер­кальное по отношению к наиболее часто употребляемому значению для квар­цевого резонатора iiii) переводит МК в режим тактирования от внешнего ге­нератора, и в этом состоянии его нельзя даже запрограммировать без подачи внешней частоты. Также если вы попытаетесь установить режим с низкочас­тотным резонатором, то от вьюокочастотного МК уже не запустится, а далеко не все программаторы могут работать при таких низких частотах тактирования. Поэтому при манипуляциях с ячейками, и не только cksel, нужно быть крайне осторожным и хорошо представлять, что именно вы устанавливаете. Подроб­нее об этом говорится в следующей главе.

Таблица 18.1. Установка конфигурационных ячеек CKSEL в зависимости от режимов тактирования

Источник тактирования

Внешняя частота

Встроенный /?С-генератор

Встроенный RC-генератор

Встроенный /?С-генератор

Встроенный RC-генератор

Внешняя RC-цепочка

Внешняя /?С-цепочка

Внешняя RC-цепочка

Внешняя RC-цепочка

Низкочастотный резонатор

Таблица 16.1 (окончание)

Источник тактирования

Керамический резонатор

Керамический резонатор

кварцевый резонатор

Кварцевый резонатор

Параллельные порты ввода/вывода

Портов ввода-вывода (повторим, что их не следует путать ни с регистрами ввода-вывода, ни с последовательными портами МК для обмена информаци­ей с внешними устройствами) в разных моделях может быть от 1 до 7. Номи­нально порты 8-разрядные, в некоторых случаях разрядность ограничена числом выводов корпуса и может быть меньше восьми. Порты обозначаются буквами А, В, С, D и т. д., причем необязательно по порядку: в младших мо­делях могут наличествовать, например, только порты В и D (как»в ATtiny2313) или вообще только один порт В (как в ATtinylх).

Для сокращения числа контактов корпуса в подавляющем большинстве слу­чаев внешние выводы, соответствующие портам, кроме своей основной функции (двунаправленного ввода/вывода) несут также и дополнительную. Отметим, что’ кроме как для вывода Reset, если он может работать в альтер­нативном режиме, никакого специального переключения выводов портов не требуется. Если вы, к примеру, в своей программе инициализируете последо­вательный порт UART, то соответствующие выводы порта (например, в ATmega8335 это выводы порта PDO и PD1) будут работать именно в альтер­нативной функции, как ввод и вывод UART. При этом в промежутках между таким специальным использованием выводов их можно в принципе исполь­зовать, как обычные двунаправленные выводы. На практике приходится применять схемотехнические меры для изоляции функций друг от друга, по­этому злоупотреблять этой возможностью не рекомендуется.

Выводы портов в достаточной степени автономны, и их режим может уста­навливаться независимо друг от друга. По умолчанию при вк;^ючении пита­ния все дополнительные устройства отключены, а порты работают на вход, причем находятся в третьем состоянии с высоким гшпедансом (то есть с вы­соким входным сопротивлением). Работа на выход требует специального указания, для чего в программе нужно установить соответствующий нужно­му выводу бит в регистре направления данных (этот регистр обозначается DDRx, где x - буква, обозначающая конкретный порт, например для порта А это будет ddra). Если бит сброшен (то есть равен логическому нулю), то вы­вод работает на вход (как по умолчанию), если установлен (то есть равен ло­гической единице) - то на выход.

Для установки выхода в состояние единицы нужно отдельно установить со­ответствующий бит в регистре данных порта (обозначается portx), а для ус­тановки в О - сбросить этот бит. Направление работы вывода (вход-выход, регистр DDRx) и его состояние (О-1, portx) путать не следует.

Регистр данных portx фактически есть просто выходной буфер, все, что в него записывается, тут же оказывается на выходе. Но если установить вывод порта на вход (то есть записать в регистр направления ddrx логический ноль), как это сделано по умолчанию, то регистр данных portx будет играть несколько иную роль - установка его разрядов в ноль означает, что вход находится в третьем состоянии с высоким сопротивлением, а установка в единицу подключит к выводу «подтягивающий» (pull-up) резистор сопротив­лением 35-120 кОм.

Заметки на полях

Встроенного pull-up-резистора в большинстве случаев оказывается недоста­точно для надежной работы - из-за наводок МК может сбоить, и лучше уста­навливать дополнительный внешний резистор параллельно этому внутренне­му, с сопротивлением от 1 до 5 кОм (в критичных по отношению к потреблению случаях его величину можно увеличить до 20-30 кОм). Например, если вы подключаете ко входу выносную кнопку с двумя выводами, которая коммути­руется на «землю», или вывод работает на «общую шину» с удаленными (на­ходящимися на другой плате) устройствами, или вывод осуществляет функ­цию внешнего прерывания (см. далее), то такой дополнительный резистор следует подключать обязательно.

Процедура чтения уровня на выводе порта, если он находится в состоянии работы на вход, не совсем тривиальна. Возникает искушение прочесть дан­ные из регистра данных portx, но это ничего не даст - вы прочтете только то, что там записано вами же ранее. А для чтения того, что действительно имеется на входе (непосредственно на выводе микросхемы) предусмотрена другая возможность. Для этого нужно обратиться к некоторому массиву, ко­торый обозначается pinx. Обращение осуществляется так же, как и к отдель­ным битам обычных РВВ (см. главу 19\ но pinx не есть регистр, это просто некий диапазон адресов, чтение по которым предоставляет доступ к инфор­мации из буферных элементов на входе порта. Записывать что-либо по адре­сам piNx, естественно, нельзя.

Прерывания

Как и в ПК, прерывания (interrupts) в микроконтроллерах бывают двух видов. Но если в ПК прерывания делятся на аппаратные (например, от таймера или клавиатуры) и программные (фактически не прерывания, а подпрограммы, записанные в. BIOS- с распространением Windows это понятие почти ис­чезло из программистской практики), то в МК, естественно, все прерыва­ния - аппаратные, а делятся они ria внутренние и внешние. Любое прерыва­ние отдельно, а также вообще возможность их возникновения требуют предварительного специального разрешения.

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

Внутренние прерывания могут возникать от любого устройства, которое яв­ляется дополнительным по отношению к ядру системы - от таймеров, от аналогового компаратора, от последовательного порта и т.д. Внутреннее прерывание - это событие, которое возникает в системе и прерывает выпол­нение основной программы. Система внутренних прерываний в AVR доволь­но разветвленная и представляет собой основную систему взаимодействия устройств с ядром системы, и к этому вопросу мы еще будем неоднократно возвращаться.

Внешних прерываний у МК AVR как минимум два, INTO, INT1 (у большин­ства Mega есть еще третье - ИЧТ2). Внешнее прерывание - событие, кото­рое возникает при появлении сигнала на одном из входов, специально пред­назначенных для этого. Различаются три вида событий, вызывающих прерывание, и их можно устанавливать в программе: это может быть низкий уровень напряжения, а также пюложительный или отрицательный фронт на соответствующем выводе. Любопытно, что прерывания по всем этим собы­тиям выполняются, даже если соответствующий вывод порта сконфигуриро­ван на выход.

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

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

Подробности

у внимательного читателя возникает законный вопрос - а зачем вообще ну­жен режим внешнего прерывания по уровню? Дело в том, что оно во всех мо­делях выполняется асинхронно - в тот момент, когда низкий уровень появил­ся на выводе МК. Конечно, обнаружение прерывания может произойти только по окончании текущей команды, так что очень короткие импульсы могут и про­пасть. Но прерывания INTO и INT1 в режиме управления по фронту у большин­ства моделей определяются наоборот, только синхронно - в момент перепа­да уровней тактового сигнала контроллера, поэтому их длительность не должна быть короче одного периода тактового сигнала. Но это не самое глав­ное: по большому счету разницы в этих режимах никакой бы не было, если бы не то обстоятельство, что синхронный режим требует непременно наличия этого самого тактового сигнала. Потому асинхронное внешнее прерывание, соответственно, может «разбудить» контроллер, находящийся в одном из ре­жимов глубокого энергосбережения, когда тактовый генератор не работает, а синхронное - нет. И обычные МК, вроде AT90S8515 семейства Classic (но не его mega-аналога!), могут выводиться из глубокого «сна» только внешним пре­рыванием по уровню, которое не всегда удобно использовать. У большинства же моделей семейства Меда (из младших моделей - кроме ATmegaS), имеет­ся еще одно прерывание INT2, которое происходит только по фронтам (по уровню не может), но, в отличие от INTO и INT1, асинхронно. В ATtiny2313 (но не в его «классическом» аналоге!) такое асинхронное прерывание может про­исходить по сигналу с любого из 8 выводов порта В. Это значительно повыша­ет удобство пользования контроллером в режиме энергосбережения.

Таймеры-счетчики

в большинстве МК AVR присутствуют два или три таймера-счетчика, один из которых- 16 разрядный, а остальные- 8-разрядные (в старших моде­лях Mega общее число счетчиков может быть до 6). Все счетчики имеют возможность предварительной загрузки значений и могут работать непо­средственно от тактовой частоты (СК) процессора или от нее же, поделен­ной на 8, 64, 256 или 1024 (в отдельных случаях еще на 16 и 32), а также от внешнего сигнала. В целом устройство таймеров в МК, как мы говорили, похоже на счетчики 561HEU/14 (см. главу 15), только функциональность их значительно расширена.

В архитектуре AVR 8-разрядным счетчикам-таймерам присвоены номера О и 2, а 16-разрядным- 1, 3 и далее. Некоторые 8-разрядные счетчики (обычно Timer 2, если их два) могут работать в асинхронном режиме от отдельного тактового генератора, причем продолжать функционировать даже в случае «спящего» состояния всей остальной части МК, что позволяет использовать их в качестве часов реального времени.

При использовании счетчиков-таймеров, как обычных счетчиков внешних импульсов (причем возможна реакция как по спаду, так и по фронту импуль­са) частота подсчитываемых импульсов не должна превышать половины час­тоты тактового генератора МК (причем при несимметричном внешнем меан­дре инструкция рекомендует еще меньшее значение предельной частоты - 0,4 от тактовой). Это обусловлено тем, что при счете внешних импульсов их фронты обнаруживаются синхронно (в моменты положительного перепада тактового сигнала). Кроме того, стоит учитывать, что задержка обновления содержимого счетчика после прихода внешнего импульса может составлять до 2,5 периода тактовой частоты.

Это довольно сильные ограничения, поэтому, например, использовать МК в качестве универсального частотомера не очень удобно - быстродействую­щие схемы лучше проектировать на соответствующей комбинационной ло­гике или на ПЛИС (программируемых логических интегральных схемах).

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

Кроме того, 16-разрядные счетчики могут осуществлять «захват» (capture) внешних одиночных импульсов на специальном выводе. При этом может вы­зываться прерывание, а содержимое счетчика помещается в некий регистр. Сам счетчик при этом может обнуляться и начинать счет заново или просто продолжать счет. Такой режим удобно использовать для измерения периода внешнего сигнала или для подсчета неких нерегулярных событий (вроде прохождения частиц в счетчике Гейгера). Немаловажно, что источником та­ких событий может быть также встроенный аналоговый компаратор, который тогда используется, как формирователь импульсов.

Все счетчики-таймеры могут работать в т. н. режимах PWM, то есть в качест­ве 8-, 9-, 10- или 16-битных широтно-импульсных модуляторов (ШИМ), при­чем независимо друг от друга, что позволяет реализовать многоканальный ШИМ. В технической документации этим режимам, в силу их сложности, многовариантности и громоздкости, посвящено много страниц. Простейший вариант использования этих режимов для воспроизведения звука мы кратко рассмотрим в главе 22 в связи с голосовой сигнализацией. Отметим, что син­тез звука - не единственное и даже не самое приоритетное назначение ре­жимов PWM, их также можно использовать для регулирования мощности или тока (например, при зарядке аккумуляторов), управления двигателями, выпрямления сигнала, при цифроаналоговом преобразовании.

Кроме таймеров-счетчиков, во всех без исключения AVR-контроллерах есть сторожевой (Watchdog) таймер. Он предназначен в основном для вывода МК из режима энергосбережения через определенный интервал времени, но мо­жет использоваться и для аварийного перезапуска МК. Например, если рабо­та программы зависит от прихода внешних сигналов, то при их потере (на­пример, из-за обрыва на линии) МК может «повиснуть», а Watchdog-таймер выведет его из этого состояния.

Последовательные порты

Последовательные порты для обмена данными с внешними устройствами - важнейшая составляющая любого МК, без них его «общение» с внешним ми­ром резко ограничено. Последовательными их называют потому, что в них в каждый момент времени передается только один бит (в некоторых случаях возможна одновременная передача и прием, но все равно только по одному биту за раз). Самое главное преимущество последовательных портов перед параллельными (когда одновременно производится обмен целыми байтами или полубайтами-тетрадами) - снижение числа соединений. Но оно не единственное: как ни парадоксально, но последовательные интерфейсы дают значительную фору параллельным на высоких скоростях, когда на скорость передачи начинают влиять задержки в линиях. Последние невозможно сде­лать строго одинаковыми, и это одна из причин того, что последовательные интерфейсы в настоящее время начинают доминировать (типовые приме­ры - USB и FireWire вместо СОМ, LPT и SCSI, или Serial ATA вместо IDE).

В микроконтроллерных устройствах с нашими объемами данных, конечно, скорость передачи нас волнует во вторую очередь, но вот количество соеди­нительных проводов - очень критичный фактор. Поэтому все внешние уст­ройства, с которыми мы будем иметь дело в этой книге, будут иметь после­довательные интерфейсы.

Практически любой последовательный порт можно имитировать программ­но, используя обычные выводы МК. Когда-то так и поступали даже в случае самого популярного из таких noptoB - UART. Однако с тех пор МК обзаве­лись аппаратными последовательными портами, что, впрочем, не означает необходимости их непременного использования. Легкость программной ими­тации последовательных портов - еще одно их достоинство.

Из всех разновидностей портов, которые могут наличествовать в МК AVR, мы особенно обратим внимание на UART- Universal Asynchronous Receiver-Transmitter, «универсальный асинхронный приемопередатчик». UART есть основная часть любого устройства, поддерживающего протокол RS-232, но и не только его (недаром он «универсальный») - например, про­мышленные стандарты RS-485 и RS-422 также реализовываются через UART, так как они отличаются от RS-232 только электрическими параметра­ми и допустимыми скоростями, а не общей логикой построения. В персо­нальных компьютерах есть СОМ-порт, который работает по тому же прото­колу RS-232, и узел UART точно так же является его базовой частью.

Поэтому UART служит основным способом обмена данными МК с компью­тером. Отметим, что отсутствие СОМ-порта в большинстве современных мо­делей ПК не является препятствием: для этого существуют переходники USB-COM, а в настольную модель можно вставить дополнительную карту с СОМ-портами.

Заметки на полях

А почему это для нас так важно? Дело в том, что, соединив макет прибора с компьютером, даже если обмен данными функциональностью прибора и не предусмотрен, программу гораздо проще отлаживать, просто временно встав­ляя в нужных местах программы операции посылки значений задействованных регистров в ПК и принимая их в реальном времени с помощью какой-либо про­граммы- эмулятора терминала. Это намного удобней, чем осваивать гро­моздкую AVR Studio, да еще и в комплекте с какой-нибудь дорогущей отладоч­ной платой. Потому мой совет: сделать себе сразу отладочную плату, содержащую программирующий разъем (см. следующую главу) и преобразо­ватель уровней UART/RS-232 с разъемом для подключения нуль-модемного кабеля (см. главу 21).

О том, как обращаться с UART на практике, рассказывается в главе 21. Кроме UART, почти все МК AVR содержат самый простой из всех последователь­ных портов - SPI (Serial Peripheral Interface, последовательный периферий­ный интерфейс). О принципе устройства SPI упоминалось в главе 16. Его принципиальная простота сыграла отчасти дурную роль: трудно встретить два устройства, где протоколы SPI полностью совпадают, обычно обмен по этому порту сопровождается теми или иными «наворотами». Следует отме­тить, что программирование AVR также осуществляется через SPI, однако в общем случае этот интерфейс и SPI для обмена данными - разные вещи, хотя в большинстве случаев выводы у них одни и те же.

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

Некоторые другие узлы МК семейства AVR (например, АЦП) мы рассмот­рим по ходу изложения конкретных схем - так будет нагляднее. Здесь же мы закончим затянувшееся знакомство с микроконтроллером и перейдем к вопросу о том, как его программировать.

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

Дисплей мы будем подключать стандартным способом 4-битным способом.

Сначала начнём, конечно, с микроконтроллера, так как с дисплеем мы уже очень хорошо знакомы из предыдущих уроков.

Откроем даташит контроллера ATtiny2313 и посмотрим его распиновку

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

Так как ножек 20 по сравнению с 28 ножками контроллера ATMega8, к которым мы уже на протяжении всего времени занимаемся и ещё будем заниматься, то, соответственно, и возможностей также будет меньше.

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

Есть ещё некоторые отличия, но они незначительны и мы с ними познакомимся по мере необходимости.

Соберём вот такую вот схемку (нажмите на картинку для увеличения изображения)

Дисплей подключен к ножкам порта D. PD1 и PD2 — к управляющим входам, а остальные к ножкам модуля дисплея D4-D7.

Проект создадим с именем TINY2313_LCD, перенесём в него всё кроме главного модуля из проекта по подключению дисплея к Atmega8.

Конечно, некоторые вещи надо будет переделать. Для этого нужно внимательно изучить, к какой ножке что подключено. Шина E дисплея подключена к PD2, а шина RS — к PD1, поэтому внесём изменения в файл lcd.h

#define e1 PORTD |=0b000001 00 // установка линии E в 1

#define e0 PORTD &=0b111110 11 // установка линии E в 0

#define rs1 PORTD |=0b0000001 0 // установка линии RS в 1 (данные)

#define rs0 PORTD &=0b1111110 1 // установка линии RS в 0 (команда)

Как мы видим из выделения жирным шрифтом, не такие уж и кардинальные изменения у нас произошли.

Теперь информационные входы. Здесь у нас используются ножки PD3-PD6, то есть на 1 пункт сдвинуты по сравнению с подключением к Atmega8, поэтому исправим ещё и кое что в файле lcd.c в функии sendhalfbyte

PORTD &=0b1 0000 111; //стираем информацию на входах DB4-DB7, остальное не трогаем

Но это ещё не всё. Мы раньше передаваемые данные сдвигали на 4, а теперь нам в связи с вышеуказанными изменениями придётся их сдвигать только на 3. Поэтому в той же функции исправим ещё и самую первую строку

c <<=3 ;

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

В главном модуле инициализацию порта D мы не трогаем, пусть весь встаёт в состояние выхода, как и в уроке 12.

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

У нас всё прекрасно работает! Вот как можно, оказывается быстро переделать проект для одного контроллера под другой.

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

Вот вся схема

Здесь всё стандартно. Подтягивающий резистор на RESET и т.д.

Теперь, прежде чем прошивать контроллер в avrdude, нам неоходимо выбрать контроллер и считать его флеш-память

Затем зайти во вкладки FUSES и установить правильно фьюзы. Так как у нас нет кварцевого резонатора, то мы устанавливаем фьюзы именно так

Мы провели эмуляцию схемы в программе Proteus, помигали светодиодом и научились прошивать наш виртуальный микроконтроллер. Наверняка многим из читателей пришла в голову мысль: “А можно ли помигать светодиодом, использую кнопку, подключенную к МК?

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


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

Итак к делу. Так выглядит у нас наша схема в программе Proteus (кликните для увеличения):

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

Как мы уже разобрали, питание и землю мы берем во вкладке “Терминал”. Обозначаются они у нас соответственно Power и Ground.

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


Перед использованием нам нужно выбрать кнопку в библиотеке аналогично остальным деталям. Для этого нужно набрать в поле “Маска” слово “but”. Затем в поле “Результаты” слово “BUTTON”:


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

Какие порты у нас используются в проекте. Ниже на рисунке мы видим отходящие линии от портов РA0, РВ0, РВ1, РВ2 и РВ3. К порту В у нас подключены светодиоды, а к порту А – кнопка.

Итак, при нажатии, мы замыкаем цепь соединяющую +5 вольт с портом РА0 и верхним выводом резистора. Для чего у нас здесь вообще установлен резистор? Дело в том, что цепь кнопки должна быть замкнутой. После того как мы установили резистор, ток у нас течет от плюса питания через кнопку, резистор и дальше на землю.

Номинал резистора достаточно взять равным 200 Ом. Итак, когда мы нажимаем кнопку, мы соединяем порт РА0 с +5 вольт питания, и если мы опросим ножку РА0 на наличие напряжения или его отсутствие, мы сможем влиять на выполнение нашей программы.

Скрины с текстом нашей программы я привел ниже:


Итак отличия от прошлого проекта заключаются в том, что все 8 выводов порта РА мы конфигурируем на вход, выводы порта РВ0 – РВ3 мы конфигурируем на выход, а РВ4 – РВ7 на вход.


Затем мы используем в нашей программе проверку условия “ if”


Итак, мы видим в строчке после “if”, в скобках, условие выполнения. Код ниже выполняется, если на порту PA0 у нас присутствует логический ноль, или ноль вольт. Этот текст в скобках – сдвиг бита порта. Мы разберем в одной из следующих статей, а пока достаточно принять на веру, что этим мы опрашиваем кнопку на отжатие . Затем в фигурных скобках идет текст программы, который выполняется, если условие верно. Если условие не верно, программа продолжает выполняться дальше, пропустив текст в фигурных скобках.

Аналогично, с помощью условия “if” мы опрашиваем кнопку на нажатие . Обратите внимание, текст у нас в скобках изменился. Это означает что если на ножке РА0 у нас логическая единица, мы выполняем условие, то есть текст в фигурных скобках. То есть другими словами, у нас при отжатой кнопке, поочередно загораются и тухнут светодиоды с первого по четвертый, а при нажатии и удерживании, загораются и тухнут с четвертого по первый. Таким образом, мы можем влиять на выполнение программы, с помощью нажатия кнопки, опрашивая наличие на ней логического нуля, или логической единицы

Также , в котором находятся файл “сишник”, HEX и файл Протеуса.

А вот и видео

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

Для начала нужно выбрать микроконтроллер. В моем случае это ATmega8535. В данном случае микроконтроллер можно брать любой, так как данная задача легко реализуется под любой МК. Писать программу для микроконтроллера можно на Ассемблере, СИ, Pascal-е и Bascom. Я использовал язык СИ, все эти языки разные.
Конкретную разницу между Си и Паскалем можно увидеть ниже.

//Мигающий светодиод void main() { ddrB = 0b11111111; //задаём порты B на выход portB = 0b11111111; //по умолчанию всё выключено while(1) { portB = ˜portB; //переключаем состояние светодиода на обратное delay_ms(100); //делаем задержку на 100 миллисекунд } }

Program First; begin ddrB:= $FF; //задаём порт B на выход portB:= $FF; //по умолчанию ничего не горит while(1) do begin portB:= not(portB); //переключаем состояние светодиода на обратное delay_ms(100); //делаем небольшую задержку end; end.

Список радиоэлементов

Обозначение Тип Номинал Количество Примечание Магазин Мой блокнот
U1 МК AVR 8-бит

ATmega8535

1 В блокнот
R1-R8 Резистор

220 Ом - 1 кОм

8 В блокнот
R9-R11 Резистор

10 кОм

3 В блокнот
V1-V8 Светодиод 8 В блокнот
Тактовая кнопка 3

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

[Подключение URM37 к микроконтроллеру AVR]

Если нужно подключить датчик к микроконтроллеру, то это сделать довольно просто благодаря наличию в датчике последовательного порта RS-232 с уровнями TTL. Для полного управления всеми возможностями датчика достаточно 5 проводов:

5V питание

GND питание, общий провод

RST сброс контроллера в URM37, если подан лог. 0 (использовать необязательно)

RXD прием данных (TTL RS232)

TXD передача данных (TTL RS232)

Есть и другие способы подключения датчика URM37 (например, чтение расстояния по сигналу PWM) - см. , но в этой статье они не рассматриваются, так как обладают ограниченными возможностями. Внимание! При подключении датчика правильно установите перемычки J1, J2, J3 (см. ), иначе можете повредить порты подключаемого микроконтроллера высоким напряжением сигнала ±12V TXD, который генерирует MAX202 (двухканальный приемопередатчик RS-232).

Подключение датчика URM37 к микроконтроллеру AVR на примере макетной платы AVR-USB-MEGA16 (ATmega32A), см. :

Чтобы осуществить работу с датчиком URM37, нужно настроить порт USART микроконтроллера на параметры соединения 9600; Parity: none; Stop bit: 1. Если используется сигнал сброса URM37 RST (что необязательно), то ножку порта RST нужно настроить как выход и вывести туда лог. уровень 1. Для чтения расстояния нужно вывести через USART 4 байта 0x22 0x00 0x00 0x22 и в ответ принять 4 байта, содержащие код команды, данные расстояния и контрольную сумму (см. в описание протокола URM37).

Пример настройки порта USART для частоты кварца 12 МГц, микроконтроллер ATmega32A (AVR-USB-MEGA16). Макрос SERIAL_2X_UBBRVAL можно подсмотреть в библиотеке LUFA, см. :

// UMSEL=0 (async UART), UPM=00 (no parity), USBS=0 (1 stop-bit),
// UCSZx=011 (8 бит), UCPOL=0 (в режиме async)
u8 ConfigMask = ((1 << UCSZ1) | (1 << UCSZ0));

// Перед реконфигурированием USART нужно выключить,
// иначе возможна некорректная работа
UCSRB = 0;
UCSRA = 0;
UCSRC = 0;

// Установка новой скорости перед конфигурированием USART
// с учетом установленного бита двойной скорости U2X
UBRR = SERIAL_2X_UBBRVAL(9600);

// Конфигурирование USART в режиме двойной скрости
UCSRC = ConfigMask;
UCSRA = (1 << U2X);
UCSRB = ((1 << RXCIE) | (1 << TXEN) | (1 << RXEN));

Пример отправки через USART команды чтения расстояния:


Пример приема через USART ответа от датчика URM37 в обработчике прерывания (реализацию обработчика прерывания и кольцевого буфера см. в библиотеке LUFA ):

ISR(USART_RX_vect, ISR_BLOCK)
{
u8 ReceivedByte = UDR;

if (rxUSART_Buffer.Count< sizeof (rxUSART_Buffer_Data))
RingBuffer_Insert(&rxUSART_Buffer, ReceivedByte);
rxUSARTtimeout = 0;
}

[Подключение URM37 к компьютеру через RS-232]

Если же нужно подключить датчик к компьютеру, то при наличии обычного порта RS-232 это сделать довольно просто - достаточно правильно установить перемычки J1, J2, J3 (см. ) для получения ±12V уровней RS-232, и правильно развести сигналы TXD и RXD. Кроме того, для питания датчика URM37 нужно напряжение +5V. Это напряжение можно взять от порта USB, либо от внешнего стабилизированного источника питания +5 вольт. Внимание! Установите перемычки J1, J2, J3 в правильное положение, иначе рискуете испортить датчик высоким уровнем напряжения ±12V, который попадет на вход RXD датчика.

Для управления датчиком (отправки специальных команд для чтения расстояния) нужно написать специальную программу. Для проверки работоспособности подключения можно взять тест-программу URM37V3.2helpmate.exe, см. , которая позволяет отправлять команды протокола датчика URM37 и принимать от него байты данных в сыром, нерасшифрованном виде.