![]() Итак, надеюсь добросовестный читатель уже собрал программатор, экспериментальную плату, а также установил и настроил требуемое программное обеспечение. Сейчас, написав первую статью из цикла, я понимаю, что несколько погорячился и сделал ту же ошибку, что и мои предшественники, поставив словосочетание «для начинающих». Вернее было бы сформулировать тему «Для начинающих программировать на ассемблере», то есть я предполагаю, что читатель уже имеет хотя бы поверхностное представление о том, что такое микроконтроллер, иначе только на знакомство с этой темой у нас уйдет уйма времени. Для тех же, кто совсем не знаком с ними, могу порекомендовать совершенно замечательный на мой взгляд цикл статей С. Рюмика «Микроконтроллеры AVR», опубликованный в журнале Радиоаматор (№№ 1-11 за 2005 год). В этом цикле в качестве базового контроллера выбран ATmega8, однако общие функциональные узлы у вышеназванного контроллера и ATtiny13 практически не отличаются. Для знакомства же непосредственно с микроконтроллером ATtiny13 я рекомендую книгу А.В. Евстифеева «Микроконтроллеры AVR семейства tiny. Руководство пользователя» (М.: Издательский дом «Додэка-XXI», 2007. — 432 с.). Она содержит переведенные и систематизированные даташиты на весь номенклатурный ряд контроллеров семейства tiny, и, на мой взгляд, должна являться настольной для тех, кто занимается программированием микроконтроллеров. Впрочем, я по мере повествования буду давать кое-какие сведения относительно тех узлов и модулей контроллера, которые будут применяться в написанных программах. Но все это лирическое отступление. Вернемся непосредственно к повествованию. Контроллер ATtiny13 несмотря на свой малый размер, имеет весьма неплохие функциональные характеристики. А небольшое количество выводов с лихвой компенсируется количеством функций, которые каждый из них выполняет. Цоколевка и описание выводов представлено ниже: Таблица взята из вышеназванной книги А.В. Евстифеева. Как можно видеть, каждый вывод может выполнять не менее трех функций, а то и намного больше. Поначалу мы не будем рассматривать альтернативные функции, а лишь базовую — цифровой вход/выход. Как видно из рисунка и таблицы, все выводы, за исключением выводов питания, имеет название РВ с последующим порядковым номером. Что же это означает? Все выводы контроллера объединены по 8 штук для удобства работы с ними, а на каждую группу из 8 выводов выделено по три специальных регистра ввода-вывода. Вообще понятие регистров является ключевым при работе в контроллерами, особенно на ассемблере. Рассмотрим более подробно каждый из трех вышеупомянутых регистров. Все они являются однобайтовыми ячейкам в памяти контроллера. Каждый бит их отвечает один из выводов контроллера, причем номер бита в регистре совпадает с номером вывода (например, 0-й бит отвечает за вывод РВ0, 1-й — за РВ1 и т.д.). Все регистры имеют свое имя, по которому к ним обращаются при написании программ. Что же это за имена? 1. Регистр DDRB отвечает за направление передачи информации каждого вывода контроллера. Если какой-либо бит этого регистра равен «0», то соответствующий ему вывод будет входом, а если «1» — то выходом. Причем каждый вывод конфигурируется индивидуально и в любом месте программы. Это значит, что при разных условиях или в разное время один и тот же вывод может быть сконфигурирован как вход либо как выход, причем независимо от остальных выводов. 2. Регистр PINB содержит в себе текущее состояние всех выводов: если на вывод подано напряжение, то в соответствующий бит записывается логическая «1», если напряжение отсутствует — логический «0». В основном этот регистр используется для считывания состояния вывода, находящегося в режиме входа. 3. Регистр PORTB выполняет двоякую функцию в зависимости направления передачи информации. Если вывод работает как цифровой выход, то запись «1» в какой-либо бит регистра PORTB приводит к появлению напряжения на соответствующем выводе, а запись «0» — к исчезновению напряжения. Таким образом, в режиме выхода именно этот регистр определяет состояние каждого вывода. В режиме цифрового входа запись логической «1» в какой-либо бит приводит к подключению встроенного подтягивающего резистора на соответствующем выводе, а запись «0» — к его отключению. Что же это за такая штука — «подтягивающий резистор», и для чего она предназначена? Если вывод работает как цифровой вход, то сопротивление входного буфера достаточно велико, а входной ток — весьма мал. Поэтому любые электрические наводки могут привести к самопроизвольному переключению вывода в произвольное состояние. Чтобы этого не происходило, между входом и источником питания включается резистор сопротивлением несколько десятков килоом, «подтягивающий» потенциал входа к напряжению питания (отсюда и название). Ток, протекающий через этот резистор достаточно мал, чтобы не мешать работе остальной схемы, но достаточно велик, чтобы воспрепятствовать случайным переключениям вывода. Мы часто будем использовать подтягивающие резисторы при работе с кнопками, поскольку когда они не нажаты, выводы, к которым они подключены, фактически «висят» в воздухе и подвержены наводкам. Следует упомянуть, что при включении питания все регистры сброшены в 0, и каждый вывод выполняет функцию цифрового входа без подтягивающего резистора. Теперь, когда мы имеем хоть какое-то представление, ЧТО нужно для работы с вводами контроллера, пришла пора узнать, КАК с ними работать. Напишем нашу первую рабочую программу на ассемблере. Вначале я дам полный алгоритм создания нового проекта, в дальнейшем же буду его опускать, останавливаясь только на самом тексте программы. 1. Заходим в папку asm, создаем в ней новую папку. Переименовываем в удобное для нас имя. Для определенности я буду называть их по номеру нашего шага. В данном случае «step2». 2. Правой кнопкой щелкаем на файле build.bat и изменяем путь к исходному файлу, указывая вновь созданную папку (step2). У меня после этого содержимое выглядит так: «F:\Prog\AVR\asm\avrasm32 -fI %F:\Prog\AVR\asm\step2\main.asm У вас оно может отличаться в зависимости от того, куда вы распаковали архив. 3. Заходим в папку Asmedit и запускаем программу ASM_Ed.exe 4. В открывшемся окне пишем текст программы. На этом пункте остановлюсь более подробно, поскольку он является основным в нашем сегодняшнем занятии, равно как и в последующих. Что же собой представляет текст ассемблерной программы? Он может включать в себя несколько элементов, записываемых по определенным правилам: — команды ассемблера с операндами или без них в зависимости от синтаксиса команды. Между именем команды и первым операндом должен быть либо пробел, либо знак табуляции, либо и то и другое в любом количестве. Операнды разделяются между собой запятой, до и после которой может стоять также произвольное количество пробелов либо знаков табуляции; — директивы, каждая из которых начинается с символа «.»; — метки, представляющие собой произвольно названные пользователем места программы, к которым может потребоваться переход. Каждая метка оканчивается символом «:»; — комментарии, начинающиеся с символа «;». Весь текст от начала комментария до конца строки игнорируется при создании hex-файла и может быть совершенно произвольным; — пустые строки для лучшей структурированности и читабельности программы. В каждой строке может быть не более одной команды. Однако одновременное присутствие в строке метки с последующей командой и комментарием допускается. Используя эти правила, напишем программу, которая будет включать светодиод LED2, пока удерживается нажатой кнопка SB1, и выключать его, если кнопка отпущена. Текст программы представлен ниже:
Разберем его поподробнее. Первая строка содержит директиву «include», написанную по указанным выше правилам с точкой в начале. Назначение ее — включать в текст программы указанный за ней файл. Как я говорил еще в первом шаге, нам потребуется файл «tn13def.inc». В этой строке вам необходимо будет изменить путь, указав расположение папки Appnotes в своем компьютере. Зачем же нам нужно подключать этот файл? Любопытный читатель может заглянуть в него и почитать его содержимое, но, скорее всего, поначалу он мало что поймет там. Пока же скажу, что в нем содержится соответствие имен регистров, которые по умолчанию ассемблер не знает, с их физическими адресами в контроллере. Следующие строки представляют собой команды ассемблера. Внимательный читатель заметит, что всего используется четыре различные команды. рассмотрим назначение каждой. Команда sbi имеет два операнда: первый — имя регистра, второй — номер бита. В результате ее выполнения указанный бит в указанном регистре устанавливается в «1». Команда cbi по синтаксису аналогична вышеприведенной и выполняет прямо противоположную функцию — сбрасывает указанный бит в указанном регистре в «0». Команда sbis также аналогична по синтаксису вышеприведенным. Однако в отличие от них она не выполняет никаких операций с регистрами, а лишь проверяет состояние указанного бита в указанном регистре, и если тот равен «1», пропускает следующую за командой строку. В противном же случае следующая за ней строка выполняется, равно как и все остальные за ней. Команда sbiс является противоположностью команды sbis. Она пропускает следующую строку, если указанный бит регистра равен «0». Теперь, суммируя все вышеизложенное, попробуем разобраться в алгоритме работы программы. Для начала я сделаю это буквально построчно. 1 строка. Директивой include подключается файл tn13def.inc, содержащий определения регистров. 2 строка. Командой sbi устанавливается «1» в бит 4 регистра DDRB, тем самым вывод РВ4 переключается на выход. Если посмотреть схему платы (рис. 1 предыдущего шага), можно видеть, что к этому выводу подключен светодиод LED2. После команды и знака «;» написан комментарий, кратко поясняющий смысл выполняемых в строке действий. 3 строка. Той же командой sbi устанавливается «1» в бит 2 регистра PORTB, подключая внутренний подтягивающий резистор к выводу РВ2, к которому подключена кнопка SB1. Поскольку мы не изменяли состояние бита 2 регистра DDRB, этот вывод так и останется входом, что нам, собственно, и нужно. 4 строка. Командой sbic проверяется наличие логического «0» на входе PB2, используя регистр PINB. Если внимательно посмотреть на схему, можно увидеть, что кнопки при нажатии, замыкают соответствующий вывод с общим проводом. Это стандартный прием, поскольку при отпущенной кнопке на выводе присутствует логическая «1» за счет подтягивающего резистора, а при нажатой появляется логический «0» благодаря подключению вывода к общему проводу. Итак, если на выводе РВ2 присутствует логический «0», то есть кнопка нажата, мы пропускаем следующую строку, а если кнопка отпущена, то выполняем ее. 5 строка. В ней командой sbi устанавливается логическая «1» в бит 4 регистра PORTB, тем самым выключая светодиод LED2. Въедливый читатель может поинтересоваться, почему же светодиод выключается, если мы подаем напряжение на выход. Ответ кроется в схеме. Светодиод анодом подключен к проводу питания, а катодом к выводу контроллера. Поэтому если подать на вывод напряжение, то потенциалы анода и катода сравняются, и светодиод погаснет. Если же на вывод выдать логический «0», то к светодиоду будет приложено напряжение, и он зажжется. Таким образом пара строк 4 и 5 выключает светодиод LED2 при отпущенной кнопке. 6 строка. Противоположна по смыслу 4-й. Командой sbis проверяется наличие логической «1» на входе РВ2, то есть проверяется, отпущена ли кнопка. Если кнопка отпущена, то следующая строка пропускается, и происходит переход к следующей за ней. Но поскольку 7-я строка последняя, то происходит переход ко 2-й строке. Если же кнопка нажата, то выполняется строка 7. 7 строка. Противоположна 5-й. Командой cbi бит 4 регистра PORTB сбрасывается в «0», тем самым включая светодиод LED2. Таким образом, пара строк 6 и 7 включает светодиод LED2 при нажатой кнопке SB1. Как видите, ничего особо сложного мы не совершили. Используя знание всего 3-х регистров и 4-х команд, мы написали нашу первую программу. Что же делать с ней дальше. Если вы еще не забыли, мы продолжаем писать алгоритм создания программы. 5. Написав текст программы в окне редактора, выбираем пункт меню «File», и в открывшемся списке нажимаем «Save As…». В окне сохранения файла выбираем созданную нами папку step2 и указываем имя файла «main», поскольку именно это имя было задано нами в файле «build.bat» После сохранения окно программы должно иметь следующий вид: 6. Создаем hex-файл. Для этого нажимаем кнопку «II» на панели инструментов. Должно появится окно следующего вида: Оно извещает нас о том, что ассемблирование прошло без ошибок и создан файл прошивки «main.hex» объемом 6 слов, то есть 12 байт. Замечу, что аналогичная программа на языке Си имела бы как минимум в 5 раз больший объем. 7. Зайдя в папку step2, обнаруживаем в ней пополнение в виде вновь созданного файла main.hex, который теперь может быть зашит в контроллер любым программатором, что и необходимо выполнить, дабы увидеть результаты работы написанной нами программы. После прошивки контроллера, если схема собрана правильно, все должно работать по разработанному нами алгоритму: при отпущенных кнопках светодиод LED2 должен быть погашен, а во время удержания нажатой кнопки SB1 — зажжен. На этом второй шаг можно считать сделанным: мы написали первую программу на ассемблере и, зашив ее в контроллер, убедились в ее работоспособности. Настало время осмыслить все написанное и выполнить самостоятельную работу. До следующего шага предлагаю сделать такие задания: 1. Добавить к программе обработку нажатия кнопки SB2 с противоположным алгоритмом: при отпущенной кнопке SB2 светодиод LED1 должен быть зажжен, а при нажатой — погашен. 2. Написать программу управления светодиодом LED2 при помощи обеих кнопок. При нажатии на кнопку SB1 светодиод должен зажигаться и оставаться включенным до тех пор, пока не будет нажата кнопка SB2, которая выключает его до следующего нажатия SB1. Если у вас возникнут вопросы, задавайте их на форуме или здесь в виде комментариев к статье. Желаю успехов! Автор: Сергей Сокол, материал взят с его сайта https://sokolsp.at.ua/ No comments yet.
|
|