Вывод ошибок на oled displey

Тема в разделе "Arduino & Shields", создана пользователем Artemka_Ivanov, 29 апр 2019.

  1. Здравствуйте форумчане, прошу вас помочь мне чем сможете.
    Задача заключается в том, чтобы считывать ошибки нескольких датчиков и выводить их на oled дисплей.
    Использую библиотеку U8G2lib. Ошибка с датчика №1 имеет название "F01", ошибка датчика №2 "F02" и т.д.

    В чем же заключается проблема? А заключается она в самом простом - переносе строки при нехватке места для печатания содержимого на экран.

    setCursor() - использую только один раз для начала печатания ошибок. Мне нужно, чтобы на экране автоматически происходил перенос строки.
    Всего в строке рационально выводить 4 ошибки (если выводить больше, то нужно уменьшать шрифт, из-за чего разобрать, то что на экране будет проблематично). Но датчиков у меня самое большое множество и все я опрашиваю на наличие ошибок. В примере, который я прикреплю будет 8 ошибок (без их считывания - это совсем иной код, который здесь не нужен).

    На данной фотокарточке видно чего хочу добиться:
    Безымянный.jpg

    Теперь сам код, в нем пояснения как я пытался добиться желаемого результата:
    Код (C++):
    #include "U8g2lib.h"
    U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0,U8X8_PIN_NONE);

    String Str0;
    String Str1;
    String Str2;
    String Str3;
    String Str4;
    String Str5;
    String Str6;
    String Str7;

    bool F01 = true;
    bool F02 = true;
    bool F03 = true;
    bool F04 = true;
    bool F05 = true;
    bool F06 = true;
    bool F07 = true;
    bool F08 = true;

    String Str;
    char Array[50];

    int quan=0;

    void setup(){
      Serial.begin(9600);
        u8g2.begin();
    }
    void loop(){
      readFalse();
      str();
      search(); //весь этот непонятный и нерабочий цикл, создан исключительно для внедрения символа
                     //переноса строки ('\n')
      Serial.write(Array,sizeof(Array));
      u8g2.firstPage();  
      do {
        u8g2.setFont(u8g2_font_helvB10_tf);
        u8g2.setFontPosTop();
        u8g2.setCursor(0,0);  // используем один раз
        u8g2.print(Str);//собстна, выводим
      } while(u8g2.nextPage());
    }
    void readFalse() {
      int f1=0;
        int f2=0;
          int f3=0;
            int f4=0;
              int f5=0;
                int f6=0;
                  int f7=0;
                    int f8=0;
      if(F01 == true) {  //Эти булевые нужны в случае нахождение ошибок, при их считывание, особой роли не
        Str0 = "F01; ";  //играют, т.к. настраиваются выше
      f1=1;
      }
      if(F02 == true) {
        Str1 = "F02; ";
      f2=1;
      }
      if(F03 == true) {
        Str2 = "F03; ";
      f3=1;
      }
      if(F04 == true) {
        Str3 = "F04; ";
      f4=1;  
      }
      if(F05 == true) {
        Str4 = "F05; ";
      f5=1;
      }  
      if(F06 == true) {
        Str5 = "F06; ";
      f6=1;
      }  
      if(F07 == true) {
        Str6 = "F07; ";
      f7=1;
      }
      if(F08 == true) {
        Str7 = "F08; ";
      f8=1;
      }
    //в случае, если булевая равна false, то в переменной StrX (x - какое-либо число, например Str1) нет
    //абсолютно ничего.
    //К вопросу о const char* - не использую, т.к. в случае если ошибки нет и место ничем не занято, появляется //пробел, который категорически все портит
    quan=f1+f2+f3+f4+f5+f6+f7+f8; //считывание количества ошибок, далее не используется добавлено на //"вырост"
    }
    void str() {
      Str = Str0 + Str1 + Str2 + Str3+ Str4 + Str5+Str6+Str7; //Записываем все в главную строку
      Str.toCharArray(Array, sizeof(Array)); //переделываем ее в массив char[] (в этом случае уже нет никаких  
      //пробелов)
    }


    void search() { //Объясню, как задумывалось внедрение переноса строки:
      for(int j=0; j<sizeof(Array); j++) {//Перебираем массив char
        char i = Array[j]; //и перебором записываем его в переменную типа char - i
          int l=0; //сяс объясню што ето с чем ето едят
            while(i == ';') { //Если i обнаружила символ ';' - который заложен в окончание ошибки см. на верху
              l+=1;      //то прибавляем единицу к переменной l
              if(l>=4) { //Если l> 4, то.... (больше 4, т.к. в 1ой строке 4 ошибки
              l=0;   //тут понятно
                      //а вот тут уже нет. Что делать дальше - не представляю, т.к. не знаю как запихнуть сюда
                      //перенос cтроки
                      //еще желательно было бы без оператора цикла while, но с if - это не работает
              }    
            }    
      }

    Как-то так, здесь я предполагаю два пути:
    1. Через функции U8G2
    2. Через математику
    Но как и что написать я не представляю.

    Вроде все разжевал, будут вопросы - поясню. Жду ваших ответов, заранее благодарствую
     
  2. Asper Daffy

    Asper Daffy Иксперд

    А кто или что мешает использовать setCursor() столько раз, сколько ошибок выводится?
     
  3. Здравствуйте, камрад. Мешает, то что если я буду использовать setCursor(), то на экране будут появляться пробелы (ниже поясняю). Вот вам для иллюстрации сие фотокарточка:
    2.jpg
    Здесь наглядно видно, что если ошибки под номером: 2,4,6,7 - отсутствуют, то на экране появляются пробелы, т.к. каждой ошибке присваивается ее место (команда setCursor()).
    Вот как должно быть:
    3.jpg
    В этом случае точно также отсутствуют ошибки, с данными выше номерами, но при всем при этом пробелов в таком случае не наблюдается
    Я намерен это избежать, но пока не знаю как.
     
  4. parovoZZ

    parovoZZ Гуру

    Так надо сделать конкатенацию строк в одну и вывести ее.
     
  5. Камрад, если я правильно понимаю определения столь сложного для дилетанта слова (а именно "конкатенация"), то она у меня присутствует в цикле void str:
    Код (C++):
    void str() {
      Str = Str0 + Str1 + Str2 + Str3+ Str4 + Str5;
      Str.toCharArray(Array, sizeof(Array));
    }  
    Проблема в ином, в том что размер содержимого больше размера дисплея по горизонтали. Поэтому при выводе переменной str часть ошибок будет скрыта за гранью дисплея и невидна людскому взору (т.е. букавы уходят за границу экрана, т.к. их слишкам многа)
    Вот, чтоб было понятней:
    4.jpg
    Здесь видно, что в конце есть символ F, на деле это F05, просто конечные символы не выводятся, т.к. нет переноса строки
     
  6. Asper Daffy

    Asper Daffy Иксперд

    начига каждой ошибке место присваивать? Заведите счётчик ошибок и выводите каждую следующую на ближайшее свободное место. Координаты места по номеру (порядковому) ошибки вычисляй.

    Например, номер строки - это частное от деление номера на три (для ошибок №№ 0-2 - нулевая строка, для №№ 3-5 - первая и т.д.). Номер столбца - остаток от деления номера ошибки на 3 умноженный на 5, скажем или 6. Вот и все дела.
     
  7. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Так надо чтоб в SetCursor(x, y) стояли динамические аргументы. Задали исходные координаты - верхняя строка S=0, знакоместо Х=L. Вывели первые данные и тут же прибавили Х=Х + W(длина сообщения). Проверили, если не поместится - S=S+1, X=L. По-моему так.
    ПС. Я не знаю какие там координаты - знакоместо+строка или попиксельные Х+У. Но принцип понятен надеюсь. Вот здесь пиксельной адресацией наложены квадраты на картинку экрана LCD.
     

    Вложения:

    • LCD.JPG
      LCD.JPG
      Размер файла:
      96,8 КБ
      Просмотров:
      489
    Последнее редактирование: 29 апр 2019
  8. parovoZZ

    parovoZZ Гуру

    так складывай до тех пор, пока строка помещается в габариты дисплея. Как только она перестала это делать - делаешь перенос строки. Я бы это делал через указатели и в отдельной функции. Внутри функции делал бы перенос строки, а затем бы вызывал её рекурсивно, пока не кончились бы строки.
     
  9. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Хорошо. Не поленюсь скачаю библу. Если найду. Загоню в Протеус. Отпишусь.
     
  10. b707

    b707 Гуру

    а не надо боятся, надо просто попробовать. Вы нагородили невероятно сложный код там, где достаточно ОДНОЙ единственной строки и динамического setCursor(),
    Реально вся ваша задачка укладывается в пяток строчек кода.Прислушайтесь к предложениям Ariadna и Asper Daffy - именно по их идеям и стоит делать

    вот держите, пользуйтесь
    Код (C++):
    #include "U8g2lib.h"
    U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0,U8X8_PIN_NONE);

    bool F[8];  //булевский массив вместо кучи переменных F01 - F08

    void setup(){
      Serial.begin(9600);
        u8g2.begin();
        for (int i =0; i< 8; i++) {  F[i] = true;}
    }

    void loop(){
    int error_cnt =0;  // число ошибок, уже выведенных на текущую строку
    int line = 0;      // номер текущей строки
    u8g2.firstPage();
      do {
        u8g2.setFont(u8g2_font_helvB10_tf);
        u8g2.setFontPosTop();
        u8g2.setCursor(0,0);

    // цикл по восьми булевым переменым
        for (int i =0; i< 8; i++) {
          if (F[i]) {            // если i-тая ошибка true
            u8g2.print("F0");
            u8g2.print(i);
            u8g2.print("; ");
            error_cnt++;}
          if (error_cnt == 4) {         // если число ошибок на строке достигло 4х
           line++;                      // переходим на следующую строку
           u8g2.setCursor(0,line*16);   // сдвигаем курсор на 16 точек вниз (сдвиг настроить для конкретного фонта)
           error_cnt =0;}
         }
      } while(u8g2.nextPage());
    }
     
    Последнее редактирование модератором: 30 апр 2019
    Artemka_Ivanov, Daniil, NikitOS и ещё 1-му нравится это.
  11. Asper Daffy

    Asper Daffy Иксперд

    А домножить номер строки и столбца на пиксельный размер текущего шрифта религия запрещает? ну, тогда осталось только молиться, чтобы все сообщения становились на свои места. если качественно помолишься. то станут.
     
    b707 и DetSimen нравится это.
  12. Daniil

    Daniil Гуру

    Нужно определить термин строка (допустим высотой символа и размерами экрана), тогда не будет философских проблем
     
    Artemka_Ivanov и b707 нравится это.
  13. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Мммдяя. Отписываюсь.Попытался в Протеусе. Модели OLED-а нет. Взял дисплей UG-2864HSWEG01 (контроллер тот же - SSD1306). Больше нету. Не кажет. Проверял разными вариантами. Видать дохлая модель. Облом.
    Вопрос. Кто-нибудь сумел "завести" в Протеусе этот дисплей ? С уважением.
     
  14. b707

    b707 Гуру

    У вас есть сомнения, что предложенный Вами же способ с setCursor() и последовательным выводом ошибок будет работать? :) Без всех этих заумных десятков String-ов. как у автора? :) - С чего бы ему не работать-то?

    По-моему это тот случай. где сам дисплей (или его модель) для решения вообще не нужен :) проблемы у ТС не с конкретным железом. а с логикой програмирования...
     
    Ariadna-on-Line и parovoZZ нравится это.
  15. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Совершенно согласен. Главное - алгоритм. Пробовал Ваш код в Протеусе. Виртуальный осцилл сигналы (цикл) кажет. Картинки - нет. Выяснить про Протеусную модель - не помешает, на то оно и хобби. Кстати, мне кажется в коде проще задать готовый двухмерный массив координат Х(n), У(n). И циклически выбирать по приходу очередных данных. Тогда из за одной ошибки вычислений координат не "съедет" вся строка. Благо - их мало.
     
    Последнее редактирование: 30 апр 2019
  16. b707

    b707 Гуру

    мне кажется такой дисплей у каждого ардуинщика есть...быстрее железо собрать, чем модель в протеусе :)
     
  17. Попробовал, не получается, сейчас по подробней.
    Загрузил сначала без изменений. Выводит всего 4 ошибки в 1-ну строку, остальные 4 пропадают.
    Решил сменить одну ячейку булевого массива на false, тоже не работает, стало даже хуже.
    Вот так выглядит, то что я изменил:
    Код (C++):
        F[0] = false;
    Как работает ваш скетч без моих изменений (извиняюсь, за качество):
    1.jpg

    С изменением:
    [​IMG]

    Вот аналогичное, но нарисованное в paint'e:
    [​IMG][​IMG]

    Не подумайте плохого, ваш скетч луч в пучине тьмы, его нужно лишь доработать и тогда точно проблема решиться
     

    Вложения:

    • 5.jpg
      5.jpg
      Размер файла:
      313,8 КБ
      Просмотров:
      577
    • 6.jpg
      6.jpg
      Размер файла:
      39,1 КБ
      Просмотров:
      428
    • 7.jpg
      7.jpg
      Размер файла:
      32,2 КБ
      Просмотров:
      557
    Последнее редактирование: 1 май 2019
  18. b707

    b707 Гуру

    Похоже смещения по вертикали не хватает
    Попробуйте так:
    Код (C++):
    #include "U8g2lib.h"
    U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0,U8X8_PIN_NONE);

    bool F[8];  //булевский массив вместо кучи переменных F01 - F08

    void setup(){
      Serial.begin(9600);
        u8g2.begin();
        for (int i =0; i< 8; i++) {  F[i] = true;}
    }

    void loop(){
    int error_cnt =0;  // число ошибок, уже выведенных на текущую строку
    int line = 0;      // номер текущей строки
    u8g2.firstPage();
      do {
        u8g2.setFont(u8g2_font_helvB10_tf);
        u8g2.setFontPosTop();
        u8g2.setCursor(0,0);

    // цикл по восьми булевым переменым
        for (int i =0; i< 8; i++) {
          if (F[i]) {            // если i-тая ошибка true
            u8g2.print("F0");
            u8g2.print(i);
            u8g2.print("; ");
            error_cnt++;}
          if (error_cnt == 4) {         // если число ошибок на строке достигло 4х
           u8g2.println(" ");
           error_cnt =0;}
         }
      } while(u8g2.nextPage());
    }
     
  19. Что касается 2-ого варианта вашего скетча, он также не работает, подобный перенос с помощью функции u8g2.prinltn() я уже пробовал, эксперимент в этом случае провалился.

    Давайте вернемся к предыдущему вашему скетчу. Частично доработав, он стал частично работать. А теперь поподробней.

    Главная лажа заключается в переменной line. Не подумайте, избавляться от нее не следует. Проблема в том, что line постоянно увеличивается, а потом сбрасывается до нуля и так циклично. Вот, что происходит с ней:
    upload_2019-5-3_17-38-6.png
    Я зафиксировал ее на значение 1 и тогда все ошибки вывелись. Но проблема не решилась, т.к. это всего 8 ошибок, а в случае если их больше?
    Тогда появилась идея фиксированного значения line, зависящего от кол-ва ошибок и наполнения строки.
    Добавил вот такое чудо:
    Код (C++):
    #include "U8g2lib.h"
    U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0,U8X8_PIN_NONE);

    bool F[9];  //булевский массив вместо кучи переменных F01 - F08


    void setup(){
      Serial.begin(9600);
        u8g2.begin();
        for (int i =0; i< 9; i++) {F[i] = true;}
    }

    void loop(){
    int error_cnt =0;  // число ошибок, уже выведенных на текущую строку
    int line = 0;      // номер текущей строки
    u8g2.firstPage();
      do {
        u8g2.setFont(u8g2_font_helvB10_tf);
        u8g2.setFontPosTop();
        u8g2.setCursor(0,0);

    // цикл по восьми булевым переменым
    F[0] = false;  
      byte f1=0;
        byte f2=0;
          byte f3=0;
            byte f4=0;
              byte f5=0;
                byte f6=0;
                  byte f7=0;
                    byte f8=0;
                      byte f9=0;
      if(F[0] == true) {f1=1;}              
      if(F[1] == true) {f2=1;}              
      if(F[2] == true) {f3=1;}
      if(F[3] == true) {f4=1;}              
      if(F[4] == true) {f5=1;}
      if(F[5] == true) {f6=1;}            
      if(F[6] == true) {f7=1;}
      if(F[7] == true) {f8=1;}
    //  if(F[8] == true) {f9=1;}    
    byte quan=f1+f2+f3+f4+f5+f6+f7+f8+f9; //колво ошибок

    bool a = false;
    bool b = false;
    bool c = false;

    if (quan>=4)  {a=true;}
    if (quan>=8)  {b=true;}
    if (quan>=12) {c=true;}  

        for (int i =0; i<8; i++) {
          if (F[i]==true) {          
            u8g2.print("F0");
            u8g2.print(i);
            u8g2.print("; ");
            error_cnt++;
            Serial.println(error_cnt);
            }
         if (error_cnt==4 && a==true) {
           line=1;                  
           //u8g2.print('\n');
           u8g2.setCursor(0,line*16);
           Serial.println("line 1");
        if (error_cnt==8 && b==true) {      
           line=2;                  
           u8g2.setCursor(0,line*16);
           Serial.println("line 2");
         if (error_cnt == 12 && c==true) {
           line=3;                  
           u8g2.setCursor(0,line*16);
           }}
           if((a==true&&b==false) || (a==true&&b==true&&c==false) || (a==true&&b==true&&c==true)) { //об этом ниже, у                                                                                            //самого мозг от этого кипит, но лучше пока не придумал
           error_cnt =0;
           Serial.println("error_cnt = 0");}
           }
        }  
      } while(u8g2.nextPage());
    }
    Вывелось. Но с вытекающими проблемами.
    1. Если ошибок больше в данном случае 8-ми или меньше, то на экране происходит нечто странное, а именно:
    9cae7ed9-51a6-4d01-8b3f-4274fa2b9486.jpg
    P.S. если в миниатюре фотокарточки не видно, то я могу в следующем ответе прикрепить их в полном виде.
    2. 3-ую строку не переносит, скорее всего потому что я не правильно это реализовываю

    Давайте поподробнее о том, что по добавлял.

    Считывание количества ошибок:
    Код (C++):
      byte f1=0;
        byte f2=0;
          byte f3=0;
            byte f4=0;
              byte f5=0;
                byte f6=0;
                  byte f7=0;
                    byte f8=0;
                      byte f9=0;
      if(F[0] == true) {f1=1;}              
      if(F[1] == true) {f2=1;}              
      if(F[2] == true) {f3=1;}
      if(F[3] == true) {f4=1;}              
      if(F[4] == true) {f5=1;}
      if(F[5] == true) {f6=1;}            
      if(F[6] == true) {f7=1;}
      if(F[7] == true) {f8=1;}
      if(F[8] == true) {f9=1;}    
    byte quan=f1+f2+f3+f4+f5+f6+f7+f8+f9;
    От количества ошибок зависят данные булевые:
    Код (C++):
    bool a = false;
    bool b = false;
    bool c = false;

    if (quan>=4)  {a=true;}
    if (quan>=8)  {b=true;}
    if (quan>=12) {c=true;}    
    Вот тут происходит перенос строки.
    Первый блок, назовем его a в честь булевой переменной с тем же названием, переносит 2-ую строку, а именно с 5 по 8 ошибку (или так как перебирать мы начинаем с 0, то с 4 по 7).
    Второй блок b, названный также в честь булевой, переносит 3ую строку, но это в теории, на деле - нет.
    Код (C++):
         if (error_cnt==4 && a==true) {
           line=1;                  
           //u8g2.print('\n');
           u8g2.setCursor(0,line*16);
           Serial.println("line 1");
         if (error_cnt==8 && b==true) {      
           line=2;                  
           u8g2.setCursor(0,line*16);
           Serial.println("line 2");
    Как, вы, возможно заметили, то у меня здесь не наблюдается строчки:
    Код (C++):
      error_cnt =0;
    Она чуть позже и это отдельный геморрой:
    Код (C++):
           if((a==true&&b==false) || (a==true&&b==true&&c==false) || (a==true&&b==true&&c==true)) {
           error_cnt =0;
           Serial.println("error_cnt = 0");}
    Значит-с идея такая. Чтобы error_cnt очищался после того, как все ошибки были выведены и распределены по своим местам. В 1-ом случае, если присутствуют >=4х ошибок мы очищаем error_cnt, во втором, если их >=8, то мы очищаем, ну и в третьем мы очищаем их, если >=12 (Если не понятно, см от чего зависят булевые a\b\c)
    Как вы понимаете, должным образом это не работает

    Как-то так, надеюсь ничего не забыл, будут вопросы, будут ответы, отпишитесь, а я уверен, что они будут. Заранее благодарствую.
     
  20. Asper Daffy

    Asper Daffy Иксперд

    Так, ты сам себе этот геморрой создаёшь!

    Нафига воротить такие сложности? Сколько у тебя должно быть ошибок на строке? Восемь? Ну чего париться? Считай выводимые ошибки (с 0) и тогда номер строки ВСЕГДА будет равен "номер ошибки" / 8. И это всё! никаких других премудростей не нужно! Я писал тебе про это ещё несколько дней назад.
     
    Artemka_Ivanov нравится это.