AVR pins - el-pths/w GitHub Wiki

Управление выводами AVR - подробнее

Итак мы уже научились немного мигать светодиодом подавая сигнал на ноги контроллера с помощью регистра PORTx (где X - буква B, C, D в зависимости от того какой набор ног нам нужен - и в каждом ведь ещё по 8 ног). Можно заметить при этом что светодиод горит слабо. Давайте разберемся почему так а заодно научимся считывать сигнал с ног (например, от кнопки).

Каскадное включение генераторов NE555 с двумя светодиодами

На этой страшной схеме показано внутреннее устройство логики управляющей каждой ногой и подписаны названия регистров за это отвечающие. Видно что регистр PORTx выполняет больше одной функции. Однако сначала рассмотрим новый но важный регистр DDRx - он позволяет подключить к ноге плюс или минус питания контроллера напрямую, то есть подать на ногу "сильный" 0 или "сильную" 1. Но это только если в данный порт на соответствующий ноге бит записана единица. Например если мы хотим подавать полноценные логические сигналы на 2-ю (считая с 0) ногу порта B, то нужно будет записать

ldi r16, 0b0100  ; установлен 2й бит считая с 0, справа
out DDRB, r16

Слово DDRx расшифровывается как "data direction register" - иными словами регистр, отвечающий за направление передачи данных по этой ноге. Если там 1 то данные можно только выводить через эту ногу, если же 0 то удобнее их считывать (хотя как мы видели при этом можно и слабый выходной сигнал подать).

На картинке это показано так что красная или синяя магистраль (плюс или минус) могут быть подключены к ноге если DDRx их "пропускает". При этом какая из двух будет подключена (не обе вместе) зависит от состояния PORTx - если там 1, подключится плюс, если же 0 то минус.

В том же случае когда DDRx не пропускает "сильный" сигнал от магистралей, нога не подключена никуда. На ней "high-Z" - высокоимпедансное состояние (высокое сопротивление для любых сигналов, как бы обрыв цепи). Однако если на PORTx подать 1 при этом, он включит дополнительный "резистор подтяжки" который проводит на ногу слабенький сигнал логической единицы. Этот резистор 50-100 килоом, поэтому светодиод светится так слабо.

При этом интересный момент - единицу, хоть и слабую, мы подать можем - а ноль - никак! (покуда DDRx установлен в 0) Если мы подключим светодиод между ногой и минусом, его можно легонько зажечь используя как раз этот внутренний резистор. Если бы мы его наоборот подключили к плюсу, без манипуляций DDRx засветить его было бы нельзя.

Зачем же нужен этот резистор подтяжки? Дело в том что когда DDRx=0 мы рассматриваем ногу как работающую на вход. Например можно подключить к ней кнопку, закорачивающую эту ногу на минус (можно и на плюс, но не так удобно, сейчас мы это поймём). Когда кнопка нажата, на ногу приходит полноценный минус. Внутри контроллера есть регистр PINx который позволяет считать сигнал на ноге (при любых настройках других регистров):

in r16, PINB  ; в r16 попадёт состояние сигналов на 8 ногах от PB0 до PB7

Но что если кнопка отпущена? тогда нога "болтается" в воздухе, в высокоимпедансном состоянии. На неё не приходят никакие сигналы, но она может улавливать радиоволны (скорее просто помехи) из эфира и хаотически показывать то 0 то 1. Чтобы этого не происходило, её нужно "подтянуть" резистором в сторону противоположную кнопке. То есть если кнопка ведет к минусу, резистор должен идти к плюсу. Через него будет приходить слабая единица когда кнопка не нажата (а при нажатии сильный 0 через кнопку "переборет" эту слабую единицу - под этим словом мы подразумеваем что из законов ома и кирхгоффа на ноге будет низкий потенциал т.к. сопротивление кнопки гораздо меньше чем у резистора).

Чтобы не подпаивать внешний резистор, разработчики как раз и придумали внутренний управляемый резистор подтяжки.

Как использовать состояние ноги

Давайте используем ногу PC4 - к ней у нас припаяна кнопка отвечающая за выбор "режима программирования" при старте - но ею же можно пользоваться и для личных целей когда программа уже запущена. Если считать с PINC значения, состояние этой ноги окажется в бите 4 (считая с нуля). Мы можем погасить все остальные биты в 0 с помощью команды ANDI и тогда результат (либо 00000 либо 10000 смотря нажата кнопка или нет) из регистра r16 можно прибавить например к регистру определяющему длительность мигания светодиода. То есть светодиод будет мигать медленнее или быстрее в зависимости от того нажата ли кнопка.

Попробуйте это проделать!