Пятница, 26.04.2024, 16:06
Приветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
Меню сайта
Реклама Google
Форма входа
Категории раздела
Это нужно знать! [17]
Изучаем AVR [30]
Программаторы [12]
Необходимое ПО [8]
Готовые устройства [73]
Справочная [38]
Инструмент [0]
Технология [8]
Литература [0]
Arduino скетчи [18]
Поиск
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Микроконтроллеры - это просто!
Главная » Статьи » Изучаем AVR

Порты ввода/вывода
Любая интегральная схема, даже рассматриваемая в качестве черного ящика (black box), немыслима без портов ввода/вывода (ПВВ). Без преувеличения, ПВВ участвуют в абсолютно каждом проекте с использованием микроконтроллеров :

через порты ввода/вывода микроконтроллер получает сигналы (будь то аналоговые или цифровые) от внешних устройств (для их последующей обработки)
управляет или обменивается данными с внешними устройствами
сигнализирует о проделанной работе и т.д.
поэтому понимание работы ПВВ является одним из столпов понимания работы всего микроконтроллера.

1. Структура вывода ("ножка”)
Вывод микроконтроллера, это довольно сложный механизм (регистры + триггеры + мультиплексоры + фильтры + тактирование и т.д.), над которым разработчики изрядно ломают себе голову. За каждым выводом, практически любого AVR микроконтроллера, закреплено по несколько функций, число которых зависит от того, сколько периферийных устройств подключено к данному выводу. Но несмотря на относительно сложную конструкцию, управление выводом (в режиме общего назначения) осуществляется всего лишь через два регистра, плюс еще один регистр для контроля состояния вывода, но об этом чуть дальше.


Рис.1 Цоколевка микроконтроллера ATmega16

Поскольку AVR являются восьмиразрядными микроконтроллерами, то разработчики для удобства пользователей объединили выводы в группы по восемь. Такая группа называется порт (Port). Удобство заключается в том что, для управления восьмиразрядными портами используются такие же восьмиразрядные регистры/переменные, как следствие, минимум кода и максимальное быстродействие.

На рис.1, для примера, показана цоколевка микроконтроллера ATmega16, где закрашенные выводы являются "ресурсными” выводами, через которые микроконтроллер получает напряжение питания (VCC, GND), тактирующий сигнал (XTAL1, XTAL2), сигнал сброса (RESET), а также питание и опорное напряжение для встроенного АЦП (AVCC, AGND, AREF) и некоторых регистров. Этими выводами микроконтроллер не может никак управлять или использовать в различных целях. Их либо используют для подачи "ресурсов", либо вообще не используют. Все остальные выводы, могут быть использованы либо как выводы общего назначения, либо как выводы встроенных периферийных устройств.

Название вывода формируется из инициала слова Port ("P"), после чего идет имя порта (к примеру "B") и порядковый  номер вывода в этом порте (к примеру "0"). В даташите можно встретить такое обозначение : "Pxn”, где "x” это имя порта, а "n” это номер вывода.

Одним из преимуществ микроконтроллеров AVR, является тот факт что, при включении какого-нибудь периферийного устройства или его отдельной функции, выводы соответствующие этому устройству/функции автоматически перенастраиваются под задачи этого устройства. В этой статье мы будем рассматривать работу ПВВ только в режиме общего назначения (запись/чтение двоичных значений). Альтернативные функции каждого вывода будут рассмотрены в статьях посвященных тому или иному периферийному устройству.


Рис.2 Блок-схема вывода (ножки) AVR микроконтроллера

На рис.2 показана упрощенная блок-схема одного вывода. Эту блок-схему можно прочитать так : "любой вывод микроконтроллера может быть настроен как на вход (Input) так и на выход (Output), причем читать состояние пина можно в любой момент, даже когда пин настроен как выход или альтернативная функция (АФ)".

Приведенные на рис.2 диоды D1 и D2, предназначены для защиты вывода от напряжений, превышающих напряжение питания (электростатика (ESD) и т.п.), а емкость Cpin это паразитная емкость вывода.

2. Настройка вывода
Управление, настройка, контроль и другие всевозможные операции с выводами AVR микроконтроллеров осуществляется всего лишь через три регистра :
  • DDRx
  • PORTx
  • PINx
где "x” это имя порта которому принадлежит вывод. Поскольку в состав одного порта входят восемь выводов, то управлять/настраивать/контролировать и т.д. можно восемью выводами одновременно. Каждый n-ый бит этих регистров управляет/настраивает/контролирует и т.д. n-ым выводом данного порта микроконтроллера.

Как уже было сказано, в режиме общего назначения, вывод может либо принимать (читать), либо отпралять (писать) логические уровни (лог. единицу или лог. нуль), поэтому первым делом следует определить направление работы (выход или вход) вывода или всего порта ввода/вывода.

2.1 Настройка вывода на вход/выход

Для настройки направления работы каждого порта или отдельного вывода из этого порта, используется регистр DDR (Data Direction Register). К примеру регистр DDRB предназначен для настрайки выводов порта B на вход или на выход, а отдельно взятый бит этого регистра, соответственно, отвечает за настройку отдельно взятого вывода этого порта. К примеру бит DDB3 отвечает за настройку вывода номер 3 порта B. Регистр DDRx любого порта можно как читать (Read), для того чтобы узнать как настроен тот или иной вывод (бывают и такие ситуации :) ), так и писать (Write), т.е. менять при необходимости направление работы того или иного вывода (или все сразу).

Чтобы определить тот или иной вывод порта "x” как выходной, следует записать в соответствующий бит регистра DDRx – лог. единицу, а чтобы настроить тот или иной вывод порта "x” на вход, следует записать в соответствующий бит регистра DDRx – лог. нуль :

  • DDRxn = "1” – вывод "n” порта "x” настроен на выход
  • DDRxn = "0” – вывод "n” порта "x” настроен на вход
В качестве примера, давайте настроим, скажем, первый и последний выводы порта B как выходы, а все остальные выводы как входы :

DDRB = 0b10000001; // двоичная настройка. Не все IDE поддержива
DDRB = 0x81; // шестнадцатиричная настройка
DDRB = 129; // десятиричная настройка
DDRB = (1<<7) | (1<<0); // побитовая настройка
DDRB = (1<<DDB7) | (1<<DDB0); // побитовая настройка

Все эти примеры делают одно и то же (первый и последний выводы настроены как выходные, все остальные как входные), но выглядит это по разному. DDB7 и DDB0 (определены в заголовочных файлах каждого микроконтроллера) это макросы, представляющие собой имя/номер битов (по даташиту).

Гарантированно что после сброса или подачи напряжения питания, значение (Initial Value) любого DDRx регистра равно 0×00, что означает что по умолчанию весь порт настроен на вход.


Рис.3 Пример регистра направления выводов (порт B)

2.2 Управление состоянием вывода

Регистр PORTx, управляет состоянием выводов порта "x”. В зависимости от выбранного направления работы (вход или выход) порта или отдельно взятого вывода (при помощи регистра DDRx), значение записанное в регистр PORTx того же порта, может присваивать выводу различные сосотяния.


Рис.4 Состояние вывода

На рис.4 показана таблица возможных состояний вывода, в зависимости от значений записанных в соответствующие биты регистров DDxn и PORTxn.  Эта таблица становится более понятной при ее рассмотрении совместно с блок-схемой вывода, приведенной на рис.2.

Когда вывод настроен как выход (DDxn = "1", ключ К1 на рис.2 замкнут), то любое значение записанное в соответствующий бит регистра PORTx, поступает на выход :

  • PORTxn = "1” – состояние вывода соответствует лог. единице (Output High)
  • PORTxn = "0” – состояние вывода соответствует лог. нулю (Output Low)
т.е. состояние вывода (когда он настроен на выход) может изменяться только между лог. единицей и лог. нулем. В этом режиме, резистор Pull-up (Rpu на рис.2) отключен и никак не влияет на состояние вывода (No Pull-up).

Когда вывод настроен как вход (DDxn = "0", ключ К1 на рис.2 разомкнут), то значение записанное в соответствующий бит регистра PORTx, либо подключает подтягивающий резистор Rpu (pull-up resistor) к выводу, либо отключает его. В этом режиме, текущее состояние выводов, можно прочитать при помощи регистра PINx этого же порта.

  • PORTxn = "1” – подключить подтягивающий резистор к выводу
  • PORTxn = "0” – отключить подтягивающий резистор, высокий импеданс (Hi-Z)

Зачем вообще нужен подтягивающий резистр? Дело в том, что когда вывод настроен как вход, то общее сопротивление (импеданс) вывода очень сильно возрастает (гига омы). Это можно сравнить с обрывом вывода (на рис.2 ключ К1 разомкнут, а входное сопротивление триггера Шмитта очень высокое). Это происходит по нескольким причинам. Во первых, как известно, AVR микроконтроллеры построены по КМОП технологии, что подразумевает малое потребление, а также позволяет работать с очень слабыми входными сигналами. Но в тех случаях, когда входной сигнал слабее даже чем окружающее электромагнитное излучение, чтобы "не ловить” различные электромагнитные наводки (превращающие сигнал в кашу), подключается (слабый) подтягивающий резистор (около 100К), который благодаря разность потенциалов с источником сигнала, приводит сигнал к одному из двух значений : лог. единица или лог. нуль. Так что подтягивающий резистор (pull-up resistor) позволяет избежать чтение с входа различных помех, что повышает надежность устройства в целом. Но за эту надежность придется заплатить дополнительным энергопотреблением (макс. около 120 мкА). В тех случаях когда вы уверены в мощности входного сигнала, то подтягивающий резистор подключать нет необходимости, к тому же повышается энергоэффективность.

Гарантированно что после сброса или подачи напряжения питания, значение (Initial Value) любого PORTx регистра равно 0×00, что означает что по умолчанию весь порт будет находится в состоянии высокого импеданса.



Итак, промежуточный итог : для того чтобы управлять выводом нам необходимо настройть регистры DDRx и PORTx.

2.3 Пример управления выводом

Предположим у нас есть схема приведенная на рис.5, где к одному выводу AVR микроконтроллера подключено сразу два СИда, напряжение отпирания которых равно 2.0В. К СИДам подключены токоограничевающие резисторы, тем самым понижая максимальный ток через любой СИД до 10.0мА.


Рис.5 Подключение двух СИДов к одному выводу

Чтобы управлять СИДами настроем вывод как выход :

DDRB = 0x01; // первый вывод делаем выходным

Чтобы зажечь верхний СИД, нам надо подать лог. нуль на вывод, что приведет к тому что 10.0мА протекут через R1, верхний СИД и далее через вывод на землю.

PORTB &=(1<<PB0); // используем маску

Чтобы зажечь нижний СИД, нам надо подать лог. единицу на вывод, что приведет к тому что 10.0мА вытекут из вывода и дальше через резистор R2, нижний СИД уйдут на землю.

PORTB |= (1<<PB0); // включаем нижний СИД

В этом примере, какой бы лог. уровень мы не подадим на выход, один СИД всегда будет гореть, что повышает энергопотребление устройства, к тому же дает нагрузку в 10.0мА на вывод, независимо от того входит ток или выходит. Чтобы избежать ненужных трат и не нагружать вывод, можно перевести вывод в состояние высокого импеданса (Hi-Z), что приведет к тому что сопротивление вывода резко возрастет (нет ни входного ни выходного тока), а также не хватит напряжения для отпирания сразу двух СИДов. В результате, ни один СИД не будет гореть (как минимум так же ярко).

// повышаем импеданс вывода
DDRB &=(1<<DDB0); // переводим вывод на вход
PORTB &=(1<<PB0); // отключаем подтягивающий резистор

Таким образом при помощи одного вывода, можно управлять зразу двумя СИДами.

2.3 Чтение текущего состояния вывода

Для того чтобы прочитать текущее состояние любого вывода или всего порта, используется регистр PINx, где "x” имя порта. Чтение состояния вывода можно производить при любых настройках вывода : будь то вход, выход или альтернативная функция вывода. Также регистр PINx можно только читать (Read only).

unsigned char pin_value; // переменная для хранения состояний выводов
pin_value = PINB; // читаем состояние порта B

После сброса или подачи напряжения питания, значение (Initial Value) любого PINx регистра неопределено, так как порт находится в состоянии высокого импеданса.




3. Запоминалка по настройке выводов

Чтобы каждый раз не заглядывать в даташит, да и не запоминать тупо комбинации для настройки выводов, предлагаю вашему вниманию небольшую шпаргалку. Основное правило шпаргалки заключается в том что, лог. уровни (лог. единица или лог. нуль) могут только скатываться/спускаться с горки (на санках, как шарики/мячики, и т.д. и т.п.), в то время как подниматься в гору они не могут (гора скользкая/крутая и т.д.). Тогда, под это дело нам нужен DDRx регистр (представим его в качестве горки/трапа самолета или т.п.), лог. уровни (представим их в качестве мячиков) и вывод микроконтроллера, который я представляю в качестве двухэтажного дома, у которого вход (регистр PINx) находится на первом этаже, а выход (регистр PORTx) на втором.

Итак поехали.

Основное правило гласит что лог.уровни (мячики) могут только катиться по наклонной. Чтобы настроить порт как вход, а мячики катились по наклонной, надо горку развернуть нижним краем (DDRxn = "0″) к дому, тогда все мячики (лог.уровни) попадут на вход. Таким образом, любые данные (0 or 1) поданные на вход, будут доступны через регистр PINx.



Основное правило гласит что лог.уровни (мячики) могут только катиться по наклонной. Чтобы настроить порт как выход, а мячики катились по наклонной, надо горку развернуть высоким краем (DDRxn = "1″) к дому, тогда все мячики (лог.уровни) выкатятся из дома. Таким образом, любые данные (0 or 1) записанные в регистр PORTx, поступят на выход.



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

Основное правило гласит что лог.уровни (мячики) могут только катиться по наклонной. Чтобы настроить порт как вход с подтягивающим резистором, а мячики катились по наклонной, надо горку развернуть нижним краем (DDRxn = "0″) к дому, но поскольку сигнал слабый, его понадобится подбрасывать (при помощи большой "накаченной” единицы и качелей), чтобы мячики (лог.уровни) могли катиться по наклонной в дом. При этом все помехи отбрасываются в сторону. Таким образом, любые данные (0 or 1) поданные на вход, будут доступны через регистр PINx.



Настройка входа с высоким импедансом (обрыв) у меня ассоциируется с бессмыслицей.

Основное правило гласит что лог. уровни (мячики) могут только катиться по наклонной. Чтобы настроить порт как вход с высоким импедансом (обрыв вывода), гору надо развернуть нижним краем (DDRxn = "0″) к дому, без использования "подтягивающей единицы”. В таком случае все данные поступающие на вход будут блокированы высоким импедансом, а поскольку нет подтягивающего резистора, то к слабому сигналу прибавятся еще и помехи (спрыгивают с самолета). Таким образом, любые данные поданные или наведенные на вход, будут доступны через регистр PINx.



4. Электрическая характеристика вывода

Когда мы настраиваем вывод как выход, то при установке вывода в состояние лог. единицы, напряжение на выводе зависит от тока, который потребляет устройство подключенное к выводу (к примеру нижний СИД из рис.5). Итак на рис.6 приведена зависимости выходного напряжения от потребляемого тока. Если внешнее устройство потребляет 20.0 мА, то выходное напряжение (лог. единица) будет равно 4.5В, что означает что источник подсядит на 0.5В. При потреблении 40.0мА, выходное напряжение подсядит на чуть более одного вольта (красная линия на графике). На графике приведена характеристика и для больших токов, но в большинстве случаев потребление более чем 20 .. 25 мА из одного вывода приводит к повреждению данного вывода. Также максимальный ток который можно выкачать из всех выводов не должен превышать 200.0мА.


Рис.6 Выходное напряжение выода в зависимости от потребляемого тока

Также когда мы настраиваем вывод как выход, то при установке вывода в состояние лог. нуля, напряжение на выводе зависит от тока, который протекает через вывод на землю (к примеру верхний СИД из рис.5). Если через вывод на землю протекает 20.0мА, то напряжение на выводе будет не 0.0В а около 0.5В (красная линия на графике). Если через вывод на землю протекает 40.0мА, то на выводе уже будет около 0.9В, а не идеальные 0.0В. Это происходит из за того что сопротивление между выводом и землей имеет конечное значение (от 20 до 30 ом).


Рис.7 Ток протекающий через вывод на землю

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

Когда вывод настроен как вход, то напряжения ≤ 2.0 В, при напряжении питания в 4.5В будет считаться как лог. нуль (красная линия на графике). Если на вывод подать напряжения ≤ 2.2 В, при напряжении питания в 5.0В, состояние вывода будет считаться как лог. нуль.


Рис.8 Максимальное (пороговое) значение лог. нуля
Когда вывод настроен как вход, то напряжения ≥ 2.4 В, при напряжении питания в 4.5В будет считаться как лог. единица (красная линия на графике). Если на вывод подать напряжения ≥ 2.6 В, при напряжении питания в 5.0В, состояние вывода будет считаться как лог. единица.


Рис.9 Минимальное (пороговое) значение лог. единицы

В КМОП и ТТЛ логике, между лог. единицей (пороговое значение) и лог. нулем (пороговое значение) имеется небольшой интервал, для повышения точности при работе с лог. уровнями. Этот интервал называется гистерезис. В AVR микроконтроллерах (и не только) этот гистерезис зависит от напряжения питяния. Если напряжение питяния равно 5.0В, то гистерезис между лог. единицей (минимальное значение) и лог. нулем (максимальное значение) равно около 0.47В. Если напряжение питания равно 4.5В, то гистерезис между лог. единицей (мин. значение) и лог. нулем (макс. значение) равен около 0.42В (красная линия на графике).


Рис.10 Гистерезис лог. уровней в зависимости от напряжения питания

При подключении подтягивающего резистора, для повышения мощности входящего сигнала, чезер подтягивающий резистор будет протекать некоторый ток. Если на выводе напряжение сигнала равно 4.2В, то через подтягивающий резистор будет протекать 20.0 мкА (красная линия на графике). Если напряжение сигнала находится в пределах 0.0В, то через pull-up резистор будет протекать максимальный ток, около 120мкА.  Если напряжение сигнала равно 5.0В, то никакого тока протекать не будет.


Рис.11 Ток потребляемый подтягивающим резистором (Pull-up resistor)

Если есть вопросы, милости просим в комментарии. Спасибо за внимание. Продолжение следует ..

Категория: Изучаем AVR | Добавил: Alex (28.12.2013)
Просмотров: 8233 | Рейтинг: 5.0/2
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Copyright MyCorp © 2024