Классы Ардуино по qwone для чайников.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016
Извините на громкое название темы, но похоже я тоже чайник. Так что вменяемого текста от меня не ждите.
Что я требую от классов:
1 - что бы в них обязательно были public методы setup() и loop()
2-  что бы представители этих классов,что из одного класса,что из разных, могли взаимно не тормозить друг друга. 
qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Вот примерно мой типичный каркас программы, я бы сказал разметка каркаса.

/* здесь идет заглавие программы
  и электрические подключения элементов
*/
unsigned long mill;// переменная для millis()
typedef void (*pDo)() ;// тип -функция обработчик
//---------------структуры классы---------
/* здесь идет объявдение и описание структур классов +подключаемые быблиотеки

*/
//--------------Компоновка------------
/* здесь  глобальные переменные программы и создание объектов

*/
//------------main()--------------
void setup() {
  Serial.begin(9600);/*если это надо*/

}

void loop() {
  mill = millis();/*один запрос millis() на один цикл*/


}
/*Скетч использует 1428 байт (4%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 186 байт (9%) динамической памяти, оставляя 1862 байт для локальных переменных. Максимум: 2048 байт.
*/

Что такое классы в языке С++ и в Ардуне тоже читать здесь http://cpp.com.ru/lippman/c13.html

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Следующий этап Пример 1

/* Пример 1

*/
//---------------классы---------
// пример класса Cl_AAA
class Cl_AAA {
   int data;// параметры класса
  public:
    // конструктор класса
    Cl_AAA(int _data):data(_data) {}
    // метод setup()
    void setup() {} //<--- обязательные компоненты класса
    // метод loop()
    void loop() {} //<--- обязательные компоненты класса
}; // <--- не забуде поставить ;
//--------------компоновка------------
Cl_AAA AAA(/*данные класса*/ 10);
//------------main()--------------
void setup() {
  AAA.setup();//<--- здесь идет инициализация компонента класса
}

void loop() {
  AAA.loop();//<--- здесь идет основная работа компонента класса
}

ПС: Пример зажигания светодиода

/* Пример 1.1
  зажигание светодиода
*/
//---------------классы---------
//класс Cl_LED просто зажигает светодиод
class Cl_LED {
    byte pin;//нога светодиода
  public:
    // конструктор класса
    Cl_LED(int _pin): pin(_pin) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      digitalWrite(pin,HIGH);
    }
    // метод loop()
    void loop() {}
};
//--------------компоновка------------
Cl_LED LED(/*нога светодиода*/ 13);
//------------main()--------------
void setup() {
  LED.setup();
}
void loop() {
  LED.loop();
}

ППС:Пример мигания светодиода 

/* Пример 1.2
  мигание светодиода
*/
//---------------классы---------
//класс Cl_LED просто светодиод мигает с полупериодом time
class Cl_LED {
    uint32_t past; // время послед переключения
    uint32_t time; // время полупериода
    bool led; // состояние на светодиоде
    byte pin;//нога светодиода
  public:
    // конструктор класса
    Cl_LED(int _pin, uint32_t _time = 500)
      :    pin(_pin),    time(_time) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      digitalWrite(pin, led = 1);
      past = millis(); //<--- сохраняем время переключения
    }
    // метод loop()
    void loop() {
      if (millis() - past >= time) {
        digitalWrite(pin, led = !led);//<--- переключаем светодиод
        past = millis(); //<--- сохраняем время переключения
      }
    }
};
//--------------компоновка------------
Cl_LED LED(/*нога светодиода*/ 13,/*полу период переключения*/300);
//------------main()--------------
void setup() {
  LED.setup();
}
void loop() {
  LED.loop();
}

ПППС: мигание светодиода по определеной последовательности

/* Пример 1.3
  мигание светодиода с определеной последовательностью
*/
//---------------классы---------
//класс Cl_LED просто светодиод мигает с полупериодом time
const int time[] = {200, 200, 500, 500, 1000, 1000, 300, 300};
const byte num_time = 8; //количество чисел в time[]
class Cl_LED {
    uint32_t past; // время послед переключения
    byte i_time;//номер в последовательности мигания
    bool led; // состояние на светодиоде
    byte pin;//нога светодиода
  public:
    // конструктор класса
    Cl_LED(int _pin): pin(_pin) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      i_time = 0; //устанавливаем послед мигания в начало
      digitalWrite(pin, led = 1);
      past = millis();
    }
    // метод loop()
    void loop() {
      if (millis() - past >= time[i_time]) {
        ++i_time; // переход на след шаг последовательности
        if (i_time >= num_time)i_time = 0;//если послед закончилась,начать с начала
        digitalWrite(pin, led = !led);//<--- переключаем светодиод
        past = millis(); //<--- сохраняем время переключения
      }
    }
};
//--------------компоновка------------
Cl_LED LED(/*нога светодиода*/ 13);
//------------main()--------------
void setup() {
  LED.setup();
}
void loop() {
  LED.loop();
}

 

b707
Онлайн
Зарегистрирован: 26.05.2017

черезчур академично. Новички ничего не поймут, а кто разбирается - умрут со скуки.

Кстати, теоретически ваши ссылочные классы таят в себе потенциальные проблемы... вот почитайте

http://pages.cs.wisc.edu/~hasti/cs368/CppTutorial/NOTES/CLASSES-PTRS.html

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Выкладываю дальше . Кнопки

Этот пример для кнопки подключеной на вывод и землю.

/* Пример 2.0
  Кнопка пин 1 <-> Ардуино пин 2
         пин 2 <-> Ардуино GND
         принцип кода : нажатие на кнопку отсылает в Serial что кнопку нажали
*/
unsigned long mill;// переменная для millis()
typedef void (*pDo)() ;// тип -функция обработчик
//--------------- Cl_Btn---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
  protected:
    byte pin; // номер ноги на кнопке
    pDo Do;// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    /* конструктор класса*/
    Cl_Btn( byte p ,pDo Do_): pin(p), Do(Do_) {}
    // метод setup()
    void init() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void run() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//--------------компоновка------------
void Do_Btn1() {
  Serial.println("Btn1 press");
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);
//------------main()--------------
void setup() {
  Serial.begin(9600);
  Btn1.init();
}
void loop() {
  mill = millis();
  Btn1.run();
}
/*Скетч использует 2020 байт (6%) памяти устройства. Всего доступно 30720 байт.
  Глобальные переменные используют 210 байт (10%) динамической памяти, оставляя 1838 байт для локальных переменных. Максимум: 2048 байт.
*/

ПС: Такой же код для кнопки подключеной на+5В через резистор 10к

/* Пример 2.1
  Кнопка пин 1 <-> Ардуино пин 2
         пин 2 <-> на +5В, через резистор 10кОм 
         принцип кода : нажатие на кнопку отсылает в Serial кнопкe нажали
*/
//---------------классы---------
//класс кнопка подключ на питание через резистор 10кОм
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (!btn_old && btn) Do();
      }
    }
};
//--------------компоновка------------
void Do_Btn1() {
  Serial.println("Btn1 press");
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);
//------------main()--------------
void setup() {
  Serial.begin(9600);
  Btn1.setup();
}
void loop() {
  Btn1.loop();
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

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

/* Пример 3.0
  Кнопка 1 пин 1 <-> Ардуино пин 2
           пин 2 <-> Ардуино GND
  Кнопка 2 пин 1 <-> Ардуино пин 3
           пин 2 <-> Ардуино GND
  Кнопка 3 пин 1 <-> Ардуино пин 4
           пин 2 <-> Ардуино GND
   принцип кода : нажатие на кнопку отсылает в Serial что кнопку нажали
*/
//---------------классы---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//--------------компоновка------------
// надо повторить в разделе компоновка объявление для каждой кнопки

// кнопка 1
void Do_Btn1() {
  Serial.println("Btn1 press");
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);
// кнопка 2
void Do_Btn2() {
  Serial.println("Btn2 press");
}
Cl_Btn Btn2(/*пин*/3,/*обработчик*/Do_Btn2);
// кнопка 3
void Do_Btn3() {
  Serial.println("Btn3 press");
}
Cl_Btn Btn3(/*пин*/4,/*обработчик*/Do_Btn3);
//------------main()--------------
void setup() {
  Serial.begin(9600);
  Btn1.setup();  //<  так же для каждой кнопки вставить свой  setup()
  Btn2.setup();  //<
  Btn3.setup();  //<
}
void loop() {
  Btn1.loop();  //<  так же для каждой кнопки вставить свой  loop()
  Btn2.loop();  //<
  Btn3.loop();  //<
}

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

Такой же код для кнопок подключеных к +5В через резистор 10к

/* Пример 3.1
  Кнопка 1 пин 1 <-> Ардуино пин 2
           пин 2 <-> на +5В, через резистор 10кОм 
  Кнопка 2 пин 1 <-> Ардуино пин 3
           пин 2 <-> на +5В, через резистор 10кОм 
  Кнопка 3 пин 1 <-> Ардуино пин 4
           пин 2 <-> на +5В, через резистор 10кОм 
   принцип кода : нажатие на кнопку отсылает в Serial что кнопку нажали
*/
//---------------классы---------
//класс кнопка подключ на питание через резистор 10кОм
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (!btn_old && btn) Do();
      }
    }
};
//--------------компоновка------------
// надо повторить в разделе компоновка объявление для каждой кнопки

// кнопка 1
void Do_Btn1() {
  Serial.println("Btn1 press");
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);
// кнопка 2
void Do_Btn2() {
  Serial.println("Btn2 press");
}
Cl_Btn Btn2(/*пин*/3,/*обработчик*/Do_Btn2);
// кнопка 3
void Do_Btn3() {
  Serial.println("Btn3 press");
}
Cl_Btn Btn3(/*пин*/4,/*обработчик*/Do_Btn3);
//------------main()--------------
void setup() {
  Serial.begin(9600);
  Btn1.setup();  //<  так же для каждой кнопки вставить свой  setup()
  Btn2.setup();  //<
  Btn3.setup();  //<
}
void loop() {
  Btn1.loop();  //<  так же для каждой кнопки вставить свой  loop()
  Btn2.loop();  //<
  Btn3.loop();  //<
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Теперь вариант 3 кнопки управляют 1 светодиодом: первая включает, вторая выключает, третья заставляет мигать светодиод.

/* Пример 4.0
  светодиод пин(+) <-> через резистор 1кОм Ардуино пин 13
            пин(-) <-> Ардуино GND
  Кнопка 1 пин 1 <-> Ардуино пин 2
           пин 2 <-> Ардуино GND
  Кнопка 2 пин 1 <-> Ардуино пин 3
           пин 2 <-> Ардуино GND
  Кнопка 3 пин 1 <-> Ардуино пин 4
           пин 2 <-> Ардуино GND
   принцип кода : нажатие на кнопку отсылает в Serial что кнопку нажали
*/
//---------------Cl_Led---------
//класс Cl_Led управление  светодиодом
class Cl_Led {
    byte pin;//нога светодиода
    bool led;// уровень на выводе светодиода
    bool blink_ON;// если 1, то мигать
    uint32_t time;// полупериод мигания светодиода
    uint32_t past;// время последнего переключения
  public:
    // конструктор класса
    Cl_Led(int _pin): pin(_pin) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      digitalWrite(pin, HIGH);
    }
    // метод loop()
    void loop() {
      if (!blink_ON) return; // выход если нет режима мигания
      if (millis() - past >= time) { // если подошло время переключить светодиод
        past = millis();
        digitalWrite(pin, led = !led);
      }
    }
    // включить светодиод
    void ON() {
      blink_ON = 0;// режим не мигать
      digitalWrite(pin, led = 1);// и зажечь светодиод
    }
    // выключить светодиод
    void OFF() {
      blink_ON = 0;// режим не мигать
      digitalWrite(pin, led = 0);// и погасить светодиод
    }
    // мигать светодиодом
    void blink(uint32_t _time = 500) {
      time = _time;
      blink_ON = 1;// режим мигать
      past = millis();
      digitalWrite(pin, led = 1);// и зажечь светодиод
    }
};
//---------------Cl_Btn---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//--------------компоновка------------
// светодиод 1
Cl_Led Led1(/*пин*/13);
// кнопка 1
void Do_Btn1() {
  Led1.ON();// включить светодиод
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);
// кнопка 2
void Do_Btn2() {
  Led1.OFF();// выключить светодиод
}
Cl_Btn Btn2(/*пин*/3,/*обработчик*/Do_Btn2);
// кнопка 3
void Do_Btn3() {
  Led1.blink(300);// мигать с полупериодом 0.3 сек
}
Cl_Btn Btn3(/*пин*/4,/*обработчик*/Do_Btn3);
//------------main()--------------
void setup() {
  Led1.setup(); //<  теперь уже 4 setup : для 1 светодиода и 3-х кнопок
  Btn1.setup();
  Btn2.setup();
  Btn3.setup();
}
void loop() {
  Led1.loop(); //<  теперь уже 4 loop : для 1 светодиода и 3-х кнопок
  Btn1.loop();
  Btn2.loop();
  Btn3.loop();
}

ПС: Добавлен бит инверсии, который позволяет зажигать светодиод 0 и гасить 1

/* Пример 4.1
  светодиод <-> через резистор 1кОм Ардуино пин 12
  Кнопка 1 пин 1 <-> Ардуино пин 2
           пин 2 <-> Ардуино GND
  Кнопка 2 пин 1 <-> Ардуино пин 3
           пин 2 <-> Ардуино GND
  Кнопка 3 пин 1 <-> Ардуино пин 4
           пин 2 <-> Ардуино GND
   принцип кода : нажатие на кнопку отсылает в Serial что кнопку нажали
*/
//---------------Cl_Led---------
//класс Cl_Led управление  светодиодом
class Cl_Led {
    const byte pin;//нога светодиода
    bool led;// уровень на выводе светодиода
    const bool inv;// 1, если при 0 светодиод горит при 0 нет
    bool blink_ON;// если 1, то мигать
    uint32_t time;// полупериод мигания светодиода
    uint32_t past;// время последнего переключения
  public:
    // конструктор класса
    Cl_Led(int _pin, bool _inv = 0): pin(_pin), inv(_inv) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      led = 0;
      digitalWrite(pin, led ^ inv);
    }
    // метод loop()
    void loop() {
      if (!blink_ON) return; // выход если нет режима мигания
      if (millis() - past >= time) { // если подошло время переключить светодиод
        past = millis();
        led = !led;
        digitalWrite(pin, led ^ inv);
      }
    }
    // включить светодиод
    void ON() {
      blink_ON = 0;// режим не мигать
      led = 1; // и зажечь светодиод
      digitalWrite(pin, led ^ inv);
    }
    // выключить светодиод
    void OFF() {
      blink_ON = 0;// режим не мигать
      led = 0;// и погасить светодиод
      digitalWrite(pin, led ^ inv);
    }
    // мигать светодиодом
    void blink(uint32_t _time = 500) {
      time = _time;
      blink_ON = 1;// режим мигать
      past = millis();
      led = 1;// и зажечь светодиод
      digitalWrite(pin, led ^ inv);
    }
};
//---------------Cl_Btn---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
    const byte pin; // номер ноги на кнопке
    const void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//--------------компоновка------------
Cl_Led Led1(/*пин*/12,/*инверсия*/1);
void Do_Btn1() {
  Led1.ON();// включить светодиод
}
void Do_Btn2() {
  Led1.OFF();// выключить светодиод
}
void Do_Btn3() {
  Led1.blink(200);// мигать с полупериодом 0.3 сек
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);
Cl_Btn Btn2(/*пин*/3,/*обработчик*/Do_Btn2);
Cl_Btn Btn3(/*пин*/4,/*обработчик*/Do_Btn3);
//------------main()--------------
void setup() {
  Led1.setup();
  Btn1.setup();
  Btn2.setup();
  Btn3.setup();
}
void loop() {
  Led1.loop();
  Btn1.loop();
  Btn2.loop();
  Btn3.loop();
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Если вам надо одной кнопкой выбирать 1 из трех режимов, то вот вам пример программы

/* Пример 5.0
  светодиод <-> через резистор 1кОм Ардуино пин 13
  Кнопка 1 пин 1 <-> Ардуино пин 2
           пин 2 <-> Ардуино GND
   принцип кода : 1 нажатие включает светодиод
                  2 нажатие выключает светодиод
                  3 нажатие мигание
                  и дальше по кругу
*/
//---------------Cl_Led---------
//класс Cl_Led управление  светодиодом
class Cl_Led {
    const byte pin;//нога светодиода
    bool led;// уровень на выводе светодиода
    const bool inv;// 1, если при 0 светодиод горит при 0 нет
    bool blink_ON;// если 1, то мигать
    uint32_t time;// полупериод мигания светодиода
    uint32_t past;// время последнего переключения
  public:
    // конструктор класса
    Cl_Led(int _pin, bool _inv = 0): pin(_pin), inv(_inv) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      led = 0;
      digitalWrite(pin, led ^ inv);
    }
    // метод loop()
    void loop() {
      if (!blink_ON) return; // выход если нет режима мигания
      if (millis() - past >= time) { // если подошло время переключить светодиод
        past = millis();
        led = !led;
        digitalWrite(pin, led ^ inv);
      }
    }
    // включить светодиод
    void ON() {
      blink_ON = 0;// режим не мигать
      led = 1; // и зажечь светодиод
      digitalWrite(pin, led ^ inv);
    }
    // выключить светодиод
    void OFF() {
      blink_ON = 0;// режим не мигать
      led = 0;// и погасить светодиод
      digitalWrite(pin, led ^ inv);
    }
    // мигать светодиодом
    void blink(uint32_t _time = 500) {
      time = _time;
      blink_ON = 1;// режим мигать
      past = millis();
      led = 1;// и зажечь светодиод
      digitalWrite(pin, led ^ inv);
    }
};
//---------------Cl_Btn---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
    const byte pin; // номер ноги на кнопке
    const void (* Do1)(), (* Do2)(), (* Do3)(); // указатели на обработчики 1,2,3
    byte mode;// какой из 3 обработчиков выполнить
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do1)(), void (* _Do2)(), void (* _Do3)())
      :      pin(_pin),    Do1(_Do1) ,      Do2(_Do2) ,      Do3(_Do3) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
      mode = 0;
      Do1();
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) {
          ++mode;
          if (mode >= 3) mode = 0;
          if (mode == 0) Do1();
          else if (mode == 1) Do2();
          else Do3();
        }
      }
    }
};
//--------------компоновка------------
Cl_Led Led1(/*пин*/13,/*инверсия*/0);
void Do1_Btn1() {
  Led1.ON();// включить светодиод
}
void Do2_Btn1() {
  Led1.OFF();// выключить светодиод
}
void Do3_Btn1() {
  Led1.blink(500);// мигать с полупериодом 0.5 сек
}
Cl_Btn Btn1(/*пин*/2,/*обработчик 1*/Do1_Btn1,/*обработчик 2*/Do2_Btn1,/*обработчик 3*/Do3_Btn1);
//------------main()--------------
void setup() {
  Led1.setup();
  Btn1.setup();
}
void loop() {
  Led1.loop();
  Btn1.loop();
}

 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

qwone, ну шо за ересь? - прекращай бредить.

не существует никаких особенных классов для Ардуино - в Ардуино ИДЕ работают классы С++.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Следующий вариант: кнопка на пине 2 переключает мигание одного из четырех светодиодов (пины 6,7,8,9)

/* Пример 5.1
  светодиод 1 через резистор 1кОм <->Ардуино пин 6
  светодиод 2 через резистор 1кОм <->Ардуино пин 7
  светодиод 3 через резистор 1кОм <->Ардуино пин 8
  светодиод 4 через резистор 1кОм <->Ардуино пин 9
  Кнопка 1 пин 1 <-> Ардуино пин 2
           пин 2 <-> Ардуино GND
   принцип кода : 1 нажатие 1 светодиод горит остальные погашены
                  2 нажатие 2 светодиод горит остальные погашены
                  3 нажатие 3 светодиод горит остальные погашены
                  4 нажатие 4 светодиод горит остальные погашены
                  и дальше по кругу
*/
//---------------Cl_Led---------
//класс Cl_Led управление  светодиодом
class Cl_Led {
    const byte pin;//нога светодиода
    bool led;// уровень на выводе светодиода
    const bool inv;// 1, если при 0 светодиод горит при 0 нет
    bool blink_ON;// если 1, то мигать
    uint32_t time;// полупериод мигания светодиода
    uint32_t past;// время последнего переключения
  public:
    // конструктор класса
    Cl_Led(int _pin, bool _inv = 0): pin(_pin), inv(_inv) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      led = 0;
      digitalWrite(pin, led ^ inv);
    }
    // метод loop()
    void loop() {
      if (!blink_ON) return; // выход если нет режима мигания
      if (millis() - past >= time) { // если подошло время переключить светодиод
        past = millis();
        led = !led;
        digitalWrite(pin, led ^ inv);
      }
    }
    // включить светодиод
    void ON() {
      blink_ON = 0;// режим не мигать
      led = 1; // и зажечь светодиод
      digitalWrite(pin, led ^ inv);
    }
    // выключить светодиод
    void OFF() {
      blink_ON = 0;// режим не мигать
      led = 0;// и погасить светодиод
      digitalWrite(pin, led ^ inv);
    }
    // мигать светодиодом
    void blink(uint32_t _time = 500) {
      time = _time;
      blink_ON = 1;// режим мигать
      past = millis();
      led = 1;// и зажечь светодиод
      digitalWrite(pin, led ^ inv);
    }
};
//---------------Cl_Btn---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
    const byte pin; // номер ноги на кнопке
    const void (*Do1)(), (*Do2)(), (*Do3)(), (*Do4)(); // указатели на обработчики 1,2,3,4
    byte mode;// какой из 4 обработчиков выполнить
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do1)(), void (* _Do2)(), void (* _Do3)(), void (* _Do4)())
      :      pin(_pin),    Do1(_Do1)  ,     Do2(_Do2)  ,     Do3(_Do3)  ,     Do4(_Do4) {}
    // метод setup(
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
      mode = 0;
      Do1();
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) {
          ++mode;
          if (mode >= 4) mode = 0;
          if (mode == 0) Do1();
          else if (mode == 1) Do2();
          else if (mode == 2) Do3();
          else Do4();
        }
      }
    }
};
//--------------компоновка------------
Cl_Led Led1(/*пин*/6,/*инверсия*/1);
Cl_Led Led2(/*пин*/7,/*инверсия*/1);
Cl_Led Led3(/*пин*/8,/*инверсия*/1);
Cl_Led Led4(/*пин*/9,/*инверсия*/1);

void Do1_Btn1() {
  Led1.blink(200);// мигать с полупериодом 0.2 сек
  Led2.OFF(); // выключить светодиод
  Led3.OFF(); // выключить светодиод
  Led4.OFF(); // выключить светодиод
}
void Do2_Btn1() {
  Led1.OFF(); // выключить светодиод
  Led2.blink(200); // мигать с полупериодом 0.2 сек
  Led3.OFF(); // выключить светодиод
  Led4.OFF(); // выключить светодиод
}
void Do3_Btn1() {
  Led1.OFF(); // выключить светодиод
  Led2.OFF(); // выключить светодиод
  Led3.blink(200);// мигать с полупериодом 0.2 сек
  Led4.OFF(); // выключить светодиод
}
void Do4_Btn1() {
  Led1.OFF(); // выключить светодиод
  Led2.OFF(); // выключить светодиод
  Led3.OFF(); // выключить светодиод
  Led4.blink(200);// мигать с полупериодом 0.2 сек
}
Cl_Btn Btn1(/*пин*/2,/*обработчик 1*/Do1_Btn1,/*обработчик 2*/Do2_Btn1,/*обработчик 3*/Do3_Btn1,/*обработчик 4*/Do4_Btn1);
//------------main()--------------
void setup() {
  Led1.setup();
  Led2.setup();
  Led3.setup();
  Led4.setup();
  Btn1.setup();
}
void loop() {
  Led1.loop();
  Led2.loop();
  Led3.loop();
  Led4.loop();
  Btn1.loop();
}

Такая же программа но с записью состояния в EEPROM

/* Пример 5.1
  светодиод 1 через резистор 1кОм <->Ардуино пин 6
  светодиод 2 через резистор 1кОм <->Ардуино пин 7
  светодиод 3 через резистор 1кОм <->Ардуино пин 8
  светодиод 4 через резистор 1кОм <->Ардуино пин 9
  Кнопка 1 пин 1 <-> Ардуино пин 2
           пин 2 <-> Ардуино GND
   принцип кода : 1 нажатие 1 светодиод горит остальные погашены
                  2 нажатие 2 светодиод горит остальные погашены
                  3 нажатие 3 светодиод горит остальные погашены
                  4 нажатие 4 светодиод горит остальные погашены
                  и дальше по кругу
*/
//---------------Cl_Led---------
//класс Cl_Led управление  светодиодом
class Cl_Led {
    const byte pin;//нога светодиода
    bool led;// уровень на выводе светодиода
    const bool inv;// 1, если при 0 светодиод горит при 0 нет
    bool blink_ON;// если 1, то мигать
    uint32_t time;// полупериод мигания светодиода
    uint32_t past;// время последнего переключения
  public:
    // конструктор класса
    Cl_Led(int _pin, bool _inv = 0): pin(_pin), inv(_inv) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      led = 0;
      digitalWrite(pin, led ^ inv);
    }
    // метод loop()
    void loop() {
      if (!blink_ON) return; // выход если нет режима мигания
      if (millis() - past >= time) { // если подошло время переключить светодиод
        past = millis();
        led = !led;
        digitalWrite(pin, led ^ inv);
      }
    }
    // включить светодиод
    void ON() {
      blink_ON = 0;// режим не мигать
      led = 1; // и зажечь светодиод
      digitalWrite(pin, led ^ inv);
    }
    // выключить светодиод
    void OFF() {
      blink_ON = 0;// режим не мигать
      led = 0;// и погасить светодиод
      digitalWrite(pin, led ^ inv);
    }
    // мигать светодиодом
    void blink(uint32_t _time = 500) {
      time = _time;
      blink_ON = 1;// режим мигать
      past = millis();
      led = 1;// и зажечь светодиод
      digitalWrite(pin, led ^ inv);
    }
};
//---------------Cl_Btn---------
#include <EEPROM.h>
//класс кнопка подключ на землю с программной подтяжкой и сохранением состояния в EEPROM
class Cl_Btn {
    const int adrEEPROM;// адресс ячейки памяти для сох сост в памяти
    const byte pin; // номер ноги на кнопке
    const void (*Do1)(), (*Do2)(), (*Do3)(), (*Do4)(); // указатели на обработчики 1,2,3,4
    byte mode;// какой из 4 обработчиков выполнить
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do1)(), void (* _Do2)(), void (* _Do3)(), void (* _Do4)(), int _adrEEPROM)
      :      pin(_pin),    Do1(_Do1)  ,     Do2(_Do2)  ,     Do3(_Do3)  , Do4(_Do4), adrEEPROM(_adrEEPROM) {}
    // метод setup(
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
      mode = EEPROM.read(adrEEPROM);
      if (mode >= 4) mode = 0;
      EEPROM.update(adrEEPROM, mode);
      if (mode == 0) Do1();
      else if (mode == 1) Do2();
      else if (mode == 2) Do3();
      else Do4();
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) {
          ++mode;
          if (mode >= 4) mode = 0;
          EEPROM.update(adrEEPROM, mode);
          if (mode == 0) Do1();
          else if (mode == 1) Do2();
          else if (mode == 2) Do3();
          else Do4();
        }
      }
    }
};
//--------------компоновка------------
Cl_Led Led1(/*пин*/6,/*инверсия*/1);
Cl_Led Led2(/*пин*/7,/*инверсия*/1);
Cl_Led Led3(/*пин*/8,/*инверсия*/1);
Cl_Led Led4(/*пин*/9,/*инверсия*/1);

void Do1_Btn1() {
  Led1.blink(200);// мигать с полупериодом 0.2 сек
  Led2.OFF(); // выключить светодиод
  Led3.OFF(); // выключить светодиод
  Led4.OFF(); // выключить светодиод
}
void Do2_Btn1() {
  Led1.OFF(); // выключить светодиод
  Led2.blink(200); // мигать с полупериодом 0.2 сек
  Led3.OFF(); // выключить светодиод
  Led4.OFF(); // выключить светодиод
}
void Do3_Btn1() {
  Led1.OFF(); // выключить светодиод
  Led2.OFF(); // выключить светодиод
  Led3.blink(200);// мигать с полупериодом 0.2 сек
  Led4.OFF(); // выключить светодиод
}
void Do4_Btn1() {
  Led1.OFF(); // выключить светодиод
  Led2.OFF(); // выключить светодиод
  Led3.OFF(); // выключить светодиод
  Led4.blink(200);// мигать с полупериодом 0.2 сек
}
Cl_Btn Btn1(/*пин*/2,/*обработчик 1*/Do1_Btn1,/*обработчик 2*/Do2_Btn1,
                      /*обработчик 3*/Do3_Btn1,/*обработчик 4*/Do4_Btn1,/*адр EEPROM*/ 0x10);
//------------main()--------------
void setup() {
  Led1.setup();
  Led2.setup();
  Led3.setup();
  Led4.setup();
  Btn1.setup();
}
void loop() {
  Led1.loop();
  Led2.loop();
  Led3.loop();
  Led4.loop();
  Btn1.loop();
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Теперь покажу взаимодествие кнопок (+ и -) и серво

/* Пример 6.0
  серва    пин <-> Ардуино пин 4
  Кнопка 1 пин 1 <-> Ардуино пин 2 нажатие на эту кнопку поворачивает серво на 1 шаг против часов
           пин 2 <-> Ардуино GND
  Кнопка 2 пин 1 <-> Ардуино пин 3  нажатие на эту кнопку поворачивает серво на 1 шаг по часов
           пин 2 <-> Ардуино GND
*/
//---------------Cl_Servo---------
// класс серво
#include <Servo.h>
class Cl_Servo {
    Servo *myServo = NULL;// указатель на серво
    const int angle_min = 0;
    const int angle_max = 179;
    const byte pin; // номер ноги на серво
    int angle;// угол сервы
    byte step;// щаг угла поворота
  public:
    // конструктор класса
    Cl_Servo ( byte _pin, byte _step = 5): pin(_pin), step(_step) {}
    // метод setup()
    void setup() {
      myServo = new Servo;// создать серво
      myServo->attach(pin);// активировать серво
      angle = 0;// выставить начальный угол
      myServo->write(angle);// выставить серво на начало
    }
    // метод loop()
    void loop() {}
    // метод write()
    void write(int angle) {
      myServo->write(angle);
    }
    // повернуть серво на шаг вперед
    void up() {
      angle += step;
      if (angle > angle_max) angle = angle_max;
      myServo->write(angle);
    }
    // повернуть серво на шаг назад
    void down() {
      angle -= step;
      if (angle < angle_min) angle = angle_min;
      myServo->write(angle);
    }
};
//---------------Cl_Btn---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void loop() {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//--------------компоновка------------
Cl_Servo Servo(/*пин*/4);
void Do_Btn1() {
  Servo.up();
}
void Do_Btn2() {
  Servo.down();
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);
Cl_Btn Btn2(/*пин*/3,/*обработчик*/Do_Btn2);
//------------main()--------------
void setup() {
  Servo.setup();
  Btn1.setup();
  Btn2.setup();
}
void loop() {
  Servo.loop();
  Btn1.loop();
  Btn2.loop();
}

Та же программа, но если кнопки будут удерживаться, то будут повторно посылаться команды

/* Пример 6.1
  серва    пин <-> Ардуино пин 4
  Кнопка 1 пин 1 <-> Ардуино пин 2 нажатие на эту кнопку поворачивает серво на 1 шаг против часов
           пин 2 <-> Ардуино GND
  Кнопка 2 пин 1 <-> Ардуино пин 3  нажатие на эту кнопку поворачивает серво на 1 шаг по часов
           пин 2 <-> Ардуино GND
*/
//---------------Cl_Servo---------
// класс серво
#include <Servo.h>
class Cl_Servo {
    Servo *myServo = NULL;// указатель на серво
    const int angle_min = 0;
    const int angle_max = 179;
    const byte pin; // номер ноги на серво
    int angle;// угол сервы
    byte step;// щаг угла поворота
  public:
    // конструктор класса
    Cl_Servo ( byte _pin, byte _step = 5): pin(_pin), step(_step) {}
    // метод setup()
    void setup() {
      myServo = new Servo;// создать серво
      myServo->attach(pin);// активировать серво
      angle = 0;// выставить начальный угол
      myServo->write(angle);// выставить серво на начало
    }
    // метод loop()
    void loop() {}
    // метод write()
    void write(int angle) {
      myServo->write(angle);
    }
    // повернуть серво на шаг вперед
    void up() {
      angle += step;
      if (angle > angle_max) angle = angle_max;
      myServo->write(angle);
    }
    // повернуть серво на шаг назад
    void down() {
      angle -= step;
      if (angle < angle_min) angle = angle_min;
      myServo->write(angle);
    }
};
//---------------Cl_Btn---------
//класс кнопка подключ на землю с программной подтяжкой
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn_next, btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
    uint32_t past1 = 0 ;
    const uint16_t time = 200; // если кнопка нажата больше 0,2 секунды, то вызывается еще раз обработчик
  public:
    // конструктор класса
    Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    // метод setup()
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // метод loop()
    void loop() {
      btn_next = digitalRead(pin); // считать состояние кнопки
      if (! bounce && btn != btn_next) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = btn_next ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) {
          Do();
        }
      }
      if (btn_next) past1 = millis();
      if (!btn_next && millis() - past1 >= time) { // если кнопка все еще нажата
        past1 = millis();
        Do();
      }
    }
};
//--------------компоновка------------
Cl_Servo Servo(/*пин*/4);
void Do_Btn1() {
  Servo.up();
}
void Do_Btn2() {
  Servo.down();
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);
Cl_Btn Btn2(/*пин*/3,/*обработчик*/Do_Btn2);
//------------main()--------------
void setup() {
  Servo.setup();
  Btn1.setup();
  Btn2.setup();
}
void loop() {
  Servo.loop();
  Btn1.loop();
  Btn2.loop();
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Cкетч на тему LCD Key Shield . Мой аналог этого скетча https://geekelectronics.org/arduino/podklyuchenie-lcd-keypad-shield-k-arduino.html

/*LCD Key Shield
*/
#include <LiquidCrystal.h>
//--------------------Cl_analog--------------------------------
class Cl_analog {
    const byte pin;
    int  data_next, data, data_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
    void (*Do_Right)(), (*Do_Up)(), (*Do_Down)(), (*Do_Left)(), (*Do_Select)();
  public:
    Cl_analog(byte _pin, void (*_Do_Right)(), void (*_Do_Up)(), void (*_Do_Down)(), void (*_Do_Left)(),  void (*_Do_Select)())
      :       pin(_pin), Do_Right(_Do_Right),  Do_Up(_Do_Up),  Do_Down(_Do_Down) , Do_Left(_Do_Left), Do_Select(_Do_Select) {}
    void setup() {
      data = analogRead (pin);
    }
    void loop() {
      data_next = analogRead (pin);
      if (! bounce && data != data_next) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        data_old = data ;
        data = data_next ;
        if (data_old > 1000) {
          if (data < 60) Do_Right();
          else if (data < 200) Do_Up();
          else if (data < 400) Do_Down();
          else if (data < 600) Do_Left();
          else if (data < 800) Do_Select() ;
        }
      }
    }
};
//---------------Компоновка----------------------------------------------
LiquidCrystal lcd(/*RS*/8,/*Enable*/9,/*DB4*/4,/*DB5*/5,/*DB6*/6,/*DB7*/7);
void lcd_setup() {
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("LCD Key Shield");
  lcd.setCursor(0, 1);
  lcd.print("Press Key:None  ");
}
void Do_Right() {
  lcd.setCursor(10, 1);
  lcd.print ("Right ");
}
void Do_Up() {
  lcd.setCursor(10, 1);
  lcd.print ("Up    ");
}
void Do_Down() {
  lcd.setCursor(10, 1);
  lcd.print ("Down  ");
}
void Do_Left() {
  lcd.setCursor(10, 1);
  lcd.print ("Left  ");
}
void Do_Select() {
  lcd.setCursor(10, 1);
  lcd.print ("Select");
}
Cl_analog Keys(/*пин*/A0,/*обработчик вправо*/Do_Right,/*обработчик вверх*/Do_Up,/*обработчик вниз*/Do_Down,/*обработчик влево*/Do_Left,/*обработчик селект*/Do_Select);
//----------------- Main() -----------------------
void setup() {
  lcd_setup();
  Keys.setup();
}
void loop() {
  Keys.loop();
}

 

b707
Онлайн
Зарегистрирован: 26.05.2017

qwone пишет:

Что я требую от классов:
1 - что бы в них обязательно были public методы setup() и loop()

надеюсь, ты не против комментариев? а то пока выглядит, будто это "только твоя" тема :)

По пункту 1 выше я бы все-таки немного подробнее обьяснил - если это тема для новичков. Пока твой текст выглядит так, будто методы setup() и loop() - обязательны для любых классов.  Стоило бы просто написать, что ты создаешь в своих классах единый интерфейс для инициализации и запуска в loop

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

b707, из меня никакой учитель. Просто я в некотором виде создаю библиотеку решений . Ведь одна из сложностей в "новичковом" программировании Ардуины, не возможность работы разных скетчей. Я бы не выкладывал бы эти скетчи, но похоже что это для многих они кажутся загадкой. Вот пусть просвещаются. Тем более для меня это уже прошедший этап. Кому интересно, пусть просвещаются. Можете и вы выкладывать свое и давать свои объяснения. Я не против. 

b707
Онлайн
Зарегистрирован: 26.05.2017

qwone пишет:

ПППС: мигание светодиода по определеной последовательности

/* Пример 1.3
  мигание светодиода с определеной последовательностью
*/
//---------------классы---------
//класс Cl_LED просто светодиод мигает с полупериодом time
const int time[] = {200, 200, 500, 500, 1000, 1000, 300, 300};
const byte num_time = 8; //количество чисел в time[]
class Cl_LED {
    uint32_t past; // время послед переключения
    byte i_time;//номер в последовательности мигания
    bool led; // состояние на светодиоде
    byte pin;//нога светодиода
  public:
    // конструктор класса
    Cl_LED(int _pin): pin(_pin) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      i_time = 0; //устанавливаем послед мигания в начало
      digitalWrite(pin, led = 1);
      past = millis();
    }
    // метод loop()
    void loop() {
      if (millis() - past >= time[i_time]) {
        ++i_time; // переход на след шаг последовательности
        if (i_time >= num_time)i_time = 0;//если послед закончилась,начать с начала
        digitalWrite(pin, led = !led);//<--- переключаем светодиод
        past = millis(); //<--- сохраняем время переключения
      }
    }
};
//--------------компоновка------------
Cl_LED LED(/*нога светодиода*/ 13);
//------------main()--------------
void setup() {
  LED.setup();
}
void loop() {
  LED.loop();
}

 

Позволю себе запостить свой вариант, сделанный из твоего примера 1.3. Главное отличие - схема мигания светодиода хранится в виде битовой маски, что позволяет компакто задавать весьма сложные последовательности.  Если таких последовательностей много( скажем, если делать индикацию работы прибора разными типами миганий) - вариант с битовой маской дает очень серьезный выигрыш в расходе памяти.

/* Пример 1.3.707
  мигание светодиода с последовательностью
  заданной битовой маской
*/
//---------------классы---------
// класс Cl_LED светодиод мигает в последовательности 
// заданной битами числа mode,
// 1- светодиод горит в течении времени period, 0 - выключен

// сигнал СОС азбуки Морзе: ... - - - ... 10101000 11101110 11100010 10100000
const uint32_t mode = ( ((uint32_t)B10101000) << 24)  
                      + ( ((uint32_t)B11101110) <<16 ) 
                      + ( ((uint32_t)B11100010) <<8 ) + B10100000;  

const int period = 100; //Длительность точки, мс
class Cl_LED {
    uint32_t past; // время послед переключения
    uint32_t mask; //  указатель на бит в последовательности мигания
    byte pin; //нога светодиода
  public:
    // конструктор класса
    Cl_LED(int _pin): pin(_pin) {}
    // метод setup()
    void setup() {
      pinMode(pin, OUTPUT);
      mask = 1; //устанавливаем послед мигания в начало
      digitalWrite(pin, HIGH);
      past = millis();
    }
    // метод loop()
    void loop() {
      if (millis() - past >= period) {
        mask <<=1; // переход на след шаг последовательности
        if (mask == 0) mask = 1;//если послед закончилась,начать с начала
        if (mode & mask) digitalWrite(pin,HIGH);
        else digitalWrite(pin,LOW);
        past = millis(); //<--- сохраняем время переключения
      }
    }
};
//--------------компоновка------------
Cl_LED LED(/*нога светодиода*/ 13);
//------------main()--------------
void setup() {
  LED.setup();
}
void loop() {
  LED.loop();
}

 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

qwone, перепроверь как это у тебя работает bool bounce = 0; // антидребезговый флаг

потому как, если у тебя это компилится, то bounce может быть только общей для всех экземпляров класса константой.

так на Дуино ИДЕ 1.0.6 выдаёт правильную ошибку: error: ISO C++ forbids initialization of member 'bounce'

на Дуино ИДЕ 1.8.2 молча компилит, но подозреваю, то само превращает bounce в константу.

ЗЫ. минуса не я ставил - надеюсь, что у этого кармодрочера отсохнет член.

b707
Онлайн
Зарегистрирован: 26.05.2017

Клапауций 112 пишет:

qwone, перепроверь как это у тебя работает bool bounce = 0; // антидребезговый флаг

потому как, если у тебя это компилится, то bounce может быть только общей для всех экземпляров класса константой.

так на Дуино ИДЕ 1.0.6 выдаёт правильную ошибку: error: ISO C++ forbids initialization of member 'bounce'

на Дуино ИДЕ 1.8.2 молча компилит, но подозреваю, то само превращает bounce в константу.

Не, насколько я знаю, раньше это было ошибкой, а в новых версиях стандарта C++ уже допустимо. Это, по-моему, default_member_initialization

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

b707 пишет:

Не, насколько я знаю, раньше это было ошибкой, а в новых версиях стандарта C++ уже допустимо. Это, по-моему, default_member_initialization

ок. а, то я уже расстроился, что новые версии Дуино ИДЕ ломают С++

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

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

/* Cl_Btn.ino
  (Светодиод+R=1кОм)    ардуина
  пин 1 <==> пин 12
  пин 2 <==> GND
    (Светодиод+R=1кОм)    ардуина
  пин 1 <==> пин 11
  пин 2 <==> GND
  кнопка1    ардуина
  пин 1 <==> пин 2 программная подтяжка
  пин 2 <==> GND
    кнопка2    ардуина
  пин 1 <==> пин 3 программная подтяжка
  пин 2 <==> GND
*/
//----------------Led------------------------------------------------------------
class Led {
    byte pin; // нога для подключения светодиода
    bool inv; // 0 светодиод горит при 1/ 1 светодиод горит при 0
    bool stat_ON = 0, led = 0;
    uint32_t time = 500, past = 0;
  public:
    //конструктор
    Led (byte _pin, bool _inv): pin(_pin), inv(_inv) {}
    // setup()
    void setup() {
      pinMode(pin, OUTPUT);// подключить светодиод
      led = 0;
      digitalWrite(pin, led ^ inv) ; // погасить светодиод
    }
    // loop()
    void loop() {
      if (stat_ON && millis() - past >= time)OFF();
    }
    // включить светодиод
    void ON() {
      stat_ON = 0;
      led = 1;
      digitalWrite(pin, led ^ inv) ; // зажечь светодиод
    }
    // включить светодиод на время
    void ON( uint32_t _time) {
      time = _time;
      stat_ON = 1;
      past = millis();
      led = 1;
      digitalWrite(pin, led ^ inv) ; // зажечь светодиод
    }
    // выключить светодиод
    void OFF() {
      stat_ON = 0;
      led = 0;
      digitalWrite(pin, led ^ inv) ; // погасить светодиод
    }
};
//----------------Cl_Btn------------------------------------------------------------
// класс на механич кнопку подкл к кнопке Ардуины.
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (*Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    //конструктор
    Cl_Btn(byte _pin, void (* _Do)()): pin(_pin), Do(_Do){}
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    void loop () {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//------------------компоновка-------------------------------------------------------
Led Led1(/*пин*/12,/*инверсия*/0);// создать светодиод Led1
Led Led2(/*пин*/11,/*инверсия*/0);// создать светодиод Led2
uint32_t time_2s = 2000; //временая константа 2 секунды
void Do_Btn1() {
  Led1.ON(time_2s);
}
void Do_Btn2() {
  Led2.ON(time_2s);
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);// создать кнопку Btn1
Cl_Btn Btn2(/*пин*/3,/*обработчик*/Do_Btn2);// создать кнопку Btn2
//------------------ main()----------------------------------------------------------
void setup() {
  Led1.setup();
  Led2.setup();
  Btn1.setup();
  Btn2.setup();
}

void loop() {
  Led1.loop();
  Led2.loop();
  Btn1.loop();
  Btn2.loop();
}

 

Logik
Offline
Зарегистрирован: 05.08.2014

Вы это специально пример для ООП без ООП сделали)))

Ваше требование - чтоб всегда был сетап и лоп - это методы базового класса. А от него наследуется кнопка и прочие для которых важно чтоб всегда был сетап и лоп. Бонус - все обекты можна хранить в массиве, а значить вызывать их в сетапе и лопе не один за другим (если их много будет - тоска) а в цикле по очереди из массива.

Дальше убираем указатель на Do. В классах так не принято, ведь внутри вашего обработчика Do не получится добратся к данным класа кнопки, а это плохо, там например могут быть флаги двойного клика или еще какая инфа. Для этого в классе кнопки делаете виртуальный метод Do, без реализации. А когда понадобится конкретная кнопка с нужным действием -наследуете от абстрактного типа задав соответствующий обработчик. Бонус - ну допустим нужны кнопки с цифрами 0-9, от абстрактного класса кнопка наследуете класс цифровая кнопка у которого обработчик Do и новое поле - цифра этой кнопки. В конструкторе эту цифру задаете вместе с пином на котором кнопка висит. Дальше создаете 10 обектов класса цифровая кнопка инициализировав их соответствующими цифрами. В итоге при нажатии любой из десяти кнопок вызывается Do цифровой кнопки и в нем есть значение от нажатой кнопки. Ляпота!

Получается иерархия наследования абстрактный класс ардуины-абстрактный класс кнопки-класс цифровой кнопки-обекты кнопок. А если потребуются кнопки со стрелками - от абстрактного класса кнопки унаследуете класс кнопок со стрелками и создадите его обекты стрелка влево и стрелка вправо. Получим 2 обработчика Do один для цифр другой для стрелок - что очень логично. Ну просто оргазм ООПешника!!

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Logik,Разумеется можно и так. Но просто я пока сюда скидываю простые скетчи. Так для "новичков", для которых и классы - "открытие". А для ООП это как до Луны пехом.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Задача : Подключить кнопку Btn1 и два светодиода Led1 и Led2. Нажатие на кнопку - начинает гореть светодиод Led1 5 сек, отжатие кнопки - начинает гореть светодиод Led2 5 сек.

Скетч 

/* 
*/
//----------------Led------------------------------------------------------------
class Led {
    byte pin; // нога для подключения светодиода
    bool inv; // 0 светодиод горит при 1/ 1 светодиод горит при 0
    bool stat_ON = 0, led = 0;
    uint32_t time = 500, past = 0;
  public:
    //конструктор
    Led (byte _pin, bool _inv): pin(_pin), inv(_inv) {}
    // setup()
    void setup() {
      pinMode(pin, OUTPUT);// подключить светодиод
      led = 0;
      digitalWrite(pin, led ^ inv) ; // погасить светодиод
    }
    // loop()
    void loop() {
      if (stat_ON && millis() - past >= time)OFF();
    }
    // включить светодиод
    void ON() {
      stat_ON = 0;
      led = 1;
      digitalWrite(pin, led ^ inv) ; // зажечь светодиод
    }
    // включить светодиод на время
    void ON( uint32_t _time) {
      time = _time;
      stat_ON = 1;
      past = millis();
      led = 1;
      digitalWrite(pin, led ^ inv) ; // зажечь светодиод
    }
    // выключить светодиод
    void OFF() {
      stat_ON = 0;
      led = 0;
      digitalWrite(pin, led ^ inv) ; // погасить светодиод
    }
};
//----------------Cl_Btn------------------------------------------------------------
// класс на механич кнопку подкл к кнопке Ардуины.
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (*Do1)(), (*Do2)(); // указатели на обработчики (нажатия,отжатия)
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    //конструктор
    Cl_Btn(byte _pin, void (* _Do1)(), void (* _Do2)()): pin(_pin), Do1(_Do1), Do2(_Do2) {}
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку  с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    void loop () {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do1(); //если произошло нажатие
        if (!btn_old && btn) Do2(); //если произошло отжатие
      }
    }
};
//------------------компоновка-------------------------------------------------------
Led Led1(/*пин*/12,/*инверсия*/0);// создать светодиод Led1
Led Led2(/*пин*/11,/*инверсия*/0);// создать светодиод Led2
uint32_t time_5s = 5000; //временая константа 5 секунды
void Do1_Btn1() {
  Led1.ON(time_5s);
}
void Do2_Btn1() {
  Led2.ON(time_5s);
}
Cl_Btn Btn1(/*пин*/2,/*обработчик нажатия*/Do1_Btn1,/*обработчик отжатия*/Do2_Btn1);// создать кнопку Btn1
//------------------ main()----------------------------------------------------------
void setup() {
  Led1.setup();
  Led2.setup();
  Btn1.setup();
}

void loop() {
  Led1.loop();
  Led2.loop();
  Btn1.loop();
}
qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

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

/*
*/
//-------------Cl_Btn---------------------------
// класс кнопка без подавления дребезга
class Cl_Btn {
    const byte _pin;// нога
    const void (*_Do)();// указатель на обработчик кнопки
    bool btn, btn_old;
  public:
    Cl_Btn(byte pin, void (*Do)()): _pin(pin), _Do(Do) {}
    void setup() {
      pinMode(_pin, INPUT_PULLUP);
      btn_old = digitalRead(_pin);

    }
    void loop() {
      btn = digitalRead(_pin);
      if (!btn && btn_old) {
        btn_old = 0;// вообщем это сокращение 2-х операций btn_old=btn, где btn=0
        _Do();
      }
      else if (btn && !btn_old) {
        btn_old = 1;// аналогично
      }
    }
};
//---------------компоновка---------------------------
void Do_Btn1() {
    Serial.println("Do_Btn1");
}
Cl_Btn Btn1(/*пин*/2,/*обработчик*/Do_Btn1);// подключим кнопку

//---------------main()---------------------------
void setup() {
  Serial.begin(9600);
  Btn1.setup();
}

void loop() {
  Btn1.loop();
}

 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

масло масляное

void setup() {button.setup();}
void loop () {button.loop ();}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Вот тоже интересный скетч. Вобщем очередь с возможностью добавить элемент в начало или в конец.

/*Lesson1.2
*/
//-------------------------------------------
struct str_Line { // структура формата упаковки
  struct str_Line*next; // указатель на след элемент
  int d; // указатель на строку данных
};
struct str_Line *Start = NULL;
struct str_Line *End = NULL;
int Num = 0;
void AddStart(int data) {   //загрузка буфера
  ++Num;
  struct str_Line *New = new struct str_Line();
  if (End == NULL) End = New;
  New->d = data;
  New->next = Start;
  Start = New;
}
void AddEnd(int data) {   //загрузка буфера
  ++Num;
  struct str_Line *New = new struct str_Line();
  New->d = data;
  New->next = NULL;
  if (Start == NULL) Start = New;
  if (End != NULL) End->next = New;
  End = New;
}
void viev() {  // показ информации
  for (struct str_Line *ii = Start; ii != NULL ; ii = ii->next) {
    Serial.println(ii->d);
  }
}
//------------компоновка----------------------
//------------main()--------------------------
void setup() {
  for (int i = 0; i < 10; ++i) AddStart(i);
  for (int i = 0; i < 10; ++i) AddEnd(i);
  Serial.begin(9600);
  viev();
}

void loop() {
}

То же самое, но добавлены методы убрать элемент в начале, убрать элемент в конце

/*Lesson1.3
*/
//-------------------------------------------
struct str_Line { // структура формата упаковки
  struct str_Line*next; // указатель на след элемент
  int d; // указатель на строку данных
};
class Cl_Sys {
    struct str_Line *Start = NULL;
    struct str_Line *End = NULL;
    int Num = 0;
  public:
    void AddStart(int data) {   //добавить элемент в начало
      ++Num;
      struct str_Line *New = new struct str_Line();
      if (End == NULL) End = New;
      New->d = data;
      New->next = Start;
      Start = New;
    }
    void DelStart() {   //убрать элемент из началa
      if (Start == NULL) return;
      --Num;
      struct str_Line *New = Start->next;
      delete Start;
      Start = New;
    }
    void AddEnd(int data) {   //добавить элемент в конец
      ++Num;
      struct str_Line *New = new struct str_Line();
      New->d = data;
      New->next = NULL;
      if (Start == NULL) Start = New;
      if (End != NULL) End->next = New;
      End = New;
    }
    void DelEnd() {   //убрать элемент из конца
      if (End == NULL) return;
      --Num;
      struct str_Line *New = Start;
      for (int i = 2; i <= Num; ++i)
        New = New->next;
      New->next = NULL;
      delete End;
      End = New;
    }
    void viev() {  // показ информации
      for (struct str_Line *ii = Start; ii != NULL ; ii = ii->next) {
        Serial.println(ii->d);
      }
    }
};
//------------компоновка----------------------
Cl_Sys Sys;
//------------main()--------------------------
void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 5; ++i) Sys.AddEnd(i);
  Sys.viev();
  Serial.println();
  Sys.DelEnd();
  Sys.DelEnd();
  Sys.viev();
}

void loop() {
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Скеч. Два датчика , "мозг" и два исполнительных механизма. Может кому пригодится как схема написания программы.

/**/
//------------------------------------
// класс сенсор
class Cl_sens {
    const byte _pin; // пин
    byte * const _stat;//указатель на состояние датчика
  public:
    Cl_sens(byte pin, byte * stat): _pin(pin), _stat(stat) {}
    void setup() {
      pinMode(_pin, INPUT);
      *_stat = digitalRead(_pin);
    }
    void loop() {
      *_stat = digitalRead(_pin);
    }
};
//-----------------------------------
// класс мозг
class Cl_brain {
    byte * const _brain_array;//указатель на анализируемый массив
  public:
    Cl_brain(byte * brain_array): _brain_array(brain_array) {}
    void setup() {
      _brain_array[2] = _brain_array[0];
      _brain_array[3] = _brain_array[1];
    }
    void loop() {
      _brain_array[2] = _brain_array[0];
      _brain_array[3] = _brain_array[1];
    }
};
//----------------------------------------------------
// класс исполнительный механизм
class Cl_actuating_mechanism {
    const byte _pin; // пин
    byte * const _stat;//указатель на состояние механизма
  public:
    Cl_actuating_mechanism(byte pin, byte * stat): _pin(pin), _stat(stat) {}
    void setup() {
      pinMode(_pin, OUTPUT);
      digitalWrite(_pin, * _stat);
    }
    void loop() {
      digitalWrite(_pin, * _stat);
    }
};
//-------компоновка-------------------------
byte Array[4] = {0, 0, // -- данные сенсора
                 0, 0  // -- команды на исполнительные механизмы
                };
Cl_sens Sens1(/*пин*/2,/*ячейка памяти*/&Array[0]);
Cl_sens Sens2(/*пин*/3,/*ячейка памяти*/&Array[1]);
Cl_brain Brain(/*анализируемый массив*/Array);
Cl_actuating_mechanism Mech1(/*пин*/4,/*ячейка памяти*/&Array[2]);
Cl_actuating_mechanism Mech2(/*пин*/5,/*ячейка памяти*/&Array[3]);
//-------main()-----------------------------
void setup() {
  Sens1.setup();
  Sens2.setup();
  Brain.setup();
  Mech1.setup();
  Mech2.setup();
}

void loop() {
  Sens1.loop();
  Sens2.loop();
  Brain.loop();
  Mech1.loop();
  Mech2.loop();
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Добавлю и этот скетч. Аналог верхнего, но со структурой.

/**/
//------------------------------------
struct str_Array {
  bool sens1; // сенсор 1
  bool sens2; // сенсор 2
  bool mech1; // испол. механ 1
  bool mech2; // испол. механ 2
  str_Array(bool b1, bool b2, bool b3, bool b4 ): sens1(b1), sens2(b2), mech1(b3), mech2(b4) {}
};
//------------------------------------
// класс сенсор
class Cl_sens {
    const byte _pin; // пин
    bool  *_stat;//указатель на состояние датчика
  public:
    Cl_sens(byte pin, bool * stat): _pin(pin), _stat(stat) {}
    void setup() {
      pinMode(_pin, INPUT);
      *_stat = digitalRead(_pin);
    }
    void loop() {
      *_stat = digitalRead(_pin);
    }
};
//-----------------------------------
// класс мозг
class Cl_brain {
    struct str_Array  *Array;//указатель на анализируемый массив
  public:
    Cl_brain(struct str_Array *_Array): Array(_Array) {}
    void setup() {
      Array->mech1 = Array->sens1;
      Array->mech2 = Array->sens2;
    }
    void loop() {
      Array->mech1 = Array->sens1;
      Array->mech2 = Array->sens2;
    }
};
//----------------------------------------------------
// класс исполнительный механизм
class Cl_actuating_mechanism {
    const byte _pin; // пин
    bool * const _stat;//указатель на состояние механизма
  public:
    Cl_actuating_mechanism(byte pin, bool * stat): _pin(pin), _stat(stat) {}
    void setup() {
      pinMode(_pin, OUTPUT);
      digitalWrite(_pin, * _stat);
    }
    void loop() {
      digitalWrite(_pin, * _stat);
    }
};
//-------компоновка-------------------------
struct str_Array Array(0, 0, // -- данные сенсора
                       0, 0  // -- команды на исполнительные механизмы
                      );
Cl_sens Sens1(/*пин*/2,/*ячейка памяти*/&Array.sens1);
Cl_sens Sens2(/*пин*/3,/*ячейка памяти*/&Array.sens2);
Cl_brain Brain(/*анализируемый массив*/&Array);
Cl_actuating_mechanism Mech1(/*пин*/4,/*ячейка памяти*/&Array.mech1);
Cl_actuating_mechanism Mech2(/*пин*/5,/*ячейка памяти*/&Array.mech2);
//-------main()-----------------------------
void setup() {
  Sens1.setup();
  Sens2.setup();
  Brain.setup();
  Mech1.setup();
  Mech2.setup();
}

void loop() {
  Sens1.loop();
  Sens2.loop();
  Brain.loop();
  Mech1.loop();
  Mech2.loop();
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Вот еще код под RFID. Переделал свой старый код под существующую концепцию

/*
  ардуино пин 8  <--> светодиод  0 горит/ 1 нет
  ардуино пин 5  <--> серва
  ардуино пин A3 <--> геркон  0 дверь закрыта / 1 нет
  ардуино пин A1 <--> кнопка1  0 нажата/ 1 нет
  ардуино пин A2 <--> кнопка2  0 нажата/ 1 нет

  ардуино пин 9    <-->  RFID_RC522 RST
  ардуино пин 10   <-->  RFID_RC522 SDA(SS)
  ардуино пин 11   <-->  RFID_RC522 MOSI
  ардуино пин 12   <-->  RFID_RC522 MISO
  ардуино пин 13   <-->  RFID_RC522 SCK
  ардуино пин 3,3В <-->  RFID_RC522 3,3В
  ардуино пин GND  <-->  RFID_RC522 GND

  Card UID: 3862494739  брелок
  Card UID: 1516059093  пластик
*/
//---------------Cl_Lock----------------------------
// класс Замок
#include <Servo.h>
const int time = 2000 ; // интервал после нажатия клавиши 2 сек
const int servo_OFF = 0; // серва закрыта
const int servo_ON = 90; // серва открыта
class Cl_Lock {
    const byte Led_pin     ; // нога светодиода
    const byte servo_pin   ; // нога серво
    const byte gercon_pin  ; // нога геркона
    bool Led ;
    bool gercon ;
    Servo * myservo;
    uint32_t past = 0 ;
  public:
    Cl_Lock(byte _1pin,       byte _2pin,        byte _3pin)
      :  Led_pin(_1pin), servo_pin(_2pin), gercon_pin(_3pin) {}
    void setup() {
      pinMode(Led_pin, OUTPUT);
      digitalWrite(Led_pin, Led = 0);
      myservo = new Servo;
      myservo->attach(servo_pin);
      pinMode(gercon_pin, INPUT_PULLUP);
    }
    void loop() {
      gercon = digitalRead(gercon_pin); // опрос состояния двери
      if (!gercon && !Led && (millis() - past >= time)) { // убеждаемся что дверь закрыта и подошло время закрывать ее на замок
        digitalWrite(Led_pin, Led = 1);
        myservo->write(servo_OFF);  // закрываем
      }
    }
    void ON () {
      digitalWrite(Led_pin, Led = 0);  // oткрываем
      past = millis();
      myservo->write(servo_ON);
    }
};
//----------------Cl_Btn------------------------------------------------------------
// класс на механич кнопку подкл к кнопке Ардуины.
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (*Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    //конструктор
    Cl_Btn(byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {}
    void setup() {
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    void loop () {
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//---------------Cl_RFID----------------------------
#include <SPI.h>
#include <MFRC522.h>
uint32_t Card1 = 3862494739;// 1-я карточка
uint32_t Card2 = 1516059093;// 2-я карточка
class Cl_RFID {
    const int SDA_pin ;
    const int RST_pin ;
    void (*Do)();// указатель на обработчик
    MFRC522 *rfid;
    uint32_t Card;
    uint32_t past = 0 ;
  public:
    Cl_RFID(byte _1pin, byte _2pin, void (* _Do)()): SDA_pin(_1pin), RST_pin(_2pin), Do(_Do) {}
    void setup() {
      SPI.begin(); // Init SPI bus
      rfid = new MFRC522(SDA_pin, RST_pin);
      rfid->PCD_Init();
    }
    void loop() {
      if (millis() - past >= 1000)   {
        past = millis() ;
        if ( rfid->PICC_IsNewCardPresent() && rfid->PICC_ReadCardSerial()) {
          Card = 0;
          for (byte i = 0; i < rfid->uid.size; i++) {// Выдача серийного номера метки.
            Card = Card * 256 + rfid->uid.uidByte[i];
          }
          if (Card == Card1) Do();
          if (Card == Card2) Do();
        }
      }
    }
};
//-------------------------------------------
Cl_Lock  Lock(/*пин светодиода*/8,/*пин сервы*/5,/*пин геркона*/A3);
void Do() {
  Lock.ON();
}
Cl_Btn Btn1 (/*пин*/A1         ,/*обработчик*/Do);// создать кнопку Btn1
Cl_Btn Btn2 (/*пин*/A2         ,/*обработчик*/Do);// создать кнопку Btn2
Cl_RFID RFID(/*SDA*/10,/*RST*/9,/*обработчик*/Do);// создать RFID датчик
//-------------------------------------------
void setup() {
  Lock.setup();
  Btn1.setup();
  Btn2.setup();
  RFID.setup();
}

void loop() {
  Lock.loop();
  Btn1.loop();
  Btn2.loop();
  RFID.loop();
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Продолжение скетча на тему LCD Key Shield #11. Теперь долгое нажатие кнопки вызывает повторно обработчик. На экране не видно. Надо смотреть Serial

/*LCD Key Shield
*/
#include <LiquidCrystal.h>
//--------------------Cl_analog_Keys--------------------------------
class Cl_analog_Keys {
    const byte delta = 5;
    const byte pin;
    int  data_next, data, data_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
    void (*Do_Right)(), (*Do_Up)(), (*Do_Down)(), (*Do_Left)(), (*Do_Select)();
  public:
    Cl_analog_Keys(byte _pin, void (*_Do_Right)(), void (*_Do_Up)(), void (*_Do_Down)(), void (*_Do_Left)(),  void (*_Do_Select)())
      :       pin(_pin), Do_Right(_Do_Right),  Do_Up(_Do_Up),  Do_Down(_Do_Down) , Do_Left(_Do_Left), Do_Select(_Do_Select) {}
    void setup() {
      data = analogRead (pin);
    }
    void loop() {
      data_next = analogRead (pin);
      if (! bounce && millis() - past >= 500) {
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветк
        data = 1100;
      }
      if (! bounce && (data + delta < data_next || data - delta > data_next)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;     // то снять флаг
        past = millis();
        data_old = data ;
        data = data_next ;
        if (data_old > 1000) {
          if (data < 60) Do_Right();
          else if (data < 200) Do_Up();
          else if (data < 400) Do_Down();
          else if (data < 600) Do_Left();
          else if (data < 800) Do_Select() ;
        }
      }
    }
};
//---------------Компоновка----------------------------------------------
LiquidCrystal lcd(/*RS*/8,/*Enable*/9,/*DB4*/4,/*DB5*/5,/*DB6*/6,/*DB7*/7);
void lcd_setup() {
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("LCD Key Shield");
  lcd.setCursor(0, 1);
  lcd.print("Press Key:None  ");
}
void Do_Right() {
  lcd.setCursor(10, 1);
  lcd.print ("Right ");
  Serial.println("Right ");
}
void Do_Up() {
  lcd.setCursor(10, 1);
  lcd.print ("Up    ");
  Serial.println("Up    ");
}
void Do_Down() {
  lcd.setCursor(10, 1);
  lcd.print ("Down  ");
  Serial.println("Down  ");
}
void Do_Left() {
  lcd.setCursor(10, 1);
  lcd.print ("Left  ");
  Serial.println("Left  ");
}
void Do_Select() {
  lcd.setCursor(10, 1);
  lcd.print ("Select");
  Serial.println("Select");
}
Cl_analog_Keys Keys(/*пин*/A0,/*обработчик вправо*/Do_Right,/*обработчик вверх*/Do_Up,/*обработчик вниз*/Do_Down,/*обработчик влево*/Do_Left,/*обработчик селект*/Do_Select);
//----------------- Main() -----------------------
void setup() {
  Serial.begin(9600);
  lcd_setup();
  Keys.setup();
}
void loop() {
  Keys.loop();
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Программа для регулирования времени впрыска с помощью потенциометра

/*
  ардуино пин A0 <--> средний вывод потенциометра
  ардуино пин 2 <--> датчик холла 1
  ардуино пин 3 <--> датчик холла 2
  ардуино пин 4 <--> датчик холла 3
  ардуино пин 5 <--> датчик холла 4
  ардуино пин 6 <--> инжектор 1
  ардуино пин 7 <--> инжектор 2
  ардуино пин 8 <--> инжектор 3
  ардуино пин 9 <--> инжектор 4
*/
//--------------------Cl_Potentiometer---------------------------------------------
class Cl_Potentiometer {
    const byte _pin;
    int *const _pnt;// указатель переменную которая меняет значение по положению ручки потенциометра
    uint32_t past = 0;
  public:
    Cl_Potentiometer(byte pin, int *pnt): _pin(pin), _pnt(pnt) {}
    void setup() {
      *_pnt = map(analogRead(_pin), 0, 1023, 10, 1000);
    }
    void loop() {
      if (millis() - past > 100) {
        *_pnt = map(analogRead(_pin), 0, 1023, 10, 1000);
      }
    }
};
//--------------------Cl_HallToInject-------------------------------
// класс Датчик Холла задает начало открытия инжектора
class Cl_HallToInject {
    uint32_t time = 1000; // длительность 1 секунда
    int *const _pnt;// указатель переменную которая задает новое значение time
    const byte _Hall_pin  ; // пин холла
    const byte _Inject_pin;// пин инжектора
    bool Hall, Hall_old;
    bool Inject;
    bool _invH, _invI; // инверсия выходов датчика Холла и инжектора
    uint32_t past = 0;
  public:
    Cl_HallToInject(byte Hall_pin, bool invH, byte Inject_pin, bool invI, int *pnt)
      : _Hall_pin(Hall_pin), _invH(invH), _Inject_pin(Inject_pin), _invI(invI) , _pnt(pnt) {}
    void setup() {
      pinMode(_Hall_pin, INPUT);
      Hall_old = _invH ^ digitalRead( _Hall_pin);
      pinMode(_Inject_pin, OUTPUT);
      Inject = 0;
      digitalWrite(_Inject_pin, _invI ^ Inject);
    }
    void loop() {
      Hall = _invH ^ digitalRead( _Hall_pin);
      if (Hall && !Hall_old) { // если сработал датчик Холла
        Hall_old = 1;
        Inject = 1;            // то вкл Инжектор
        digitalWrite(_Inject_pin, _invI ^ Inject);
        time = *_pnt; // выставить новое время впрыска
        past = millis();
      }
      else if (!Hall && Hall_old) {
        Hall_old = 0;
      }
      if (Inject && millis() - past >= time) { // если истекло время
        Inject = 0;                            // то выкл Инжектор
        digitalWrite(_Inject_pin, _invI ^ Inject);
      }
    }
};
//------------------Компоновка---------------------------------
int time = 1000; // длительность впрыска
Cl_Potentiometer Potentiometer(/*пин потенциометра*/A0,/*переменая*/&time);// подключить потенциометр
// Замечание: Если вам нужно проинвертировать сигнал, то замените 0 на 1
Cl_HallToInject HallToInject1(/*датчик холла*/2,/*инверт сиг с датХолла*/0,/*инжектор*/6,/*инверт сиг на инжектор*/0,/*время впрыска*/&time);
Cl_HallToInject HallToInject2(/*датчик холла*/3,/*инверт сиг с датХолла*/0,/*инжектор*/7,/*инверт сиг на инжектор*/0,/*время впрыска*/&time);
Cl_HallToInject HallToInject3(/*датчик холла*/4,/*инверт сиг с датХолла*/0,/*инжектор*/8,/*инверт сиг на инжектор*/0,/*время впрыска*/&time);
Cl_HallToInject HallToInject4(/*датчик холла*/5,/*инверт сиг с датХолла*/0,/*инжектор*/9,/*инверт сиг на инжектор*/0,/*время впрыска*/&time);
//------------------main()---------------------------------
void setup() {
  Serial.begin(9600);
  Potentiometer.setup();
  HallToInject1.setup();
  HallToInject2.setup();
  HallToInject3.setup();
  HallToInject4.setup();
}

void loop() {
  Serial.println(time);
  Potentiometer.loop();
  HallToInject1.loop();
  HallToInject2.loop();
  HallToInject3.loop();
  HallToInject4.loop();
}

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

qwone пишет:

Программа для регулирования времени впрыска с помощью потенциометра

А из каких соображений в классе Cl_Potentiometer второе измерение напряжения на пине происходит через 100 мс после первого, а третье и все последующие при каждом проходе loop? В этом есть какой-то тайный смысл?

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

ЕвгенийП пишет:

А из каких соображений в классе Cl_Potentiometer второе измерение напряжения на пине происходит через 100 мс после первого, а третье и все последующие при каждом проходе loop? В этом есть какой-то тайный смысл?

О это очень тайный смысл. Если вы будете постояно бегать на работу и обратно . Раз 100 или тысячу в день, то у вас не хватит времени на работу. Все время уйдет на дорогу и обратно. Крутит потенциометр человек. А человек с точки зрения МК устройство медленое. И регулярно проверять , чаще 0.1 секунды МК нет смысла. Пусть МК лучше четче отслеживает время открытия и закрытия форсунок.

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

/**/
//--------Cl_Task_Manager-------------------------------
//класс диспетчер задач
class Cl_Task_Manager {
    uint32_t time, time_new;
    uint32_t past = 0;
  public:
    Cl_Task_Manager() {}
    void setup() {
      time = 0;
    }
    void loop() {
      if (millis() - past >= 1000) {
        past = millis();
        Serial.println();
        Serial.print(time / 10);
        Serial.print("%");
        time = 0;
      }
    }
    void Start_of_count() {
      time_new = millis();
    }
    void End_of_count() {
      time += millis() - time_new;
    }
};
//---------------------------------------
Cl_Task_Manager Manager;
//---------------------------------------
void setup() {
  Serial.begin(9600);
  Manager.setup();

}

void loop() {
  Manager.Start_of_count();
  Manager.loop();
  Manager.End_of_count();
}

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

qwone пишет:

О это очень тайный смысл. Если вы будете постояно бегать на работу и обратно . Раз 100 или тысячу в день, то у вас не хватит времени на работу. 

Вы мой пост внимательно прочитали? Я писал о том, что Вы как раз это и сделали - читаете пин в каждом вызове loop (см. код в посте #29). Вот и поинтересовался для чего.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

ЕвгенийП пишет:

qwone пишет:

О это очень тайный смысл. Если вы будете постояно бегать на работу и обратно . Раз 100 или тысячу в день, то у вас не хватит времени на работу. 

Вы мой пост внимательно прочитали? Я писал о том, что Вы как раз это и сделали - читаете пин в каждом вызове loop (см. код в посте #29). Вот и поинтересовался для чего.

Вот если запустить этот код с Менеджером задач

/*
  ардуино пин A0 <--> средний вывод потенциометра
  ардуино пин 2 <--> датчик холла 1
  ардуино пин 3 <--> датчик холла 2
  ардуино пин 4 <--> датчик холла 3
  ардуино пин 5 <--> датчик холла 4
  ардуино пин 6 <--> инжектор 1
  ардуино пин 7 <--> инжектор 2
  ардуино пин 8 <--> инжектор 3
  ардуино пин 9 <--> инжектор 4
*/
//--------Cl_Task_Manager-------------------------------
//класс диспетчер задач
class Cl_Task_Manager {
    uint32_t time, time_new;
    uint32_t past = 0;
  public:
    Cl_Task_Manager() {}
    void setup() {
      time = 0;
    }
    void loop() {
      if (millis() - past >= 1000) {
        past = millis();
        Serial.println();
        Serial.print(time / 100);
        Serial.print("%");
        time = 0;
      }
    }
    void Start_of_count() {
      time_new = millis();
    }
    void End_of_count() {
      time += millis() - time_new;
    }
};
//--------------------Cl_Potentiometer---------------------------------------------
class Cl_Potentiometer {
    const byte _pin;
    int *const _pnt;// указатель переменную которая меняет значение по положению ручки потенциометра
    uint32_t past = 0;
  public:
    Cl_Potentiometer(byte pin, int *pnt): _pin(pin), _pnt(pnt) {}
    void setup() {
      *_pnt = map(analogRead(_pin), 0, 1023, 10, 1000);
    }
    void loop() {
      //if (millis() - past > 100) {
      *_pnt = map(analogRead(_pin), 0, 1023, 10, 1000);
      //}
    }
};
//--------------------Cl_HallToInject-------------------------------
// класс Датчик Холла задает начало открытия инжектора
class Cl_HallToInject {
    uint32_t time = 1000; // длительность 1 секунда
    int *const _pnt;// указатель переменную которая задает новое значение time
    const byte _Hall_pin  ; // пин холла
    const byte _Inject_pin;// пин инжектора
    bool Hall, Hall_old;
    bool Inject;
    bool _invH, _invI; // инверсия выходов датчика Холла и инжектора
    uint32_t past = 0;
  public:
    Cl_HallToInject(byte Hall_pin, bool invH, byte Inject_pin, bool invI, int *pnt)
      : _Hall_pin(Hall_pin), _invH(invH), _Inject_pin(Inject_pin), _invI(invI) , _pnt(pnt) {}
    void setup() {
      pinMode(_Hall_pin, INPUT);
      Hall_old = _invH ^ digitalRead( _Hall_pin);
      pinMode(_Inject_pin, OUTPUT);
      Inject = 0;
      digitalWrite(_Inject_pin, _invI ^ Inject);
    }
    void loop() {
      Hall = _invH ^ digitalRead( _Hall_pin);
      if (Hall && !Hall_old) { // если сработал датчик Холла
        Hall_old = 1;
        Inject = 1;            // то вкл Инжектор
        digitalWrite(_Inject_pin, _invI ^ Inject);
        time = *_pnt; // выставить новое время впрыска
        past = millis();
      }
      else if (!Hall && Hall_old) {
        Hall_old = 0;
      }
      if (Inject && millis() - past >= time) { // если истекло время
        Inject = 0;                            // то выкл Инжектор
        digitalWrite(_Inject_pin, _invI ^ Inject);
      }
    }
};
//------------------Компоновка---------------------------------
Cl_Task_Manager Manager;
int time = 1000; // длительность впрыска
Cl_Potentiometer Potentiometer(/*пин потенциометра*/A0,/*переменая*/&time);// подключить потенциометр
// Замечание: Если вам нужно проинвертировать сигнал, то замените 0 на 1
Cl_HallToInject HallToInject1(/*датчик холла*/2,/*инверт сиг с датХолла*/0,/*инжектор*/6,/*инверт сиг на инжектор*/0,/*время впрыска*/&time);
Cl_HallToInject HallToInject2(/*датчик холла*/3,/*инверт сиг с датХолла*/0,/*инжектор*/7,/*инверт сиг на инжектор*/0,/*время впрыска*/&time);
Cl_HallToInject HallToInject3(/*датчик холла*/4,/*инверт сиг с датХолла*/0,/*инжектор*/8,/*инверт сиг на инжектор*/0,/*время впрыска*/&time);
Cl_HallToInject HallToInject4(/*датчик холла*/5,/*инверт сиг с датХолла*/0,/*инжектор*/9,/*инверт сиг на инжектор*/0,/*время впрыска*/&time);
//------------------main()---------------------------------
void setup() {
  Manager.setup();
  Serial.begin(9600);
  Potentiometer.setup();
  HallToInject1.setup();
  HallToInject2.setup();
  HallToInject3.setup();
  HallToInject4.setup();
}

void loop() {
  Manager.loop();
  //Serial.println(time);
  Manager.Start_of_count();
  Potentiometer.loop();
  Manager.End_of_count();
  HallToInject1.loop();
  HallToInject2.loop();
  HallToInject3.loop();
  HallToInject4.loop();
  Manager.End_of_count();
}

То выходит, что на метод loop Cl_Potentiometr уходит 17% времени. Что с millis(), что без

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Чёт не пойму Вы уж либо исправьте ошибку и скажите "спасибо", либо объясните для чего Вы на словах читаете через каждые 100мс, а на деле - при каждом проходе loop. Ошибка-то в коде до сих пор не исправлена, а это материал для чайников - лучше ляпов не оставлять.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

А Вы опять за свое. Видно прямо сказать, что я пропустил строку  past = millis(); религия не позволяет. И да с этой строкой загрузка процесора переместилась с 17% на 9%. 

ПС: Воспользуюсь вашим приемом. И ничего менять не буду.И так в теме намеки есть.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

qwone пишет:

прямо сказать, что я пропустил строку  past = millis(); религия не позволяет. 

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

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

ЕвгенийП пишет:

считаю такую запись неверной

а я уж подумал, что я один это замечаю.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Ворота пишет:
а я уж подумал, что я один это замечаю.
А вот это уже радует. Сначало смотришь на чужой код с восхищением, потом замечаешь, что там что-то не так, затем начинаешь потихоньку переписывать и узнаешь, что мало знаешь в языке Си,Си++,Си++11.

  Я выкладываю свой код не для тупого копирования, и да у меня тоже есть описки и ошибки. Просто это вариант привыкнуть и к такому стилю организации программы.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

qwone пишет:

это вариант привыкнуть и к такому стилю организации программы.

А какой смысл привыкать к неправильному и неэффективному программированию? Как я понял, неверной он считает твою привычку вызывать millis дважды – первый раз, чтобы проверить, не истёк ли интервал, и второй раз – чтобы запомнить начало нового интервала.

То, что это неэффектвно, понятно. Какой бы быстрой ни была функция millis, она в разы медленнее, чем запомнить результат первого вызова и просто использовать его для начала нового интервала.

Ну и в общем случае это неправильно. Если бы millis вызывалась один раз, интервал соблюдался бы точно (насколько вообще может быть точным такой подход). А так интервал получается «тот, что надо» + время, прошедшее между вызовами millis.

В большинстве случаев, это неважно, там разница маленькая, но методологически это неправильно.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Привыкать надо не писать, а читать. Как правило программист чаще читает чужой код, а не пишет свой. Да и свой через несколько лет уже воспринимается чужеродным, если конечно программист развивается. Опять же не надо путать написание кода с его заточкой на скорость- вылизывание скорости в ущерб восприятию. Разберем этот код 

void setup() {
}

void loop() {
  static uint32_t past = 0;
  if (millis() - past >= 1000) {
    past = millis();
  }
}

Вопрос : Сколько раз вызывается функция millis() за проход loop(). два, один. И оба раза не верны. Так как иногда вызываются два, но чаще один. Так что здесь работает статистика . И чем больше число после >= , тем ближе к 1.  И я могу облизать это код, но тогда он станет не читаем для большинства.  Вы же можете взять учебники русского языка и воспринять, что тексты там написаны тупыми и примитивными . Так и здесь я выкладываю тупой и примитивный код. А вот получше пишите сами.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Вот никак не могу понять чем вот такой код менее читабелен?

void loop() {
  static uint32_t periodStart = 0, currentMillis;
  currentMillis = millis();
  if (currentMillis - periodStart >= 1000) {
    periodStart = currentMillis;
  }
}

То, что он даёт более точный интервал и сам по себе быстрее - да. А чем он менее читабелен - не вижу. Читабельность та же самая.

qwone пишет:

А вот получше пишите сами.

Да, спасибо, я так и поступаю.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Ворота пишет:

Вот никак не могу понять чем вот такой код менее читабелен?

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

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Бертран Мейер Объектно-ориентированное конструирование программных систем https://vk.com/doc232854130_357487973?hash=2dbb274d25eea6ebba&dl=c0285623a86be348f0

пс:https://vk.com/wall-43948962_41995

пс2:https://vk.com/wall-54530371_591

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Ворота пишет:

void loop() {
  static uint32_t periodStart = 0, currentMillis;
  currentMillis = millis();
  if (currentMillis - periodStart >= 1000) {
    periodStart = currentMillis;
  }
}

Я бы не стал делать currentMillis  static - зачем? По мне, вот так лучше:

void loop() {
  static uint32_t periodStart = 0;
  const  uint32_t  currentMillis = millis();
  if (currentMillis - periodStart >= 1000) {
    periodStart = currentMillis;
  }
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Подброшу еще два варианта кода. 

const uint32_t & currentMillis = millis();
void loop() {
  static uint32_t periodStart = 0;
  if (millis() - periodStart >= 1000) {
    periodStart = currentMillis;
  }
}

И

uint32_t && currentMillis = millis();
void loop() {
  static uint32_t periodStart = 0;
  if (millis() - periodStart >= 1000) {
    periodStart = currentMillis;
  }
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

Ну и этот код на закуску.

bool led = 0;
void setup() {
  pinMode(13, OUTPUT);

}
extern unsigned long timer0_millis;
void loop() {
  static uint32_t periodStart = 0;
  if (timer0_millis - periodStart >= 200) {
    periodStart = timer0_millis;
    digitalWrite(13, led = !led);
  }
}

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016
ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

qwone пишет:

Ну и этот код на закуску.

А без ошибок никак нельзя? Даже не знаю как Вам про неё, опять начнёте гадать о национальной специфики моего образования и откажетесь исправлять (назло мамке уши отморозите).

Посмотрите на текст функции millis, возможно поймёте:

unsigned long millis()
{
	unsigned long m;
	uint8_t oldSREG = SREG;

	// disable interrupts while we read timer0_millis or we might get an
	// inconsistent value (e.g. in the middle of a write to timer0_millis)
	cli();
	m = timer0_millis;
	SREG = oldSREG;

	return m;
}

 

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

ЕвгенийП пишет:

qwone пишет:

Ну и этот код на закуску.

А без ошибок никак нельзя? Даже не знаю как Вам про неё, опять начнёте гадать о национальной специфики моего образования и откажетесь исправлять (назло мамке уши отморозите).

Посмотрите на текст функции millis, возможно поймёте:

unsigned long millis()
{
	unsigned long m;
	uint8_t oldSREG = SREG;

	// disable interrupts while we read timer0_millis or we might get an
	// inconsistent value (e.g. in the middle of a write to timer0_millis)
	cli();
	m = timer0_millis;
	SREG = oldSREG;

	return m;
}

Так запустил. Работает. И странно вроде не сбивается. Хотя странно, прерывание должно бы отрубить.

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

или millis() криво прочитать.