Оптимизация
- Войдите на сайт для отправки комментариев
Ср, 07/02/2018 - 13:14
Всем доброго здравия! Меня зовут Александр (на случай если логин вводит в заблуждение подскажите как изменить)
Алгоритм следующий : Есть два числа типа byte и две кнопки. Одной кнопкой делаем выбор числа val1 или val2 , другой задаем предел - 1, 10,50,100. Чем дольше нажатие тем выше предел. Проще говоря зажимаем и ждем пока на дисплее отобразится строка("+1"...), затем отпускаем и для примера к числу val1 прибавляется 1...
Неблакирующую задержку добавил чтобы дисплей не мерцал. Возможно ли сделать это проще, то есть не прибегая к такому количеству переменных как у меня ?
#include <Wire.h> // библиотека для управления устройствами по I2C
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602
#include <SmartDelay.h> // библиотека для неблокирующей задержки
SmartDelay foo(200000UL); // 200 ms
LiquidCrystal_I2C lcd(0x3f,20,4); // присваиваем имя lcd для дисплея 20х4
unsigned long time_Pressed; // Переменные для работы со временем;
unsigned long timeNow;
byte val1 = 0; // мое число 0-255
byte val2 = 0; // мое число 0-255
byte val = 0; // ее меняем
byte mem_Val1 = 0;
byte mem_Val2 = 0; // запоминает предыдущее значение чисел
byte *pVal1; // объявили указатель на var1
byte *pVal2; // объявили указатель на var2
boolean flag = false;
enum bottonVariants { // Определения для работы с кнопкой;
BOTTON_CLICK,
BOTTON_SHORT,
BOTTON_NOLONG,
BOTTON_LONG,
BOTTON_NOT,
};
bottonVariants botton = BOTTON_NOT;
void setup() {
lcd.begin(); // инициализация LCD дисплея
lcd.backlight(); // включение подсветки дисплея
lcd.setCursor(1, 1);
lcd.print("PROGRAM V1.0");
delay(1000);
lcd.clear();
pinMode(8, INPUT); //пин для кнопки выбора числа
digitalWrite(8, HIGH); //подключаем подтягивающий резистор
pinMode(9, INPUT); //пин для кнопки операций над числом
digitalWrite(9, HIGH); //подключаем подтягивающий резистор
}
void alex_function() {
if (flag) { *pVal2 = val + mem_Val2;
lcd.setCursor(3, 2); lcd.write(42);
lcd.setCursor(3, 1); lcd.write(32);
}
else { *pVal1 = val + mem_Val1;
lcd.setCursor(3, 1); lcd.write(42);
lcd.setCursor(3, 2); lcd.write(32);
}
}
void loop() {
if (digitalRead(8) == 0 && (millis() - time_Pressed) > 200 ) {
time_Pressed = millis(); // Запоминаем время нажатия кнопки;
flag=!flag;
mem_Val1 = *pVal1;
mem_Val2 = *pVal2;
val = 0;
}
if (digitalRead(9) == 0 && (millis() - time_Pressed) > 200 ) {
time_Pressed = millis(); // Запоминаем время нажатия кнопки;
lcd.clear();
lcd.print(F("+1"));
botton = BOTTON_CLICK; // однократное нажатие
while (digitalRead(9) == 0) { // Ждем отпускания кнопки;
timeNow = millis(); // И засекаем время;
if (timeNow - time_Pressed > 1000 && timeNow - time_Pressed < 1500) {
// Было короткое нажатие - менее 1.5 с но более 1 с.
if (foo.Now()) {
lcd.clear();
lcd.print(F("+10"));
}
//delay(200);
botton = BOTTON_SHORT;
}
else if (timeNow - time_Pressed > 1500 && timeNow - time_Pressed < 2500) {
// Было недолгое нажатие кнопки - менее 2.5 с но более 1.5 с.
if (foo.Now()) {
lcd.clear();
lcd.print(F("+50"));
}
//delay(200);
botton = BOTTON_NOLONG;
}
else if (timeNow - time_Pressed >2500) {
// Было долгое нажатие кнопки - больше 2.5 с.
if (foo.Now()) {
lcd.clear();
lcd.print(F("+100"));
}
//delay(200);
botton = BOTTON_LONG;
}
}
}
switch (botton) { // Здесь выбираем что менять;
case BOTTON_CLICK: // При одиночном нажатии,
val++;
botton = BOTTON_NOT;
break;
case BOTTON_SHORT: // При коротком нажатии;
val+=10;
botton = BOTTON_NOT;
break;
case BOTTON_NOLONG: // При недолгом нажатии,
val+=50;
botton = BOTTON_NOT;
break;
case BOTTON_LONG: // При долгом нажатии,
val+=100;
botton = BOTTON_NOT;
break;
case BOTTON_NOT:
pVal1 = &val1;
pVal2 = &val2;
alex_function();
lcd.setCursor(0, 1); lcd.print(val1);
lcd.setCursor(0, 2); lcd.print(val2);
break;
}
}
Тебе зачем оптимизация? Тщеславие чешется? Или другие веские причины? Если код работает и пока всё устраивает - не трожь. А по сути вопроса - premature optimization is the root of all evil (c) Дональд Кнут, умный дядька.
Код рабочий. Идея в том чтобы лишнее из loop перенести в функцию(счетчик прибавления например). Но не знаю какие ей передавайть аргументы? Возможно само число val и в функции уже производить над ним операции в зависимости от длительности зажатия.
Точно такие же действия хочу сдклать и с опрерацией вычитания. С теми же пределами, вот и задумался. Допускаю что это будет на отдельной кнопке (10 пин). Но не хотелось бы загромождать код идентичной обработкой кнопки и идентичными операциями с пределом. Поэтому и создал тему
прежде чем думать об оптимизации - надо написать код поприличнее. А у вас обработка нажатия кнопки на 9-м пине - это сплошной баг. Во-первых, "короткое", "недолгое" и "долгое" нажатие будут детектироваться последовательно на одном физическом нажатии кнопки. Во-вторых, цикл while - это скрытый delay на 3 секунды, хоть и написан. якобы, на миллис.
Вообщем поразмыслив, понял что достаточно ответов на 3 вопроса, дальше своими двоими.
1. Возможна ли обработка нажатий кнопки за телом функции loop. Если да то п.2
2. Если для этого использовать отдельную функцию, то можно ей передать в качестве аргумента номер пина ардуино? Хотя абсурдный вопрос поскольку допустим сработало условие первоначально нажатия кнопки, поднялся флаг. Зашли в функцию.
Насчет длительности нажатия сразу пришла в голову такая конструкции, параметр INTERVAL будет выбран из массива [ 200, 1000, 1500].
void howLongPress(unsigned long INTERVAL ) { static unsigned long prevTime = 0; // время когда последний раз нажимали if (millis() - prevTime > INTERVAL) { prevTime = millis(); // // действие } }3. Возможно ли здесь не добавляя дополнительной переменной, сделать аналогично операцию вычитания?
switch (botton) { // Здесь выбираем что менять; case BOTTON_CLICK: // При одиночном нажатии, val++; botton = BOTTON_NOT; break; case BOTTON_SHORT: // При коротком нажатии; val+=10; botton = BOTTON_NOT; break; case BOTTON_NOLONG: // При недолгом нажатии, val+=50; botton = BOTTON_NOT; break; case BOTTON_LONG: // При долгом нажатии, val+=100; botton = BOTTON_NOT; break; case BOTTON_NOT: pVal1 = &val1; pVal2 = &val2; alex_function(); lcd.setCursor(0, 1); lcd.print(val1); lcd.setCursor(0, 2); lcd.print(val2); break; }Во-вторых, цикл while - это скрытый delay на 3 секунды, хоть и написан. якобы, на миллис.
Значит придется заменить на if. Спасибо за совет
прежде чем думать об оптимизации - надо написать код поприличнее. А у вас обработка нажатия кнопки на 9-м пине - это сплошной баг. Во-первых, "короткое", "недолгое" и "долгое" нажатие будут детектироваться последовательно на одном физическом нажатии кнопки.
Знаете, мне так и нужно. То есть удерживая кнопку значения счетчика действительно пробегают последовательно от 1 до 100. Отпуская кнопку я и выбираю предел. И этот предел добавляется к выбранному числу.
Проще так : нажал - предел(1...10...50...100) высвечивается на дисплее - отпустил на 10, она и добавилась
Тут ложная тревога
Вообщем поразмыслив, понял что достаточно ответов на 3 вопроса, дальше своими двоими.
1. Возможна ли обработка нажатий кнопки за телом функции loop. Если да то п.2
да. loop - такая же функция, как любая другая
конечно. Номер пина может быть задан переменной, а не жестко закодирован в коде
b707, очень благодарен, картина проясняется.
Значит придется заменить на if. Спасибо за совет
вы бредите... Дело не в while - дело в вашем коде внутри. Идея останавливать программу на 3 секунды, пока кнопка нажата - категорически неверная. А делаете ли вы это на while или на if - без разницы, и так и так плохо.
Нужно переписать кусок внутри while в неблокирующем виде.
Теперь понял о чем вы. Уезжаю на учебу, вечером буду пробовать
Написал код, но где то ошибка. Если заметите, поправьте
#include <Wire.h> // библиотека для управления устройствами по I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602 #include <SmartDelay.h> // библиотека для неблокирующей задержки SmartDelay foo(200000UL); // 200 ms LiquidCrystal_I2C lcd(0x3f,20,4); // присваиваем имя lcd для дисплея 20х4 unsigned long time_Pressed; // Переменные для работы со временем; unsigned long timeNow; byte val1 = 0; // мое число 0-255 byte val2 = 0; // мое число 0-255 byte val = 0; byte mem_Val1 = 0; byte mem_Val2 = 0; byte *pVal1; // объявили указатель на var1 byte *pVal2; // объявили указатель на var2 boolean flag = false; enum bottonVariants { // Определения для работы с кнопкой; BOTTON_CLICK, BOTTON_SHORT, BOTTON_NOLONG, BOTTON_LONG, BOTTON_NOT, }; bottonVariants botton = BOTTON_NOT; void setup() { lcd.begin(); // инициализация LCD дисплея lcd.backlight(); // включение подсветки дисплея lcd.setCursor(1, 1); lcd.print("PROGRAM V1.0"); delay(1000); lcd.clear(); pinMode(8, INPUT); //пин для кнопки выбора числа digitalWrite(8, HIGH); //подключаем подтягивающий резистор pinMode(9, INPUT); //пин для кнопки операций над числом digitalWrite(9, HIGH); //подключаем подтягивающий резистор } void alex_function() { if (flag) { *pVal2 = val + mem_Val2; lcd.setCursor(3, 2); lcd.write(42); lcd.setCursor(3, 1); lcd.write(32); } else { *pVal1 = val + mem_Val1; lcd.setCursor(3, 1); lcd.write(42); lcd.setCursor(3, 2); lcd.write(32); } } void loop() { if (digitalRead(8) == 0 && (millis() - time_Pressed) > 200 ) { time_Pressed = millis(); // Запоминаем время нажатия кнопки; flag=!flag; mem_Val1 = *pVal1; mem_Val2 = *pVal2; val = 0; } if (digitalRead(9) == 0) { timeNow = millis(); // засекаем время; if (timeNow - time_Pressed > 3000) {// если кому то вздумается очень долго удерживать кнопку timeNow = 0; } } if (timeNow - time_Pressed > 200 ) { time_Pressed = millis(); // Запоминаем время нажатия кнопки; if (foo.Now()) { lcd.clear(); lcd.print(F("+1")); } botton = BOTTON_CLICK; // однократное нажатие } if (timeNow - time_Pressed > 1000 && timeNow - time_Pressed < 1500) { // Было короткое нажатие - менее 1.5 с но более 1 с. if (foo.Now()) { lcd.clear(); lcd.print(F("+10")); } botton = BOTTON_SHORT; } else if (timeNow - time_Pressed > 1500 && timeNow - time_Pressed < 2500) { // Было недолгое нажатие кнопки - менее 2.5 с но более 1.5 с. if (foo.Now()) { lcd.clear(); lcd.print(F("+50")); } botton = BOTTON_NOLONG; } else if (timeNow - time_Pressed >2500) { // Было долгое нажатие кнопки - больше 2.5 с. if (foo.Now()) { lcd.clear(); lcd.print(F("+100")); } botton = BOTTON_LONG; } switch (botton) { // Здесь выбираем что менять; case BOTTON_CLICK: // При одиночном нажатии, val++; botton = BOTTON_NOT; break; case BOTTON_SHORT: // При коротком нажатии; val+=10; botton = BOTTON_NOT; break; case BOTTON_NOLONG: // При недолгом нажатии, val+=50; botton = BOTTON_NOT; break; case BOTTON_LONG: // При долгом нажатии, val+=100; botton = BOTTON_NOT; break; case BOTTON_NOT: pVal1 = &val1; pVal2 = &val2; alex_function(); lcd.setCursor(0, 1); lcd.print(val1); lcd.setCursor(0, 2); lcd.print(val2); break; } }if (digitalRead(9) == 0) { timeNow = millis(); // засекаем время; if (timeNow - time_Pressed > 3000) {// если кому то вздумается очень долго удерживать кнопку timeNow = 0; } }!!!Ошибка этой конструкции в том, что я присваиваю переменной timeNow значение миллис, которое она приняла в данный момент. Мне же надо запустить отсчет времени как только сработало условие нажатия
Написал код, но где то ошибка. Если заметите, поправьте
Так Вы бы сообщение компилятора скопипастии, что ли....
5N62V, постараюсь объяснится понятнее. Код компилируется без ошибок, но работает не так как мне нужно. На дисплее отображается непонять что
Это и понятно. Когда работаешь с множеством задач висящих на millis, надо быть очень внимательным. Особено если это скетч на традиционном ардуино стиле.
Но я начинал бы так.
/**/ /*переменная var1*/ int Var1 = 0; void getVar1() {} void plusVar1() {} void minusVar1() {} void saveVar1() {} /*переменная var2*/ int Var2 = 0; void getVar2() {} void plusVar2() {} void minusVar2() {} void saveVar2() {} //----main-------------------------------- void setup() { } void loop() { } /*Скетч использует 444 байт (1%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт. */qwone, спасибо вам за идею. Действительно можно сделать обработку событий для кнопок в отдельных функциях. Подумаю над этим.
Пока сделал простейшее: функцию одной кнопки - выбор числа. То что закомментировано не хочет корректно работать
#include <Wire.h> // библиотека для управления устройствами по I2C #include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602 #include <SmartDelay.h> // библиотека для неблокирующей задержки SmartDelay foo(200000UL); // 200 ms LiquidCrystal_I2C lcd(0x3f,20,4); // присваиваем имя lcd для дисплея 20х4 unsigned long time_Pressed = 0; // Переменные для работы со временем; unsigned long timeNow = 0; byte val1 = 0; // мое число 0-255 byte val2 = 0; // мое число 0-255 byte val = 0; byte mem_Val1 = 0; byte mem_Val2 = 0; byte *pVal1; // объявили указатель на var1 byte *pVal2; // объявили указатель на var2 boolean flag = false; enum bottonVariants { // Определения для работы с кнопкой; BOTTON_CLICK, BOTTON_SHORT, BOTTON_NOLONG, BOTTON_LONG, BOTTON_NOT, }; bottonVariants botton = BOTTON_NOT; void setup() { lcd.begin(); // инициализация LCD дисплея lcd.backlight(); // включение подсветки дисплея lcd.setCursor(1, 1); lcd.print("PROGRAM V1.0"); delay(1000); lcd.clear(); pinMode(8, INPUT); //пин для кнопки выбора числа digitalWrite(8, HIGH); //подключаем подтягивающий резистор pinMode(9, INPUT); //пин для кнопки операций над числом digitalWrite(9, HIGH); //подключаем подтягивающий резистор } void alex_function() { if (flag) { *pVal2 = val + mem_Val2; lcd.setCursor(3, 2); lcd.write(42); lcd.setCursor(3, 1); lcd.write(32); } else { *pVal1 = val + mem_Val1; lcd.setCursor(3, 1); lcd.write(42); lcd.setCursor(3, 2); lcd.write(32); } } void loop() { if (digitalRead(8) == 0 ) { Press_8pin_Button(200); } /* if (digitalRead(9) == 0) { //timeNow = millis(); // засекаем время; if (millis() - time_Pressed > 3000) {// если кому то вздумается очень долго удерживать кнопку time_Pressed = millis(); // Запоминаем время нажатия кнопки; //timeNow = 0; } } if (millis() - time_Pressed > 200) { if (foo.Now()) { lcd.clear(); lcd.print(F("+1")); } botton = BOTTON_CLICK; // однократное нажатие } if (millis() - time_Pressed > 1000 && timeNow - time_Pressed < 1500) { // Было короткое нажатие - менее 1.5 с но более 1 с. if (foo.Now()) { lcd.clear(); lcd.print(F("+10")); } botton = BOTTON_SHORT; } else if (millis() - time_Pressed > 1500 && timeNow - time_Pressed < 2500) { // Было недолгое нажатие кнопки - менее 2.5 с но более 1.5 с. if (foo.Now()) { lcd.clear(); lcd.print(F("+50")); } botton = BOTTON_NOLONG; } else if (millis() - time_Pressed >2500) { // Было долгое нажатие кнопки - больше 2.5 с. if (foo.Now()) { lcd.clear(); lcd.print(F("+100")); } botton = BOTTON_LONG; }*/ switch (botton) { // Здесь выбираем что менять; case BOTTON_CLICK: // При одиночном нажатии, val++; botton = BOTTON_NOT; break; case BOTTON_SHORT: // При коротком нажатии; val+=10; botton = BOTTON_NOT; break; case BOTTON_NOLONG: // При недолгом нажатии, val+=50; botton = BOTTON_NOT; break; case BOTTON_LONG: // При долгом нажатии, val+=100; botton = BOTTON_NOT; break; case BOTTON_NOT: pVal1 = &val1; pVal2 = &val2; alex_function(); lcd.setCursor(0, 1); lcd.print(val1); lcd.setCursor(0, 2); lcd.print(val2); break; } } void Press_8pin_Button(unsigned long INTERVAL ) { // функция отвечющая за выбор числа static unsigned long prevTime = 0; // время когда последний раз нажимали if (millis() - prevTime > INTERVAL) { prevTime = millis(); // flag=!flag; mem_Val1 = *pVal1; mem_Val2 = *pVal2; val = 0; } }Вот вам класс - короткое и длиное нажатие.
/**/ unsigned long mill;// переменная для millis() typedef void (*pDo)() ;// тип -функция обработчик //------Cl_BtnLong---------------------- // класс кнопка class Cl_BtnLong { protected: const byte pin; pDo Do1, Do2; //обработчик короткий,длиный bool bounce = 0; bool btn = 1, oldBtn; unsigned long past; const uint32_t time = 500 ; bool flag = 0; uint32_t past_flag = 0 ; public: /*конструктор*/ Cl_BtnLong(byte pin_, pDo Do1_, pDo Do2_) : pin(pin_), Do1(Do1_), Do2(Do2_) {} /*инициализация-вставить в setup()*/ void init() { pinMode(pin, INPUT_PULLUP); } /*работа-вставить в loop()*/ void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { bounce = 1; past = mill; } if (bounce && mill - past >= 10) { bounce = 0 ; oldBtn = btn; btn = newBtn; if (!btn && oldBtn) { flag = 1; past_flag = mill; } if (!oldBtn && btn && flag && mill - past_flag < time ) { flag = 0; Do1();// короткое нажатие } } if (flag && mill - past_flag >= time ) { flag = 0; Do2();//длиное нажатие } } }; //-----Компоновка---------------------- void DoBtn1() { Serial.println("Do_Btn1"); } void DoBtn2() { Serial.println("DoLong_Btn1"); } Cl_BtnLong Btn1(/*пин*/2,/*обработчик короткого*/DoBtn1,/*обработчик длиного*/DoBtn2); //-----main---------------------- void setup() { Serial.begin(9600); Btn1.init(); } void loop() { mill = millis(); Btn1.run(); } /*Скетч использует 2242 байт (7%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 231 байт (11%) динамической памяти, оставляя 1817 байт для локальных переменных. Максимум: 2048 байт. */ПС: Написание кода делится на 4 стадии- (1)составление ТЗ,(2) проектирование программы, (3)написание кода, (4)заливка кода. Но на деле на 2 пункт народ тупо забивает. Вот недано я проработал как графически просто проектировать программу. И да по вашему ТЗ уже нормально нарисовал картинку.
Немного переделал код qwone под свою задачу. Алгоритм такой: короткими одиночными нажатиями задаем предел(1,10, 100). Далее более длительным нажатием прибавляем к исходному числу(у меня val ) этот предел. Предел можно менять в ходе прибавления,
byte count = 0; // предел byte val = 0; // число /**/ unsigned long time_Now;// переменная для millis() typedef void (*pDo)() ;// тип -функция обработчик //------Cl_BtnLong---------------------- // класс кнопка class Cl_BtnLong { protected: const byte pin; pDo Do1, Do2, Do3; //обработчик короткий, длиный bool bounce = 0; bool btn = 1, oldBtn; unsigned long time_Last; //const uint32_t time = 100; bool button_state = 0; // bool button_long_state = 0; uint32_t time_Pressed = 0 ; public: /*конструктор*/ Cl_BtnLong(byte pin_, pDo Do1_, pDo Do2_, pDo Do3_) : pin(pin_), Do1(Do1_), Do2(Do2_), Do3(Do3_) {} /*инициализация-вставить в setup()*/ void init() { pinMode(pin, INPUT_PULLUP); } /*работа-вставить в loop()*/ void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { bounce = 1; time_Last = time_Now; } if (bounce && time_Now - time_Last >= 10) { bounce = 0 ; oldBtn = btn; btn = newBtn; if (!btn && oldBtn) { button_state = 1; time_Pressed = time_Now; } if (!oldBtn && btn && button_state && time_Now - time_Pressed < 200 ) { // короткое нажатие button_state = 0; count++; } } if (button_state && time_Now - time_Pressed >= 200) { //длиное нажатие button_state = 0; if (count == 0) { Do1(); } else if (count == 1){ Do2(); } else if (count == 2){ Do3(); } else { count = 0; } } } }; //-----Компоновка---------------------- void DoBtn1() { val += 100; Serial.println(val); //Serial.println("Do_Btn1"); } void DoBtn2() { val += 10; Serial.println(val); //Serial.println("DoNoLong_Btn1"); } void DoBtn3() { val ++; Serial.println(val); //Serial.println("DoLong_Btn1"); } Cl_BtnLong Btn1(/*пин*/9,/*обработчик короткого*/DoBtn1,/*обработчик недлиного*/DoBtn2,/*обработчик длиного*/DoBtn3); //-----main---------------------- void setup() { Serial.begin(9600); Btn1.init(); } void loop() { time_Now = millis(); Btn1.run(); }qwone, у меня к вам просьба. Я нашел на форуме amperka.ru тему Долгое нажатие клавиши
В #30 посте вы вылжили код и библиотеку, скажите можно ли ваш класс - "короткое и длиное нажатие" и эту библиотеку совместить
http://forum.amperka.ru/threads/%D0%94%D0%BE%D0%BB%D0%B3%D0%BE%D0%B5-%D0...
/*Cl_do_btn.h */ #ifndef Cl_do_btn_h #define Cl_do_btn_h #include "Arduino.h" class Cl_do_btn { private: byte pin ; // номер ноги на кнопке bool low; // уровень когда кнопка нажата bool btn, btn_old; bool bounce = 0; // антидребезговый флаг uint32_t past = 0 ; inline bool read() { //return digitalRead(pin)^low; return (PINB & (1 << pin))^low; }; void (* Do_Btn)(); //указатель на обработчик кнопки public: // указатель на класс Cl_do_btn * pnt; /* Создать новую кнопку Параметры : _pin вывод для подключения high уровень на выводе когда кнопка нажата _Do_Btn уазатель на функцию которую надо выполнить при нажатии кнопки */ Cl_do_btn(byte _pin, bool high, void (* _Do_Btn)()); // разместить эту функцию внутри setup() void setup(); // разместить эту функцию внутри loop() void loop(); }; // указатель на начало пакета кнопок extern Cl_do_btn * StartBtn; // вставить новую кнопку в пакет кнопок extern void Plug_btm (byte pin, bool high, void (* Do)()) ; // цикличная обработка пакета кнопок extern void Btns_loop(); #endif //Cl_do_btn_h/*Cl_do_btn.cpp */ #include "Arduino.h" #include "Cl_do_btn.h" // указатель на начало пакета кнопок Cl_do_btn * StartBtn = NULL; // вставить новую кнопку в пакет кнопок void Plug_btm (byte pin, bool high, void (* Do)()) { Cl_do_btn * pnt = new Cl_do_btn(pin, high, Do); //пин 2, 0 уров наж.кнопки , выполнить функцию f1() ; pnt->setup(); pnt->pnt = StartBtn; StartBtn = pnt; } // цикличная обработка пакета кнопок void Btns_loop() { for (Cl_do_btn * pnt = StartBtn; pnt != NULL; pnt = pnt->pnt) pnt->loop(); } // конструктор класса Cl_do_btn::Cl_do_btn(byte _pin, bool high, void (* _Do_Btn)()) { pin = _pin; low = !high; Do_Btn = _Do_Btn; } // setup() класса void Cl_do_btn::setup() { //pinMode(pin, INPUT);// подключить кнопку //pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой DDRB |= (0 << pin); // Пин 6 - на вход PORTB |= (1 << pin); // Включаем подтягивающий (Pull-UP) резистор для пина 6 btn = read(); // прочитать реальное значение на выводе } // loop() класса void Cl_do_btn::loop() { if (! bounce && btn != read()) { // если прошел фронт изм на выводн bounce = 1; // выставить флаг past = millis(); // сделать временую засветку } else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время bounce = 0; // то снять флаг btn_old = btn ; btn = read(); // прочитать реальное значение на выводе if (! btn_old && btn) Do_Btn(); } }Да и посмотрите хотелось бы передавать в библиотеку не номер пина ардуино а номер пина atmega328. То есть допустим не Plug_btm(10, 0, f2); //пин 10, 0 уров наж.кнопки , выполнить функцию f2()
а Plug_btm(PB2, 0, f2); //пин PB2, 0 уров наж.кнопки , выполнить функцию f2()
Пробовал не работает
Все можно. Похоже вы не видели эту тему:http://arduino.ru/forum/programmirovanie/klassy-arduino-po-qwone-dlya-chainikov
А организовывать для кнопок единую пакетную обработку хлопотно. Но если привыкнуть можно. Сейчас мне проще в setup и loop кинуть нужные методы всех предсутсвующих объектов класса. И даже тех, кому это не надо. Компилятор пустые методы сам выкинет. А я так банально посчитаю столько объектов в программе и столько методов.
Как я вас правильно понял все это реально, а насчет замена стандартных библиотечных функций ардуино на регистровые PORTB DDRB не уверены
Думаю сэкономить память, поэтому по возможности в коде библиотек хотелось бы избавиться от digitalRead и остального. Кнопок пять будет, как это организовать по ссылке я увидел
конкретно это равносильно же?
Но в коде биюлиотеки у вас pin передается типа byte, тогда PB1 какой типа?
Думаю сэкономить память
конкретно это равносильно же?
вы для начала напишите простенький скетч с digitalRead. а потом точно такой же - c вашей работой через регистры. И сравните обьем после компиляции.
А то, подозреваю, все это "ловля блох", а не экономия...
Думаю сэкономить память, поэтому по возможности в коде библиотек хотелось бы избавиться от digitalRead и остального. Кнопок пять будет, как это организовать по ссылке я увидел
qwone, извините может надоедаю, но можете мне подсказать с классом для 3 кнопок и для каждой кнопки требуется короткое и длительное нажатие. Конкретно могли бы вы объяснить как написать конструктор. Только учусь, извините
#include <avr/io.h> //---------------класс кнопка--------- class Cl_Btn { protected: byte pin; // номер ноги на кнопке void (* Do)();// указатель на обработчик bool btn = 1, btn_old; bool bounce = 0; // антидребезговый флаг bool flag = 0; uint32_t past_flag = 0 ; uint32_t past = 0 ; public: // конструктор класса Cl_Btn( byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {} // метод init() void init() { btn = digitalRead(pin); // прочитать реальное значение на выводе}; } // метод run() void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { // если прошел фронт изм на выводн bounce = 1; // выставить флаг past = millis(); // сделать временую засветку } else if ( bounce && millis() - past >= 10 ) { // если прошло антидребезговое время bounce = 0; // то снять флаг btn_old = btn ; btn = newBtn ; // прочитать реальное значение на выводе if (btn_old && !btn) { Do(); flag = 1; past_flag = millis(); } if (!btn_old && btn && flag && millis() - past_flag < 500 ) { flag = 0; // Do1();// короткое нажатие } } if (flag && millis() - past_flag >= 500 ) { flag = 0; // Do2();//длиное нажатие } } }; //--------------компоновка------------ // надо повторить в разделе компоновка объявление для каждой кнопки // кнопка 1 void Do_Btn1() { Serial.println("Btn1 press"); } Cl_Btn Btn1(/*пин*/9,/*обработчик*/Do_Btn1); // кнопка 2 void Do_Btn2() { Serial.println("Btn2 press"); } Cl_Btn Btn2(/*пин*/10,/*обработчик*/Do_Btn2); // кнопка 3 void Do_Btn3() { Serial.println("Btn3 press"); } Cl_Btn Btn3(/*пин*/11,/*обработчик*/Do_Btn3); //------------main()-------------- void setup() { Serial.begin(9600); DDRB = 0x00; // назначить пины кнопок на вход PORTB = 0b00111111; // подключить внутренние подтягивающие pull-up резисторы Btn1.init(); //< так же для каждой кнопки вставить свой init() Btn2.init(); //< Btn3.init(); //< } void loop() { Btn1.run(); //< так же для каждой кнопки вставить свой run() Btn2.run(); //< Btn3.run(); //< }Понял несколько вещей...
Имя функции конструктора должно совпадать с именем класса, а после него должны следовать круглые скобки ().
функция конструктора должна располагаться под ключевым словом public.
Функция конструктора всегда возвращает значение типа void
Берем скетч от сюда #18 и делаем на каждую кнопку свой объект
/**/ unsigned long mill;// переменная для millis() typedef void (*pDo)() ;// тип -функция обработчик //------Cl_BtnLong---------------------- // класс кнопка class Cl_BtnLong { protected: const byte pin; pDo Do1, Do2; //обработчик короткий,длиный bool bounce = 0; bool btn = 1, oldBtn; unsigned long past; const uint32_t time = 500 ; bool flag = 0; uint32_t past_flag = 0 ; public: /*конструктор*/ Cl_BtnLong(byte pin_, pDo Do1_, pDo Do2_) : pin(pin_), Do1(Do1_), Do2(Do2_) {} /*инициализация-вставить в setup()*/ void init() { pinMode(pin, INPUT_PULLUP); } /*работа-вставить в loop()*/ void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { bounce = 1; past = mill; } if (bounce && mill - past >= 10) { bounce = 0 ; oldBtn = btn; btn = newBtn; if (!btn && oldBtn) { flag = 1; past_flag = mill; } if (!oldBtn && btn && flag && mill - past_flag < time ) { flag = 0; Do1();// короткое нажатие } } if (flag && mill - past_flag >= time ) { flag = 0; Do2();//длиное нажатие } } }; //-----Компоновка---------------------- // кнопка 1 void Do1Btn1() { Serial.println("Do_Btn1"); } void Do2Btn1() { Serial.println("DoLong_Btn1"); } Cl_BtnLong Btn1(/*пин*/9,/*обработчик короткого*/Do1Btn1,/*обработчик длиного*/Do2Btn1); // кнопка 2 void Do1Btn2() { Serial.println("Do_Btn2"); } void Do2Btn2() { Serial.println("DoLong_Btn2"); } Cl_BtnLong Btn2(/*пин*/10,/*обработчик короткого*/Do1Btn2,/*обработчик длиного*/Do2Btn2); // кнопка 3 void Do1Btn3() { Serial.println("Do_Btn3"); } void Do2Btn3() { Serial.println("DoLong_Btn3"); } Cl_BtnLong Btn3(/*пин*/11,/*обработчик короткого*/Do1Btn3,/*обработчик длиного*/Do2Btn3); //-----main---------------------- void setup() { Serial.begin(9600); Btn1.init(); Btn2.init(); Btn3.init(); } void loop() { mill = millis(); Btn1.run(); Btn2.run(); Btn3.run(); } /*Скетч использует 2434 байт (7%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 313 байт (15%) динамической памяти, оставляя 1735 байт для локальных переменных. Максимум: 2048 байт. */ПС: Почитай это.Да закинь к себе ссылку. Там много всего. Но не адаптировано под Ардуину. :(
http://document.saraff.ru/
Поправил
Спасибо, больше беспокоить вас пустяковыми вопросами сегодня не буду. Сяду разберусь
Ссылка не рабочая :(
Увеличил количество кнопок до 5 и добавил действие на отпускание. За все спасибо
/**/ typedef void (*pDo)() ;// тип -функция обработчик //------Cl_BtnLong---------------------- // класс кнопка class Cl_BtnLong { protected: const byte pin; pDo Do1, Do2, Do3, Do4, Do5; //обработчик короткий,длиный bool bounce = 0; bool btn = 1, oldBtn; unsigned long time_Pressed; bool flag = 0; uint32_t last_flag = 0 ; public: /*конструктор*/ Cl_BtnLong(byte pin_, pDo Do1_, pDo Do2_, pDo Do3_) : pin(pin_), Do1(Do1_), Do2(Do2_), Do3(Do3_) {} /*инициализация-вставить в setup()*/ void init() { pinMode(pin, INPUT_PULLUP); } /*работа-вставить в loop()*/ void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { bounce = 1; time_Pressed = millis(); } if (bounce && millis() - time_Pressed >= 10) { //bounce = 0 ; oldBtn = btn; btn = newBtn; if (!btn && oldBtn) { flag = 1; last_flag = millis(); } if (!oldBtn && btn && flag && millis() - last_flag < 500 ) { flag = 0; Do1();// короткое нажатие } } if (flag && millis() - last_flag >= 500 ) { flag = 0; Do2();//длиное нажатие } if (bounce && !flag && btn && millis() - time_Pressed > 500) { bounce = 0; Do3(); } // отпускание } }; //-----Компоновка---------------------- // кнопка 1 void Do1Btn1() { //Serial.println("Do_Btn1"); } void Do2Btn1() { //Serial.println("DoLong_Btn1"); } void Do3Btn1() { //Serial.println("Long_Btn1"); } Cl_BtnLong Btn1(/*пин*/9,/*обработчик короткого*/Do1Btn1,/*обработчик длиного*/Do2Btn1,/*обработчик длиного*/Do3Btn1 ); // кнопка 2 void Do1Btn2() { //Serial.println("Do_Btn2"); } void Do2Btn2() { //Serial.println("DoLong_Btn2"); } void Do3Btn2() { //Serial.println("Long_Btn1"); } Cl_BtnLong Btn2(/*пин*/10,/*обработчик короткого*/Do1Btn2,/*обработчик длиного*/Do2Btn2,/*обработчик длиного*/Do3Btn2); // кнопка 3 void Do1Btn3() { //Serial.println("Do_Btn3"); } void Do2Btn3() { //Serial.println("DoLong_Btn3"); } void Do3Btn3() { //Serial.println("Long_Btn1"); } Cl_BtnLong Btn3(/*пин*/11,/*обработчик короткого*/Do1Btn3,/*обработчик длиного*/Do2Btn3,/*обработчик длиного*/Do3Btn3); void Do1Btn4() { Serial.println("Do_Btn3"); } void Do2Btn4() { Serial.println("DoLong_Btn3"); } void Do3Btn4() { Serial.println("Long_Btn1"); } Cl_BtnLong Btn4(/*пин*/12,/*обработчик короткого*/Do1Btn4,/*обработчик длиного*/Do2Btn4,/*обработчик длиного*/Do3Btn4); void Do1Btn5() { Serial.println("Do_Btn3"); } void Do2Btn5() { Serial.println("DoLong_Btn3"); } void Do3Btn5() { Serial.println("Long_Btn1"); } Cl_BtnLong Btn5(/*пин*/13,/*обработчик короткого*/Do1Btn5,/*обработчик длиного*/Do2Btn5,/*обработчик длиного*/Do3Btn5); //-----main---------------------- void setup() { Serial.begin(9600); Btn1.init(); Btn2.init(); Btn3.init(); Btn4.init(); Btn5.init(); } void loop() { Btn1.run(); Btn2.run(); Btn3.run(); Btn4.run(); Btn5.run(); }Александр лови. Разберешься будет толк. А нет тогда смысла нет.
//**/ unsigned long mill;// переменная для millis() typedef void (*pDo)() ;// тип -функция обработчик typedef struct { // тип строка меню pDo viev; pDo inc; pDo dec; } NoteMenu; //------Cl_Display---------------------- // класс регулярный вывод на дисплей class Cl_Display { protected: pDo Do;//обработчик unsigned long interval, past; public: /*конструктор*/ Cl_Display(unsigned long i, pDo D): interval(i), Do(D) {} /*инициализация-вставить в setup()*/ void init() { } /*работа-вставить в loop()*/ void run() { if (mill - past >= interval) { past = mill; Do(); } } /*записать новый обработчик*/ void write( pDo D) { Do = D; } }; //------Cl_Btn---------------------- // класс кнопка class Cl_Btn { protected: const byte pin; pDo Do;//обработчик bool bounce = 0; bool btn = 1, oldBtn; unsigned long past; public: /*конструктор*/ Cl_Btn(byte p, pDo D): pin(p), Do(D) {} /*инициализация-вставить в setup()*/ void init() { pinMode(pin, INPUT_PULLUP); } /*работа-вставить в loop()*/ void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { bounce = 1; past = mill; } if (bounce && mill - past >= 10) { bounce = 0 ; oldBtn = btn; btn = newBtn; past = mill; if (!btn && oldBtn) Do(); } } /*записать новый обработчик*/ void write( pDo D) { Do = D; } }; //------Cl_BtnR---------------------- // класс кнопка с повтором при удерж кнопки class Cl_BtnR { protected: const byte pin; pDo Do;//обработчик bool bounce = 0; bool btn = 1, oldBtn; unsigned long past; public: /*конструктор*/ Cl_BtnR(byte p, pDo D): pin(p), Do(D) {} /*инициализация-вставить в setup()*/ void init() { pinMode(pin, INPUT_PULLUP); } /*работа-вставить в loop()*/ void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { bounce = 1; past = mill; } if (bounce && mill - past >= 10) { bounce = 0 ; oldBtn = btn; btn = newBtn; past = mill; if (!btn && oldBtn) Do(); } if (!newBtn && !btn && mill - past >= 300) { past = mill; Do(); } } /*записать новый обработчик*/ void write( pDo D) { Do = D; } }; //-----Компоновка---------------------- //переменая var1 const int minVar1 = 10; const int maxVar1 = 100; int var1 = minVar1; /*вывевети на экран var1*/ void vievVar1() { Serial.print("var1: "); Serial.print(var1); Serial.println(); } /*прочитать var1*/ void loadVar1() {} /*записать var1*/ void saveVar1() {} /*увеличить var1*/ void incVar1() { ++var1; if (var1 > maxVar1) var1 = maxVar1; } /*уменьшить var1*/ void decVar1() { --var1; if (var1 < minVar1) var1 = minVar1; } //переменая var2 const int minVar2 = 10; const int maxVar2 = 100; int var2 = minVar2; /*вывевети на экран var2*/ void vievVar2() { Serial.print("var2: "); Serial.print(var2); Serial.println(); } /*прочитать var2*/ void loadVar2() {} /*записать var2*/ void saveVar2() {} /*увеличить var2*/ void incVar2() { ++var2; if (var2 > maxVar2) var2 = maxVar2; } /*уменьшить var2*/ void decVar2() { --var2; if (var2 < minVar2) var2 = minVar2; } // меню int maxScreen = 2; int screen = 0; NoteMenu NM[] = { {vievVar1, incVar1, decVar1}, /*1 экран*/ {vievVar2, incVar2, decVar2} /*2 экран*/ }; // дисплей Cl_Display Display(/*интервал*/500,/*обработчик*/NM[screen].viev); // кнопки Cl_BtnR Btn1(/*пин*/2,/*обработчик*/NM[screen].inc);/*инкрем*/ Cl_BtnR Btn2(/*пин*/3,/*обработчик*/NM[screen].dec);/*декримент*/ void DoBtn3() { ++screen; if (screen >= maxScreen) screen = 0; Display.write(NM[screen].viev); Btn1.write(NM[screen].inc); Btn2.write(NM[screen].dec); } Cl_Btn Btn3(/*пин*/4,/*обработчик*/DoBtn3);/*Next*/ //-----main---------------------- void setup() { Serial.begin(9600); Display.init(); Btn1.init(); Btn2.init(); Btn3.init(); } void loop() { mill = millis(); Display.run(); Btn1.run(); Btn2.run(); Btn3.run(); } /*Скетч использует 3090 байт (10%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 262 байт (12%) динамической памяти, оставляя 1786 байт для локальных переменных. Максимум: 2048 байт. */ПС: Там еще и модернизировать и модернизировать. Но это уже с области ТЗ(технической задачи)
Спасибо конечно, но для меня это и правда сложно. А ваш класс кнопки разобрал и усвоил. И использовал под свою задачу