Способы чтения и управления портами ввода-вывода Arduino

Для взаимодействия с окружающим миром нужно настроить выводы микроконтроллера на приём или передачу сигнала. В результате каждый пин будет работать в режиме входа и выхода. На всеми любимой плате Arduino сделать это можно двумя способами, как именно вы узнаете из этой статьи.

Способ первый – стандартный язык для Arduino IDE

Всем известно, что Ардуино программируется на C++ с некоторой адаптацией и упрощениями для новичков. Он называется Wiring. Изначально все порты ардуино определяются как входы, и нет нужды задавать это в коде.

Порты обычно прописываются в функции инициализации переменных:

void setup ()
{
// код
}

Для этого используется команда pinMode, у неё достаточно простой синтаксис, сначала указывается номер порта, затем его роль через запятую.

pinMode (nomer_porta, naznachenie)

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

Есть три режима в которых может работать порт: INPUT – вход, в этом режиме происходит считывание данных с датчиков , состояния кнопок, аналогового и цифрового сигнала. Порт находится в т.н. высокоимпедансном состоянии, простыми словами – у входа высокое сопротивление. Устанавливается это значение, на примере 13 пина платы, при необходимости так:

pinMode (13, INPUT);

OUTPUT – выход, в зависимости от команды прописанной в коде порт принимает значение единицы или нуля. Выход становится своего рода управляемым источником питания и выдаёт максимальный ток (в нашем случае 20 мА и 40 мА в пике) в нагрузку к нему подключенную. Чтобы назначить порт как выход на Arduino нужно ввести:

pinMode (13, OUTPUT);

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

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

pinMode (13, INPUT_PULLUP);

Данные принимаются с портов и передают на них командами:

  • digitalWrite(пин, значение) – переводит выходной пин в логическую 1 или 0, соответственно на выходе появляется или исчезает напряжение 5В, например digitalWrite (13, HIGH) – подаёт 5 вольт (логическую единицу) на 13 пин, а digitalWrite (13, low) – переводит 13 пин в состояние логического ноля (0 вольт);

  • digitalRead(пин) – считывает значение со входа, пример digitalRead (10), считывает сигнал с 10 пина;

  • analogRead(пин) – считывает аналоговый сигнал с аналогового порта, вы получаете значение в диапазоне от 0 до 1023 (в пределах 10-битного АЦП), пример analogRead (3).

Способ два – управление портами через регистры Atmega и ускорение работы кода

Такое управление конечно простое, но в этом случае есть два недостатка – большее потребление памяти и низкое быстродействие при работе с портами. Но вспомните что такое Arduino независимо от варианта платы (uno, micro, nano)? В первую очередь, это микроконтроллер AVR семейства ATMEGA , в последнее время используется МК atmega328.

В Arduino IDE вы можете программировать на родном для этого семейства языке C AVR, так, как если бы вы работали с отдельным микроконтроллером. Но обо всем по порядку. Чтобы управлять портами Ардуино таким образом вам нужно сначала внимательно рассмотреть следующую иллюстрацию.

Возможно кому-то будет нагляднее изучать порты в таком виде (на рисунке тоже самое, но в другом оформлении):

Здесь вы видите соответствие выводов Ардуино и названий портов атмеги. Итак, у нас есть 3 порта:

  • PORTB;

  • PORTC;

  • PORTD.

Исходя из изображенного на рисунках, я составил таблицу соответствия портов Ардуино и Атмеги, она пригодится вам в дальнейшем.

У Atmega есть три регистра длиной в 8 бит, которые управляют состоянием портов, например, порта B разберемся в их назначении проведя аналогии со стандартными средствами wiring описанными в начале статьи:

  • PORTB – Управление состоянием вывода. Если пин находится в режиме «Выхода», то 1 и 0 определяют наличие этих же сигналов на выходе. Если же пин находится в режиме «Входа», то 1 подключает подтягивающий резистор (тоже что и INPUT_PULLUP рассмотренный выше), если 0 – высокоимпедансное состояние (аналог INPUT);

  • PINB – регистр чтения. Соответственно в нём находится информация о текущем состоянии выводов порта (логическая единица или ноль).

  • DDRB – регистр направления порта. С его помощью вы указываете микроконтроллеру чем является порт – входом или выходом, при этом «1» — выход, а «0» — вход.

Вместо буквы «В» может быть любая другая согласно названиям портов, например, PORTD или PORTC аналогично работают и другие команды.

Научитесь разрабатывать устройства на базе микроконтроллеров и станьте инженером умных устройств с нуля: Инженер умных устройств

Помигаем светодиодом, заменим стандартную функцию digitalWrite(). Для начала вспомним как выглядит исходный пример из библиотеки Arduino IDE.

Это код всем известного «blink», который демонстрирует мигание светодиодом, встроенным в плату.

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

Команда PORTB B00100000 переводит PB5 в состояние логической единицы, смотрим, а те картинки и таблицу что расположены ниже и видим, что PB5 соответствует 13 пину Ардуины.

Буква «В» перед цифрами говорит о том, что мы в записываем значения в двоичном виде. Нумерация в двоичном коде идёт справа налево, т.е. здесь единица стоит в шестом с правого края бите, что говорит микроконтроллеру о взаимодействии с состоянием шестого бита регистра порта B (PB5). В таблице ниже изображена структура порта D, она аналогична и приведена для примера.

Вы можете задавать значение не в двоичном, а в шестнадцатеричном виде, например, для этого открываем калькулятор windows и в режиме «ВИД», выбираем вариант «Программист».

Вводим желаемое число:

И нажимаем на HEX:

В таком случае переносим это всё в Arduino IDE, но уже вместо приставки «В» будет «0х».

Но при таком вводе возникает проблема. Если у вас к другим пинам подключено что-либо, то внося команду типа B00010000 – вы все выводы кроме 13 (PB5) обнулите. Вы можете вносить данные на каждый пин по отдельности. Это будет выглядеть следующим образом:

Такая запись может показаться непонятной, давайте разберемся.

Это операция логического сложения, |= значит прибавить к содержимому порту что-либо.

А это значит, что нужно сложить слово из 8 бит в регистре с единицей, смещенной на 5 бит – в результате, если было 11000010 получается 11010010. На этом примере видно, что изменился только PB5, остальные биты этого регистра остались без изменений, как и остались неизменными состояния выводов микроконтроллера.

Но при логическом сложении возникает проблема – вы не можете превратить единицу в ноль, потому что:

0+0=1

1+0=1

0+1=1

Нам на помощь придёт логическое умножение и инвертирование:

&= значит умножить содержимое порта на определенное число.

А это число, на которое мы умножает. Знак «~» обозначает инвертирование. В нашем случае проинвертированная единица является нулем. То есть мы умножаем содержимое порта на ноль, сдвинутый на 5 бит. Например, было 10110001, стало 10100001. Остальные биты остались без изменений.

Тоже самое можно сделать с помощью операции инвертирования (^):

Чтение с портов, аналог digitalRead() выполняют с помощью регистра PIN, на практике это выглядит так:

Здесь мы проверяем равно ли выражение в скобках реальному состоянию портов, т.е. аналогично тому, если бы мы написали if (digitalRead(12) == 1).

Пошаговое обучение программированию и созданию устройств на микроконтроллерах AVR: Программирование микроконтроллеров для начинающих

Заключение

Для чего такие сложности с управлением портами, если можно использовать стандартные удобные функции? Всё дело в быстродействии и размерах кода. При использовании второго способа, рассмотренного в статье размер кода, значительно снижается, а быстродействие увеличивается на несколько порядков. Стандартный digitalWrite() выполнялся за 1800 мкс, а запись прямо в порт за 0,2 мкс, а digitalRead() за 1900 мкс, а стал также за 0,2 мкс. Этот способ управления был найден на просторах сети и часто встречается в коде готовых проектов .

Смотрите также:

7 учебных курсов по работе с Ардуино, онлайн обучение проектированию и конструированию электронной аппаратуры

Информация, опубликованная на данном веб-сайте, представлена исключительно в ознакомительных целях, за применение этой информации администрация сайта ответственности не несет.

admin

Share
Published by
admin

Recent Posts

Консоль удаленного рабочего стола(rdp console)

Клиент удаленного рабочего стола (rdp) предоставляет нам возможность войти на сервер терминалов через консоль. Что…

1 месяц ago

Настройка сети в VMware Workstation

В VMware Workstation есть несколько способов настройки сети гостевой машины: 1) Bridged networking 2) Network…

1 месяц ago

Логи брандмауэра Windows

Встроенный брандмауэр Windows может не только остановить нежелательный трафик на вашем пороге, но и может…

1 месяц ago

Правильный способ отключения IPv6

Вопреки распространенному мнению, отключить IPv6 в Windows Vista и Server 2008 это не просто снять…

1 месяц ago

Ключи реестра Windows, отвечающие за параметры экранной заставки

Параметры экранной заставки для текущего пользователя можно править из системного реестра, для чего: Запустите редактор…

1 месяц ago

Как управлять журналами событий из командной строки

В этой статье расскажу про возможность просмотра журналов событий из командной строки. Эти возможности можно…

1 месяц ago