ЗАДАЧА
Требуется создать свою библиотеку. Библиотеки предоставляют удобный способ использования одного и того же кода во многих скетчах, а также дают другим разработчикам возможность использовать ваш код.
РЕШЕНИЕ
Библиотека представляет собой набор методов и переменных, объединенных в формате, предоставляющем пользователю стандартный способ доступа к этим функциям и переменным.
Большинство библиотек Arduino создаются в виде класса. Те из вас, кто знаком с языком С++ или Java, должны знать, что такое класс. Однако библиотеки можно также создавать и без использования классов, и здесь мы увидим, как это сделать.
Итак, давайте модифицируем скетч решения из разд. 7.1, чтобы включить функцию BlinkLED() в библиотеку.
Схема подключения светодиодов приводится на рис. 7.2, а описание ее работы — в разд. 7.1. Создаваемая нами библиотека будет содержать функцию blinkLED() из этого решения. В листинге 16.5 приводится код скетча blinkLibTest, с помощью которого будет выполняться тестирование созданной библиотеки.
Листинг 16.5. Скетч для тестирования созданной библиотеки
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /* * Скетч blinkLibTest */ #include "blinkLED.h" const int firstLedPin = 3; // Контакты для подключения светодиодов const int secondLedPin = 5; const int thirdLedPin = 6; void setup(){ pinMode(firstLedPin, OUTPUT); // Задаем выходной режим работы для // контактов светодиодов pinMode(secondLedPin, OUTPUT); pinMode(thirdLedPin, OUTPUT); } void loop(){ // Мигаем каждым светодиодом один раз в 1,000 мс (1 секунду) blinkLED(firstLedPin, 1000); blinkLED(secondLedPin, 1000); blinkLED(thirdLedPin, 1000); } |
Функцию blinkLED() нужно удалить из скетча решения, приведенного в разд. 7.1, и поместить в отдельный файл с названием blinkLED.cpp, как показано в листинге 16.6 (файлы *.cpp рассматриваются более подробно далее — в разд. «Обсуждение работы решения и возможных проблем» этого раздела).
Листинг 16.6. Код библиотеки blinkLED
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* blinkLED.cpp * Простая библиотека для мигания светодиодом с периодом в миллисекундах */ #include "Arduino.h" // Для версий среды Arduino IDE более ранних, // чем версия 1.0, используйте файл Wprogram.h #include "blinkLED.h" // Мигаем светодиодом на этом контакте в течение duration миллисекунд void blinkLED(int pin, int duration) { digitalWrite(pin, HIGH); // Включаем светодиод delay(duration); digitalWrite(pin, LOW); // Выключаем светодиод delay(duration); } |
Большинство библиотек разрабатывается программистами, которые используют для этого свою среду разработки, но их с таким же успехом можно создавать и в любом обычном текстовом редакторе типа Блокнот. |
А теперь создайте заголовочный файл blinkLED.h и скопируйте в него следующий код:
1 2 3 4 5 6 | /* * blinkLED.h * Заголовочный файл для библиотеки BlinkLED */ #include "Arduino.h" void blinkLED(int pin, int duration); // Прототип функции |
Обсуждение работы решения и возможных проблем
Наша библиотека будет называться blinkLED и храниться в папке libraries (см. разд. 16.2). Создайте в этой папке вложенную папку blinkLED и переместите в нее файлы blinkLED.h и blinkLED.cpp. Затем создайте в папке blinkLED вложенную папку examples, а в ней — вложенную папку blinkLibTest. Создайте из скетча для тестирования библиотеки (см. листинг 16.5) файл с именем blinkLibTest.ino и поместите его в папку blinkLibTest. Путь к этому файлу должен выглядеть так: examples/blinkLibTest/ blinkLibTest.ino.
В результате мы переместили функцию blinkLED() скетча решения из разд. 7.1 в файл библиотеки blinkLED.cpp (расширением cpp обозначаются файлы с исходным кодом, созданным на языке С++, — С plus plus).
Используемые в документации библиотек Arduino термины функция и метод обозначают блоки кода — такие как blinkLED(). Термин метод служит для обозначения функциональных блоков классов. Оба термина обозначают именованные функциональные блоки, доступ к которым предоставляется посредством библиотек. |
Файл blinkLED.cpp содержит исходный код функции blinkLED(), который идентичен коду этой функции в скетче из листинга 7.1, за исключением следующих двух строк в начале кода:
1 2 | #include "Arduino.h" // Подключение заголовочного файла Arduino.h #include "blinkLED.h" |
Оператор #include “Arduino.h” требуется для библиотек, использующих любые функции или константы языка Arduino. При отсутствии этого оператора компилятор будет выдавать сообщения об ошибке для всех функций, используемых в скетче.
Заголовочный файл Arduino.h был добавлен в версии 1.0 среды Arduino IDE, заменив заголовочный файл WProgram.h, используемый в более ранних версиях среды. При работе с такими более ранними версиями среды Arduino IDE можно использовать следующую конструкцию, чтобы подключать правильный заголовочный файл:
|
Следующая строка кода: #include “blinkLED.h” — содержит определение функции (которое также называется прототипом функции) для нашей библиотеки. Компилятор Arduino автоматически создает прототипы для всех функций в скетче при его компилировании, но не создает прототипов для функций, содержащихся в библиотеках, поэтому при создании библиотеки необходимо самому создать заголовочный файл, содержащий эти прототипы. При подключении библиотеки к скетчу в него добавляется именно этот заголовочный файл (см. разд. 16.1).
Каждая библиотека должна иметь файл, в котором объявляются названия предо- ставляемых функций. Такой файл называется заголовочным (header file) или включаемым (include file), а его название имеет формат НазваниеБиблиотеки.h. В рассматриваемом примере заголовочный файл называется blinkLED.h и размещается в той же папке, что и файл blinkLED.cpp. |
Содержимое заголовочного файла для нашей библиотеки очень простое — объявление одной функции:
1 | void blinkLED(int pin, int duration); // Прототип функции |
Это объявление почти такое же, как и объявление этой функции в файле blinkLED.cpp:
1 | void blinkLED(int pin, int duration) |
Однако разница между этими двумя объявлениями функции хотя и тонкая, но критическая. Объявление прототипа функции в заголовочном файле завершается точкой с запятой. Это сообщает компилятору, что это просто объявление формата для функции, но не ее кода. А отсутствие завершающей точки с запятой в объявлении функции в файле исходного кода blinkLED.cpp сообщает компилятору, что это собственно исходный код функции.
Библиотеки могут содержать несколько заголовочных файлов и несколько файлов исходного кода. Но они должны иметь минимум один заголовочный файл, название которого должно быть идентичным названию библиотеки. Название именно этого файла вставляется вверху скетча при подключении библиотеки. |
Более подробную информацию по использованию заголовочных файлов и файлов *.cpp для создания модулей кода можно получить, прочитав какую-либо хорошую книгу по языку C++ (в разд. «Дополнительная информация» этого раздела рекомендуется несколько таких весьма популярных книг).
Разместив файлы blinkLED.cpp, blinkLED.h и blinkLibTest.ino в соответствующие вложенные папки в папке libraries, закройте среду разработки Arduino IDE, а затем снова запустите ее. Структура задействованных папок и файлов должна выглядеть следующим образом:
libraries/
└── blinkLED/
├── blinkLED.cpp
├── blinkLED.h
└── examples/
└── blinkLibTest/
└── blinkLibTest.ino
Среда Arduino IDE обновляет список доступных библиотек только при ее запуске. Чтобы установленная вручную библиотека отобразилась в этом списке, необходимо закрыть, а затем снова запустить среду Arduino IDE. И хотя среду Arduino IDE нужно перезапустить при исходном добавлении библиотеки в папку libraries, впоследствии — после модифицирования библиотеки — перезапуск не требуется. |
Выполнив команду меню Файл | Примеры (Примеры из пользовательских библиотек) | blinkLED | blinkLibTest, откройте в окне Arduino IDE тестовый скетч blinkLibTest. Загрузите этот скетч в свою плату Arduino, и подключенные к ней светодиоды должны начать мигать так же, как и при исполнении скетча решения из разд. 7.1.
Добавить новую функциональность в существующую библиотеку не составляет никаких проблем. Предположим, например, что вы хотите добавить в нее несколько постоянных, наиболее часто используемых значений задержки, чтобы пользователи библиотеки могли применять описательные названия констант вместо значений в миллисекундах.
Эта задача решается добавлением в заголовочный файл библиотеки трех строк кода со значениями констант, которые обычно размещаются непосредственно перед кодом объявления прототипа функции:
1 2 3 4 5 | // Константы для периода мигания светодиодов const int BLINK_SHORT = 250; const int BLINK_MEDIUM = 500; const int BLINK_LONG = 1000; void blinkLED(int pin, int duration); // Прототип функции |
Затем надо модифицировать код в функции loop() скетча примера, как показано в листинге 16.7. Загрузив модифицированный скетч в плату, мы увидим, что каждый светодиод мигает с другой частотой.
Листинг 16.7. Модифицированный код функции loop() для мигания светодиодами с разной частотой
1 2 3 4 5 | void loop(){ blinkLED(firstLedPin, <strong>BLINK_SHORT</strong>); blinkLED(secondLedPin, <strong>BLINK_MEDIUM</strong>); blinkLED(thirdLedPin, <strong>BLINK_LONG</strong>); } |
Также легко добавляются в библиотеку и новые функции. В листинге 16.8 приводится код главного цикла loop(), который мигает каждым светодиодом заданное для него количество раз.
Листинг 16.8. Код цикла loop() для мигания каждым светодиодом в течение заданного для него периода
1 2 3 4 5 | void loop(){ blinkLED(firstLedPin, BLINK_SHORT, 5); // <strong>Мигает 5 раз</strong> blinkLED(secondLedPin, BLINK_MEDIUM, 3); // <strong>Мигает 3 раза</strong> blinkLED(thirdLedPin, BLINK_LONG); // <strong>Мигает один раз</strong> } |
Чтобы добавить эту функцию в библиотеку, в файл blinkLED.h нужно добавить ее прототип, как показано в листинге 16.9.
Листинг 16.9. Добавление прототипа новой функции в заголовочный файл
1 2 3 4 5 6 7 8 9 10 11 12 | /* * blinkLED.h * Заголовочный файл для библиотеки blinkLED */ #include "Arduino.h" // Константы для периода мигания светодиодов const int BLINK_SHORT = 250; const int BLINK_MEDIUM = 500; const int BLINK_LONG = 1000; void blinkLED(int pin, int duration); <strong>// Определение новой функции для мигания заданного количества раз</strong> <strong>void blinkLED(int pin, int duration, int repeats);</strong> |
А в файл blinkLED.cpp добавляем исходный код функции, как показано в листинге 16.10.
Листинг 16.10. Исходный код функции мигания светодиодами заданное количество раз
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | * blinkLED.cpp * Простая библиотека для мигания светодиодом с периодом в миллисекундах */ #include "Arduino.h" #include "blinkLED.h" // Мигаем светодиодом на этом контакте в течение duration миллисекунд void blinkLED(int pin, int duration) { digitalWrite(pin, HIGH); // Включаем светодиод delay(duration); digitalWrite(pin, LOW); // Выключаем светодиод delay(duration); } /* Функция для повторения мигания */ void blinkLED(int pin, int duration, int repeats) { while(repeats) { blinkLED(pin, duration); repeats = repeats -1; }; } |
Для созданной библиотеки можно добавить возможность выделения цветом ключевых слов при просмотре исходного кода скетча в окне редактора скетчей среды IDE. Для этого нужно создать специальный файл keywords.txt. Это обычный текстовый файл, который содержит список ключевых слов и их типов: каждый тип ключевого слова выделяется другим цветом. Ключевые слова и типы разделяются табуляцией, а не просто пробелом. В листинге 16.11 приводится пример файла keywords.txt, в котором задается выделение цветом констант периода мигания светодиода.
Листинг 16.11. Файл keywords.txt для библиотеки blinkLED
1 2 3 4 5 6 7 8 9 10 11 | ####################################### # Methods and Functions (KEYWORD2) ####################################### blinkLED KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### BLINK_SHORT LITERAL1 BLINK_MEDIUM LITERAL1 BLINK_LONG LITERAL1 |
Сохраните его в папке blinkLED и перезапустите среду Arduino IDE. Если теперь открыть файл скетча blinkLibTest.ino в среде Arduino IDE, то константы BLINK_SHORT, BLINK_MEDIUM и BLINK_LONG будут выделяться цветом.
Дополнительная информация
Дополнительные примеры создания библиотек рассматриваются в разд. 16.5.
Дополнительная информация по созданию библиотек для Arduino приводится в справочном документе «Writing a Library for Arduino» (https://oreil.ly/vLNvx).
Рекомендуем также следующие книги по программированию на C++:
- «Practical C++ Programming» («Практическое программирование на языке C++»), автор Steve Oualline, издательство O’Reilly;
- «C++ Primer Plus» («Язык программирования С++»), автор Stephen Prata, издательство Sams;
- «C++ Primer» («Учебник C++ для начинающих»), авторы Stanley B. Lippman, Josee Lajoie и Barbara E. Moo, издательство Addison-Wesley Professional.