Разберемся, как создать свою собственную библиотеку для Arduino. Начнем с эскиза, который позволит мигать кодом Морзе и объясним, как преобразовать его функции в библиотеку. Это позволит пользователю, подключив библиотеку, использовать написанный код и легко обновлять его при обновлении библиотеки.
Начнем с эскиза, который воспроизводит код Морзе:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
int pin = 13; void setup() { pinMode(pin, OUTPUT); } void loop() { dot(); dot(); dot(); dash(); dash(); dash(); dot(); dot(); dot(); delay(3000); } void dot() { digitalWrite(pin, HIGH); delay(250); digitalWrite(pin, LOW); delay(250); } void dash() { digitalWrite(pin, HIGH); delay(1000); digitalWrite(pin, LOW); delay(250); } |
При запуске программы мы получим на выводе 13 цифровой сигнал — код SOS (сигнал бедствия).
В эскизе есть несколько частей, которые необходимо будет внести в нашу библиотеку. Во-первых, у нас есть две функции dot() и dash(), которые обеспечивают «мигание» на выходе. Во-вторых, есть переменная ledPin, которая указывает функциям, какой пин использовать. Наконец, есть вызов pinMode(), который инициализирует пин в качестве вывода.
Давайте начнем превращать эскиз в библиотеку!
Вам нужно как минимум два файла для библиотеки: заголовочный файл (с расширением .h) и исходный файл (с расширением .cpp). Файл заголовка имеет определения для библиотеки: в основном список всего, что находится внутри; в то время, как исходный файл имеет фактический код. Мы будем называть нашу библиотеку «Morse», поэтому нашим заголовочным файлом будет Morse.h. Давайте посмотрим, что в нем происходит. Сначала он может показаться немного странным, но смысл станет понятен, если посмотреть исходный файл, который будет с ним работать.
Ядро файла заголовка состоит из строк для каждой функции в библиотеке, завернутой в класс вместе с различными переменными, которые вам нужны:
1 2 3 4 5 6 7 8 9 |
class Morse { public: Morse(int pin); void dot(); void dash(); private: int _pin; }; |
Класс — это просто набор функций и переменных, которые хранятся в одном месте. Эти функции и переменные могут быть общедоступными (public) , что означает, что к ним могут обращаться люди, использующие вашу библиотеку, или частные (private), то есть они могут быть доступны только из самого класса. Каждый класс имеет специальную функцию, называемую конструктором, которая используется для создания экземпляра класса. Конструктор имеет то же имя, что и класс, но не имеет возвращаемого значения.
Вам нужно еще несколько вещей в файле заголовка. Один из них — это оператор #include, который дает вам доступ к стандартным типам и константам языка Arduino (это автоматически добавляется к эскизам, но не к библиотекам). Это выглядит так (и идет выше определения класса, данного ранее):
1 |
#include "Arduino.h" |
И второе — обычно весь заголовочный файл «обертывается» в следующую конструкцию:
1 2 3 4 5 6 |
#ifndef Morse_h #define Morse_h // the #include statment and code go here... #endif |
Данная конструкция предотвращает проблемы, если кто-то случайно подключит вашу библиотеку дважды.
Обычно в верхней части библиотеки помещается комментарий, содержащий имя библиотеки, краткое описание того, что она делает, кто ее написал, дату и лицензию.
В конечном итоге получаем файл, следующего содержания:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* Morse.h - Library for flashing Morse code. Created by David A. Mellis, November 2, 2007. Released into the public domain. */ #ifndef Morse_h #define Morse_h #include "Arduino.h" class Morse { public: Morse(int pin); void dot(); void dash(); private: int _pin; }; #endif |
Теперь давайте рассмотрим различные части исходного файла Morse.cpp.
Сначала указывается пара операторов #include. Они предоставляют доступ ко всем стандартным функциям Arduino и определениям в вашем файле-заголовке:
1 2 |
#include "Arduino.h" #include "Morse.h" |
Затем пишется конструктор. Конструктор показывает, что должно произойти, когда кто-то создает экземпляр вашего класса. В нашем случае пользователь указывает, какой пин он хотел бы использовать. Мы настраиваем пин в качестве вывода, сохраняем его в частной переменной для использования в других функциях:
1 2 3 4 5 |
Morse::Morse(int pin) { pinMode(pin, OUTPUT); _pin = pin; } |
Рассмотрим некоторые особенности данного кода. Прежде всего это Morse :: перед именем функции. Такая запись говорит о том, что эта функция является частью класса Morse. Вы увидите это снова в других функциях класса. Вторая необычная вещь — это символ подчеркивания в имени нашей частной переменной _pin . Эта переменная может иметь любое имя, которое вы хотите, если оно соответствует определению в файле-заголовке. Добавление подчеркивания к началу имени является общим соглашением, позволяющим понять, какие переменные являются частными, а также отличать имя от имени аргумента функции ( в нашем случае — pin).
Далее идет код из эскиза, который мы переводим в библиотеку. Код выглядит примерно так же, как в скетче. Только добавляется Morse :: перед именами функций и _pin вместо pin :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void Morse::dot() { digitalWrite(_pin, HIGH); delay(250); digitalWrite(_pin, LOW); delay(250); } void Morse::dash() { digitalWrite(_pin, HIGH); delay(1000); digitalWrite(_pin, LOW); delay(250); } |
Обычно в верхней части исходного файла включают комментарий. Выглядит это следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/* Morse.cpp - Library for flashing Morse code. Created by David A. Mellis, November 2, 2007. Released into the public domain. */ #include "Arduino.h" #include "Morse.h" Morse::Morse(int pin) { pinMode(pin, OUTPUT); _pin = pin; } void Morse::dot() { digitalWrite(_pin, HIGH); delay(250); digitalWrite(_pin, LOW); delay(250); } void Morse::dash() { digitalWrite(_pin, HIGH); delay(1000); digitalWrite(_pin, LOW); delay(250); } |