Инструкция по Arduino: Финальная программа
Друзья, это снова я, Алексей, и наш небольшой цикл статей по использованию платы Arduino Nano с адресной лентой, на основе светодиодов ws2812b. На сегодня это уже шестая статья. И прежде, чем браться за чтение конкретно этой статьи, я бы посоветовал прочитать предыдущие. Так полученная информация гораздо лучше усвоится. Тем более, что здесь и сейчас речь пойдет о программировании, пускай и достаточно простом, но все же, предварительно стоит иметь определенную базу знаний.
Я хочу напомнить, что мы уже поговорили об основах программирования, а также подключили нашу управляемую ленту к плате Arduino Nano. Подключение изображено на картинке снизу, тут и схема, и фотография.
А теперь настало время написать программу посерьезнее.
Программа
Я не буду долго ходить вокруг да около, и сразу же скину скетч, который я написал. И сейчас мы его разберем, буквально каждую строчку.
#include "Adafruit_NeoPixel.h"
#define LED_COUNT 5
#define LED_PIN 5
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
strip.begin(); //Инициализируем ленту.
}
void loop() {
for(int m = 0; m < 3; m++)
{
for (int i = 0; i < LED_COUNT; i++)
{
strip.setPixelColor(i, color(m));
strip.show();
delay(300);
}
}
}
uint32_t color(int c)
{
if(c == 0)
{
return strip.Color(255, 0, 0);
}
if(c == 1)
{
return strip.Color(0, 255, 0);
}
if(c == 2)
{
return strip.Color(0, 0, 255);
}
}
- В первой строке мы подключаем библиотеку Adafruit_NeoPixel.h, для управления адресной лентой. Мы уже говорили, для чего это нужно и как установить библиотеку, поэтому внимание заострять не станем.
- Во второй строке мы задаем количество пикселей на адресной ленте. Кстати, если установить тут значение, отличное от пяти и подключить ленту с таким же количеством пикселей, то программа также будет работать с необходимым количеством пикселей. Так что директива define очень удобна, когда дело касается изначальных констант, влияющих на гибкость программы.
- В третьей строке мы задаем номер вывода МК, по которому происходит управление адресной лентой. Вы можете использовать свой вывод под другим номером.
- В пятой строке у нас идет инициализация объекта управления лентой strip. С передачей в конструктор объекта параметров о длине, типе и выводе управления ленты.
- В седьмой строке у нас начинается выполнение функции setup, которая производится единожды при запуске МК. В восьмой строке мы сообщаем программе о твердой решимости начать управление адресной лентой через созданный ранее объект.
- В одиннадцатой строке у нас уже начинается функция loop. Это основное тело программы, которое будет повторяться до бесконечности, пока работает микроконтроллер. И именно в этой функции начинается наша "магия".
- С двенадцатой по двадцатую строку начинается цикл, он рассчитан на 3 итерации: где счетчик m меняется от 0 до 2. В этот цикл вложен еще один цикл, находится он с 14 по 19 строку.
- Вложенный цикл имеет количество итераций, равное количеству пикселей на ленте. Счетчик i меняется в диапазоне от нуля до количества пикселей минус один.
- Теперь давайте разберем тело второго, вложенного цикла. Тут у нас всего лишь три команды. На семнадцатой строке мы выводим хранящийся в памяти массив цветов на адресную ленту. А на восемнадцатой делаем задержку в 300 мс. Но нас больше всего интересует 16 строка, где мы заполняем массив цветов. Тут нам все знакомо, кроме того, вместо явного обозначения цвета, мы вызываем функцию color и передаем ей значение счетчика m.
- Функция color описана с двадцать третьей по тридцать седьмую строку. Функция принимает значение типа int в переменную «c» – это будет как раз значение счетчика m, основного цикла из функции loop. Также данная функция возвращает значение типа uint32_t – это еще один тип данных в этом "си"- подобном языке программирования. Он очень похож на int, потому что хранит в себе целочисленные значения чисел, но только в большем диапазоне (от 0 до 4 294 967 295). И если на int выделено 2 байта памяти, то на uint32_t уже целых 4. Этого как раз достаточно, чтобы хранить значения всех трех цветов для пикселя, даже один байт лишний. И в классе Adafruit_NeoPixel именно таким образом и хранятся цвета.
- Давайте разберем, что же содержит функция color. Тут у нас три условия для трех значений счетчика m, и при выполнении какого-то из условий, функция возвращает один из трех цветов. Например, если счетчик равен единице, то условие, находящееся в двадцать девятой строке, будет верным, и из тридцать первой строки функция вернет значение синего цвета.
Думаю, что мое описание вполне исчерпывающее, но давайте пробежимся по строчкам, словно мы исполняем данную программу, и проработаем буквально все действия. Начнем сразу с тела программы и функции loop(), так как все остальное - это либо инициализация, либо наша функция color(), которая вызывается из тела loop().
12 строка – начало цикла, при переходе к следующей команде, переменная цикла «m» будет ровна нулю. Значение «m» будет влиять на цвет пикселя и изменяться от 0 до 2. Затем начинается следующий цикл.
14 строка – начинается вложенный цикл. Переменная цикла «i» будет равна нулю. Значение «i» изменяется от 0 до 4. Значение «i» отвечает за номер пикселя, цвет которого мы будем изменять. Во вложенном цикле у нас имеется три команды.
16 строка – вызывается метод класса адресной ленты, отвечающий за изменение цвета какого-то конкретного пикселя. Передаем два параметра. В качества первого параметра у нас номер изменяемого пикселя. В качестве второго параметра у нас цвет. Но цвет указан не явно, тут идет вызов функции color(). В функцию color(), в качестве параметра, мы передаем значение переменной «m». И результатом выполнения данной функции, будет значение, которое данная функция вернет. Переходим к выполнению вызванной функции.
23 строка – функция вызвана, и в качестве параметра «c»функция получает значение переменной «m», которую мы передали при вызове функции. То есть «c» равно нулю. Дальше переходим в "тело" функции. Тут у нас последовательно идет три условия.
25 строка – первое условие проверяет, равна ли переменная «c» нулю. В нашем случае равна. Тогда выполняется "тело" условия. Тут всего лишь одна строка.
27 строка – "тело" первого условия функции color(). Тут идет команда return – эта команда прерывает работу функции и возвращает на место вызова функции указанное значение. В данном случае это значение цвета. Если более конкретно, мы возвращаем значение красного цвета. Данное значение имеет тип uint32_t (как уже было сказано раньше), но для того, чтобы задать эту величину, я использовал готовый метод объекта, передав ему необходимые значения. Если говорить проще, то мы вернули в место вызова функции значение цвета.
16 строка – мы получили значение цвета. Следовательно, мы меняем на нулевом пикселе цвет на красный. Переходим к следующей команде.
17 строка – выводим весь массив цветов из памяти МК на адресную ленту. В данном случае наш массив состоит из значений пяти пикселей. И все, кроме нулевого, не имеют цвета, а нулевой красный.
18 строка – делаем задержку на 300 мс. Это сделано для того, чтобы увидеть анимацию смены цветов. В данном случае лента будет обновлять цвета очень быстро, и чтобы увидеть смену, нужно выставить небольшую задержку между отправлением пакетов команд на адресную ленту. На этом первая итерация вложенного цикла закончилась. На ленте горит нулевой пиксель красным цветом.
14 строка – началась вторая итерация вложенного цикла, тут значение «i» будет равно 1.
16 строка – функция color() вернет красный цвет, так как значение переменной «m» не менялось. В массиве цветов пикселей ленты мы присвоим значение красного цвета первому пикселю. На данный момент красными у нас являются первый и нулевой пиксели, остальные не имеют цвета (Color(0, 0, 0)).
17 строка – выводим массив значений пикселей на ленту. Сейчас на столе горят красным уже два первых пикселя.
18 строка – снова задержка.
14 строка – данный цикл будет происходить до тех пор, пока значение переменной «i» меньше 5. То есть еще 3 раза. С каждой последующей итерацией мы будем зажигать красным все новый и новый пиксель. После того, как значение «i» станет равным пяти, цикл прервется и перестанет существовать.
12 строка – перешли к основному циклу. Это только его вторая итерация. В данный момент переменная «m» будет равна единице. И после этого начнет заново выполняться вложенный цикл.
16 строка – описывать работу вложенного цикла уже не имеет смысла, мы и так все разобрали. Но в этот раз, при вызове функции color() мы передадим ей иное значение, и оно будет равным единице.
23 строка – функция получает значение, равное единице и начинает выполняться.
25 строка – условие будет не выполнено, так как переменная «c» не равна нулю.
29 строка – условие выполнено. Значит выполнится "тело" условия.
31 строка – возвращаем в место вызова функции значение зеленого цвета.
14 строка – думаю, уже понятно, что на второй итерации родительского цикла, данный цикл будет снова заполнять значения цветов пикселей и выводить их на ленту. Только в этот раз светодиоды будут последовательно загораться зеленым цветом. Соответственно, красный цвет будет поочередно, меняться на зеленый. Разделять смены цветов пикселей будет по-прежнему задержка в 300 мс.
12 строка - на третей итерации общего цикла, значение переменной «m» будет равно 2 и функция color() будет возвращать значение синего цвета, заполняя поочередно каждый светодиод.
Все описанное выше будет выполняться бесконечное кол-во раз. Это нам обеспечит особенность работы функции loop(), в которой находится наш основной код. Прилагаю иллюстрацию, чтобы продемонстрировать, как это все работает.
Заключение
В рамках одного курса невозможно научить программировать с полным пониманием дела, он слишком маленький. Данная программа, из сегодняшней статьи, очень простая, хоть на нее и потребовалось потратить достаточно большое количество слов, чтобы описать работу, но на самом деле такие программы пишутся буквально за пару минут. Я преследовал цель не научить круто программировать, а передать культуру мышление разработчика, хотя бы на примитивном уровне. Нашему читателю я хотел бы порекомендовать больше практиковаться, не бояться пробовать новые решения, пускай они и кажутся вам сомнительными, ведь отрицательный результат тоже дает опыт. Также призываю вас искать информацию о том, что осталось не понятно, пусть это будет команда в коде или подключение устройства. Тут поможет и книга, и поисковик, и даже друг, который продвинулся в вопросе гораздо глубже вас. Именно по этой причине я и не стал организовывать какие-то сложные эффекты, это просто могло бы сбить новичков с толку, так как материал оказался бы через слишком сложным.
В рамках данного курса выйдет еще две статьи. Там речь пойдет уже не об Arduino Nano, а о другой плате, под названием Wemos. Она построена на МК ESP8266, и главная ее особенность в том, что есть возможность подключить МК в Wi-Fi сети и управлять, к примеру, адресной лентой, через интернет. Но об мы поговорим уже в следующей статье.
Товары
- Комментарии