Рано или поздно вы создадите нечто замечательное, что, по вашему мнению, могли бы использовать другие. Это будет самый подходящий момент оформить свой код в виде библиотеки и выпустить ее в свет. Эта глава покажет вам, как это сделать.
Когда создавать библиотеки
Библиотеки создаются не только разработчиками Arduino — любой пользователь Arduino может создать свою библиотеку. Если библиотека окажется по-настоящему полезной, в адрес ее создателя потечет поток благодарностей. Никто не занимается продажей библиотек, так как это противоречит ценностям сообщества Arduino. Библиотеки должны публиковаться с открытым исходным кодом и рассматриваться как помощь своим собратьям по увлечению Arduino.
Часто наиболее полезными оказываются библиотеки, дающие доступ к некоторому аппаратному обеспечению. Они нередко упрощают процесс использования аппаратных средств и некоторых сложных протоколов. Нет причин, почему более одного человека должны преодолевать тернистый путь, выясняя, как работает некоторая аппаратура, и, если вы опубликуете свою библиотеку, благодаря Интернету люди смогут отыскать ее.
СОВЕТ
Прикладной программный интерфейс (Application Programmer Interface, API) — это комплект функций, которые пользователь библиотеки будет включать в свой скетч. Проектируя API, всегда задавайте себе вопрос: «Что действительно волнует пользователя?» Низкоуровневые детали реализации должны быть максимально скрыты. В примере библиотеки, который будет представлен в разделе «Пример библиотеки (радиоприемник TEA5767)», мы продолжим обсуждение этой проблемы.
Использование классов и методов
Создатели скетчей обычно полагают, что пишут код на языке C, и используют довольно ограниченный круг возможностей, в действительности скетчи пишутся на языке C++, объектно-ориентированном расширении языка C. В этом языке используется понятие классов объектов, объединяющих информацию об объектах (их данные) и функции, которые применяются к этим данным. Эти функции похожи на обычные функции, но, когда они ассоциируются с конкретным классом, их называют методами. Кроме того, методы могут объявляться общедоступными, и тогда они доступны всем, кто пользуется ими, или приватными, и тогда они доступны только из методов внутри класса.
Я говорю об этом, потому что создание расширений — один из немногих видов деятельности в мире Arduino, где использование классов считается нормой. Класс — отличный способ заключить все необходимое в некое подобие модуля. Кроме того, различия между закрытыми и общедоступными членами помогают спроектировать API так, чтобы заставить разработчиков скетчей думать о том, как взаимодействовать с библиотекой (общедоступные члены), а не о том, как она работает (приватные члены).
В дальнейшем в процессе изучения примеров вы увидите, как пользоваться классами.
Пример библиотеки (радиоприемник TEA5767)
Чтобы показать, как писать библиотеки для Arduino, я возьму программный код, который использовался в главе 7 для работы с УКВ-приемником TEA5767, и превращу его в библиотеку. Скетч очень прост и в основном занимается настройкой библиотеки, тем не менее он служит хорошим примером.
Далее перечислены основные этапы процесса.
1. Определение API.
2. Создание заголовочного файла.
3. Создание файла реализации.
4. Создание файла с ключевыми словами.
5. Создание нескольких примеров.
С точки зрения файлов и папок библиотека включает папку с именем, совпадающим с именем библиотечного класса. В данном случае я выбрал имя TEA5767Radio для библиотеки и класса. Внутри этой папки должны находиться два файла: TEA5767Radio.h и TEA5767Radio.cpp.
При желании можно также создать файл keywords.txt и папку examples, содержащую примеры скетчей, использующих библиотеку. Структура папок для этого примера показана на рис. 15.1.
Рис. 15.1. Структура папок примера проекта
Библиотеку проще использовать, если она находится непосредственно в папке libraries в Arduino IDE, куда устанавливаются другие сторонние библиотеки. Файлы можно править прямо в этой папке. Среда разработки Arduino IDE заметит существование библиотеки только после перезапуска, но после этого любые изменения в содержимом файлов будут учитываться во время сборки проекта автоматически.
Оригинальный скетч, на котором основана библиотека, находится в файле sketch_07_01_I2C_TEA5767, а законченную библиотеку можно загрузить по адресу http://playground.arduino.cc//Main/TEA5767Radio.
Определение API
На первом этапе определяется интерфейс, которым будут пользоваться другие.
Если вам доводилось пользоваться разными библиотеками, вы наверняка заметили, что обычно они соответствуют двум шаблонам. Самый простой иллюстрирует библиотека Narcoleptic. Чтобы задействовать эту библиотеку, достаточно подключить ее и затем обращаться к ее методам, предваряя их имена именем библиотеки Narcoleptic, как в следующем фрагменте:
#include
// и потом где-то в скетче
Narcoleptic.delay(500);
Этот же шаблон использует библиотека Serial. Если библиотека поддерживает только один объект, то применение этого шаблона оправданно. Но если есть вероятность, что в скетче потребуется использовать несколько объектов, то необходим другой подход. Поскольку есть шанс, что к плате Arduino будет подключено более одного радиоприемника, данный пример попадает во вторую категорию.
В таких ситуациях применяется шаблон, сходный с тем, что используется библиотекой SoftwareSerial. Чтобы на одной плате организовать несколько последовательных портов, обслуживаемых программно, скетч создает именованные экземпляры библиотеки SoftwareSerial, используя следующий синтаксис:
#include
SoftwareSerial mySerial(10, 11); // RX, TX
Когда возникнет потребность использовать данный конкретный последовательный порт (связанный с контактами 10 и 11), достаточно создать именованный объект для его обслуживания — в данном случае mySerial — и затем выполнить в него запись, как показано далее:
mySerial.begin(9600);
mySerial.println("Hello World");
Не заботясь о конкретной реализации, определим, как должен выглядеть код, использующий библиотеку.
После импортирования библиотеки было бы желательно иметь возможность создать именованный радиоприемник и определить, какой адрес I2C он будет обслуживать. Для простоты неплохо было бы иметь на выбор два варианта: первый, с использованием адреса по умолчанию 0x60, и второй, позволяющий определять нестандартный адрес:
#include
TEA5767Radio radio = TEA5767Radio();
// или TEA5767Radio radio = TEA5767Radio(0x60);
Поскольку библиотека обслуживает УКВ-радиоприемник, она должна уметь настраивать частоту, то есть пользователь должен иметь возможность написать такой код:
radio.setFrequency(93.0);
Числовой параметр здесь представляет частоту в мегагерцах. Автор скетча хотел бы задавать частоту именно в таком виде, а не в малопонятном формате int, который передается аппаратному модулю. Библиотека должна скрывать технические детали и самостоятельно выполнять необходимые преобразования.
Это все, что касается проектирования данной библиотеки. Теперь приступим к созданию кода.
Заголовочный файл
Обычно программный код библиотеки хранится в двух файлах. Один из них называется заголовочным и имеет расширение .h. Этот файл будет указываться в скетчах в инструкции #include. Заголовочный файл не содержит выполняемого программного кода, он лишь определяет имена классов и методов в библиотеке. Далее приводится заголовочный файл примера библиотеки:
#include
#ifndef TEA5767Radio_h
#define TEA5767Radio_h
class TEA5767Radio
{
private:
int _address;
public:
TEA5767Radio();
TEA5767Radio(int address);
void setFrequency(float frequency);
};
#endif
Команда #ifndef предотвращает многократное импортирование библиотеки и представляет стандартный прием для заголовочных файлов.
Далее следует определение класса, который имеет приватный (private) раздел с единственной переменной _address. Эта переменная хранит адрес I2C устройства.
Общедоступный раздел (public) включает две функции для создания объекта-радиоприемника, одна позволяет указать адрес устройства, а другая не позволяет и использует адрес по умолчанию. В общедоступном разделе имеется также функция setFrequncy.
Файл реализации
Код, фактически реализующий функции, находится в файле TEA5767Radio.cpp:
#include
#include
TEA5767Radio::TEA5767Radio(int address)
{
_address = address;
}
TEA5767Radio::TEA5767Radio()
{
_address = 0x60;
}
void TEA5767Radio::setFrequency(float frequency)
{
unsigned int frequencyB = 4 * (frequency *
1000000 + 225000) / 32768;
byte frequencyH = frequencyB >> 8;
byte frequencyL = frequencyB & 0XFF;
Wire.beginTransmission(_address);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x10);
Wire.write(0x00);
Wire.endTransmission();
delay(100);
}
Создают новый объект радиоприемника два метода. Оба просто записывают в переменную _address адрес I2C устройства, либо переданный в параметре address, либо адрес по умолчанию 0x60. Метод setFrequency содержит почти весь код из оригинального скетча (sketch_07_01_I2C_TEA5767), кроме следующей строки, использующей значение переменной _address, чтобы соединиться с устройством I2C:
Wire.beginTransmission(_address);
Файл с ключевыми словами
Папка с библиотекой может также содержать файл с именем keywords.txt. Этот файл не является обязательным, библиотека будет работать и без него. Но этот файл позволяет среде разработки Arduino IDE выделять цветом любые ключевые слова библиотеки. В нашей библиотеке только два таких слова: ее имя TEA5767Radio и имя метода setFrequency. Файл с ключевыми словами может сдержать комментарии в строках, начинающихся с символа #. Далее приводится содержимое этого файла:
#######################################
# Карта подсветки синтаксиса для TEA5767Radio
#######################################
#######################################
# Типы данных (KEYWORD1)
#######################################
TEA5767Radio KEYWORD1
#######################################
# Методы и функции (KEYWORD2)
#######################################
setFrequency KEYWORD2
Ключевые слова должны определяться как KEYWORD1 или KEYWORD2, даже при том что версия 1.4 среды разработки Arduino IDE выделяет ключевые слова обоих типов оранжевым цветом.
Папка с примерами
Если внутри папки библиотеки создать папку с именем examples, все скетчи в этой папке автоматически будут регистрироваться средой разработки Arduino IDE во время запуска, и вы сможете получить доступ к ним через меню Examples (Примеры) в подменю с именем библиотеки. Примеры скетчей могут быть самыми обычными скетчами, только хранящимися в папке библиотеки. Далее приводится пример использования этой библиотеки:
#include
#include
TEA5767Radio radio = TEA5767Radio();
void setup()
{
Wire.begin();
radio.setFrequency(93.0); // выберите свою частоту
}
void loop()
{
}
Тестирование библиотеки
Чтобы протестировать библиотеку, достаточно запустить пример скетча, использующего библиотеку. Если вам не повезло (или вы были недостаточно внимательны) и первая попытка скомпилировать библиотеку завершилась неудачей, прочитайте сообщения об ошибках в информационной области в нижней части окна Arduino IDE.
Выпуск библиотеки
Созданную библиотеку можно передать сообществу. Чтобы другие наверняка могли найти ее, создайте запись на общедоступной вики-странице http://playground.arduino.cc//Main/LibraryList. Библиотеку можно распространять в виде zip-архива, но некоторые предпочитают использовать репозитории на сайтах GitHub, Google Code или других и размещать на вики-странице ссылку на сайт хостинга.
Если вы пожелаете выгрузить свою библиотеку на сайт Arduino Playground, выполните следующие шаги.
1. Протестируйте библиотеку, чтобы убедиться в ее безупречной работе.
2. Создайте zip-архив с папкой библиотеки и дайте ему имя, совпадающее с именем класса, но с расширением .zip.
3. Зарегистрируйтесь на сайте www.arduino.cc.
4. Добавьте запись на вики-странице Arduino Playground http://playground.arduino.cc//Main/LibraryList, описывающую библиотеку и порядок ее использования. Посмотрите, как оформлены записи для других библиотек, и скопируйте соответствующие фрагменты вики-разметки. Создайте ссылку, используя, например, текст [[TEA5767Radio]], чтобы создать заполнитель для новой страницы, который появится в списке библиотек в сопровождении знака ?. Щелкните на ссылке, чтобы создать новую страницу и открыть ее в вики-редакторе. Скопируйте вики-код из записи для другой библиотеки (например, TEA5767Radio) и приведите его в соответствие со своей библиотекой.
5. Чтобы выгрузить zip-архив с библиотекой, нужно включить в вики-разметку вкладку, такую как Attach:TEA5767Radio.zip. Сохранив страницу, щелкните на ссылке download (загрузить) и укажите имя zip-архива для выгрузки на вики-сервер.
В заключение
Создание библиотек — весьма похвальное занятие. Но прежде чем приступать к созданию какой-либо библиотеки, всегда проверяйте, не была ли создана подобная библиотека кем-то другим.
Книги по своей природе не в состоянии охватить все, что хотел бы узнать читатель. Но я надеюсь, что эта книга помогла вам разобраться в некоторых вопросах программирования Arduino.
Заходите ко мне в Twitter, где я зарегистрирован как @simonmonk2. Кроме того, подробную информацию об этой и других моих книгах можно найти на моем веб-сайте www.simonmonk.org.