Цикл в цикле

Alex178
Offline
Зарегистрирован: 06.03.2018

Задание: В одном из пунктов главного меню организовать установку времени посредством энкодера (d2,d3,d4), поворачивая меняются часы, при нажатии на энкодер настрйока перескакивает на установку минут. И организовать выход из установки часов и минут посредством длинного тапа.

Проблема: Часы с минутами устанавливаются одновременно, то по очереди. )))

Кусок кода прилагаю. Заранее благодарю за помощь.

void action1() {          //       ----------- Выполнение 1 пункта меню ---------------------------------


   if (millis() - lasttime > 1000) {
    lasttime = millis();
    
    tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
    tft.setCursor (20, 20);
    tft.print(rtc.getTimeStr());   } 
 
 do {
 switch (tset) {
 
  case 0:
   tset =1;  
   break; 
      
  case 1: 
    tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
    tft.setCursor (20, 40);
    if (hsetON < 10) tft.print('0');
    tft.print(hsetON);
   
    tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
    tft.setCursor (55, 40);
    tft.print(msetON);
  
    if (enc1.isRight()) {
       hsetON++;
    if (hsetON >=24) hsetON=0;   }
    
    if (enc1.isLeft()) {
       hsetON--;
    if (hsetON <=0) hsetON=0;   }
    
    if (enc1.isPress()){
      tset++;
      break;    }
    


 case 2:  
    tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
    tft.setCursor (20, 40);
    tft.print(hsetON);
   
    tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
    tft.setCursor (55, 40);
    if (msetON < 10) tft.print('0');
    tft.print(msetON);
    
    if (enc1.isRight()) {
       msetON++;
    if (msetON >=60) msetON=0;   }
    
    if (enc1.isLeft()) {
       msetON--;
    if (msetON <=0) msetON=0;   }
    
    if (enc1.isPress()){
    tset--;
    break;
    }


 case 3:
   tset = 1;
   break; 
}
 }    
   while (enc1.isHolded() !=1 );  
   tft.fillScreen(ST77XX_BLACK);
   
}

void action2() {          //       ----------- Выполнение 2 пункта меню ---------------------------------

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Что то ересь какая то...

Alex178
Offline
Зарегистрирован: 06.03.2018

Вот целый код.

#include "SPI.h"
#include "Adafruit_GFX.h"
#include <Adafruit_ST7735.h>

#include <Adafruit_INA219.h>


#include <BH1750.h>
#include <DS3231.h>

#define TFT_DC 9
#define TFT_CS 10
#define TFT_RST -1

#define CLK 2
#define DT 3
#define SW 4


#include <Wire.h>
#include <AT24CX.h>

AT24CX mem;


byte luxset;
byte hsetON =12;
byte msetON =45;

unsigned long lasttime; 

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

Adafruit_INA219 ina219;

DS3231  rtc(SDA, SCL);
BH1750 lightMeter;

#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW);

 int menu = 1;
 int tset = 1;

void setup() {
  
  lightMeter.begin();

  ina219.begin();

  rtc.begin();
  
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(3);
  tft.fillScreen(ST77XX_BLACK);
//  tft.setTextSize(2);

  enc1.setType(TYPE1);
  enc1.setTickMode(AUTO);
  
  
  float busvoltage = 0;
   
  updateMenu();
}

void loop() {
   
  if (enc1.isRight()) {
    menu++;
    updateMenu();
    while (enc1.isRight());
  }
  if (enc1.isLeft()) {
    menu--;
    updateMenu();
    while (enc1.isLeft());
  }
  if (enc1.isPress()) {
    tft.fillScreen(ST77XX_BLACK);
    tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
    executeAction();
    updateMenu();
    delay(50);
    while (enc1.isPress());
  }
}

void updateMenu(){
  tft.setTextSize(2);
  switch (menu) {
  case 0:
     menu = 1;
   break;    
  case 1:
     tft.setCursor(20, 10);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_RED);
     tft.print("Set Time   ");
     tft.setCursor(20, 30);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Luxometer  ");
     tft.setCursor(20, 50);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Battery    ");
     tft.setCursor(20, 70);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Exit       ");
   break;
  case 2:
     tft.setCursor(20, 10);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Set Time   ");
     tft.setCursor(20, 30);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_RED);
     tft.print("Luxometer  ");
     tft.setCursor(20, 50);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Battery    ");
     tft.setCursor(20, 70);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Exit       ");
   break;
  case 3:
     tft.setCursor(20, 10);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Set Time   ");
     tft.setCursor(20, 30);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Luxometer  ");
     tft.setCursor(20, 50);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_RED);
     tft.print("Battery    ");
     tft.setCursor(20, 70);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Exit       ");
   break;  
  case 4:
     tft.setCursor(20, 10);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Set Time   ");
     tft.setCursor(20, 30);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Luxometer  ");
     tft.setCursor(20, 50);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
     tft.print("Battery    ");
     tft.setCursor(20, 70);
     tft.setTextColor(ST77XX_YELLOW, ST77XX_RED);
     tft.print("Exit       ");    
   break;  
  case 5:
     menu = 4;
   break;
     }  
}

void executeAction() {
  switch (menu) {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
    case 3:
      action3();
      break;
    case 4:
      action4();
      break;
  }
}

void action1() {          //       ----------- Выполнение 1 пункта меню ---------------------------------


   if (millis() - lasttime > 1000) {
    lasttime = millis();
    
    tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
    tft.setCursor (20, 20);
    tft.print(rtc.getTimeStr());   } 
 
 do {
 switch (tset) {
 
  case 0:
   tset =1;  
   break; 
      
  case 1: 
    tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
    tft.setCursor (20, 40);
    if (hsetON < 10) tft.print('0');
    tft.print(hsetON);
   
    tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
    tft.setCursor (55, 40);
    tft.print(msetON);
  
    if (enc1.isRight()) {
       hsetON++;
    if (hsetON >=24) hsetON=0;   }
    
    if (enc1.isLeft()) {
       hsetON--;
    if (hsetON <=0) hsetON=0;   }
    
    if (enc1.isPress()){
      tset++;
      break;    }
    


 case 2:  
    tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
    tft.setCursor (20, 40);
    tft.print(hsetON);
   
    tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
    tft.setCursor (55, 40);
    if (msetON < 10) tft.print('0');
    tft.print(msetON);
    
    if (enc1.isRight()) {
       msetON++;
    if (msetON >=60) msetON=0;   }
    
    if (enc1.isLeft()) {
       msetON--;
    if (msetON <=0) msetON=0;   }
    
    if (enc1.isPress()){
    tset--;
    break;
    }


 case 3:
   tset = 1;
   break; 
}
 }    
   while (enc1.isHolded() !=1 );  
   tft.fillScreen(ST77XX_BLACK);
   
}

void action2() {          //       ----------- Выполнение 2 пункта меню ---------------------------------

 byte luxset = mem.read(19);

do {
 if (millis() - lasttime > 1000) {
  lasttime = millis();
  
  float lux = lightMeter.readLightLevel();
  
  tft.setCursor (10, 30);
  tft.print(lux);
 }

  tft.setCursor (10, 10);
  tft.print(luxset);
   
  if (enc1.isRight()) {
       luxset++;
     if (luxset >=100) luxset=99; 

  }
  if (enc1.isLeft()) {
       luxset--;
       if (luxset <=0) luxset=1;
   }
  }
while (enc1.isHolded() !=1);

  mem.write(19, luxset);
  tft.fillScreen(ST77XX_BLACK);
  }

void action3() {       //       ----------- Выполнение 3 пункта меню ---------------------------------
 
 float minvoltage = mem.readFloat(24);

do {
 if (millis() - lasttime > 1000) {
    lasttime = millis();
        
    tft.setCursor (10, 30);
    tft.print(ina219.getBusVoltage_V());
 }

    tft.setCursor (10, 10);
    tft.print(minvoltage);
  
  if (enc1.isRight()) {
    minvoltage=minvoltage+0.1;
    if (minvoltage >=25.1) minvoltage=25.0;
  }

  if (enc1.isLeft()) {
    minvoltage=minvoltage-0.1;
    if (minvoltage <=4.9) minvoltage=5.0;
  }
  }
while (enc1.isHolded() !=1);
  mem.writeFloat(24, minvoltage);
  tft.fillScreen(ST77XX_BLACK);
  }
  
void action4() {      //       ----------- Выполнение 4 пункта меню ---------------------------------

    tft.setTextSize(1);
  byte luxset = mem.read(19);
  float minvoltage = mem.readFloat(24);
 do {
     if (millis() - lasttime > 1000) {
    lasttime = millis();
    tft.setCursor (5, 5);
    tft.print(rtc.getTimeStr());
    tft.print(" / ");
    tft.print(rtc.getTemp());
    tft.print(" C");

    float lux = lightMeter.readLightLevel();
    
    tft.setCursor (5, 30);
    tft.print(lux);
    tft.print(" / ");
    tft.print(luxset);
    
    tft.setCursor (5, 55);
    tft.print(ina219.getBusVoltage_V());
    tft.print(" / ");
    tft.print(minvoltage);
 } 
  } 
while (enc1.isHolded() !=1);
  tft.fillScreen(ST77XX_BLACK);
  }

 

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

Alex178 пишет:
организовать выход из установки часов и минут посредством длинного тапа.
А что такое длинный тап и чем он отличается от короткого тапа?

Alex178
Offline
Зарегистрирован: 06.03.2018

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

Alex178 пишет:
организовать выход из установки часов и минут посредством длинного тапа.
А что такое длинный тап и чем он отличается от короткого тапа?

нажатие и удержание кнопки энкодера в несколько секунд.

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

Если кнопка не нажата, то после case 1 срезу же выполняется case2 - там брейка нет. После case 2 брейка, кстати, тоже нет. Так и должно быть? Думаю именно поэтому всё одновременно устанавливается.

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

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

Alex178
Offline
Зарегистрирован: 06.03.2018

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

Если кнопка не нажата, то после case 1 срезу же выполняется case2 - там брейка нет. После case 2 брейка, кстати, тоже нет. Так и должно быть? Думаю именно поэтому всё одновременно устанавливается.

Строка 209 и 233. При нажатии должен быть брейк и переход на след. кейс. При повороте брейка нет.

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

И что это за название case 1,case 2 . Ну зачем так шифроваться . назовите  clock, setHour,setMin,setSec.

Alex178
Offline
Зарегистрирован: 06.03.2018

qwone пишет:

И что это за название case 1,case 2 . Ну зачем так шифроваться . назовите  clock, setHour,setMin,setSec.

А как? там по флажку tset, при нажатии 1 раз плюсует, при повторном отнимает.

Alex178
Offline
Зарегистрирован: 06.03.2018

Выпилил все ненужное.

#include "Adafruit_GFX.h"
#include <Adafruit_ST7735.h>

#define TFT_DC 9
#define TFT_CS 10
#define TFT_RST -1

#define CLK 2
#define DT 3
#define SW 4


byte hsetON =12;
byte msetON =45;

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);


#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW);

 int tset = 1;


void setup() {
  
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(3);
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextSize(2);

  enc1.setType(TYPE1);
  enc1.setTickMode(AUTO);


do {
 switch (tset) {
 
  case 0:
   tset =1;  
   break; 
      
  case 1: 
    tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
    tft.setCursor (20, 40);
    if (hsetON < 10) tft.print('0');
    tft.print(hsetON);
       
    tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
    tft.setCursor (55, 40);
    tft.print(msetON);
    
    if (enc1.isRight()) {
       hsetON++;
    if (hsetON >=24) hsetON=0;   }
    
    if (enc1.isLeft()) {
       hsetON--;
    if (hsetON <=0) hsetON=23;   }
    
    if (enc1.isPress()) {
        tset++;
          break;    }
    


 case 2:  
    tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
    tft.setCursor (20, 40);
    tft.print(hsetON);
   
    tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
    tft.setCursor (55, 40);
    if (msetON < 10) tft.print('0');
    tft.print(msetON);
    
    if (enc1.isRight()) {
       msetON++;
    if (msetON >=60) msetON=0;   }
    
    if (enc1.isLeft()) {
       msetON--;
    if (msetON <=0) msetON=59;   }
    
    if (enc1.isPress()){
      tset--;
      break;     }

}
 }    
   while (enc1.isHolded() !=1 );  
   tft.fillScreen(ST77XX_BLACK);
   
}

void loop() {
  // put your main code here, to run repeatedly:

}

 

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

Ну если вам нравится гайвер с библиотеками, то почему не организовать так #63

Добавьте нужное и поиск косяков в меню упростися.

Alex178
Offline
Зарегистрирован: 06.03.2018

qwone пишет:

Ну если вам нравится гайвер с библиотеками, то почему не организовать так #63

Добавьте нужное и поиск косяков в меню упростися.

Мне понравилось, что у него в библиотеке есть нажатие и долгое нажатие. Что вполне инктуитивно. Если есть у Вас другая аналогичная, буду рад попробовать. И с меню у меня проблем нет. Есть проблема цикла в цикле. Внешний do пока долго не удерживать кнопку энкодера, и внутренний switch с флажком, для установки часов и минут. Внешний работает, а внутренний запускает оба блока одновременно при повороте энкодера, сразу меняет значение часов и значение минут.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Вынеси брейки 2 и 3 кейсов за операторные скобки условий. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

63 строка и 87-я

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

Alex178 пишет:
При нажатии должен быть брейк и переход на след. кейс. При повороте брейка нет.

Вы решили поспорить?

Брейк - это не переход на следующий кейс, а выход из свич целиком. А вот отсутствие брейка - как раз переход на следующий кейс.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

А если еще и форматировать код, то его и читать удобнее и ошибки находить )))

Чем отличается?

Это:

  switch (tset) {
    case 0:
      tset =1;  
      break; 

    case 1: 
      tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
      tft.setCursor (20, 40);
      if (hsetON < 10) {
        tft.print('0');
      }
      tft.print(hsetON);
      tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
      tft.setCursor (55, 40);
      tft.print(msetON);
    
      if (enc1.isRight()) {
        hsetON++;
        if (hsetON >=24) 
          hsetON=0;   
      }
      if (enc1.isLeft()) {
        hsetON--;
        if (hsetON <=0) {
          hsetON=23;
        }   
      }
      if (enc1.isPress()) {
         tset++;
         break;    
      }
    
    case 2:  
      tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
      tft.setCursor (20, 40);
      tft.print(hsetON);
      tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
      tft.setCursor (55, 40);
      if (msetON < 10) {
        tft.print('0');
      }
      tft.print(msetON);
    
      if (enc1.isRight()) {
        msetON++;
        if (msetON >=60) {
          msetON=0;   
        }
      }
      if (enc1.isLeft()) {
        msetON--;
        if (msetON <=0) {
          msetON=59;   
        }
      }
      if (enc1.isPress()){
        tset--;
        break;     
      }
  }

От этого:

  switch (tset) {
    case 0:
      tset =1;  
      break; 

    case 1: 
      tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
      tft.setCursor (20, 40);
      if (hsetON < 10) {
        tft.print('0');
      }
      tft.print(hsetON);
      tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
      tft.setCursor (55, 40);
      tft.print(msetON);
    
      if (enc1.isRight()) {
        hsetON++;
        if (hsetON >=24) 
          hsetON=0;   
      }
      if (enc1.isLeft()) {
        hsetON--;
        if (hsetON <=0) {
          hsetON=23;
        }   
      }
      if (enc1.isPress()) {
        tset++;
      }
      break;    
    
    case 2:  
      tft.setTextColor(ST77XX_MAGENTA, ST77XX_BLACK);
      tft.setCursor (20, 40);
      tft.print(hsetON);
      tft.setTextColor(ST77XX_RED, ST77XX_BLACK);
      tft.setCursor (55, 40);
      if (msetON < 10) {
        tft.print('0');
      }
      tft.print(msetON);
    
      if (enc1.isRight()) {
        msetON++;
        if (msetON >=60) {
          msetON=0;   
        }
      }
      if (enc1.isLeft()) {
        msetON--;
        if (msetON <=0) {
          msetON=59;   
        }
      }
      if (enc1.isPress()){
        tset--;
      }
      break;     
  }

???

Alex178
Offline
Зарегистрирован: 06.03.2018

Всем спасибо. Разобрался. Все прекрасно заработало одним циклом.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Я все еще охреневаю от того, что в названии темы и что в итоге решали....

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

qwone пишет:

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

а, шо такоэ лямбда функции?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Клапа, это новая секта такая, в которую Пух попал, не разбираясь 

bwn
Offline
Зарегистрирован: 25.08.2014

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

а, шо такоэ лямбда функции?

Пятнадцать лет он не был дома (с).))))

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

А можно пример такого меню на всём этом и во всей красе (простенькое)? Хочу понять как это реализовано, а то представить или возраст или уровень знаний не позволяют. Собаки этакие...

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

Ну вот под гайверовкие кнопки и простой вариант меню

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
typedef void (*pDo)();
#include <GyverButton.h>
//github.com/AlexGyver/GyverLibs/blob/master/GyverButton/GyverButton.h
GButton btnS(/*пин*/2);//кнопка селект
GButton btnU(/*пин*/3);//кнопка вверх
int  var1 = 0, var2 = 0, var3 = 0; //некие переменные
pDo Do_btnS_Click = [] {};
pDo Do_btnU_Click = [] {};
const byte page0 = 0;//главный экран
const byte page1 = 10;// 1-я страница
const byte page2 = 20;// 2-я страница
const byte page3 = 30;// 3-я страница
byte page;
void goPage(byte p) {
  page = p;
  switch (page) {
    case page0:
      {
        Serial << "\npage0 var1:" << var1 << " var2:"<< var2 << " var3:" << var3;
      }
      Do_btnS_Click = [] {goPage(page1);};
      Do_btnU_Click = [] {};
      break;
    case page1:
      {
        Serial << "\npage1 var1:" << var1;
      }
      Do_btnS_Click = [] {goPage(page2);};
      Do_btnU_Click = [] {
        var1++; if (var1 > 59)var1 = 0;
        goPage(page1);
      };
      break;
    case page2: {
        Serial << "\npage2 var2:" << var2;
      }
      Do_btnS_Click = [] {goPage(page3);};
      Do_btnU_Click = [] {
        var2++; if (var2 > 59)var2 = 0;
        goPage(page2);
      };
      break;
    case page3:
      {
        Serial << "\npage2 var3:" << var3;
      }
      Do_btnS_Click = [] {goPage(page0);};
      Do_btnU_Click = [] {
        var3++; if (var3 > 59)var3 = 0;
        goPage(page3);
      };
      break;
  }
}
void init_menu() {
  goPage(page0);
}
void run_menu() {}
//--------------------------------------
void setup() {
  Serial.begin(9600);
  init_menu();
}
void loop() {
  btnS.tick();
  btnU.tick();
  if (btnS.isClick()) Do_btnS_Click();
  if (btnU.isClick()) Do_btnU_Click();
  run_menu();
}

Управление двумя кнопками - Селект и Верх. Вывод в Сериал.