Оптимизация
- Войдите на сайт для отправки комментариев
Ср, 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].
3. Возможно ли здесь не добавляя дополнительной переменной, сделать аналогично операцию вычитания?
Во-вторых, цикл while - это скрытый delay на 3 секунды, хоть и написан. якобы, на миллис.
Значит придется заменить на if. Спасибо за совет
прежде чем думать об оптимизации - надо написать код поприличнее. А у вас обработка нажатия кнопки на 9-м пине - это сплошной баг. Во-первых, "короткое", "недолгое" и "долгое" нажатие будут детектироваться последовательно на одном физическом нажатии кнопки.
Знаете, мне так и нужно. То есть удерживая кнопку значения счетчика действительно пробегают последовательно от 1 до 100. Отпуская кнопку я и выбираю предел. И этот предел добавляется к выбранному числу.
Проще так : нажал - предел(1...10...50...100) высвечивается на дисплее - отпустил на 10, она и добавилась
Тут ложная тревога
Вообщем поразмыслив, понял что достаточно ответов на 3 вопроса, дальше своими двоими.
1. Возможна ли обработка нажатий кнопки за телом функции loop. Если да то п.2
да. loop - такая же функция, как любая другая
конечно. Номер пина может быть задан переменной, а не жестко закодирован в коде
b707, очень благодарен, картина проясняется.
Значит придется заменить на if. Спасибо за совет
вы бредите... Дело не в while - дело в вашем коде внутри. Идея останавливать программу на 3 секунды, пока кнопка нажата - категорически неверная. А делаете ли вы это на while или на if - без разницы, и так и так плохо.
Нужно переписать кусок внутри while в неблокирующем виде.
Теперь понял о чем вы. Уезжаю на учебу, вечером буду пробовать
Написал код, но где то ошибка. Если заметите, поправьте
!!!Ошибка этой конструкции в том, что я присваиваю переменной timeNow значение миллис, которое она приняла в данный момент. Мне же надо запустить отсчет времени как только сработало условие нажатия
Написал код, но где то ошибка. Если заметите, поправьте
Так Вы бы сообщение компилятора скопипастии, что ли....
5N62V, постараюсь объяснится понятнее. Код компилируется без ошибок, но работает не так как мне нужно. На дисплее отображается непонять что
Это и понятно. Когда работаешь с множеством задач висящих на millis, надо быть очень внимательным. Особено если это скетч на традиционном ардуино стиле.
Но я начинал бы так.
qwone, спасибо вам за идею. Действительно можно сделать обработку событий для кнопок в отдельных функциях. Подумаю над этим.
Пока сделал простейшее: функцию одной кнопки - выбор числа. То что закомментировано не хочет корректно работать
Вот вам класс - короткое и длиное нажатие.
ПС: Написание кода делится на 4 стадии- (1)составление ТЗ,(2) проектирование программы, (3)написание кода, (4)заливка кода. Но на деле на 2 пункт народ тупо забивает. Вот недано я проработал как графически просто проектировать программу. И да по вашему ТЗ уже нормально нарисовал картинку.
Немного переделал код qwone под свою задачу. Алгоритм такой: короткими одиночными нажатиями задаем предел(1,10, 100). Далее более длительным нажатием прибавляем к исходному числу(у меня val ) этот предел. Предел можно менять в ходе прибавления,
qwone, у меня к вам просьба. Я нашел на форуме amperka.ru тему Долгое нажатие клавиши
В #30 посте вы вылжили код и библиотеку, скажите можно ли ваш класс - "короткое и длиное нажатие" и эту библиотеку совместить
http://forum.amperka.ru/threads/%D0%94%D0%BE%D0%BB%D0%B3%D0%BE%D0%B5-%D0...
Да и посмотрите хотелось бы передавать в библиотеку не номер пина ардуино а номер пина 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 кнопок и для каждой кнопки требуется короткое и длительное нажатие. Конкретно могли бы вы объяснить как написать конструктор. Только учусь, извините
Понял несколько вещей...
Имя функции конструктора должно совпадать с именем класса, а после него должны следовать круглые скобки ().
функция конструктора должна располагаться под ключевым словом public.
Функция конструктора всегда возвращает значение типа void
Берем скетч от сюда #18 и делаем на каждую кнопку свой объект
ПС: Почитай это.Да закинь к себе ссылку. Там много всего. Но не адаптировано под Ардуину. :(
http://document.saraff.ru/
Поправил
Спасибо, больше беспокоить вас пустяковыми вопросами сегодня не буду. Сяду разберусь
Ссылка не рабочая :(
Увеличил количество кнопок до 5 и добавил действие на отпускание. За все спасибо
Александр лови. Разберешься будет толк. А нет тогда смысла нет.
ПС: Там еще и модернизировать и модернизировать. Но это уже с области ТЗ(технической задачи)
Спасибо конечно, но для меня это и правда сложно. А ваш класс кнопки разобрал и усвоил. И использовал под свою задачу