Для того чтобы опросить пин микроконтроллера AVR настроенный на ввод существует несколько команд. Команда SBIS делает пропуск следующей после неё команды если на опрашиваемом пине высокий уровень напряжения (+5В (логическая единица)) и не делает этот пропуск если на этом пине низкий уровень напряжения. Существует команда SBIC которая делает такой пропуск если на опрашиваемом пине низкий уровень и не делает его если высокий. Т.о. система микроконтроллера AVR позволяет опросить отдельный пин, какого либо порта, одной командой и сделать это за один такт. Как было показано ранее вывод логической единицы или нуля на пин настроенный на выход также можно одной командой за один такт. Есть команды для работы с портом целиком - это команда OUT для вывода и команда IN для ввода (т.е. опроса порта целиком). Чтобы проверить на практике ввод с кнопкой, можно использовать схему:
Рисунок 1 - Мигалка с кнопкой с подтягивающим резистором на ATtiny2313
Можно взять код из предыдущей статьи, дополнить его одной строкой и получить мигалку работающую при нажатой кнопке и не работающую при отпущенной кнопке:
здесь добавлена строка:
SBIS 0x10, 1 ; пропустить следующий команду если кнопка не нажата
0x10 - это адрес регистра для опроса порта D,
1 - это номер пина порта D к которому подключена кнопка.
Т.о. получается что светодиод может загораться только в случае если кнопка нажата т.к. только тогда команда SBIS будет позволять выполниться команде установки пина, к которому подключен светодиод, в единицу.
Можно упростить схему на рисунке 1 убрав резистор для подтягивания пина к плюсу питания когда кнопка не нажата.
Рисунок 2 - Мигалка с кнопкой на ATtiny2313
Но чтобы схема работала также как раньше надо подключить внутренний подтягивающий резистор. Сделать это можно такой же командой какой мы устанавливали логическую единицу на пине настроенном на выход. Т.е. командой SBI но для пина к которому подключена кнопка.
Здесь добавлена строка:
SBI 0x12, 1 ; подача на пин 1 порта D высокого уровня
Прежде чем добавлять такую строку надо сначала убедиться что пин настроен на вход. Убедиться в этом можно посмотрев строки:
LDI R16, 0b00000001 ; поместим в регистр R16 число 1
OUT 0x11, R16 ; загрузим значение из регистра R16 в DDRD
в которых мы видим что первый пин порта D настроен на вход т.к. в соответствующий бит соответствующего регистра записан ноль. После того как программа написана её можно откомпилировать и загрузить в микроконтроллер (см. предыдущую статью).
Для программирования микроконтроллеров существуют два основных языка - это язык Си и Ассемблер. Бывают и другие языки но Си и Ассемблер используются чаще других т.к. их можно использовать для создания программ оптимально использующих ресурсы микроконтроллера. Язык Си более прост в изучении чем Ассемблер, более прост для понимания человеком вообще (на нем можно писать более читабельный код) а также более просто переносим между разными микроконтроллерами и вообще разными устройствами. Ассемблер же не так прост в понимании и хуже переносим т.к. он имеет множество разных команд которые отличаются друг от друга при программировании разных микроконтроллеров и устройств и даже при программировании одного и того же устройства но при использовании разных компиляторов. Однако язык ассемблер дает больше возможностей управлять ресурсами микроконтроллера. Программы написанные на Ассемблере могут быть более оптимальными чем программы на Си. Также изучение Ассемблера позволяет лучше понять работу микроконтроллера и писать более оптимальные программы на языке Си. Поэтому данный низкоуровневый язык стоит изучить даже если необходимость в его изучении и применении на практике никогда не возникала. Данный язык сильно отличается для разных микроконтроллеров но всё таки некоторые общие принципы наверняка должны присутствовать в той или иной степени для разных устройств. Начать скорее всего будет лучше с какого нибудь простого микроконтроллера. Например, для старта, можно взять ATtiny2313 и написать для него мигалку а если это получиться то делать далее уже более сложные устройства и переходить на более сложные микроконтроллеры например какие нибудь из STM32. Чтобы писать саму программу можно использовать какой либо текстовый редактор. Обычно в ОС Windows присутствует текстовый редактор "блокнот". После написания программы в "блокноте"её можно сохранить в формате с расширением .asm потом откомпилировать в файл с расширением .hex каким нибудь компилятором ассемблера для микроконтроллеров avr напр. компилятором avra (который можно скачать по ссылке https://sourceforge.net/projects/avra/files/1.2.3/ (для windows нужно скачать avra-1.2.3-win32.zip)) (для установки достаточно разархивировать) и записать полученный файл с расширением .hex в микроконтроллер утилитой avrdude (устанавливается вместе с arduino IDE, WinAVR или отдельно) через программатор. Рассмотрим схему устройства которое будем программировать:
Рисунок 1 - Светодиодная мигалка на микроконтроллере ATtiny2313 с программатором
На рисунке выше приведена схема светодиодной мигалки на микроконтроллере ATtiny2313 с программатором. Микроконтроллер ATtiny2313 имеет встроенный тактовый RC генератор и встроенный внутренний резистор для подтяжки вывода reset к нужному для работы микроконтроллера уровню также ему не нужно много внешних конденсаторов и прочей дополнительной обвязки (этим данный микроконтроллер прост и хорош). В качестве программатора можно использовать Arduino с записанным в неё скетчем ISP программатора:
Рисунок 2 - Светодиодная мигалка на микроконтроллере ATtiny2313 с программатором на Arduino Uno
Если все необходимые элементы имеются то можно начинать писать программу. Давайте рассмотрим простую программу мигания светодиодом на Ассемблере:
Ассемблер, в отличии от Си, регистронезависимый язык поэтому команды можно писать и большими буквами и маленькими и вперемешку. Команды которые начинаются с точки называются директивами. Директивы - это команды не для микроконтроллера а для компилятора. Директива .CSEG означает начало сегмента кода, помимо сегмента кода существует также сегмент данных и сегмент EEPROM. Директива .ORG указывает адрес с которого начинается сегмент. В ассемблере можно делать комментарии т.е. строки которые игнорируются компилятором и нужны для помощи программисту, комментарии начинаются с точки с запятой и завершаются концом строки. Команда LDI нужна для помещения в регистр какой либо константы. Константу можно записать в десятичном, шестнадцатеричном или двоичном виде. Если она записана в двоичном виде то перед ней ставиться нолик и английская буква b т.е. например 0b00000001. Двоичные числа удобны для конфигурирования порта микроконтроллера т.к. по ним наглядно видно в каком бите есть ноль а в каком единица. Если константа пишется в десятичном виде то перед ней ставить ничего не надо а надо просто написать число. Если константа пишется в шестнадцатеричном виде то перед ней ставиться 0x. Чтобы настроить второй пин микроконтроллера на выход нужно в записать единицу в нулевой разряд регистра DDRD. DDRD - это просто название регистра для удобства, на самом деле важно знать что этот регистр имеет какой то адрес в памяти и для того чтобы записать в этот регистр какое либо число и т.о. поместить либо ноль либо единицу в нужный его разряд, нужно записать это число по соответствующему адресу для регистра DDRD в микроконтроллере ATtiny2313 этот 0x11. Для того чтобы настроить второй пин микроконтроллера ATtiny2313 на выход мы сначала командой LDI записываем в регистр R16 число 0b00000001 а потом командой OUT из регистра R16 мы это число помещаем в регистр DDRD по тому что записать сразу константу в DDRD нельзя. Далее идет основной цикл программы т.е. "бесконечный" цикл в котором выполняются основные постоянные действия. Чтобы организовать этот цикл на ассемблере используется оператор безусловного перехода RJMP. В самом низу кода мы видим строку RJMP Start а в самом верху основного цикла мы видим метку Start. Команда RJMP просто переводит выполнение программы на то место где стоит метка т.о. если метку поставить перед этой командой после которой идет название этой метки то можно получить бесконечный цикл. Командой SBI мы устанавливаем высокий уровень т.е. пять вольт на нужном пине микроконтроллера. Если мы используем пин который связан с нулевым битом порта D то после команды SBI мы пишем адрес порта D (для микроконтроллера ATtiny2313 это 0x12) ставим запятую и после этого пишем номер бита который мы хотим установить в логическую единицу чтобы на нужном пине стало пять вольт. Аналогично командой CBI мы делаем ноль вольт на нужном нам пине. Для создания задержки сначала в регистр r18 записывается число 250 (максимальное которое можно записать = 255, минимальное = 0) потом 250 записывается в регистр r19. После чего командой dec (декремент) происходит уменьшение на единицу числа находящегося в регистре r19. Далее имеется команда brne - это оператор условного перехода т.е. он переносит выполнение программы на место с меткой при выполнении условия. Если результатом операции предшествовавшей данной команде был ноль то перехода туда где стоит метка не происходит и выполнение программы продолжается, если был получился не ноль то происходит переход на строку с меткой в данном случае это L1. Т.о. получается цикл выход из которого происходит тогда когда число в регистре r19 становиться равным нулю. Далее происходит декремент числа в регистре r18 и так как сразу там ноль не получиться то переход происходит на строку с меткой L1 а там стоит декремент числа в регистре r18 но так как там уже ноль то декремент делает там 255 и всё повторяется заново т.о. получается вложенный цикл. Эти циклы выполняются какое то время и делают задержку для того чтобы можно было наблюдать мигание светодиода.
После того как программа написана (например в имеющемся в windows текстовом редакторе "блокнот" или любом другом подходящем текстовом редакторе (неважно каком (это дело вкуса (на результат не повлияет (если текстовый редактор подходит для данных целей и позволяет сохранять текст в формате .asm))))) её можно сохранить в формате .asm и откомпилировать в cmd (командной строке windows) командой:
путь_до_компилятора_avra путь_до_файла.asm
например:
F:\avra-1.2.3\bin\avra F:\avr\blink.asm
Если компиляция пройдет успешно то компилятор создаст файл с расширением .hex который можно загрузить в микроконтроллер например командой:
avrdude -c avrisp -P COM3 -b 19200 -p t2313 -U flash:w:blink.hex
(avrdude перед этим надо установить на компьютер)
Эта команда сработает если используется микроконтроллер ATtiny2313 (-p t2313), программатор avrisp (-c avrisp (он же arduino, он же stk500, он же "пять проводков" (avrdude не поймет "пять проводков" (остальное должна понять)))) который подключен к порту который называется COM3 (-P COM3) (если называется по другому то в команду надо вписать соответствующее название). blink.hex - это название откомпилированного файла который надо загрузить в микроконтроллер. При этом в данной программе не прописана установка фьюзов и считается что микроконтроллер либо новый с завод и на нем установлены фьюзы по молчанию либо фьюзы ранее были установлены как надо и менять их не требуется. Если hex файл успешно запишется то светодиод должен замигать!