Программирование AVR Arduino: как создать свою библиотеку кода? Fri, September 22 2017  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Arduino: как создать свою библиотеку кода? Печать
Добавил(а) microsin   

На основе примера генератора кода Морзе здесь показано, как сконвертировать его функции в библиотеку (перевод официальной документации [1]). Это позволит другим людям проще использовать код, и проще обновить свой проект, когда Вы улучшите библиотеку. Начнем с простого примера скетча, который генерирует морзянку, мигая светодиодом (после его запуска он постоянно выдает сигнал SOS):

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); }

В этом скетче есть несколько разных частей, которые нам нужно перевести в библиотеку. Первое, конечно же, это функции dot() и dash(), которые выполняют основную работу по миганию светодиодом . Второе это переменная ledPin, которая используется функциями - эта переменная определяет, какой вывод порта использовать. И наконец, здесь есть вызов pinMode(), который настраивает вывод порта как выход. Итак, давайте превратим код скетча в библиотеку.

Для библиотеки нам нужно как минимум 2 файла: файл заголовка (header file, файл с расширением .h) и файл исходного кода (с расширением .cpp). В заголовочном файле есть определения для библиотеки: в основном здесь кратко описано все, что есть внутри библиотеки; файл исходного кода в то же время содержит действительный код. Назовем нашу библиотеку "Morse", так что заголовочный файл получит имя Morse.h.

[Заголовочный файл библиотеки]

Ядро файла заголовка состоит из нескольких строк, в каждой из которых описана одна функция, и все это объединено в класс вместе со всеми переменными, которые Вам нужны:

class Morse
{
  public:
    Morse(int pin);
    void dot();
    void dash();
  private:
    int _pin;
};

Класс это просто набор функций и переменных, содержащихся в одном месте. Функции и переменные имеют атрибут public, который означает, что эти функции доступны для всех, кто использует библиотеку, или private, который означает, что доступ возможен только из самого класса. В каждом классе есть специальная функция, называемая конструктором, которая используется для создания экземпляра (instance) класса. Конструктор всегда имеет то же самое имя, что и имя класса, и у не указан возвращаемый тип (потому что заранее известно, что он возвратит тип класса).

Примечание: определение класса в заголовке можно рассматривать как пользовательский ТИП (по аналогии с typedef struct), а экземпляр класса можно рассматривать как ПЕРЕМЕННУЮ, которая имеет этот тип. Конструктор предназначен для инициализации этой переменной. Может быть также еще и деструктор, который предназначен для уничтожения переменной класса. Наличие и конструктора, и деструктора необязательно: это зависит от реализации класса.

Кроме определения класса, в заголовочный файл нужно добавить подключение заголовка Arduino.h директивой #include. Это дает доступ к стандартным типам и константам языка Arduino. Заголовочный файл Arduino.h автоматически добавляется при компиляции скетча (см. [3]), но для библиотек это нужно сделать самому. Подключение заголовка Arduino.h будет выглядеть следующим образом:

#include "Arduino.h"

В завершение нужно обернуть заголовочный файл в стандартную конструкцию #ifndef / #define / #endif (это защита от повторного включения заголовка []). Также в начало заголовка добавляют комментарии, описывающие содержимое библиотеки. В результате получится вот такой заголовок:

/*
 Morse.h - библиотека для генерации кода Morse.
 Автор 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

[Файл исходного кода библиотеки]

Займемся конструктором. В нем расположен код, который вызывается при создании экземпляра класса. В нашем примере пользователь в параметре конструктора указывает номер цифрового порта, который будет использоваться. Таким образом, конструктор у нас будет конфигурировать ножку порта, и сохранит номер используемого порта в частную переменную _pin (эта переменная будет использоваться функциями класса):

Morse::Morse(int pin)
{
  //Конфигурируем порт как выход:
  pinMode(pin, OUTPUT);
  //Сохраним номер порта во внутреннюю переменную класса:
  _pin = pin;
}

В коде конструктора видно кое-что, с чем мы раньше не встречались. Первое это необычный префикс Morse:: перед именем функции. Это говорит о том, что функция входит в состав класса Morse. Тот же самый префикс мы увидим позже в определении других функций класса. Второе это private-переменная _pin. В принципе имя этой переменной может быть любым, лишь бы оно соответствовало определению класса в файле заголовка. Добавление символа подчеркивания к имени файла является стандартным соглашением - чтобы сразу было видно, что это частная (private) переменная, и чтобы получить отдельное имя, отличающееся от имени входной переменной функции конструктора.

Теперь напишем код для функций библиотеки. Код будет выглядеть точно таким же, как он был в скетче, за исключением того, что к имени функции будет добавлен префикс Morse::, и будет использоваться частная переменная _pin вместо глобальной переменной pin. Нужно также добавить подключение заголовочных файлов и текст комментария в начало файла. В результате получится файл исходного кода (модуль) библиотеки:

/*
 Morse.h - библиотека для генерации кода Morse.
 Автор 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);
}

[Как использовать библиотеку]

Файлы библиотеки готовы. Теперь надо разобраться, как использовать библиотеку в среде разработки Arduino.

Сначала создайте папку Morse как поддиректорию в папке libraries (папка libraries находится в каталоге установки системы Arduino, полный путь до папки Morse будет наподобие C:\Program Files\Arduino\libraries\Morse). Скопируйте файлы Morse.h и Morse.cpp в директорию Morse. После этого запустите среду разработки Arduino IDE. Если Вы зайдете в меню Sketch -> Import Library (Скетч -> Импортировать библиотеку), то среди списка библиотек Вы должны увидеть Morse. Библиотека будет компилироваться вместе с теми скетчами, которые её используют. Если у Вас имеются проблемы при создании или компиляции библиотеки, то проверьте, что файлы действительно имеют расширения .cpp и .h - например, без дополнительного расширения .pde или .txt (имейте в виду, что подобная ситуация может произойти, когда в Проводнике Windows отключено отображение расширений зарегистрированных типов файлов).

Теперь давайте посмотрим, как можно создать скетч, который будет делать то же самое, что и раньше, но с использованием библиотеки:

#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. Первое отличие - добавлен оператор #include в самом начале скетча. Это делает библиотеку Morse доступной для использования внутри скетча, и её код (при компиляции) будет добавлен в общий код, который будет впоследствии прошит в память микроконтроллера платы Arduino. Это означает, что если больше в скетче не нужна библиотека, то Вы должны удалить подключение её заголовочный файла (закомментировать или удалить строку с соответствующей директивой #include).

Обратите внимание, что имя подключаемого файла теперь указано в угловых скобках, а не в двойных кавычках. Это обычная практика программирования на языках C/C++: имена стандартных библиотечных файлов в директиве #include указываются с использованием угловых скобок, а подключение заголовочных файлов пользователя указывается с помощью двойных кавычек.

Вызов конструктора класса. Второе отличие - как создается переменная класса Morse (в нашем примере мы создаем переменную класса morse):

Morse morse(13);

Когда выполняется эта строка кода (это происходит до вызова функции setup()), то будет вызвана функция конструктора класса Morse, и ей будет передан аргумент (в нашем случае номер цифрового порта 13).

Обратите внимание, что функция setup() теперь пуста; это потому, что вызов pinMode() происходит внутри библиотеки (когда конструктор создает экземпляр переменной класса).

Вызов функций класса. Последнее отличие - функции dot() и dash() вызываются с префиксом из имени экземпляра класса и точки (morse.). У нас может быть несколько экземпляров класса Morse, каждый из них будет использовать свой номер порта. Путем вызова функции с отдельным экземпляром класса, мы указываем, какие экземпляры переменных используются для вызова функции. К примеру, если у нас есть два экземпляра класса:

Morse morse1(13);
Morse morse2(12);

то внутри вызова morse2.dot(), значение переменной _pin будет 12.

[Подсветка синтаксиса библиотеки]

Если Вы попробуете использовать библиотеку в новом скетче, то не увидите, что наша библиотека не будет подсвечиваться особым образом в редакторе кода Arduino IDE, как это принято для стандартных библиотек (например, для общеизвестной библиотеки Serial). К сожалению, программное обеспечение среды разработки Arduino не может автоматически распознать определения в Вашей библиотеке (что было бы приятной возможностью), так что Вам нужно ей немного в этом помочь. Чтобы настроить подсветку синтаксиса для Вашей библиотеки, создайте файл keywords.txt в каталоге Morse. Его содержимое должно выглядеть так:

Morse KEYWORD1
dash  KEYWORD2
dot   KEYWORD2

В каждой строке должно быть имя ключевого слова, за которым через табуляцию (не через пробелы) должен идти тип ключевого слова. Имя класса должно быть обозначено как KEYWORD1, и это дает оранжевую подкраску; функции (методы) класса должны обозначены как KEYWORD2, и имена функций будут коричневыми. После создания файла keywords.txt в каталоге Morse нужно перезапустить среду разработки Arduino, чтобы она распознала новые ключевые слова.

[Пример кода использования библиотеки]

Вместе с библиотекой полезно предоставить пример скетча с демонстрацией использования библиотеки. Для этого в директории Morse создайте подкаталог examples. Затем скопируйте или переместите папку, содержащую код скетча (пусть эта папка называется SOS), в папку examples. Где находится копируемый скетч можно узнать из меню Sketch -> Show Sketch Folder (Скетч -> Показать папку скетчей). Если после этого Вы еще раз перезапустите среду разработки Arduino, то в меню File -> Sketchbook -> Examples (Файл -> Примеры) увидите Morse, и внутри неё пример SOS. Также для кода примера можно создать дополнительные комментарии, чтобы лучше разъяснить, как использовать Вашу библиотеку.

Если Вы хотите проверить содержимое готовой библиотеки, то можете загрузить её: Morse.zip [3]. Вы также можете просмотреть реализации других готовых библиотек, которые можете найти в папке libraries каталога установки Arduino. Дополнительную информацию по Arduino-стилю оформления библиотек можете получить из [2]. Если у Вас есть вопросы, то можете задать их на форуме разработчиков Arduino [4].

[Ссылки]

1. Writing a Library for Arduino site:arduino.cc.
2. Arduino Style Guide for Writing Libraries site:arduino.cc.
3. Morse.zip - архив копии каталога библиотеки, содержимое архива следует поместить в папку libraries каталога установки Arduino IDE.
4. Arduino Forum > Software > Development site:forum.arduino.cc.

 

Добавить комментарий


Защитный код
Обновить

Top of Page