Порты ввода-вывода микроконтроллера

Порты ввода – вывода микроконтроллера

Устройство микроконтроллера:
– назначение, устройство и программирование портов ввода-вывода микроконтроллера

Доброго дня уважаемые радиолюбители!
Приветствую вас на сайте “Радиолюбитель

Ну вот, уважаемые радиолюбители, сегодня этой статьей я закончу загрузку ваших (и своих) мозгов чистой теорией. Дальше будет легче и приятней: теорию совместим с практикой.
Ну а сегодня мы рассмотрим очень важный и интересный вопрос – порты ввода/вывода микроконтроллера.

Порты ввода/вывода микроконтроллера AVR

Порты ввода/вывода (далее я буду писать сокращенно – ПВВ) – предназначены для общения микроконтроллера с внешними устройствами. С их помощью мы передаем информацию другим устройствам и принимаем информацию от них. В зависимости от типа, микроконтроллер может иметь на своем борту от одного до семи ПВВ. Каждому порту ввода/вывода присвоено буквенное обозначение – A, B, C, D, E, F, G. Все порты в микроконтроллере равнозначные, восьмиразрядные (содержат восемь линий, они же выводы, они же разряды, они же биты) и двунаправленные – могут как передавать, так и принимать информацию. ПВВ в микроконтроллере обслуживают все его устройства, в том числе и периферийные. Поэтому, в зависимости от того какое устройство будет работать с портом он может принимать и передавать или цифровую информацию, или аналоговую.

Вообще, порты классифицируются по типу сигнала:
цифровые порты – которые работают с цифровыми сигналами – логическими “нулями” и логическими “единицами”
- аналоговые порты – которые работают с аналоговыми сигналами – использующими плавно весь диапазон входных напряжений от нуля вольт до напряжения питания МК
- смешанные порты – они и используются в наших МК, могут оперативно переключаться с режима “цифровой порт” в режим “аналоговый порт”, и обратно.

В технической литературе и схемам ПВВ обозначаются следующим образом:
– “Р” – первая буква, означающая слово “порт”
– “А” (В, С, D, E, F, G) – вторая буква, обозначающая конкретный порт
– “0” (1, 2, 3, 4, 5, 6, 7) – третий символ – цифра, обозначающая конкретный вывод (регистр, бит) порта.
К примеру: “порт А” – РА, “пятый разряд порта А” – РА5.
Если в МК есть несколько портов, то не обязательно их имена могут идти по порядку – A, B, C. Может быть и так – В, С, D. Поэтому пугаться и судорожно искать где же порт А не надо.
Кроме того, хотя порты восьмиразрядные, выводов у порта не обязательно должно быть 8, может быть и меньше, к примеру 3 – PA0, PA1, PA2. В таком случае порт называют неполным, или урезанным.
Давайте посмотрим на конкретный МК – ATmega8:

Порты ввода-вывода микроконтроллера
Как видите, в этом МК порта с именем “А” нет (отсутствует как класс ;). Порт РВ и порт PD – полные, имеют по восемь выводов. А порт С – неполный (ущемленный, нет места в корпусе МК для его вывода), в нем отсутствует восьмой разряд (реально, внутри корпуса МК, он есть, но работать мы с ним не можем).

Для управления портами в их электрической схеме имеется два переключателя, которыми мы можем “щелкать” программно, используя специальные регистры ввода/вывода. Такие переключатели имеются для каждого вывода, что означает возможность управлять любым выводом порта. К примеру,  один вывод порта можно настроить на ввод информации, три разряда этого же порта на вывод, а оставшиеся вообще не настраивать, оставить их в “Z- состоянии” .
Давайте разберемся с этим вопросом конкретней, на примере вот этой схемы:

Структурная схема порта ввода-вывода

Обратите внимание на два переключателя – Sin и Sout, и сопротивление Rup.
С помощью Sin осуществляется переключение вывода порта или для работы на вход, или для работы на выход. Управляется этот переключатель с помощью регистра ввода/вывода DDRx. У каждого порта свой регистр. Каждый разряд регистра управляет соответствующим разрядом порта (нулевой – нулевым, первый – первым и т.д.). Символ “x” в названии порта заменяется соответствующим именем порта: для порта А – DDRA, для порта С – DDRC. При записи в разряд регистра DDRx “единицы”, соответствующий ему разряд порта переключается на вывод информации, а при записи “нуля” – на ввод информации. Просмотрите рисунки ниже, и вы поймете как работать с регистром DDRx.

1. Переключение всех выводов порта на вывод информации:

5
2. Переключение всех выводов порта на ввод информации:

10
3. Переключение части выводов порта на ввод, и части на вывод информации:

15

В “классическом” Ассемблере настройка выводов портов на ввод и вывод информации выглядит так (просто пример 3-го рисунка):

Idi    R20, 0b01100010 - этой командой мы записываем в РОН R20 двоичное число 01100010, которым определяем – какой вывод порта будет работать на вывод (1), а какой на ввод (0) информации. В данном случаем разряды порта В 1,5,6 – настраиваются на вывод информации, а 0,2,3,4,7 – на ввод информации
Out   DDRB, R20 - этой командой мы переносим содержимое РОН R20 в регистр ввода/вывода порта В.

В Algorithm Builder запись немного отличается:
#b01100010 –> DDRB
Дело в том, что Algorithm Builder несколько более смещен к языкам высокого уровня, поэтому мы просто прописываем “свое желание” одной строчкой, но а при компилировании (переводе в машинные коды), программа сама преобразует эту строчку как и в “классической” записи.

Второй переключатель – Sout. Этот переключатель имеет двойное назначение, в зависимости от настройки разрядов порта на вывод или ввод информации.
Если разряд порта настроен на вывод информации, то с его помощью мы устанавливаем на выходе разряда или логическую “1”, или логический “0”.
Если разряд порта настроен на ввод информации
, то с его помощью подключается так называемый “подтягивающий резистор” – Rup, или “внутренний нагрузочный резистор”
. Благодаря этому резистору упрощается подключение внешних кнопок и переключателей, т.к. обычно контакты требуют внешнего резистора.
Как и переключатель Sin, Sout – это регистр ввода/вывода под названием PORTx, где “х” – буквенное обозначение порта (к примеру для порта D регистр будет иметь вид – PORTD).
В семейств МК Mega имеется дополнительный переключатель – PUD, - 2-й разряд регистра ввода/вывода SFIOR (он называется “Регистр специальных функций”). С помощью этого PUD осуществляется общее управление подтягивающими резисторами:
- при записи в этот разряд “1” – все подтягивающие резисторы для всех портов отключаются;
– при записи в этот разряд “0” – состояние подтягивающих резисторов определяется регистром PORTx.
Зачем нужно общее отключение резисторов, да и этот PUD заодно, мы сегодня рассматривать не будем.
В режиме работы разрядов порта на вывод, задача регистра PORTx очень проста – то, что мы в него запишем, то и будет на выходе. Запишем одни “нули” – на выходах буду логические нули, запишем “единицы” – на выходе буду логические “единицы”.
Например:
Настраиваем порт В на вывод информации:
Idi    R20, 0b11111111
Out   DDRB, R20
Выводим в разряды 0-3 логический ноль, а в разряды 4-7 логическую единицу:
Idi    R20, 0b11110000
Out   PORTB, R20
В Algorithm Builder:
#b11111111 –> DDRB
#b11110000 –> PORTB
Надеюсь, что пока все понятно.
Вышеприведенные примеры позволяют настроить весь порт сразу, и вывести нужные значения на все выводы порта за один раз.
Если необходимо настроить только один разряд порта на ввод или вывод, а также вывести “0” или “1” только в один разряд порта, не затрагивая состояние и содержание других разрядов этого порта, существуют следующие команды:
SBI A,b – установить разряд регистра
CBI A,b – сбросить разряд регистра
При этом: “А” – номер регистра, “b” – разряд этого регистра.
Данные команды работают не только с РВВ DDRx и PORTx, но и с теми, которые имеют номера от 0 до 31.

Установить разряд РВВСброс разряда РВВ

Пример:
- “классический” Ассемблер:
Настраиваем порт В на вывод информации:
Idi R20, 0b11111111
Out DDRB, R20
Нам нужно переключить 1-й разряд порта на ввод информации:
CBI $17, 1 (где $17 – номер РВВ порта В – DDRB, 1 – разряд порта В)
- Algorithm Builder:
#b11111111 –> DDRB
0 –> PORTB.1

У портов ввода/вывода есть еще один регистр: PINx, регистр выводов порта (“х” – буквенное обозначение порта)
Этот регистр предназначен для считывания информации с вывода порта, независимо в какой он конфигурации – на ввод, или на вывод. Записать в этот регистр мы ничего не можем, он предназначен только для считывания. 

Состояние выводов портов в зависимости от их конфигурации:

Конфигурация выводов портов * PUD нет в МК Tiny и в МК модели ATMega161

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

Некоторые рекомендации по использованию портов ввода/вывода:

При сбросе или включении питания микроконтроллера все выводы всех портов (за очень-очень редким случаем) переводятся в высокоимпедансное состояние – “Z- состояние”. Этот момент следует учитывать в реальных схемах. Если нагрузкой выхода служит транзисторный ключ, то для того, чтобы его база (затвор полевого транзистора) не болтались в воздухе, необходимо ставить дополнительные внешние резисторы сопротивлением 10-100 кОм.

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

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

Подтягивающие резисторы не совсем “резисторы” – их роль выполняют полевые транзисторы, которые имеют большой технологический разброс – номинал подтягивающего сопротивления может колебаться в пределах 30-100 кОм. При мощных помехах, да и в других “критических случаях” рекомендуется (хотя такой рекомендации и нет в даташитах) подключать дополнительные подтягивающие резисторы номиналом 2-5 кОм. Такие резисторы следует устанавливать на вывод “Reset”, на выводы внешних прерываний, если они не используются. Также следует устанавливать резисторы при работе выводов МК на общую шину (I2C, или просто при подсоединении выхода МК к выходу другого устройства с открытым коллектором, при подключении к двухвыводным кнопкам). Сопротивление встроенного резистора в таких случаях слишком велико, чтобы отсеивать электромагнитные помехи.


Создаем программу «мигалку»

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

Для этого нам понадобится среда AVRStudio (о которой упоминалось раньше) и середа для симуляции микроконтроллера – Proteus 7. В сети маса примеров по установке этих программ, так что на этом останавливаться не будем.

Первая наша программа будет состоять из:

Подключения файла директив, инициализации МК;

Настройки портов ввода-вывода МК;

Простейшего цикла переключения портов из логического состояния «0» в «1»;

Подпрограммы простой задержки с использованием регистров общего назначения.

При штатной установке программы AVR Studio, файлы с директивами микроконтроллера располагается по следующему адресу C:\Program Files\Atmel\AVR Tools\AvrAssembler\Appnotes.

В нашем примере будем использовать микроконтроллер Attiny2313. Его inc файл имеет название 2313def.

Для начала откроем программу AVR Studio 4 и создадим проект.

Нажимаем на клавишу создания нового проекта.

1

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

2

В последнем окне необходимо выбрать симулятор и тип нашего МК. Далее, нажимаем на клавишу «finish» и можно будет увидеть, как откроется новое окно нашего проекта.

3

4

Наш проект уже создан и его можно наполнять программным кодом. Как говорилось раньше, первым делом нужно подключить файл директив данного микроконтроллера. Если возникнет необходимость проводить симуляцию проекта в среде AVR Studio 4, то желательно указать еще и имя нашего МК. Для этого нужно прописать следующую строку «.device ATtiny2313».

Для подключения inc файла, нужно прописать .include “tn2313def.inc”. Тем самым мы разрешим компилятору использовать файл директив данного МК.

Этот файл существенно упрощает задачу программирования, так как мы можем придерживаться определенных стандартов и обращаться к разным адресам МК словами, а не цифрами.

К примеру, на следующем рисунке обозначена строка значения ОЗУ нашего МК. В программе мы пишем «spl», хотя можно написать и« $3d».

5

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

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

Итак, на Листинге 1 приведу пример нашей простой программы.

Листинг 1.

.device Attiny2313 ; указываем тип устройства

.include “tn2313def.inc” ; подключаем файл директив МК ATtiny2313

.def temp = r16 ; задаем имя нашему регистру общего назначения

.org 0x0000 ; начало программы с 0 адреса

ldi temp,ramend ; грузим значение ramend в регистр temp

out $3d, temp ;

ser temp ; настраиваем все выводы порта В на выход

out DDRB, temp ;

main:

sbi portb,5; устанавливаем логическую «1» в PORTB5

rjmp main

Итак, разберем все по строкам, что мы сделали.

Первым делом, на всякий случай указали тип устройства .device Attiny2313.

Подключили файл директив .include “tn2313def.inc”.

Для простоты написания программы задали регистру R16 имя .def temp = r16. Такая операция хорошо будет упрощать написание программы в дальнейшем. Ведь словесное название регистра нам проще запомнить, нежели просто писать R16. Таким образом, можно присвоить имя любому регистру начинаю от R0 и заканчивая R31.

Командой ser temp мы грузим в регистр temp значение 255 и выгружаем его в out DDRB. Тем самым конфигурируем порт на выход. В дальнейшем, при симуляции программы в Proteus 7, мы увидем как данные порты приймут состояние логического нуля.

Устанавливаем на порте вывода PB5 логическую единицу с помощью команды sbi portb,5.

В самом конце необходимо организовать какой-то цикл, чтобы микроконтроллер не завис.

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

6

Открываем среду моделирования Proteus 7 и смотрим результат.

7

Теперь немного усложним задачу и заставим порт вывода переключаться с логического нуля в единицу. Для этого нам необходимо немного доработать нашу программу, Листинг 2. Все изменения происходит только в цикле «main», так что весь код не будем повторять.

main:

sbi portb,5; устанавливаем логическую “1” в PORTB5

cbi portb,5; устанавливаем логический “0” в PORTB5

rjmp main

Смотрим результат моделирования в среде Proteus 7, пподключив к выводу PB5 осциллограф.

8

Как видно, сигнал на выходе порта появился. Однако частота переключения близка к частоте микроконтроллера.

Чтобы понизить скорость переключения, нам необходимо воспользоваться простой задержкой. На Листинге 3 показан простой пример реализации задержки.

Листинг 3.

main:

sbi portb,5; устанавливаем логическую “1” в PORTB5

rcall delay ;вызываем подпрограмму задержки

cbi portb,5; устанавливаем логический “0” в PORTB5

rcall delay

rjmp main

delay:

clr r20; очистить регистры

clr r21

d_1:

inc r20; добавить 1

cpi r20,200 ; сравниваем, R20 = 200 ?

brne d_1; если не равно, то переходим по метке d_1, иначе пропускаем

d_2:

inc r21

cpi r21,50 ;

brne d_1

ret

После выполнения данной программы скорость переключения порта снизилась до 100мс. Задавая значения сравнения в регистры R20 и R21 можно регулировать этот интервал. На следующем рисунке видим результат работы программы.

9

На этом закончим. В следующей части мы разберем примеры программы с подключением кнопок, напишем цикл бегущей строки.

Предыдущие статьи:

 Микроконтроллер и как его победить
 Микроконтроллер и системы счисления
 Микроконтроллер и логические операции
 Общее устройство микроконтроллера
 Арифметико-логическое устройство и организация памяти – память программ, память данных, энергонезависимая память
 Регистры общего назначения, регистры ввода/вывода, стек, счетчик команд
 Регистр состояния SREG




Комментарии

Порты ввода-вывода микроконтроллера — 5 комментариев

  1. Огромное спасибо за статьи! Всё супер понятно и имтересно.
    А продолжение есть? Или я просто не могу его найти.

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *


Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>