Arduino:Хакинг/Написание библиотеки
Содержание | Знакомство с Arduino | Продукты | Основы | Справочник языка Arduino | Примеры | Библиотеки | Хакинг | Изменения | Сравнение языков Arduino и Processing |
Написание библиотеки[1]
Эта статья объясняет, как создать собственную библиотеку для Arduino. Объяснение будет на примере кода, позволяющего моргать азбукой Морзе на светодиодах Arduino. Далее будет показано, как конвертировать этот код в библиотеку. Это позволит другим пользователям без особого труда использовать и обновлять написанный вами код.
Более подробно читайте в этом руководстве – оно объясняет, как написать хороший API в стиле Arduino для вашей библиотеки.
Начнем со скетча, который выполняет простой код с азбукой Морзе:
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(), которая выставляет контакт в режим OUTPUT.
Итак, приступим к превращению скетча в библиотеку!
Для библиотеки понадобится как минимум два файла: заголовочный файл (с расширением «*.h») и файл-исходник (с расширением «*.cpp»). Заголовочный файл содержит эдакий список основных понятий, т.е. список всего, что находится внутри библиотеки. Сам код находится внутри файла-исходника. Мы даем нашей библиотеке название «Morse», поэтому наш заголовочный файл будет называется «Morse.h».
Давайте-ка взглянем, что у него внутри. На первый взгляд, его содержимое может показаться странным, но вы все поймете, когда мы заглянем внутрь файла-исходника.
«Сердцевина» заголовочного файла состоит из списка функций и необходимых переменных (одна строчка/переменная – одна функция), «обернутых» в класс:
class Morse
{
public:
Morse(int pin);
void dot();
void dash();
private:
int _pin;
};
Класс – это просто коллекция функций и переменных, хранящихся в одном месте. Эти функции и переменные могут быть public («публичными», могут употребляться внутри любой функции) или private («приватными», могут употребляться лишь внутри самого класса). У каждого класса есть специальная функция-конструктор, которая используется для создания экземпляра класса. Конструктор имеет то же имя, что и класс, но ничего не возвращает.
Содержимое заголовочного файла на этом, впрочем, не заканчивается. Во-первых, вам нужно вписать туда директиву #include, дающую доступ к стандартным типам и константам языка Arduino (она автоматически добавляется к обычным скетчам, но не к библиотекам). Это выглядит примерно так (и ставится выше блока с классом, о котором писалось выше):
#include "Arduino.h"
Во-вторых, весь заголовочный файл нужно «обернуть» в одну очень странную конструкцию:
#ifndef Morse_h
#define Morse_h
// директива #include и код пишутся тут...
#endif
Это призвано предотвратить проблемы, которые могут возникнуть, если кто-то случайно подключит (#include) вашу библиотеку дважды.
Наконец, в верхней части заголовочного файла пишется комментарий с названием библиотеки, кратким описанием того, что она делает, автором, датой и лицензией.
Давайте взглянем, как заголовочный файл будет выглядеть полностью:
/*
Morse.h – Библиотека для азбуки Морзе на светодиодах.
Создана Дэвидом А. Меллисом (David A. Mellis)
2 ноября 2007 года.
Опубликована без защиты авторских прав.
*/
#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, а также к понятиям, указанным в «Morse.h»:
#include "Arduino.h"
#include "Morse.h"
Затем идет конструктор. Опять же, он объясняет, что должно произойти, если кто-то создаст экземпляр вашего класса. В данном случае пользователь должен указать, какой контакт он будет использовать. Мы выставляем этот контакт в режим OUTPUT и сохраняем в приватную переменную для использования в других функциях:
Morse::Morse(int pin)
{
pinMode(pin, OUTPUT);
_pin = pin;
}
Далее идет пара странных вещей. Сначала
Morse::
перед названием функции. Это значит, что эта функция является частью класса Morse. Вы увидите такой фрагмент и при указании других функций этого класса.
Вторая непонятная вещь – это нижнее подчеркивание при написании приватной переменной, _pin. По сути, эту переменную можно назвать как угодно – до тех пор, пока она соответствует определению, указанному в заголовочном файле. Добавление нижнего подчеркивания перед названием переменной – это общепринятый способ показать, что эта переменная является приватной, а также отличить ее от аргумента функции (в данном случае – pin).
Дальше идет, собственно, сам код из скетча, который мы превращаем в библиотеку (наконец-то!). Он выглядит примерно так же, как в скетче, за исключением
Morse::
, стоящим перед названиями функций, а также _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);
}
Наконец, пишем в верхней части файла-исходника заголовочный комментарий. И давайте взглянем, что получилось:
/*
Morse.cpp – Библиотека для азбуки Морзе на светодиодах.
Создана Дэвидом А. Меллисом (David A. Mellis) 2 ноября 2007 года.
Выпущена без защиты авторских прав.
*/
#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);
}
По сути, это все, что нужно (но есть пара дополнений, о которых мы поговорим чуть позже).
Теперь давайте рассмотрим, как использовать эту библиотеку. Сначала идем в папку «libraries», которая находится в папке скетчей (расположение папки скетчей можно узнать, кликнув в IDE Arduino на Файл > Настройки; откроется окно, в самой верхней части которого будет поле «Размещение папки скетчей») и создаем там папку «Morse». Затем копируем в эту папку файлы «Morse.h» и «Morse.cpp». Теперь запускаем IDE Arduino и кликаем по Скетч > Подключить библиотеку. Откроется выпадающее меню со списком загруженных библиотек, и в их числе уже должна быть наша Morse. Библиотека будет скомпилирована вместе со скетчами, которые ее используют. Если библиотеки не видно, то убедитесь, что скопированные вами файлы действительно имеют расширения «*.h» и «*.cpp» (то есть, к примеру, без дополнительных «*.pde» или «*.txt»).
Теперь давайте посмотрим, как можно воспроизвести наш старый скетч «SOS» при помощи новой библиотеки:
#include <Morse.h>
Morse morse(13);
void setup()
{
}
void loop()
{
morse.dot(); morse.dot(); morse.dot();
morse.dash(); morse.dash(); morse.dash();
morse.dot(); morse.dot(); morse.dot();
delay(3000);
}
Как видите, этот скетч имеет пару отличий от старой версии (не считая того факта, что некоторый код переместился в саму библиотеку).
Сначала в самом верху скетча добавляется директива #include. Благодаря этому скетч получает доступ к библиотеке Morse, а сама библиотека подключается к коду, который отправляется на плату. Таким образом, если вам в этом скетче больше не понадобится библиотека Morse, удалите директиву #include – чтобы сэкономить программную память.
Во-вторых, создаем экземпляр класса Morse и называем его morse:
Morse morse(13);
При обработке этой строки – а это происходит до обработки функции setup() – вызывается конструктор для класса Morse, после чего ему передается аргумент в виде числа «13».
Обратите внимание, что блок setup() пуст, потому что вызов pinMode() теперь происходит внутри библиотеки (при создании экземпляра класса).
Наконец, чтобы вызвать функции dot() и dash(), нужно подставить к ним префикс morse. Это название экземпляра класса, которое мы хотим использовать. Мы можем использовать несколько экземпляров класса Morse – каждый со своим контактом, хранящимся в приватной переменной _pin. Таким образом, при вызове функции, использующей какой-либо из этих экземпляров, будет использоваться переменная, указанная при создании этого экземпляра. Например, если воспользоваться двумя экземплярами класса Morse...
Morse morse(13);
Morse morse2(12);
...то внутри morse2.dot() приватной переменной _pin будет «12».
Если вы попытаетесь написать новый скетч, то IDE Arduino, возможно, не распознает ничего из вашей новой библиотеки, окрасив неизвестные конструкции цветными полосками. К сожалению, IDE Arduino не умеет автоматически распознавать, что именно вы задали в своей библиотеке (хотя такая функция очень пригодилась бы), поэтому ей нужно немножко помочь. Для этого в папке «Morse» нужно создать специальный файл «keywords.txt». Его содержимое должно выглядеть следующим образом:
Morse KEYWORD1
dash KEYWORD2
dot KEYWORD2
Здесь каждая строчка начинается с ключевого слова, после чего идет Tab ⇆ (не пробелы) и тип ключевого слова. Классы – это KEYWORD1 и окрашиваются в оранжевый; функции – это KEYWORD2 и окрашиваются в коричневый. Чтобы IDE Arduino начала распознавать новые ключевые слова, ее нужно перезапустить.
Также будет полезно снабдить вашу библиотеку скетчем-примером, который демонстрирует, как ее использовать. Для этого создайте внутри папки «Morse» папку «examples». Затем переместите или скопируйте папку со скетчем (можно назвать ее «SOS»), который мы написали выше, в папку «examples». Чтобы найти скетч, в данный момент загруженный в IDE Arduino, кликните на Скетч > Показать папку скетча. Далее перезапускаем IDE Arduino (обещаю, это в последний раз!), кликаем на Файл > Примеры; откроется выпадающий список, в котором должен быть пункт «Library-Morse». Также имеет смысл добавить пару комментариев, объясняющих, как использовать вашу библиотеку.
Если вы хотите сами опробовать библиотеку, создание которой объяснялось в этой статье (в комплекте с ключевыми словами и скетчем-примером), то загрузить ее можно здесь.
На этом все, но в будущем, возможно, мы напишем более подробное руководство по написанию библиотек. Если у вас возникли какие-то проблемы или пожелания, поделиться ими можно на форуме.
Дополнительную информацию читайте в руководстве по написанию API для Arduino.
См.также
Внешние ссылки
Arduino продукты | |
---|---|
Начальный уровень | Arduino Uno • Arduino Leonardo • Arduino 101 • Arduino Robot • Arduino Esplora • Arduino Micro • Arduino Nano • Arduino Mini • Arduino Starter Kit • Arduino Basic Kit • MKR2UNO • TFT-дисплей Arduino |
Продвинутые функции | Arduino Mega 2560 • Arduino Zero • Arduino Due • Arduino Mega ADK • Arduino Pro • Arduino Motor Shield • Arduino USB Host Shield • Arduino Proto Shield • MKR Proto Shield • MKR Proto Large Shield • Arduino ISP • Arduino USB 2 Serial Micro • Arduino Mini USB Serial Adapter |
Интернет вещей | Arduino Yun • Arduino Ethernet • Arduino MKR1000 • Arduino WiFi 101 Shield • Arduino GSM Shield V2 • Arduino WiFi Shield • Arduino Wireless SD Shield • Arduino Wireless Proto Shield • Arduino Ethernet Shield V2 • Arduino Yun Shield • Arduino MKR1000 Bundle |
Носимые устройства | Arduino Gemma • Lilypad Arduino Simple • Lilypad Arduino Main Board • Lilypad Arduino USB • LilyPad Arduino SimpleSnap |
3D-печать | Arduino Materia 101 |
Устаревшие устройства | - |
Примеры Arduino | |
---|---|
Стандартные функции | |
Основы |
|
Цифровой сигнал |
|
Аналоговый сигнал |
|
Связь |
|
Управляющие структуры |
|
Датчики |
|
Дисплей |
Примеры, объясняющие основы управления дисплеем:
|
Строки |
|
USB (для Leonardo, Micro и Due плат) |
В этой секции имеют место примеры, которые демонстрируют использование библиотек, уникальных для плат Leonardo, Micro и Due.
|
Клавиатура |
|
Мышь |
|
Разное |