Освой Arduino играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Мигаем светодиодом на любом выводе
Принимаем сигнал из цифрового вывода
02.Digital: BlinkWithoutDelay (Мигаем светодиодом без delay())
Режим INPUT
В прошлом уроке мы использовали вывод под номером 13. Познакомимся с другими портами и как можно их использовать.
У каждой платы Arduino есть свой набор выводов, которые также могут называться порты, выходы, пины (pin). В большинстве случаев рассматривается плата Arduino UNO. Набравшись опыта, вам не составит труда разобраться с другими платами.
Хорошенько осмотрите плату. По краям платы вы увидите колодки, в которые можно вставлять провода. Они все подписаны. С одной стороны идут цифровые выводы от 0 до 13 и GND, с другой стороны аналоговые выводы от A0 до A5 и GND (2 шт.), 5V, 3.3V. Запомните их расположение, оставшиеся выводы используются гораздо реже, особенно на начальном этапе. Подробнее о плате есть в отдельной статье.
Обратите внимание, что аналоговые выводы на самом деле являются цифровыми и их можно использовать в таком качестве, если вам не хватило стандартных выводов от 0 до 13. Поэтому аналоговые выводы можно представлять как 14, 15, 16, 17, 18, 19 вместо A0, A1, A2, A3, A4, A5. Может пригодиться при создании массива пинов, так проще перечислять все пины от 0 до 19. Но это происходит достаточно редко, вам должно хватить уже существующих выводов.
Аналоговые и цифровые выводы могут принимать цифровой сигнал. Цифровым сигналом называют последовательность нулей и единиц от скачков напряжения от 0 до 5 вольт. Вдобавок, аналоговые выводы могут принимать аналоговые сигналы - диапазон плавно изменяющего напряжения от 0 до 5 вольт с маленьким шагом.
Датчики могут быть тоже цифровыми и аналоговыми и подключаться к соответствующим выводам. Как минимум, у датчиков есть три провода: один ведёт к питанию, второй к земле, по третьему передаются данные.
Можно программно управлять цифровыми выводами - подавать ток и не подавать ток. А также можно считывать информацию - подаётся ли ток или нет. Чтобы проверить эти утверждения, необходимо создать замкнутую цепь. Но есть одна проблема - мы не можем увидеть проходящий ток. Поэтому для наглядности будем добавлять в цепь светодиод. Если ток в цепи есть, то светодиод будет светиться. Удобно. А также мы будем использовать Serial Monitor (о нём позже), чтобы выводить информацию на экран.
Старайтесь не использовать выводы 0 и 1. Они используются для приёма и передачи данных по USB, если в вашем проекте появится такая необходимость, а вы уже припаяли провода, то будут лишние проблемы и трата времени. Выводы 2 и 3 используются в прерываниях. Конечно, в простых проектах это не принципиально, но лучше сразу привыкнуть к правильному порядку. Таблица приоритетов может выглядеть следующим образом: D4, D7, D8...D5, D6, D9, D10...D2, D3...D11, D12, D13, D0, D1.
Прежде чем мы двинемся дальше, следует познакомиться ещё с одним важным инструментом - макетная плата. Для сложных схем требуется больше места. В таких случаях соединяют отдельные компоненты схемы с помощью проводов. Для лучшего соединения провода желательно использовать пайку. Но для новичка это сложно, да и муторно. Ведь если схема сложная и мы где-то сделали ошибку, то придётся все заново отпаивать и припаивать.
Специально для этих целей была придумана макетная плата Breadboard. Когда я впервые взял её в руки, то растерялся. Интуитивно-понятным интерфейсом здесь и не пахло. Множество дырочек, красные и синие полосочки, буковки, циферки... Радиолюбители на форумах говорят, что это примитивная штука, не требующая объяснений. Но, когда впервые сталкиваешься с таким предметом, то так не думаешь.
Итак, плата Breadboard позволяет обойтись без пайки и собрать схему для испытаний. Внутри макетной платы проложены проводочки хитрым образом, что позволяет вам собирать довольно сложные конструкции.
На моей доске доступно 830 контактов. Четыре рельсы по бокам предназначены для подключения питания и земли. Между ними — 126 групп соединённых между собой контактов. У вас могут быть платы другого размера, но общая идея остаётся прежней.
Давайте соберём нашу первую схему на макетной плате. Нам понадобятся плата Arduino, Breadboard, светодиод, резистор и перемычки (или провода). Начнём с Breadboard. Вставляем в него светодиод следующим образом - длинную ножку вставляем в один из выводов, например, A5, а короткую ножку в отверстие синей рельсы, т.е. минус.
Берём резистор и вставляем его следующим образом (напоминаю, что у резистора порядок выводов не важен) - одну ножку вставляем в одно из свободных отверстий, которое находится на одной линии с занятым светодиодом отверстием. Вторую ножку втыкаем в любое отверстие красной рельсы (плюс). Наша схема готова.
Далее необходимо соединить Breadboard с платой Arduino. Располагаем их рядышком и соединяем их с помощью перемычек. Первая перемычка вставляется так - на Breadboard ножка перемычки вставляется в свободное отверстие красной рельсы, а вторая ножка втыкается на Arduino в порт вывода с меткой 5V. Вторую перемычку ставим так - первая ножка вставляется на Breadboard в отверстие синей рельсы, а вторая ножка вставляется на Arduino в порт вывода с меткой GND (на плате несколько меток GND, подойдёт любой).
Подключаем плату к компьютеру. Если все сделано правильно, то светодиод должен загореться. Ура, получилось!
Посмотрим, что мы сделали. Мы последовательно соединили светодиод с резистором к источнику питания на 5 Вольт. По этой схеме ток течёт из вывода с меткой 5V, далее проходит через резистор, потом через светодиод и попадает в вывод с меткой GND.
Предположим, мы хотим поделиться описанием собранной схемы со своими друзьями, чтобы они сами собрали такую же штуку. Например, можно сделать фото и переслать его через электронную почту. Но радиолюбители пользуются в подобных случаях специальными схемами. И нам необходимо научиться рисовать и читать подобные схемы, чтобы собирать более сложные конструкции.
Каждый электронный компонент имеет свой графический символ. Например, для резистора используется следующий символ (используется в США, в России и Европе используется другой символ):
Как видите, символ резистора симметричен, как и сам компонент.
Светодиод обозначается символом:
Положительный вывод находится слева, а отрицательный справа. Кроме того, у символа имеются две маленькие стрелки, которые показывают, что это не просто диод, а светодиод.
Плюс (слева) и минус (справа) питания также имеют символы:
Попробуем соединить все описанные детали вместе, чтобы изобразить нашу цепь.
Дополним схему информацией об используемом резисторе, цвете светодиода, напряжении, и получим схему, которую можно отдать другу.
Мы создали примитивную схему, которой нельзя управлять. Ток течёт через резистор и светодиод, минуя порты ввода/вывода.
Изменим схему следующим образом. Сейчас у нас резистор соединяется с выводом 5V. Давайте соединим его теперь с выводом 13. Вытащим ножку резистора из вывода 5V и вставим его в отверстие на Breadboard таким образом, чтобы оно находилось на одной линии с другой ножкой резистора. Далее соединяем перемычкой вывод 13 на Arduino и соседнее отверстие рядом с ножкой резистора. Светодиод оставляем на месте.
На схеме это будет выглядеть следующим образом.
Откройте предыдущую программу с миганием встроенного светодиода и запустите её. У вас теперь будут мигать два светодиода одновременно - встроенный и наш, так как они оба использует выход 13.
Для закрепления материала перебросим перемычку на вывод с меткой 12. Схема теперь выглядит так:
Стандартный пример Blink уже не будет работать, так как использует вывод 13. Следует переписать скетч для мигания своим светодиодом на своём выводе.
int ledPin = 12;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPIn, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(ledPin, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Рассмотрим урок BlinkWithoutDelay из меню File | Examples | 02.Digital.
В самом простом примере с миганием светодиода мы использовали функцию delay(). У данного способа есть большой недостаток, проявляемый в сложных проектах - во время вызова функции программа "замораживается" и не может выполнять других действий. В реальных задачах часто требуется, чтобы программа не только мигала светодиодом, но и выполняла другую работу в это же время. Решим проблему можно хитрым образом - программа будет запоминать время, когда был включён или выключен светодиод и в каждом цикле loop() будет проверять, не прошло ли достаточно времени для переключения светодиода.
В коде используется функция millis(), возвращающая количество миллисекунд с момента начала работы текущей программы.
Для демонстрации нужен светодиод с резистором и кнопка.
const int ledPin = LED_BUILTIN;// встроенный вывод 13
int ledState = LOW; // состояние светодиода
// Используйте тип "unsigned long" для переменных, работающих со временем
// Так как значение очень быстро становится слишком большим для типа int
unsigned long previousMillis = 0; // храним время последнего переключения светодиода
const long interval = 1000; // интервал между миганиями (миллисекунды)
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
// проверяем не прошёл ли нужный интервал
// вычисляется разница между текущим временем и временем последнего мигания.
// если разница больше, то
if (currentMillis - previousMillis >= interval) {
// сохраняем время последнего переключения
previousMillis = currentMillis;
// если светодиод не горит, то включаем его, и наоборот
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
// устанавливаем состояние светодиода
digitalWrite(ledPin, ledState);
}
}
В примерах с миганием светодиодов мы устанавливали режим OUTPUT. По умолчанию, все выводы имеют режим INPUT и можно не указывать этот режим.
pinMode(ledPin, OUTPUT);
Но лучше контролировать данный процесс и явно прописывать, чтобы всегда видеть перед глазами код и понимать происходящее. С режимом ввода связан один интересный и важный момент. Воспроизведём следующую ситуацию. Подключим светодиод к выводу 13 (для наглядности, чтобы не всматриваться в встроенный маленький светодиод) и установим для вывода 7 режим ввода. Провод соединим между выводом 7 и 5V.
int testPin = 7;
void setup()
{
pinMode(testPin, INPUT);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
bool val = digitalRead(testPin);
digitalWrite(LED_BUILTIN, val);
}
Светодиод будет светиться, если на выводе 7 есть ток, иначе светиться не будет. Мы следим за выводом 7, считывая показания через digitalRead(). Соединив второй конец провода от вывода 7 с выводом 5V, мы замыкаем цепь - ток течёт, функция получает значение логической единицы (true) и светодиод светится.
Вытаскиваем провод из вывода 5V и вставляем в вывод GND - ток не течёт, функция получает значение логического ноля и светодиод не светится.
В обоих случаях мы получаем логическую единицу или логический ноль, т.е. true или false.
Казалось, всё очевидно и понятно. Но сделаем одну вещь - вытащим провод из вывода GND и оставим его болтаться в воздухе. Теперь попробуйте взять провод в руки или просто проведите рукой над проводом - вы увидите, что иногда светодиод начинает светиться. Чудо! На самом деле всё просто - вход 7 находится в «никаком» состоянии. Он может срабатывать и не срабатывать хаотично, непредсказуемым образом, а причиной являются шумы, образующиеся вокруг: провода действуют как маленькие антенны и производят электричество из электромагнитных волн среды. На состояние могут действовать самые разные наводки - датчики, рука, другие устройства, провода и т.д.
Запомните это состояние, когда провод болтается в воздухе и мы получаем случайные данные. Данная ситуация нам встретится при работе с кнопками, где это будет проблемой, с которой нужно бороться.
В теории считается, что за логическую единицу принимается 5В, а за логический ноль - 0В. Но на самом деле это не так. Значения от 2.6В платой уже воспринимается как логическая единица. А логический ноль наступает при значении 2.1В и ниже. У нас возникает диапазон от 2.1 до 2.6, который является неопределённым и плата не может гарантированно опознать эти значения и может считать их в случайном порядке как единицу и как ноль. Именно это и произошло в нашем примере с висящим проводом. Причиной является делитель напряжение, который находится у каждого цифрового вывода
Старайтесь не использовать выводы 0 и 1 в своих схемах, так как они используются самой платой для загрузки скетча через USB. Иногда применяют следующий приём: временно убирают модуль с этих выводов, загружают скетч, а потом снова устанавливают модуль. Например, такое можно наблюдать при работе с Bluetooth-модулями.
На следующих занятиях мы подключим светодиод и заставим его не только мигать, но и плавно менять своё свечение.
Цифровые входы #3 | Arduino - учимся программировать - YouTube