Для взаимодействия с окружающим миром нужно настроить выводы микроконтроллера на приём или передачу сигнала. В результате каждый пин будет работать в режиме входа и выхода. На всеми любимой плате 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 мкс. Этот способ управления был найден на просторах сети и часто встречается в коде готовых проектов .
Смотрите также:
Информация, опубликованная на данном веб-сайте, представлена исключительно в ознакомительных целях, за применение этой информации администрация сайта ответственности не несет.