Урок 9. Создание библиотеки для Ардуино.

Библиотека Ардуино

Научимся создавать собственную библиотеку для программирования на Ардуино.

Предыдущий урок     Список уроков     Следующий урок

В прошлом уроке мы закончили создание класса Button – кнопка. Все проверили, отладили код, и собираемся использовать его в дальнейших проектах для Ардуино. Только как практически пользоваться созданным классом. Не очень удачно получилось.

  • В новую программу надо скопировать описание класса и код методов. При этом необходимо выделить эти блоки из старой программы и ничего не перепутать.
  • Эти части программы давно проверены, отлажены и забыты. Тем не менее, они будут постоянно попадаться на глаза, увеличивать код программы, ухудшать ее структурность и читаемость.
  • Еще в эти модули можно случайно занести ошибку, и потом, скопировать ошибочный вариант в следующие программы.

 

Красивое и практичное решение – создать библиотеку для объекта типа Button.

Последовательность действий для создания библиотеки в программах для Ардуино.

Библиотека в Ардуино это не что иное, как дополнительный класс. Поэтому, прежде всего, необходимо определить функции для библиотеки как класс. Как это сделать, подробно описано в уроке 7.

Оформите свои функции как класс, прежде чем производить дальнейшие действия, а мы используем готовый класс Button из урока 8.

Библиотека должна иметь как минимум два файла:

  • заголовочный файл (расширение .h);
  • файл с исходным кодом (расширение .cpp).

В первом файле содержится описание самого класса, переменные, константы. Кода программы здесь нет.  А второй файл содержит программный код методов.

Назовем новую библиотеку Button и создадим заголовочный файл Button.h.

Arduino IDE не поддерживает редактирование текстовых файлов. Редактировать файлы библиотеки можно в любой среде разработки для C++ или в текстовом редакторе, желательно с подсветкой синтаксиса. Я использую Notepad.

 

Заголовочный файл Button.h

Сначала напишем в файл текстовую информацию о библиотеке. Сообщим там все, что считаем нужным: как называется, для чего предназначена, как пользоваться, кто ее создал и т.п. Конечно, текст надо оформить как комментарий.

/*

информация о библиотеке

*/

Все остальное содержимое h-файла мы должны заключить в конструкцию:

// проверка, что библиотека еще не подключена
#ifndef Button_h  // если библиотека Button не подключена
#define Button_h  // тогда подключаем ее

// ............

#endif

Эти директивы исключают повторное подключение библиотеки.

Внутри конструкции следует написать:

#include "Arduino.h"

Директива #include предписывает компилятору включить в код программы текст из файла, имя которого следует после директивы. В данном случае будет включен файл Arduino.h, содержащий стандартные константы и переменные языка Ардуино. В обычных программах он добавляется автоматически, а для библиотеки должен быть указан явно.

Осталось добавить описание нашего класса Button. Полностью файл Button.h выглядит так.

/*
Button.h - библиотека для цифровой обработки сигналов контактов кнопок
 и сигналов других компонентов параллельным процессом
 
В параллельном процессе должен регулярно вызываться один из методов:
    void  scanState();    // метод проверки ожидание стабильного состояния сигнала
    void  filterAvarage(); // метод фильтрации сигнала по среднему значению
 
В результате формируются признаки:
 
 для метода scanState():
 - при нажатой кнопке flagPress= true
 - при отжатой кнопке flagPress= false
 - при нажатии на кнопку flagClick= true

 для метода filterAvarage() :
 - при сигнале низкого уровня flagPress= true
 - при сигнале высокого уровня flagPress= false
 - при изменении состояния с высокого на низкий flagClick= true

Объект типа Button при создании имеет параметры:
 - номер вывода, к которому подключена кнопка или сигнал
 - время обработки сигнала (умножается на период вызова метода scanState() или filterAvarage()

 Button button1(12, 15);  // создание объекта для кнопки, подключенной к 12 выводу
 с временем фильтрации 30 мс (при цикле 2 мс)

 Библиотека разработана Калининым Эдуардом
 http://mypractic.ru/urok-8-cifrovaya-filtraciya-signalov-v-programmax-dlya-arduino.html
 
*/

// проверка, что библиотека еще не подключена
#ifndef Button_h // если библиотека Button не подключена
#define Button_h // тогда подключаем ее

#include "Arduino.h"

// класс обработки сигналов
class Button {
  public:
    Button(byte pin, byte timeButton);  // конструктор
    boolean flagPress;    // признак кнопка нажата (сигнал в низком уровне)
    boolean flagClick;    // признак клика кнопки (фронт)
    void  scanState();    // метод проверки ожидание стабильного состояния сигнала
    void  filterAvarage(); // метод фильтрации по среднему значению
    void setPinTime(byte pin, byte timeButton); // установка номера вывода и времени фильтрации
 
 private:
    byte  _buttonCount;    // счетчик времени фильтрации  
    byte _timeButton;      // время фильтрации
    byte _pin;             // номер вывода
};

#endif

 

Исходный файл библиотеки Button.cpp.

В начале файла разместим ту же самую текстовую информацию, как и в Button.h. Неизвестно какой из файлов будет изучать пользователь.

Далее пишем директивы #include для включения стандартных функций Ардуино и заголовочного файла.

#include "Arduino.h"
#include "Button.h"

А затем коды методов нашего класса.

Полностью файл Button.cpp выглядит так:

/*
Button.h - библиотека для цифровой обработки сигналов контактов кнопок
 и сигналов других компонентов параллельным процессом
 
В параллельном процессе должен регулярно вызываться один из методов:
    void  scanState();    // метод проверки ожидание стабильного состояния сигнала
    void  filterAvarage(); // метод фильтрации сигнала по среднему значению
 
В результате формируются признаки:
 
 для метода scanState():
 - при нажатой кнопке flagPress= true
 - при отжатой кнопке flagPress= false
 - при нажатии на кнопку flagClick= true

 для метода filterAvarage() :
 - при сигнале низкого уровня flagPress= true
 - при сигнале высокого уровня flagPress= false
 - при изменении состояния с высокого на низкий flagClick= true

Объект типа Button при создании имеет параметры:
 - номер вывода, к которому подключена кнопка или сигнал
 - время обработки сигнала (умножается на период вызова метода scanState() или filterAvarage()

 Button button1(12, 15);  // создание объекта для кнопки, подключенной к 12 выводу
 с временем фильтрации 30 мс (при цикле 2 мс)

 Библиотека разработана Калининым Эдуардом
 http://mypractic.ru/urok-8-cifrovaya-filtraciya-signalov-v-programmax-dlya-arduino.html
*/

#include "Arduino.h"
#include "Button.h"
// метод фильтрации сигнала по среднему значению
// при сигнале низкого уровня flagPress= true
// при сигнале высокого уровня flagPress= false
// при изменении состояния с высокого на низкий flagClick= true
void Button::filterAvarage() {

 if ( flagPress != digitalRead(_pin) ) {
     //  состояние кнопки осталось прежним
     if ( _buttonCount != 0 ) _buttonCount--; // счетчик подтверждений - 1 с ограничением на 0
  }
  else {
     // состояние кнопки изменилось
     _buttonCount++;   // +1 к счетчику подтверждений

     if ( _buttonCount >= _timeButton ) {
      // состояние сигнала достигло порога _timeButton
      flagPress= ! flagPress; // инверсия признака состояния
     _buttonCount= 0;  // сброс счетчика подтверждений

      if ( flagPress == true ) flagClick= true; // признак клика кнопки      
     }   
  }
}
// метод проверки ожидание стабильного состояния сигнала
// при нажатой кнопке flagPress= true
// при отжатой кнопке flagPress= false
// при нажатии на кнопку flagClick= true
void Button::scanState() {

 if ( flagPress != digitalRead(_pin) ) {
     // признак flagPress = текущему состоянию кнопки
     // (инверсия т.к. активное состояние кнопки LOW)
     // т.е. состояние кнопки осталось прежним
     _buttonCount= 0;  // сброс счетчика подтверждений состояния кнопки
  }
  else {
     // признак flagPress не = текущему состоянию кнопки
     // состояние кнопки изменилось
     _buttonCount++;   // +1 к счетчику состояния кнопки

     if ( _buttonCount >= _timeButton ) {
      // состояние кнопки не мянялось в течение заданного времени
      // состояние кнопки стало устойчивым
      flagPress= ! flagPress; // инверсия признака состояния
     _buttonCount= 0;  // сброс счетчика подтверждений состояния кнопки

      if ( flagPress == true ) flagClick= true; // признак фронта кнопки на нажатие     
     }   
  }
}
// метод установки номера вывода и времени подтверждения
void Button::setPinTime(byte pin, byte timeButton)  {

  _pin= pin;
  _timeButton= timeButton;
  pinMode(_pin, INPUT_PULLUP);  // определяем вывод как вход
}

// описание конструктора класса Button
Button::Button(byte pin, byte timeButton) {

  _pin= pin;
  _timeButton= timeButton;
  pinMode(_pin, INPUT_PULLUP);  // определяем вывод как вход
}

 

Для того чтобы Arduino IDE выделяла цветом новые типы и методы из нашей библиотеки можно создать файл keywords.txt.

Button KEYWORD1

scanState KEYWORD2
filterAvarage KEYWORD2
setPinTime KEYWORD2

Каждая строка содержит ключевое слово, табуляцию (не пробелы) и тип ключевого слова. KEYWORD1 определяет классы, KEYWORD2 – методы.

Загрузить zip-архив с тремя файлами библиотеки Button можно здесь.

Теперь нужно правильно разместить файлы библиотеки.

Я сделал так:

  • Запустил Arduino IDE.
  • Файл -> Настройки -> Размещение папки скетчей  задал D:\Arduino Projects.  Это я  указал папку моих проектов Ардуино (D:\Arduino Projects).
  • В этой папке я создал папку libraries (D:\Arduino Projects\libraries).
  • В папке libraries создал папку новой библиотеки Button (D:\Arduino Projects\libraries\Button).
  • И уже в эту папку скопировал файлы Button.h, Button.cpp и keywords.txt.

Для проверки надо закрыть и заново запустить Arduino IDE. Открыть Скетч -> Подключть библиотеку и посмотреть, что в списке библиотек присутствует новая библиотека Button.

 

Как пользоваться библиотекой.

Очень просто. В начале программы включить заголовочный файл директивой

#include <Button.h>

Теперь можно пользоваться всеми открытыми методами и переменными класса Button абсолютно так же, как в предыдущем уроке.

Перепишем программу управления светодиодами из предыдущего урока. Естественно с использованием библиотеки Button.

/*  Программа sketch_9_1 урока 9
 *  К плате Ардуино подключены 2 кнопки и светодиод
 *  Каждое нажатие кнопки 1 инвертирует состояние светодиода на плате Ардуино
 *  Каждое нажатие кнопки 2 инвертирует состояние светодиода на макетной плате */

#include <Button.h>

#define LED_1_PIN 13     // светодиод 1 подключен к выводу 13
#define BUTTON_1_PIN 12  // кнопка 1 подключена к выводу 12
#define BUTTON_2_PIN 11  // кнопка 2 подключена к выводу 11
#define LED_2_PIN 10     // светодиод 2 подключен к выводу 10

boolean ledState1;         // переменная светодиода 1
boolean ledState2;         // переменная светодиода 2

Button button1(BUTTON_1_PIN, 15);  // создание объекта для кнопки 1
Button button2(BUTTON_2_PIN, 15);  // создание объекта для кнопки 2
  
void setup() {
  pinMode(LED_1_PIN, OUTPUT);           // определяем выводы светодиодов как выходы
  pinMode(LED_2_PIN, OUTPUT);          
}

// цикл с периодом 2 мс
void loop() {

  button1.filterAvarage();  // вызов метода фильтрации по среднему для кнопки 1
  button2.scanState();  // вызов метода ожидания стабильного состояния для кнопки 2

 
  // блок управления светодиодом 1
  if ( button1.flagClick == true ) {
    // был клик кнопки
    button1.flagClick= false;         // сброс признака
    ledState1= ! ledState1;             // инверсия состояние светодиода
    digitalWrite(LED_1_PIN, ledState1);  // вывод состояния светодиода   
  }

  // блок управления светодиодом 2
  if ( button2.flagClick == true ) {
    // был клик кнопки
    button2.flagClick= false;         // сброс признака
    ledState2= ! ledState2;             // инверсия состояние светодиода
    digitalWrite(LED_2_PIN, ledState2);  // вывод состояния светодиода   
  }

  delay(2);  // задержка 2 мс
}

Ничего лишнего. Только объекты, с которыми мы работаем.

Хороший стиль добавить в файлы библиотеки примеры. Но у нас в последующих уроках примеров будет достаточно.

 

В следующем уроке мы научимся работать с прерываниями по аппаратному таймеру.

Предыдущий урок     Список уроков     Следующий урок

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *