Прошу помощи с некорректной обработкой энкодера на ESP32 + LCD128*64 на ST7920

Gelo_D

✩✩✩✩✩✩✩
28 Окт 2021
6
0
Преамбула. Я врач-травматолог из Донецка. Спасибо сыну, 4 года назад он попросил меня найти ему кружок робототехники, ничего толкового я не нашел и пришлось вникать самому, благодаря чему я открыл дивный мир Arduino и ресурс AlexGyver и достал давно забытый паяльник. С тех пор я сделал довольно много бесполезных, но и реально полезных вещей, в частности, в своей специальности. Это я к чему, в последние 2 года свободное время стремится к -273, паять научился вместо перекуров (с электронной сигаретой) и возможности самому вникать глубоко просто нет, потому прошу помощи и не клевать за колхоз.

В общем, уже сделал вот такую штуковину, программируемый блок клапанов для промывания ран:
Рисунок1.png Рисунок2.png

После практического применения прибор оказался на 100% работоспособным, но выяснились недоработки, просралась финальная прошивка, появилась необходимость в нескольких приборах. В общем решил я доработать это все дело c основания в направлении: изменить немного работу блока клапанов, перейти на LCD128*64 на ST7920 (большой) для вывода информации в более удововоримом виде и....._ перейти на esp32, т.к. в перспективе хочется контролировать состояние аппарата через IoT. Прилепил интерфейс, припаял энкодер и...

e4c0e499-07a1-441d-afd1-b5550c238a87.jpg
...уже начал замечать легкие тормоза в виде нечеткой отработки энкодера. Когда добавил основную логику с 1 серво - просто адовые тормоза... :cry::cry::cry: .

При переключении в программе switch (run_butt) в case1 энкодер вообще практически не срабатывает... Хотя там ничего кроме таймеров и элементарной логики нет...

Собственно вопрос: в чем причина тормозов, ошибка в выборе сочетания контроллера (мегу взять...) и дисплея, выбора библиотек энкодера или в самом коде? Еще раз, код (да все) -адовый колхоз, у самого через год на него глядя слезы текут, пол дня потратил, чтоб вспомнить что и зачем. Но это как-то работает здесь и сейчас.

Хоть вникать в какую сторону....???

Спасибо откликнувшимся!

C++:
#include <Arduino.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/18, /* data=*/23, /* CS=*/5, /* reset=*/22);  // ESP32
#include <EncButton.h>
EncButton eb(15, 16, 4);
//#define EB_CLICK_TIME 700   // таймаут ожидания кликов (кнопка)
#include <ServoSmooth.h>
ServoSmooth servo1(90);
bool eepflag = 1;
uint16_t expo = 0;
static uint16_t timing = 0;
bool cclick = 0;
//const uint8_t rook_bitmap[] U8X8_PROGMEM = { };  // ВСТАВИТЬ МАССИВ С ЛОГО
//ПЕРЕМЕННЫЕ ИЗ В1
static uint32_t tmr_p1;
static uint32_t tmr_w1;
static uint32_t w11 = 0;
static uint32_t w_period1;
static uint8_t period = 0;
//bool i1 = false;   //
bool is_off = 1;
bool is_off_LCD = 1;
//uint8_t i = 0;  //clear LCD counter
bool run_butt = 0;
uint16_t stime = 0;
static int16_t w_period = 0;
uint16_t tmr_p = 0;
uint16_t tmr_w = 0;
uint16_t serv2 = 0;
uint32_t cycleft;
bool led_blink = 1;
bool vblock = 1;
bool timer_p_flag = 0;
bool vBlockFlag = 0;
bool encHoldFlag = 0;
const uint8_t PWMPin = 25;  //*******************PINS
const uint8_t Servo1Pin = 26;
void setup() {
  Serial.begin(115200);
  u8g2.begin();
  pinMode(PWMPin, OUTPUT);
servo1.attach(Servo1Pin);  // подключить
servo1.setSpeed(230);      // ограничить скорость
servo1.setAccel(0.1);      // установить ускорение (разгон и торможение)
                             //  u8g2.firstPage();                             //ВЫВОД ЛОГОТИПА
                             //  do {
                             //    u8g2.drawXBMP(0, 0, 128, 64, rook_bitmap);
                             //  } while (u8g2.nextPage());
                             //  delay(300);
                             //  clearLCD();
  eb.setBtnLevel(LOW);
  eb.setClickTimeout(700);
  eb.setDebTimeout(50);
  eb.setHoldTimeout(600);
  eb.setStepTimeout(200);
  eb.setEncReverse(0);
  eb.setEncType(EB_STEP4_LOW);
  eb.setFastTimeout(30);
  eb.counter = 0;
  while (!eb.hasClicks()) {
    eb.tick();
    servo1.tick();
    if (uint16_t start_timer; millis() - start_timer > 500) {
      start_timer = millis();
      u8g2.setFont(u8g2_font_6x10_tf);
      u8g2.setFontPosTop();
      u8g2.firstPage();
      u8g2.drawStr(10, 1, "CHECK OLL TUBES AND");
      u8g2.drawStr(9, 12, "VALVES, PRESS BUTTON");
      //u8g2.drawStr(45, 23, "TWICE");
      u8g2.drawStr(50, 31, "*RUN*");
      u8g2.setDrawColor(2);  // XOR
      u8g2.drawBox(48, 26, 33, 20);
      u8g2.nextPage();
    }
    servo1.setTargetDeg(5);
  }
}
void loop() {
  eb.tick();
  servo1.tick();
  //***************СЕКЦИЯ ОБРАБОТКИ ЭНКОДЕРА
  if (eb.hasClicks(1)) {
    run_butt = !run_butt;
  }
  if (eb.hasClicks(2)) {
    cclick = !cclick;
  }
  if (!cclick && eb.left() && period > 0) {
    period -= 1;
    eepflag = 1;  //ЕСЛИ НАДУМАЮ ХРАНИТЬ В ЕЕПРОМ
  }
  if (!cclick && eb.right() && period < 90) {
    period += 1;
    eepflag = 1;  //ЕСЛИ НАДУМАЮ ХРАНИТЬ В ЕЕПРОМ
  }
  if (cclick && eb.left() && expo > 0) {
    expo -= 1;
  }
  if (cclick && eb.right() && expo < 9) {
    expo += 1;
  }
  //}
  if (eb.holding()) {  //если кн энкодера ЗАЖАТА
    if (is_off) {
      w_period = 0;  //однократное обнуление счетчика по зажатию энк
      vblock = 0;
      vBlockFlag = !vBlockFlag;
      //     enc_butt = !enc_butt;
    }
    is_off = 0;
    //Serial.println("IS HOLD");
    //счетчик секунд для ++ в_периода
    if (millis() - w_period1 >= 1000) {
      w_period1 = millis();
      w_period += 1;
      //Serial.println(w_period);
      vblock = 0;                           //******************ПЕРЕКЛЮЧЕНИЕ ВБЛОКА В НАГРЕВ
    }
  }
  if (!eb.holding()) {  //если кн энкодера НЕ зажата
    //encHoldFlag = !encHoldFlag;
    is_off = 1;  //возвращаем флаг обнуления в_период
    if (vBlockFlag) {  //********************чтобы однократно вызвать греть
      vblock = 1;
      vBlockFlag = 0;
    }
  }
  //**************************
  //**************************ЛОГИКА
  switch (run_butt) {  //еще не нажимали ран
    case 0:
      {
        //обнуляем все внутренние таймеры
        tmr_p = 0;
        tmr_w = 0;
        uint8_t w1 = 0;  //однократно вызываем функцию блока сосать
        if (!eb.holding()) {
          while (w1 < 1) {
            vblock = 1;
            w1++;
          }
        }
      }
      break;
    case 1:
      {
        //************************************ВНУТРЕННИЕ ТАЙМЕРЫ, ЗАПУСКАЕМЫе ПО РУН
        //запускаем таймер отсчета периода вклучения цикла подогрева с 0 по клику кнопки RUN
        if (millis() - tmr_p1 >= 1000) {
          tmr_p1 = millis();
          tmr_p += 1;
          //Serial.println(tmr_p);
          //*******************************************************ЛОГИКА
          if (tmr_p / 60 >= period) {  // если таймер периода В МИН  досчитывает до выставленного энкодером!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                                       // запускаем таймер длительности цикла подогрева
            if (millis() - tmr_w1 >= 1000) {
              tmr_w1 = millis();
              tmr_w += 1;
            }
          }


          if (tmr_w + (expo) <= w_period && tmr_p / 60 >= period) {     //****************************ГЛАВНОЕ УСЛОВИЕ + ВРЕМЯ ЭКСПОЗИЦИИ НЕ ЗАБЫТЬ *60!!!!!!!!!!!!!!!
            if (!eb.holding()) {
              while (w11 < 1) {
                vblock = 0;
                w11++;
              }
              //счетчик цикла подогрева < установленного таймера цикла подогрева И счетчик таймера больше выставленного таймера
              //меняем флаг блока клапанов на подогрев!!!
            }
          }
          if (tmr_w + (expo) >= w_period && tmr_p / 60 >= period) {
            // если счетчик цикла подогрева досчитывает до w_period обнуляем счетчики и переключаем
            //блок клапанов на отсос

            tmr_p = 0;
            tmr_w = 0;
            if (!eb.holding()) vblock = 1;    //**********БЛОК В ОТСОС
          }
        }
      }
      break;
  }

  if (vblock) vBlockSuck();
  else vBlockHeat();

  //*****************ВРЕМЯ
  //время
  static uint32_t time1;
  if (millis() - time1 >= 1000) {
    time1 = millis();
    stime += 1;
  }
  //**************************ТАЙМЕР ОТРАБОТКИ ЭКРАНА
  if (millis() - timing > 500) {  // Вместо 10000 подставьте нужное вам значение паузы
    timing = millis();
    MainScreen();
    cycleft = period - (tmr_p / 60);   //*****************************CycleLEFT счетчик
  }
}

void clearLCD() {
  u8g2.firstPage();
  do {
  } while (u8g2.nextPage());
}


void MainScreen() {
  u8g2.setFont(u8g2_font_6x10_tf);
  u8g2.setFontPosTop();
  u8g2.firstPage();
  u8g2.drawLine(60, 0, 60, 64);
  u8g2.drawStr(5, 0, "Infusion");
  u8g2.drawStr(40, 16, "Sec");
  //u8g2.drawStr(9, 10, "time (s)");
  u8g2.drawStr(0, 35, "Cycle time");
  u8g2.drawStr(40, 50, "Min");
  //u8g2.drawStr(9, 40, "time (s)");
  u8g2.drawStr(62, 0, "System:");
  u8g2.drawLine(61, 11, 128, 11);
  u8g2.drawStr(65, 12, "Exposition");
  u8g2.setFontPosTop();
  u8g2.setCursor(74, 22);
  u8g2.print(expo);
  //u8g2.drawStr(74, 22, "99");
  u8g2.drawStr(95, 22, "Min");  //EXP TIME
  u8g2.drawLine(61, 31, 128, 31);

  u8g2.drawStr(65, 32, "Cycle LEFT");
  u8g2.setCursor(75, 42);
  u8g2.print(cycleft);
  u8g2.drawStr(95, 42, "Min");  //CYCLE TIMER
  u8g2.drawLine(61, 51, 128, 51);
  u8g2.drawStr(65, 52, "SysON");
  u8g2.setCursor(100, 52);
  u8g2.print(stime);
  switch (run_butt) {
    case 0:
      u8g2.drawStr(105, 0, "WAIT");  //SYSTEM STATE
      u8g2.setDrawColor(2);          // XOR
      u8g2.drawBox(103, 0, 25, 10);
      break;
    case 1:
      u8g2.drawStr(105, 0, "RUN!");  //SYSTEM STATE
      u8g2.setDrawColor(2);          // XOR
      u8g2.drawBox(103, 0, 25, 10);
      break;
  }
  if (cclick) {
    u8g2.setDrawColor(2);  // XOR
    u8g2.drawBox(72, 21, 10, 10);
  }

  u8g2.setFont(u8g2_font_fub17_tr);
  u8g2.setFontPosTop();
  u8g2.setCursor(10, 11);
  u8g2.print(w_period);
  u8g2.setCursor(10, 45);
  u8g2.print(period);



  //u8g2.drawStr(20, 12, vac_val);
  //u8g2.drawStr(20, 42, vac_set);


  //u8g2.drawStr(50, 41, "*RUN*");
  //u8g2.setDrawColor(2);  // XOR
  //u8g2.drawBox(48, 36, 33, 20);
  u8g2.nextPage();
}
//************************************************НЕ ЗАБУДЬ, НА ЭКСПОЗИЦИЮ НУЖНО ОТКЛЮЧИТЬ НАСОС!!!!!!!!!
void vBlockHeat() {
  servo1.setTargetDeg(5);
  digitalWrite(PWMPin, HIGH);
  static uint32_t tmrh;
  if (millis() - tmrh >= 500) {
    tmrh = millis();
    //led_blink = !led_blink;
    Serial.println("HEAT");
  }
  //if (led_blink) analogWrite(PWMPin, 0);
  //else analogWrite(PWMPin, 50);
}
void vBlockSuck() {
  servo1.setTargetDeg(45);
  digitalWrite(PWMPin, LOW);
  //analogWrite(PWMPin, 50);
  static uint32_t tmrs;
  if (millis() - tmrs >= 500) {
    tmrs = millis();
    Serial.println("SUCK");
  }
}
 
Изменено:

vortigont

★★★★★★✩
24 Апр 2020
936
507
Saint-Petersburg, Russia
а вы начните с того чтобы привести код немного в порядок - создайте несколько функций, спрячьте туда эти портянки, опишите что эти функции должны делать и куда дальше передвать упраление - в процессе этого сами найдете кучу проблем у себя же и исправите. Думаете кто-то разберется в вашем коде лучше вас?

При переключении в программе switch (run_butt) в case1 энкодер вообще практически не срабатывает...
это что за вопрос такой? кейс проверяет условие и выходит дальше, вы в этой проверке по пол часа зависаете что ли? Пока работает кейс, ничего другое работать не может. Энкодер обновляет свое состояние только в одном месте eb.tick(); Хотите что бы энкодер сработал, должен отрабатывать тик, а ждать чего-то в кейса смысла никакого нет.
 

Gelo_D

✩✩✩✩✩✩✩
28 Окт 2021
6
0
Спасибо за ответ! Код обязательно потихоньку причешу!

Думаете кто-то разберется в вашем коде лучше вас?
Я это прекрасно понимаю.

Пока работает кейс, ничего другое работать не может.
Т.е. кейс не проходится каждую итерацию loop насквозь, а , как while, зацикливается внутри основного цикла?

И главный вопрос сейчас в чем, допустима ли такая связка с библиотеками:

ESP32
+экран U8G2_ST7920_128X64_F_SW_SPI (на u8g2 соответственно).
+энкодер на encButton
+ кнопка на gyverButton
+1 серво на ServoSmooth
 

poty

★★★★★★✩
19 Фев 2020
3,034
904
кейс не проходится каждую итерацию loop насквозь, а , как while, зацикливается внутри основного цикла?
Нет, это было предположение.
Речь идёт о том, что для "отлова" энкодера нужно как можно чаще вызывать его tick + обрабатывать его события. Продраться через код пока не получается, смущают while, на них может тратиться довольно большое время.
 

Gelo_D

✩✩✩✩✩✩✩
28 Окт 2021
6
0
Переписал, как умею, код. Код работает, убрал все while из основного цикла, раскидал по функциям. Стало чуууууть лучше, но в рабочем режиме (runbutt, case 1) лютые тормоза остались, даже серва все так же рывками двигается. В режиме ожидания (runbutt, case 0, там вообще почти ничего нет) еще как-то, но энкодер через раз срабатывает. Сериал пробовал выбрасывать, серву пробовал - не помогает. Остается u8g2... Но без нее все теряет смысл. RTOS, мало того что сложно и неведомое, - смысла особого не вижу, там, фактически, одна задача + вывод на экран, сделал вывод через millis каждые 500 мс. Тупик. Попробую на AtMega... Может у кого идеи будут, хоть в какую сторону копать?

C++:
#include <Arduino.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/18, /* data=*/23, /* CS=*/5, /* reset=*/22);  // ESP32

#include <EncButton.h>
EncButton eb(15, 16, 4);

#include <ServoSmooth.h>
ServoSmooth servo1(90);

bool eepflag = 1;
uint16_t expo = 0;
static uint16_t timing = 0;
bool cclick = 0;
//const uint8_t rook_bitmap[] U8X8_PROGMEM = { };  // ВСТАВИТЬ МАССИВ С ЛОГО

static uint32_t tmr_p1;
//static uint32_t tmr_w1;
static uint8_t wflag = 0;
static uint8_t wflag2 = 0;
static uint32_t w_period1;
static uint16_t period = 0;
bool is_off = 1;
bool ebholdflag = 0;
bool run_butt = 0;
uint16_t stime = 0;
static int16_t w_period = 0;
uint16_t tmr_p = 0;
uint16_t tmr_w = 0;
uint16_t serv2 = 0;
uint32_t cycleft;
bool led_blink = 1;
uint8_t vblock = 1;  //состояние блока отсоса/подачи горячей воды 0 - перекрыт отсос, включена подача; 1 - отсос, нет подачи; 2 - перекрыт и отсос и подача (экспозиция)
bool vBlockFlag2;
bool timer_p_flag = 0;
bool vBlockFlag = 0;
bool encHoldFlag = 0;
const uint8_t PWMPin = 25;  //*******************PINS
const uint8_t Servo1Pin = 26;

void setup() {
  Serial.begin(115200);
  u8g2.begin();
  pinMode(PWMPin, OUTPUT);
  servo1.attach(Servo1Pin);  // подключить
  servo1.setSpeed(230);      // ограничить скорость
  servo1.setAccel(0.1);      // установить ускорение (разгон и торможение)
                             //  u8g2.firstPage();                             //ВЫВОД ЛОГОТИПА
                             //  do {
                             //    u8g2.drawXBMP(0, 0, 128, 64, rook_bitmap);
                             //  } while (u8g2.nextPage());
                             //  delay(300);
                             //    u8g2.firstPage();
                             //do {
                             //} while (u8g2.nextPage());

  eb.setBtnLevel(LOW);
  eb.setClickTimeout(700);
  eb.setDebTimeout(50);
  eb.setHoldTimeout(600);
  eb.setStepTimeout(200);
  eb.setEncReverse(0);
  eb.setEncType(EB_STEP4_LOW);
  eb.setFastTimeout(30);
  eb.counter = 0;
  while (!eb.hasClicks()) {
    eb.tick();
    servo1.tick();
    if (uint16_t start_timer; millis() - start_timer > 500) {
      start_timer = millis();

      u8g2.setFont(u8g2_font_6x10_tf);
      u8g2.setFontPosTop();
      u8g2.firstPage();
      u8g2.drawStr(10, 1, "CHECK OLL TUBES AND");
      u8g2.drawStr(9, 12, "VALVES, PRESS BUTTON");
      //u8g2.drawStr(45, 23, "TWICE");
      u8g2.drawStr(50, 31, "*RUN*");
      u8g2.setDrawColor(2);
      u8g2.drawBox(48, 26, 33, 20);
      u8g2.nextPage();
    }
    servo1.setTargetDeg(5);
  }
}

void loop() {
  eb.tick();
  servo1.tick();
  encprocess();  //функция обработки энкодера

  //Секция подсчета премени подачи горячей воды по зажатию кн энкодера

  if (ebholdflag) {  //если кн энкодера УДЕРЖИВАЕТСЯ ЗАЖАТОЙ

    vblock = 0;  // блок клапанов в подачу горячей воды
    //Serial.println("IS HOLD");

    if (is_off) {  //однократное обнуление счетчика w_period
      w_period = 0;
      vBlockFlag = !vBlockFlag;  //однократно меняем флаг чтобы потом ОДНОКРАТНО перевести блок в отсос
    }
    is_off = 0;

    if (millis() - w_period1 >= 1000) {  //старт счетчика секунд для w_period прилива горячей воды
      w_period1 = millis();
      w_period += 1;
      //Serial.println(w_period);
     }
  }

  if (!ebholdflag) {  //если кн энкодера НЕ зажата
    is_off = 1;       //поднимаем флаг обнуления w_period при следующем удержании кнопки

    if (vBlockFlag) {  //********************однократно блок в отсос, чтобы не мешал в дальнейшем
      vblock = 1;
      vBlockFlag = 0;
    }
  }


  switch (run_butt) {
    case 0:  //****************режим ожидания
      {
        //обнуляем все внутренние таймеры
        tmr_p = 0;
        tmr_w = 0;

        if (!ebholdflag) vblock = 1;  //если не удерживается кнопка энкодера - блок клапанов в отсос (1 состояние)
      }
      break;

    case 1:  //***************рабочий режим
      {
        //запускаем таймер отсчета периода включения цикла подогрева с 0 по клику кнопки RUN
        if (millis() - tmr_p1 >= 1000) {
          tmr_p1 = millis();
          tmr_p += 1;
          //Serial.println(tmr_p);

          if (tmr_p >= period * 60) tmr_w += 1;  // если таймер периода В МИН  досчитывает до выставленного энкодером period
                                                 // запускаем отсчет в сек для сравнения с ранее выставленной длительностью подачи горячей воды w_period

          if (tmr_w <= w_period && tmr_p >= period * 60) {  //****************************блок в подачу горячей воды по таймеру
                                                            //счетчик цикла подогрева < установленного таймера цикла подогрева И счетчик таймера больше выставленного таймера

            if (!ebholdflag) {  //и при этом не зажата кнопка энкодера

              if (wflag < 1) {  //однократно переводим блок в остояние подачи горячей воды 0
                vblock = 0;
              }
              wflag++;
            }
            vBlockFlag2 = 0;  //поднимаем флаг, чтобы одновременно не выполнялось условия состояния 2 (экспозиция)

          } else {
            vBlockFlag2 = 1;
            wflag = 0;
          }

          if (tmr_w + (expo) <= w_period && tmr_p >= period * 60 && vBlockFlag2) {  //ВРЕМЯ ЭКСПОЗИЦИИ НЕ ЗАБЫТЬ *60
            if (!ebholdflag) {                                                      //и при этом не зажата кнопка энкодера

              if (wflag2 < 1) {  //однократно переводим блок в остояние экспозиции горячей воды 2
                vblock = 2;
              }
              wflag2++;
            }
          } else wflag2 = 0;

          if (tmr_w + (expo) >= w_period && tmr_p >= period * 60) {
            // если счетчик цикла подогрева досчитывает до w_period обнуляем счетчики и переключаем
            //блок клапанов на отсос
            tmr_p = 0;
            tmr_w = 0;
            if (!ebholdflag) vblock = 2;
          }
        }
      }
      break;
  }

  ValveBlock();  //функция блока клапанов

  //время

  static uint32_t time1;
  if (millis() - time1 >= 1000) {
    time1 = millis();
    stime += 1;
  }

  //**************************ТАЙМЕР ОТРАБОТКИ ЭКРАНА

  if (millis() - timing > 500) {
    timing = millis();
    Serial.println(vblock);
    MainScreen();
    cycleft = (period * 60) - tmr_p;  //*****************************CycleLEFT счетчик
  }
}

void encprocess() {  //***************СЕКЦИЯ ОБРАБОТКИ ЭНКОДЕРА

  if (eb.hasClicks(1)) {
    run_butt = !run_butt;
  }

  if (eb.hasClicks(2)) {
    cclick = !cclick;
  }

  if (!cclick && eb.left() && period > 0) {
    period -= 1;
    //eepflag = 1;  //ЕСЛИ НАДУМАЮ ХРАНИТЬ В ЕЕПРОМ
  }
  
  if (!cclick && eb.right() && period < 90) {
    period += 1;
    //eepflag = 1;  //ЕСЛИ НАДУМАЮ ХРАНИТЬ В ЕЕПРОМ
  }

  if (cclick && eb.left() && expo > 0) {
    expo -= 1;
  }
  if (cclick && eb.right() && expo < 9) {
    expo += 1;
  }

  if (eb.holding()) ebholdflag = 1;
  else ebholdflag = 0;

  //**************************
}

void ValveBlock() {

  switch (vblock) {
    case 0:
      servo1.setTargetDeg(5);
      digitalWrite(PWMPin, HIGH);

      // static uint32_t tmrh;
      // if (millis() - tmrh >= 500) {
      //   tmrh = millis();
      //   //led_blink = !led_blink;
      //   Serial.println("HEAT");
      // }
      break;
    case 1:
      servo1.setTargetDeg(45);
      digitalWrite(PWMPin, LOW);

      // static uint32_t tmrs;
      // if (millis() - tmrs >= 500) {
      //   tmrs = millis();
      //   Serial.println("SUCK");
      // }
      break;

    case 2:
      servo1.setTargetDeg(5);
      digitalWrite(PWMPin, LOW);

      // static uint32_t tmrs1;
      // if (millis() - tmrs1 >= 500) {
      //   tmrs1 = millis();
      //   Serial.println("EXPO");
      // }
      break;
  }
}

void MainScreen() {

  u8g2.setFont(u8g2_font_6x10_tf);
  u8g2.setFontPosTop();
  u8g2.firstPage();
  u8g2.drawLine(60, 0, 60, 64);
  u8g2.drawStr(5, 0, "Infusion");
  u8g2.drawStr(40, 16, "Sec");
  //u8g2.drawStr(9, 10, "time (s)");
  u8g2.drawStr(0, 35, "Cycle time");
  u8g2.drawStr(40, 50, "Min");
  //u8g2.drawStr(9, 40, "time (s)");
  u8g2.drawStr(62, 0, "System:");

  u8g2.drawLine(61, 11, 128, 11);

  u8g2.drawStr(65, 12, "Exposition");
  u8g2.setFontPosTop();
  u8g2.setCursor(74, 22);
  u8g2.print(expo);
  u8g2.drawStr(95, 22, "Min");  //EXP TIME
  u8g2.drawLine(61, 31, 128, 31);

  u8g2.drawStr(65, 32, "Cycle LEFT");
  u8g2.setCursor(75, 42);
  u8g2.print(cycleft);
  u8g2.drawStr(95, 42, "Sec");  //CYCLE TIMER
  u8g2.drawLine(61, 51, 128, 51);

  u8g2.drawStr(65, 52, "SysON");
  u8g2.setCursor(100, 52);
  u8g2.print(stime);

  switch (run_butt) {
    case 0:
      u8g2.drawStr(105, 0, "WAIT");  //SYSTEM STATE
      u8g2.setDrawColor(2);          // XOR
      u8g2.drawBox(103, 0, 25, 10);
      break;
    case 1:
      u8g2.drawStr(105, 0, "RUN!");  //SYSTEM STATE
      u8g2.setDrawColor(2);          // XOR
      u8g2.drawBox(103, 0, 25, 10);
      break;
  }
  if (cclick) {
    u8g2.setDrawColor(2);  // XOR
    u8g2.drawBox(72, 21, 10, 10);
  }

  switch (vblock) {
    case 0:
      u8g2.drawStr(30, 16, "H");
      break;
    case 1:
      u8g2.drawStr(30, 16, "S");
      break;
    case 2:
      u8g2.drawStr(30, 16, "E");
      break;
  }

  u8g2.setFont(u8g2_font_fub17_tr);
  u8g2.setFontPosTop();
  u8g2.setCursor(10, 11);
  u8g2.print(w_period);
  u8g2.setCursor(10, 45);
  u8g2.print(period);
  u8g2.nextPage();
}
 
Изменено:

Gelo_D

✩✩✩✩✩✩✩
28 Окт 2021
6
0
В общем, может кому интересно будет. Проробовал на atmega2560 - те же тормоза, т.е. esp32 не при чем. Отключил полностью вывод на экран u8g2 - тормоза прошли. Вывод очевиден, корень зла - u8g2. Буду сидеть вникать, как оптимизировать и что я делаю не так.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,200
1,287
Москва
Наиболее частая причина таких тормозов - излишне частый ввод информации на дисплей.
У меня для тестов сейчас на столе стоит такая сборка на esp32:
Дисплей LCD1602, на него выводиться скорость выполнения основного цикла , ip адрес esp и счетчик с энкодера (0-100). Так же на esp запущен веб сервер с простенькой страницей, 101 ссылка которая сразу задает счетчик энкодера. А, чуть не забыл еще адресная светодиодная лента на 10 светодиодов, которая в зависимости от счетчика зажигает нужное число светодиодов. 0- все выключено, 5 -50% яркости 1-го светодиода, 24 2 светодиода горят на 100% 3-ий на 40%

Как все работает. Веб и все связанное работает на ядре 0, а все остальное на ядре 1. При этом я энкодер опрашиваю по таймеру, вывожу данные на дисплей только в том случае если были изменения в значениях.

Был у меня опыт, когда я к 1-ой esp подключал 8 дисплеев LCD13264 (а может и LCD12864, точно не помню искать лень), выводилась простенькая информация с номером дисплея, это было для теста, в работу не пошло.

Самое простое что стоит сделать
1) посчитать сколько циклов loop проходит за 1 секунду. Число должно измеряться в тысячках, а лучше в десятках тысяч.
2) Вынести обработку энкодера из loop в функцию по таймеру, от 1000 раз в секунду, лучше больше. Чем чаще тем быстрее можно крутить энкодер.
3) Не выводить данные на дисплей чаще 25 раз в секунду, иногда и 10 раз в сек хватает.
 

vortigont

★★★★★★✩
24 Апр 2020
936
507
Saint-Petersburg, Russia
Если есп32 то на ней есть аппартный квадратурный декодер. Избавляет от необходимости вообще его опрашивать.
Я планирую добавить поддержку декодера в эту либу в скором времени.
 

Gelo_D

✩✩✩✩✩✩✩
28 Окт 2021
6
0
3) Не выводить данные на дисплей чаще 25 раз в секунду, иногда и 10 раз в сек хватает.
Самое обидное, что экран я вообще обновляю раз в 500 мс. Но много всего, + графика. Надо попробовать обновлять только переменные. Руки не дошли. Остальное тоже попробую. Спасибо!

@vortigont,
Спасибо! Буду вникать.
 

Gelo_D

✩✩✩✩✩✩✩
28 Окт 2021
6
0
В общем, потихоньку начали опускаться руки... Заметил странную закономерность, "тормоза" начинались не сразу, а через промежуток времени в 1-2 мин. Перенес переменные множественных таймеров из глобальных в локальные static... И починилось!