Файл: Методические указания к выполнению лабораторных работ по дисциплине Основы электротехники в робототехнике.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 08.11.2023

Просмотров: 176

Скачиваний: 5

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.


void loop() {

if (digitalRead(BUTTON_PIN) == LOW) { //кнопка нажата

tone(BUZZER_PIN, 1000); //частота 1000 Гц на пищалку

delay (300); //задержка 0,3 сек

noTone(BUZZER_PIN);//прекращаем генерацию;

delay (300); //задержка 0,3 сек

else { //кнопка отпущена

noTone(BUZZER_PIN);//прекращаем генерацию;

}

}

2.5 Классы в программах Ардуино. Кнопка как объект.


( http://mypractic.ru/urok-7-klassy-v-programmax-arduino-knopka-kak-obekt.html )


На предыдущем этапе написали рабочий, отлаженный программный блок, который можно вполне использовать в последующих программах. Но как-то не совсем красиво получилось.

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

  • Надо определить для него переменные, ничего не забыть.

  • А если нам необходимо подключить несколько кнопок. Для каждой из них надо завести свои переменные, свои программные блоки, свои функции. И ничего не перепутать.

  • При каждом использовании программного блока обработки сигнала кнопки придется вспоминать, как он работает, какие переменные требует и, самое главное, менять имена переменных в тексте блока.

И это притом, что мы используем один и тот же простой объект – кнопку. Для красивого решения этих проблем в языке программирования Ардуино существуют классы

Классы в C++ для Ардуино.

Классы позволяют программисту создавать новые типы объектов. Они состоят из свойств и методов.  Свойства – это данные, которыми можно характеризовать объект класса. Методы – это функции, которые могут выполнять действия над свойствами класса.

  • Свойства класса это его переменные.

  • Методы класса это его  функции.

Определение класса выглядит так:

class имя_класса  { члены класса };

Члены класса это переменные, функции, другие классы и т.п.

Создание класса для обработки сигналов кнопок Button.

Создадим класс для нашего объекта кнопки. Назовем его Button.

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


boolean flagPress= false;    // признак кнопка сейчас нажата
boolean flagClick= false;    // признак кнопка была нажата (клик)
byte  buttonCount= 0;        // счетчик подтверждений стабильного состояния
#define TIME_BUTTON 15       // время стабильного состояния (* 2 мс)


К этим переменным необходимо добавить номер вывода, к которому подключена кнопка, и константу TIME_BUTTON надо объявить переменной, чтобы для каждой кнопки можно было задавать свое время подтверждения.

Оформим перечисленные переменные как свойства класса.

// Описание класса обработки сигналов кнопок
class Button {


boolean flagPress;    // признак кнопка сейчас нажата
boolean flagClick;    // признак кнопка была нажата (клик)
byte  buttonCount;    // счетчик подтверждений стабильного состояния   
byte timeButton;      // время подтверждения состояния кнопки
byte _pin;            // номер вывода
 };


Button – это имя класса, а в скобках указаны его свойства (переменные).

 
Модификаторы доступа private и public.

Все свойства и методы класса имеют права доступа. Например, счетчик buttonCount используется только самим классом для собственных вычислений. Никогда к нему не будут обращаться другие программные модули. Логично запретить доступ к нему всех функций, кроме методов своего класса Button.

Для этого в языке C++ существуют модификаторы private и public.

  • Функции и переменные, которые находятся после модификатора public, доступны из любого места программы.

  • После модификатора private размещаются закрытые функции и переменные. С ними могут работать только методы собственного класса. Если отсутствует модификатор public, то все члены класса считаются закрытыми.

Нам надо выбрать, какие переменные (свойства) сделать открытыми, а какие – закрытыми. Хороший стиль объектно-ориентированного программирования предполагает, что все переменные должны быть закрытыми. А обращение к ним происходит через методы (функции) класса. Но надо сделать поправку на то, что мы пишем программу для микроконтроллера с ограниченной производительностью. А вызов любой функции занимает определенное время. Поэтому, свойства, к которым программа обращается часто, следует сделать открытыми и обращаться к ним явно. Это уменьшит время выполнения программы.



В нашем случае это признаки flagPress и flagClick. К ним постоянно обращается программа для контроля состояния кнопок. А номер вывода _pin и время подтверждения  timeButtonобычно устанавливаются только один раз. Сделаем эти переменные закрытыми. Устанавливать их будем из дополнительного метода.

С учетом вышесказанного наш класс будет выглядеть так.

// Описание класса обработки сигналов кнопок
class Button {


  public:
    boolean flagPress;    // признак кнопка сейчас нажата
     boolean flagClick;    // признак кнопка была нажата (клик)


  private:
    byte  _buttonCount;    // счетчик подтверждений стабильного состояния   
     byte _timeButton;      // время подтверждения состояния кнопки
    byte _pin;            // номер вывода
};


Переменные timeButton и pin нам придется заявлять как аргументы метода для установки значений. Поэтому мы добавили _ перед именами, чтобы отличать аргументы метода и переменные класса.

Созданный нами класс пока состоит только из свойств. Надо добавить в него методы – функции.

Нам необходим метод для проверки состояния сигнала кнопки, тот самый, что мы вызывали в цикле каждые 2 мс. Назовем его  scanState (проверка состояния).

Принято названия классов писать в смешанном регистре, начиная с большой буквы, а названия методов - в смешанном регистре, начиная с маленькой буквы, первая часть – глагол.

Т.к. переменные номер вывода и время подтверждения мы сделали закрытыми, то необходима функция установки их значений. Например, setPinTime.

Т.е. для класса Button необходимы два метода.  С методами наш класс будет выглядеть так.
// Описание класса обработки сигналов кнопок
class Button {

  public:
    boolean flagPress;    // признак кнопка сейчас нажата
    boolean flagClick;    // признак кнопка была нажата (клик)

    void scanState();     // метод проверки состояние сигнала
    void setPinTime(byte pin, byte timeButton); // метод установки номера вывода и времени подтверждения

  private:
    byte  _buttonCount;    // счетчик подтверждений стабильного состояния   
    byte _timeButton;      // время подтверждения состояния кнопки
    byte _pin;            // номер вывода
};
Метод void scanState() не имеет аргументов и ничего не возвращает. Метод  void setPinTime(byte pin, byte timeButton) ничего не возвращает и имеет два аргумента: номер вывода и время подтверждения стабильного состояния кнопки.


 

Таким образом, мы объявили класс. Остается написать коды методов. Т.к. методы это функции, то и коды для них оформляются как функции. Можно написать коды прямо внутри класса, но это приведет к плохой читаемости текста программы. Представьте, что в начале программы, где описываются переменные, классы, будут громадные блоки кодов.  Поэтому лучше коды методов написать в конце программы. Отличие кодов методов классов от пользовательских функций заключается только в том, что в первом случае надо указать принадлежность метода к конкретному классу.
void Button:: scanState() {

// код метода

}

Button::  означает, что функция scanState()  это метод класса Button.

Напишем код метода scanState().

// метод проверки состояния кнопки
// flagPress= true  - нажата 
//  flagPress= false - отжата
//  flagClick= true - была нажата (клик)
void Button::scanState() {


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


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


 

      if ( flagPress == true ) flagClick= true; // признак клика на нажатие      
     }    
  }
}

Он повторяет код из предыдущего урока, только в качестве переменных используются свойства класса.

Теперь код  для метода setPinTime(byte pin, byte timeButton). Он совсем простой. Перегружает аргументы метода в закрытые свойства класса и устанавливает режим вывода.
// метод установки номера вывода и времени подтверждения
void Button::setPinTime(byte pin, byte timeButton)  {


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

Мы завершили создание класса Button. Осталось научиться пользоваться им.

Класс  это только описание типа объекта, самого объекта еще нет. Его надо создать. Делается это так же, как и создание переменных при использовании встроенных типов данных.
int x;     // мы создали переменную типа int с именем x


Button button1;   // мы создали объект типа Button с именем button1

Button buttonPlus;   // мы создали еще один объект типа Button с именем buttonPlus
Вы поняли, что теперь добавление новой кнопки в систему можно сделать одной строкой.

Для обращения к членам класса из любого места программы необходимо использовать имя объекта, точку и имя свойства или метода.
button1.flagClick= false;   // переменная flagClick j, объекта button1 = false

button1.scanState();       // вызов метода scanState(), объекта button1

button1.setPinTime(12, 20); // вызов метода setPinTime (), объекта button1 с параметрами 12, 20
Проверка состояния кнопки button1 из любого места программы будет выглядеть так:
if ( button1.flagPress == true )  {

// кнопка нажата  }

Думаю, теперь в программе объяснять ничего не надо. Тем более, что комментариев в ней больше, чем кода.

/*  

Программа sketch_7_1 урока 7 
 *  Каждое нажатие кнопки меняет состояние светодиода */


#define LED_PIN 13     // светодиод подключен к выводу 13
#define BUTTON_PIN 12  // кнопка подключена к выводу 12


// Описание класса обработки сигналов кнопок
class Button {
  public:
    boolean flagPress;    // признак кнопка сейчас нажата
    boolean flagClick;    // признак кнопка была нажата (клик)
    void scanState();     // метод проверки состояние сигнала
    void setPinTime(byte pin, byte timeButton); // метод установки номера вывода и времени (числа) подтверждения


  private:
    byte  _buttonCount;    // счетчик подтверждений стабильного состояния   
    byte  _timeButton;      // время подтверждения состояния кнопки
    byte  _pin;             // номер вывода
};


boolean ledState;         // переменная состояния светодиода

Button button1;   // создание объекта типа Button с именем button1
   
void setup() {
  pinMode(LED_PIN, OUTPUT);           // определяем вывод 13 (светодиод) как выход
button1.setPinTime(BUTTON_PIN, 15); // вызов метода установки объекта button1 с параметрами: номер вывода 12, число подтверждений 15
}


// бесконечный цикл с периодом 2 мс
void loop() {


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