Оптимизация

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Всем доброго здравия! Меня зовут Александр (на случай если логин вводит в заблуждение подскажите как изменить)

Алгоритм  следующий : Есть два числа типа 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;
    }
   
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Тебе зачем оптимизация? Тщеславие чешется? Или другие веские причины? Если код работает и пока всё устраивает - не трожь. А по сути вопроса - premature optimization is the root of all evil (c) Дональд Кнут, умный дядька.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Код рабочий. Идея в том чтобы лишнее из loop перенести в функцию(счетчик прибавления например). Но не знаю какие ей передавайть аргументы? Возможно само число val и в функции уже производить над ним операции в зависимости от длительности зажатия.

Точно такие же действия хочу сдклать и с опрерацией вычитания. С теми же пределами, вот и задумался. Допускаю что это будет на отдельной кнопке (10 пин). Но не хотелось бы загромождать код идентичной обработкой кнопки и идентичными операциями с пределом. Поэтому и создал тему

b707
Offline
Зарегистрирован: 26.05.2017

прежде чем думать об оптимизации - надо написать код поприличнее. А у вас обработка нажатия кнопки на 9-м пине - это сплошной баг. Во-первых, "короткое", "недолгое" и "долгое" нажатие будут детектироваться последовательно на одном физическом нажатии кнопки. Во-вторых, цикл while - это скрытый delay на 3 секунды, хоть и написан. якобы, на миллис.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Вообщем поразмыслив, понял что достаточно ответов на 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;
    }

   

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

b707 пишет:

 Во-вторых, цикл while - это скрытый delay на 3 секунды, хоть и написан. якобы, на миллис.

Значит придется заменить на if. Спасибо за совет

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

b707 пишет:

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

Знаете, мне так и нужно. То есть удерживая кнопку значения счетчика действительно пробегают последовательно от 1 до 100. Отпуская кнопку я и выбираю предел. И этот предел добавляется к выбранному числу.

Проще так : нажал - предел(1...10...50...100) высвечивается на дисплее - отпустил на 10, она и добавилась

Тут ложная тревога

b707
Offline
Зарегистрирован: 26.05.2017

BuonanotteMasha пишет:

Вообщем поразмыслив, понял что достаточно ответов на 3 вопроса, дальше своими двоими.

1. Возможна ли обработка нажатий кнопки за телом функции loop. Если да то п.2

да. loop - такая же функция, как любая другая

BuonanotteMasha пишет:
2. Если для этого использовать отдельную функцию, то можно ей передать в качестве аргумента номер пина ардуино?

конечно. Номер пина может быть задан переменной, а не жестко закодирован в коде

 

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

b707, очень благодарен, картина проясняется.

b707
Offline
Зарегистрирован: 26.05.2017

BuonanotteMasha пишет:

Значит придется заменить на if. Спасибо за совет

вы бредите... Дело не в while - дело в вашем коде внутри. Идея останавливать программу на 3 секунды, пока кнопка нажата - категорически неверная. А делаете ли вы это на while или на if - без разницы, и так и так плохо.

Нужно переписать кусок внутри while в неблокирующем виде.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Теперь понял о чем вы.  Уезжаю на учебу, вечером буду пробовать

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Написал код, но где то ошибка. Если заметите, поправьте

#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;
    }  
}
qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

BuonanotteMasha пишет:
Неблакирующую задержку добавил чтобы дисплей не мерцал. Возможно ли сделать это проще, то есть не прибегая к такому количеству переменных как у меня ? 
На счет сокращения колличества переменных я не уверен. Но если вам хочется оптимизации в программировании, то советую перейти на Си++

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018
     if (digitalRead(9) == 0) {                
            timeNow = millis();                //  засекаем время;
            if (timeNow - time_Pressed > 3000) {// если кому то вздумается очень долго удерживать кнопку
               timeNow = 0;
	         }
	      }

!!!Ошибка этой конструкции в том, что я присваиваю переменной timeNow значение миллис, которое она приняла в данный момент. Мне же надо запустить отсчет времени как только сработало условие нажатия

5N62V
Offline
Зарегистрирован: 25.02.2016

BuonanotteMasha пишет:

Написал код, но где то ошибка. Если заметите, поправьте

 

Так Вы бы сообщение компилятора скопипастии, что ли....

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

5N62V, постараюсь объяснится понятнее. Код компилируется без ошибок, но работает не так как мне нужно. На дисплее отображается непонять что 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Это и понятно. Когда работаешь с множеством задач висящих на 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 байт.
*/

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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;	 
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот вам класс - короткое и длиное нажатие. 

/**/
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 пункт народ тупо забивает.  Вот недано я проработал как графически просто проектировать программу. И да по вашему ТЗ уже нормально нарисовал картинку.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Немного переделал код 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();
}

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

qwone, у меня к вам просьба. Я нашел на форуме amperka.ru тему Долгое нажатие клавиши 

В #30 посте вы вылжили код и библиотеку, скажите можно ли ваш класс - "короткое и длиное нажатие" и эту библиотеку совместить

http://forum.amperka.ru/threads/%D0%94%D0%BE%D0%BB%D0%B3%D0%BE%D0%B5-%D0...

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018
/*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()

Пробовал не работает

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Все можно. Похоже вы не видели эту тему:http://arduino.ru/forum/programmirovanie/klassy-arduino-po-qwone-dlya-chainikov

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

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Думаю сэкономить память, поэтому по возможности в коде библиотек хотелось бы избавиться от digitalRead и остального. Кнопок пять будет, как это организовать по ссылке я увидел

конкретно это равносильно же?







//return digitalRead(pin)^low;
  return (PINB & (1 << pin))^low;




//pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
  DDRB |= (0 << pin);	// Пин  - на вход
  PORTB |= (1 << pin);	// Включаем подтягивающий (Pull-UP) резистор 

Но в коде биюлиотеки у вас pin передается типа byte, тогда PB1 какой типа?

b707
Offline
Зарегистрирован: 26.05.2017

BuonanotteMasha пишет:

Думаю сэкономить память

конкретно это равносильно же?



./return digitalRead(pin)^low;
  return (PINB & (1 << pin))^low;




//pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
  DDRB |= (0 << pin);	// Пин  - на вход
  PORTB |= (1 << pin);	// Включаем подтягивающий (Pull-UP) резистор 

 

вы для начала напишите простенький скетч с digitalRead. а потом точно такой же - c вашей работой через регистры. И сравните обьем после компиляции.

А то, подозреваю, все это "ловля блох", а не экономия...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

BuonanotteMasha пишет:

Думаю сэкономить память, поэтому по возможности в коде библиотек хотелось бы избавиться от digitalRead и остального. Кнопок пять будет, как это организовать по ссылке я увидел

Переход на прямую на пины память не экономит. И там где у вас один пин будут 4 числа - регистр настройки, регист ввода, регистр вывода и номер бита. Да конечно можно писать без классов. Тогда будет дублирование кода для каждого объекта- что приведет к расходу не ОЗУ, а флеш.  Я уже не рад что вам эти темы дал. Так как вы экономите спички паля деньги. 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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();  //<
}

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Понял несколько вещей...

Имя функции конструктора должно совпадать с именем класса, а после него должны следовать круглые скобки (). 

 функция конструктора должна располагаться под ключевым словом public.

Функция конструктора всегда возвращает значение типа void

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Берем скетч от сюда #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/

Поправил

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

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

Ссылка не рабочая :(

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Увеличил количество кнопок до 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();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Александр лови. Разберешься будет толк. А нет тогда смысла нет.

//**/
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 байт.
*/

ПС: Там еще и модернизировать и модернизировать. Но это уже с области ТЗ(технической задачи)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Спасибо конечно, но для меня это и правда сложно. А ваш класс кнопки разобрал и усвоил. И использовал под свою задачу