Классы Ардуино по qwone для чайников.
- Войдите на сайт для отправки комментариев
Сб, 08/07/2017 - 10:45
Извините на громкое название темы, но похоже я тоже чайник. Так что вменяемого текста от меня не ждите.
Что я требую от классов:
1 - что бы в них обязательно были public методы setup() и loop()
2- что бы представители этих классов,что из одного класса,что из разных, могли взаимно не тормозить друг друга.
Вот примерно мой типичный каркас программы, я бы сказал разметка каркаса.
/* здесь идет заглавие программы и электрические подключения элементов */ 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
Следующий этап Пример 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(); }черезчур академично. Новички ничего не поймут, а кто разбирается - умрут со скуки.
Кстати, теоретически ваши ссылочные классы таят в себе потенциальные проблемы... вот почитайте
http://pages.cs.wisc.edu/~hasti/cs368/CppTutorial/NOTES/CLASSES-PTRS.html
Выкладываю дальше . Кнопки
Этот пример для кнопки подключеной на вывод и землю.
/* Пример 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(); }Но бывает что одной кнопки использовать в программе тяжело. Лучше всего использовать две, а лучше три.
/* Пример 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(); //< }Теперь вариант 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(); }Если вам надо одной кнопкой выбирать 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(); }qwone, ну шо за ересь? - прекращай бредить.
не существует никаких особенных классов для Ардуино - в Ардуино ИДЕ работают классы С++.
Следующий вариант: кнопка на пине 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(); }Теперь покажу взаимодествие кнопок (+ и -) и серво
/* Пример 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(); }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(); }надеюсь, ты не против комментариев? а то пока выглядит, будто это "только твоя" тема :)
По пункту 1 выше я бы все-таки немного подробнее обьяснил - если это тема для новичков. Пока твой текст выглядит так, будто методы setup() и loop() - обязательны для любых классов. Стоило бы просто написать, что ты создаешь в своих классах единый интерфейс для инициализации и запуска в loop
b707, из меня никакой учитель. Просто я в некотором виде создаю библиотеку решений . Ведь одна из сложностей в "новичковом" программировании Ардуины, не возможность работы разных скетчей. Я бы не выкладывал бы эти скетчи, но похоже что это для многих они кажутся загадкой. Вот пусть просвещаются. Тем более для меня это уже прошедший этап. Кому интересно, пусть просвещаются. Можете и вы выкладывать свое и давать свои объяснения. Я не против.
ПППС: мигание светодиода по определеной последовательности
/* Пример 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(); }qwone, перепроверь как это у тебя работает
boolbounce = 0;// антидребезговый флагпотому как, если у тебя это компилится, то bounce может быть только общей для всех экземпляров класса константой.
так на Дуино ИДЕ 1.0.6 выдаёт правильную ошибку: error: ISO C++ forbids initialization of member 'bounce'
на Дуино ИДЕ 1.8.2 молча компилит, но подозреваю, то само превращает bounce в константу.
ЗЫ. минуса не я ставил - надеюсь, что у этого кармодрочера отсохнет член.
qwone, перепроверь как это у тебя работает
boolbounce = 0;// антидребезговый флагпотому как, если у тебя это компилится, то bounce может быть только общей для всех экземпляров класса константой.
так на Дуино ИДЕ 1.0.6 выдаёт правильную ошибку: error: ISO C++ forbids initialization of member 'bounce'
на Дуино ИДЕ 1.8.2 молча компилит, но подозреваю, то само превращает bounce в константу.
Не, насколько я знаю, раньше это было ошибкой, а в новых версиях стандарта C++ уже допустимо. Это, по-моему, default_member_initialization
Не, насколько я знаю, раньше это было ошибкой, а в новых версиях стандарта C++ уже допустимо. Это, по-моему, default_member_initialization
ок. а, то я уже расстроился, что новые версии Дуино ИДЕ ломают С++
Вот еще один пустячок. Иногда надо что бы при нажатии на кнопку на выходе был импульс к примеру продолжительностью 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(); }Вы это специально пример для ООП без ООП сделали)))
Ваше требование - чтоб всегда был сетап и лоп - это методы базового класса. А от него наследуется кнопка и прочие для которых важно чтоб всегда был сетап и лоп. Бонус - все обекты можна хранить в массиве, а значить вызывать их в сетапе и лопе не один за другим (если их много будет - тоска) а в цикле по очереди из массива.
Дальше убираем указатель на Do. В классах так не принято, ведь внутри вашего обработчика Do не получится добратся к данным класа кнопки, а это плохо, там например могут быть флаги двойного клика или еще какая инфа. Для этого в классе кнопки делаете виртуальный метод Do, без реализации. А когда понадобится конкретная кнопка с нужным действием -наследуете от абстрактного типа задав соответствующий обработчик. Бонус - ну допустим нужны кнопки с цифрами 0-9, от абстрактного класса кнопка наследуете класс цифровая кнопка у которого обработчик Do и новое поле - цифра этой кнопки. В конструкторе эту цифру задаете вместе с пином на котором кнопка висит. Дальше создаете 10 обектов класса цифровая кнопка инициализировав их соответствующими цифрами. В итоге при нажатии любой из десяти кнопок вызывается Do цифровой кнопки и в нем есть значение от нажатой кнопки. Ляпота!
Получается иерархия наследования абстрактный класс ардуины-абстрактный класс кнопки-класс цифровой кнопки-обекты кнопок. А если потребуются кнопки со стрелками - от абстрактного класса кнопки унаследуете класс кнопок со стрелками и создадите его обекты стрелка влево и стрелка вправо. Получим 2 обработчика Do один для цифр другой для стрелок - что очень логично. Ну просто оргазм ООПешника!!
Logik,Разумеется можно и так. Но просто я пока сюда скидываю простые скетчи. Так для "новичков", для которых и классы - "открытие". А для ООП это как до Луны пехом.
Задача : Подключить кнопку 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(); }Скеч для обработки кнопки без учета дребезга мех кнопки. Ведь есть просто внешние сигналы.
/* */ //-------------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(); }масло масляное
void setup() {button.setup();} void loop () {button.loop ();}Вот тоже интересный скетч. Вобщем очередь с возможностью добавить элемент в начало или в конец.
/*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() { }Скеч. Два датчика , "мозг" и два исполнительных механизма. Может кому пригодится как схема написания программы.
/**/ //------------------------------------ // класс сенсор 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(); }Добавлю и этот скетч. Аналог верхнего, но со структурой.
/**/ //------------------------------------ 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(); }Вот еще код под 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(); }Продолжение скетча на тему 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(); }Программа для регулирования времени впрыска с помощью потенциометра
/* ардуино пин 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(); }Программа для регулирования времени впрыска с помощью потенциометра
А из каких соображений в классе Cl_Potentiometer второе измерение напряжения на пине происходит через 100 мс после первого, а третье и все последующие при каждом проходе loop? В этом есть какой-то тайный смысл?
А из каких соображений в классе Cl_Potentiometer второе измерение напряжения на пине происходит через 100 мс после первого, а третье и все последующие при каждом проходе loop? В этом есть какой-то тайный смысл?
ПС: Для любителей выяснять, что лучше я предлагаю примитивный менеджер задач под мои классы.
/**/ //--------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(); }О это очень тайный смысл. Если вы будете постояно бегать на работу и обратно . Раз 100 или тысячу в день, то у вас не хватит времени на работу.
Вы мой пост внимательно прочитали? Я писал о том, что Вы как раз это и сделали - читаете пин в каждом вызове loop (см. код в посте #29). Вот и поинтересовался для чего.
О это очень тайный смысл. Если вы будете постояно бегать на работу и обратно . Раз 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(), что без
Чёт не пойму Вы уж либо исправьте ошибку и скажите "спасибо", либо объясните для чего Вы на словах читаете через каждые 100мс, а на деле - при каждом проходе loop. Ошибка-то в коде до сих пор не исправлена, а это материал для чайников - лучше ляпов не оставлять.
А Вы опять за свое. Видно прямо сказать, что я пропустил строку past = millis(); религия не позволяет. И да с этой строкой загрузка процесора переместилась с 17% на 9%.
ПС: Воспользуюсь вашим приемом. И ничего менять не буду.И так в теме намеки есть.
прямо сказать, что я пропустил строку past = millis(); религия не позволяет.
Не только религия, а также инженерное образование. Я считаю такую запись неверной, но к таким мелочам не придираюсь, потому и не тычу во все остальные места, где она используется. Ну, а в этом месте была явная ошибка, решил помочь. Наверное напрасно, т.к. вместо "спасибо" получил "религия не позволяет".
считаю такую запись неверной
а я уж подумал, что я один это замечаю.
Я выкладываю свой код не для тупого копирования, и да у меня тоже есть описки и ошибки. Просто это вариант привыкнуть и к такому стилю организации программы.
это вариант привыкнуть и к такому стилю организации программы.
А какой смысл привыкать к неправильному и неэффективному программированию? Как я понял, неверной он считает твою привычку вызывать millis дважды – первый раз, чтобы проверить, не истёк ли интервал, и второй раз – чтобы запомнить начало нового интервала.
То, что это неэффектвно, понятно. Какой бы быстрой ни была функция millis, она в разы медленнее, чем запомнить результат первого вызова и просто использовать его для начала нового интервала.
Ну и в общем случае это неправильно. Если бы millis вызывалась один раз, интервал соблюдался бы точно (насколько вообще может быть точным такой подход). А так интервал получается «тот, что надо» + время, прошедшее между вызовами millis.
В большинстве случаев, это неважно, там разница маленькая, но методологически это неправильно.
Привыкать надо не писать, а читать. Как правило программист чаще читает чужой код, а не пишет свой. Да и свой через несколько лет уже воспринимается чужеродным, если конечно программист развивается. Опять же не надо путать написание кода с его заточкой на скорость- вылизывание скорости в ущерб восприятию. Разберем этот код
void setup() { } void loop() { static uint32_t past = 0; if (millis() - past >= 1000) { past = millis(); } }Вопрос : Сколько раз вызывается функция millis() за проход loop(). два, один. И оба раза не верны. Так как иногда вызываются два, но чаще один. Так что здесь работает статистика . И чем больше число после >= , тем ближе к 1. И я могу облизать это код, но тогда он станет не читаем для большинства. Вы же можете взять учебники русского языка и воспринять, что тексты там написаны тупыми и примитивными . Так и здесь я выкладываю тупой и примитивный код. А вот получше пишите сами.
Вот никак не могу понять чем вот такой код менее читабелен?
void loop() { static uint32_t periodStart = 0, currentMillis; currentMillis = millis(); if (currentMillis - periodStart >= 1000) { periodStart = currentMillis; } }То, что он даёт более точный интервал и сам по себе быстрее - да. А чем он менее читабелен - не вижу. Читабельность та же самая.
А вот получше пишите сами.
Да, спасибо, я так и поступаю.
Вот никак не могу понять чем вот такой код менее читабелен?
ничем - опилкоголовый интуитивно пытается экономить оперативку, что не всегда правильно и к месту.
Бертран Мейер Объектно-ориентированное конструирование программных систем https://vk.com/doc232854130_357487973?hash=2dbb274d25eea6ebba&dl=c0285623a86be348f0
пс:https://vk.com/wall-43948962_41995
пс2:https://vk.com/wall-54530371_591
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; } }Подброшу еще два варианта кода.
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; } }Ну и этот код на закуску.
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); } }http://dic.academic.ru/dic.nsf/ushakov/820102
Ну и этот код на закуску.
А без ошибок никак нельзя? Даже не знаю как Вам про неё, опять начнёте гадать о национальной специфики моего образования и откажетесь исправлять (назло мамке уши отморозите).
Посмотрите на текст функции 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; }Ну и этот код на закуску.
А без ошибок никак нельзя? Даже не знаю как Вам про неё, опять начнёте гадать о национальной специфики моего образования и откажетесь исправлять (назло мамке уши отморозите).
Посмотрите на текст функции 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; }Так запустил. Работает. И странно вроде не сбивается. Хотя странно, прерывание должно бы отрубить.
или millis() криво прочитать.