Управление аналоговым ТБ с помощью Arduino

Тема в разделе "Arduino & Shields", создана пользователем Salk, 3 окт 2014.

?

Реализуема ли моя идея, с цифровым управлением 3-х канальной аудио-системы

Голосование закрыто 16 окт 2014.
  1. Да, ничего сложного в этом нет

    100,0%
  2. Нет, проще собрать на готовых аудио процессорах с функциями ТБ (TDA8425, TDA7318, TDA7439 и т.д)

    0 голосов
    0,0%
  1. geher

    geher Гуру

    С ползунком все очень просто.
    Максимальное значение числа делим на количество знакомест, отведенных под ползунок. Получаем "размер" каждого знакоместа. Дальше остается разделить текущее значение на полученный "размер", чтобы вычислить количество знакомест, занятых активной частью ползунка.
    Остается только в цикле вывести (при помощи lcd.write) знак полного квадрата (символ с кодом 0xFF на первой странице знакогенератора или 0xA0 на второй) соответствующее число раз и знак горизонтальной линии (0x2D на обеих страницах) числом <общее количество знакомест под ползунок>-<количество активных позиций>.

    Можно усложнить задачу, поделив каждое знакоместо на 5 позиций. Возможно, нужно добавить шестую позицию под зазор между знакоместами.
    Надо сгенерировать четыре символа разной степени заполненности и дать им коды, например, от 1 до 4.
    В этом случае количество знакомест под активную часть ползунка - это результат целочисленного деления на "размер" знакоместа. Остаток такого деления делим нацело на шесть и получаем количество занятых колонок пикселов в знакоместе. Если их получается больше четырех - в следующем после активной части знакоместе выводим полный квадрат. Если ноль - пробел, иначе сгенерированный символ с кодом, соответствующим количеству колонок. Дальше горизонтальную черту в количестве на единицу меньшем, чем в предыдущем простом варианте.
    Пример генерации символа приведен в примере к библиотеке LiquidCrystal, именуемом CustomCharacter.

    Получится примерно так:
    Код (Text):

    // объявление символов где-то в начале
    byte Bar1[8] = {
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000
    };
    byte Bar2[8] = {
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000
    };
    byte Bar3[8] = {
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100
    };
    byte Bar4[8] = {
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110
    };

    // создание символов где-то в setup
    lcd.createChar(1, bar1);
    lcd.createChar(2, bar2);
    lcd.createChar(3, bar3);
    lcd.createChar(4, bar4);

    //Вывод символа bar1
    lcd.write((byte) 1);
     
     
    Salk нравится это.
  2. Salk

    Salk Гик

    geher Спасибо большое! Буду разбираться. О результатах сообщу, может видео снимать не буду, но хотя бы пару фоток выложу :)
    На счет 1-го пункта моего вопроса разобрался, все оказалось правильно, как я и предполагал, теперь, если настроим громкости с пульта, то крутанув одну из ручек, не собьем все остальные - это круто ! :)
    Но вот с "полярностью" одного переменного резистора так и не смог ничего сделать. Тут либо отказаться от "class", написанного acos-ом и как-то написать по-простому, воспользовавшись функциями AndlogRead для каждого потенциометра отдельно, либо переделывать саму плату, меняя 5В и GND местами для одного из переменных резисторов.

    P.S. geher, потом возможно мне понадобится небольшая консультация на счет темы "Led Ring".
    Всем спасибо и всему форуму Amperka !:)
     
    Последнее редактирование: 2 апр 2015
  3. Salk

    Salk Гик

    Не получается у меня осилить этот ползунок :(
    Все что угодно выходит, кроме нужного эффекта:
    PHP:
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

    #define POT A1
    #define VSS 7

    byte Bar1[8] = {
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000
    };
    byte Bar2[8] = {
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000
    };
    byte Bar3[8] = {
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100
    };
    byte Bar4[8] = {
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110
    };
    byte Bar5[8] = {
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111
    };

    void setup()
    {
      lcd.init();                      // initialize the lcd
      lcd.backlight();
      Wire.begin();
      Serial.begin(9600);
      lcd.createChar(1, Bar1);
      lcd.createChar(2, Bar2);
      lcd.createChar(3, Bar3);
      lcd.createChar(4, Bar4);
      lcd.createChar(5, Bar5);
      pinMode(POT, INPUT);
      pinMode(VSS, OUTPUT);
      digitalWrite(VSS, HIGH);
    }

    void loop()
    {
      int sensorReading = analogRead(POT);
      int positions = map(sensorReading, 0, 1023, 1, 6);
      int cursors = map(sensorReading, 0, 1023, 0, 9);
      int polzunok = sensorReading / (100 / 10); // количество знакомест, занятых активной частью ползунка.

      /* Заполнение одного квадрата с помощью потенциометра
      lcd.setCursor(5, 0);
      lcd.write(positions);
      */


      // получился неплохой такой "генератор" символов, доступных дисплею
      // lcd.setCursor(5, 0);
      // lcd.write(polzunok);

      //Автоматическое последовательное заполнение 4 квадратов
      for (int a = 1; a < 6; a++)
      {
        lcd.setCursor(7, 1);
        lcd.write(constrain(a, 1, 6));
        delay(500);
      }
      for (int a = 1; a < 6; a++)
      {
        lcd.setCursor(8, 1);
        lcd.write(constrain(a, 1, 6));
        delay(500);
      }
      for (int a = 1; a < 6; a++)
      {
        lcd.setCursor(9, 1);
        lcd.write(constrain(a, 1, 6));
        delay(500);
      }
      for (int a = 1; a < 6; a++)
      {
        lcd.setCursor(10, 1);
        lcd.write(constrain(a, 1, 6));
        delay(500);
      }
      lcd.clear();

      /*
        lcd.setCursor(5, 0); // 1 вертикальная линия
        lcd.write(1);

        lcd.setCursor(6, 0); // 2 вертикальных
        lcd.write(2);

        lcd.setCursor(7, 0); // 3 вертикальных
        lcd.write(3);

        lcd.setCursor(8, 0); // 4 вертикальных
        lcd.write(4);

        lcd.setCursor(9, 0); // 5 вертикальных (полный квадрат)
        lcd.write(5);
      */

    }
    Помогите, пожалуйста, осилить :)
     
  4. geher

    geher Гуру

    Код (Text):

    void printpolzun( int x, //столбец
                      int y, //строка
                      int size, //размер в позициях на экране
                      int value, //значение
                      int maxvalue //максимальное значение
                   )
    {
         int possize=maxvalue/size;
         lcd.setCursor(x,y);
         for (int i=1;i<=value/possize;i++) // заполненная часть (от 1 до value/possize)
         {
             lcd.write(0xFF);
         }
        // частично заполненная часть (value/possize+1)
        int dotcolumns=map(value%possize,0,poszize,0,6);
        switch(dotcolumns)  // отражаем остаток неучтенной части value на 6 точек знакоместа
        {
              case 0: //пусто, остатка нет (пренебрежимо мал)
                  lcd.write(0x20);
                  break;        
              case 1:; // 1,2,3,4 колонок точек
              case 2:;
              case 3:;
              case 4:
                  lcd.write(dotcolumns);
                  break;
              case 5:; //5 колонок точек
              case 6: //5 колонок точек+зазор между позициями знаков на экране
                  lcd.write(0xFF);
                  break;
        }
         for (int i=value/possize+2;i<=size;i++) // незаполненная часть (от value/possize+2 до size)
         {
             lcd.write(0x20);
         }
    }
     
     
    Salk нравится это.
  5. Salk

    Salk Гик

    Спасибо огромное! Все работает, как часы :)
    PHOTO_20150412_211226.jpg PHOTO_20150412_211248.jpg PHOTO_20150412_211259.jpg

    PHP:
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

    #define POT A1
    #define VSS 7

    int x = 2; //столбец
    int y = 1; //строка
    int size = 16; //размер в позициях на экране
    int value; //значение
    int maxvalue = 1023; //максимальное значение
    int possize;

    byte Bar1[8] = {
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000
    };
    byte Bar2[8] = {
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000
    };
    byte Bar3[8] = {
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100
    };
    byte Bar4[8] = {
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110
    };
    byte Bar5[8] = {
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111
    };

    void setup()
    {
      lcd.init();                      // initialize the lcd
      lcd.backlight();
      Wire.begin();
      pinMode(POT, INPUT);
      pinMode(VSS, OUTPUT);
      digitalWrite(VSS, HIGH);
      lcd.createChar(1, Bar1);
      lcd.createChar(2, Bar2);
      lcd.createChar(3, Bar3);
      lcd.createChar(4, Bar4);
      lcd.createChar(5, Bar5);
    }

    void loop()
    {
      value = analogRead(POT);
      int vol = map(value, 0, 1023, 0, 100);
      possize = maxvalue / size;
      lcd.setCursor(x, y);
      for (int i = 1; i <= value / possize; i++) // заполненная часть (от 1 до value/possize)
      {
        lcd.write(0xFF);
      }
      // частично заполненная часть (value/possize+1)
      int dotcolumns = map(value % possize, 0, possize, 0, 6);
      switch (dotcolumns) // отражаем остаток неучтенной части value на 6 точек знакоместа
      {
        case 0: //пусто, остатка нет (пренебрежимо мал)
          lcd.write(0x20);
          break;
        case 1:; // 1,2,3,4 колонок точек
        case 2:;
        case 3:;
        case 4:
          lcd.write(dotcolumns);
          break;
        case 5:; //5 колонок точек
        case 6:  //5 колонок точек+зазор между позициями знаков на экране
          lcd.write(0xFF);
          break;
      }
      for (int i = value / possize + 2; i <= size; i++) // незаполненная часть (от value/possize+2 до size)
      {
        lcd.write(0x20);
      }
      lcd.setCursor(4, 0);
      lcd.print("<< VOLUME >>");
      lcd.setCursor(0, 1);
      lcd.print("-");
      lcd.setCursor(19, 1);
      lcd.print("+");
      lcd.setCursor(9, 2);
      lcd.print(vol);
      lcd.print("%");
      lcd.print(" ");
    }
    И ещё маленькая, надеюсь последняя, просьба :)
    Добавить режим "вправо-влево" для НЧ и ВЧ. Т.е. от середины влево или вправо ( ----- >-< ----- ) .
    Спасибо ;)
     
  6. geher

    geher Гуру

    Предполагается, что value может меняться от -maxvalue до maxvalue
    0 - середина шкалы
    size - четное
    Код (Text):
    void printleftrightpolzun( int x, //столбец
                      int y, //строка
                      int size, //размер в позициях на экране
                      int value, //значение
                      int maxvalue //максимальное значение
                    )
    {
        int possize=maxvalue/(size/2);
        if (value <0 )
        {
          for (int i=1;i<=size/2-(-value/possize)-1;i++) // незаполненная часть слева
          {
              lcd.write(0x20);
          }
          // частично заполненная часть
          if (-value/possize+1<=size/2) {
            int dotcolumns=map(-value%possize,0,possize,0,6);
            switch(dotcolumns)  // отражаем остаток неучтенной части value на 6 точек знакоместа
            {
                case 0: //пусто, остатка нет (пренебрежимо мал)
                    lcd.write(0x20);
                    break;  
                case 1:; // 1,2,3,4 колонок точек
                case 2:;
                case 3:;
                case 4:
                    lcd.write(dotcolumns);
                    break;
                case 5:; //5 колонок точек
                case 6: //5 колонок точек+зазор между позициями знаков на экране
                    lcd.write(0xFF);
                    break;
            }
          }
          for (int i=size/2-(-value/possize)+1;i<=size/2;i++) // заполненная часть
          {
              lcd.write(0xFF);
          }
          for (int i=1;i<=size/2;i++) // незаполненная вся часть справа
          {
              lcd.write(0x20);
          }
        }
        else
        {
          for (int i=1;i<=size/2;i++) // незаполненная вся часть слева
          {
              lcd.write(0x20);
          }
            for (int i=1;i<=value/possize;i++) // заполненная часть (от 1 до value/possize)
          {
              lcd.write(0xFF);
          }
          // частично заполненная часть (value/possize+1)
          if (value/possize+1<=size/2) {
            int dotcolumns=map(value%possize,0,possize,0,6);
            switch(dotcolumns)  // отражаем остаток неучтенной части value на 6 точек знакоместа
            {
                case 0: //пусто, остатка нет (пренебрежимо мал)
                    lcd.write(0x20);
                    break;  
                case 1:; // 1,2,3,4 колонок точек
                case 2:;
                case 3:;
                case 4:
                    lcd.write(dotcolumns);
                case 5:; //5 колонок точек
                case 6: //5 колонок точек+зазор между позициями знаков на экране
                    lcd.write(0xFF);
                    break;
            }
          }
          for (int i=value/possize+2;i<=size/2;i++) // незаполненная часть (от value/possize+2 до size)
          {
              lcd.write(0x20);
          }
        }
    }
     
    Последнее редактирование: 12 апр 2015
  7. Salk

    Salk Гик

    Круто, спасибо ! Но есть несколько недочетов по коду, которые я не смог разрешить:
    1. При регулировки в левую сторону, начало закрашивание полного квадрата начинается с лево-направо. А т.к. левая сторона, сам ползунок начинается от середины, то было бы лучше, чтобы и закрашивание квадрата начиналось не с лево-направо, а с право-налево.
      Чтобы это исправить нужно создавать заново вертикальные колонки, только закрашенные не с левой стороны, а с правой?
    2. Хотелось бы ещё в середину ползунка, вставить какой-то фиксированный знак или несколько знаков. Ну чтобы визуально было видно начало отчета, как это лучше сделать? Так сказать раздвинуть середину ползунка и "посадить" туда нечто (к примеру ">-<"):)
    PHP:
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

    #define POT A1
    #define POT_HIGH A2
    #define POT_LOW A3
    #define VSS 7

    int x = 2; //столбец
    int y = 1; //строка
    int size = 16; //размер в позициях на экране
    int value; //значение
    int valueLH; // значения для НЧ/ВЧ
    int maxvalue = 1025; //максимальное значение
    int possize;

    byte Bar1[8] = {
      0b10000,
      0b10000,
      0b10000,
      0b11111,
      0b10000,
      0b10000,
      0b10000,
      0b10000
    };
    byte Bar2[8] = {
      0b11000,
      0b11000,
      0b11000,
      0b11111,
      0b11000,
      0b11000,
      0b11000,
      0b11000
    };
    byte Bar3[8] = {
      0b11100,
      0b11100,
      0b11100,
      0b11111,
      0b11100,
      0b11100,
      0b11100,
      0b11100
    };
    byte Bar4[8] = {
      0b11110,
      0b11110,
      0b11110,
      0b11111,
      0b11110,
      0b11110,
      0b11110,
      0b11110
    };
    byte Bar5[8] = {
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111
    };
    byte Bar6[8] = {
      0b00001,
      0b00011,
      0b11101,
      0b10101,
      0b11101,
      0b00011,
      0b00001,
      0b00000
    }; // значок динамика в правую сторону
    byte Bar7[8] = {
      0b10000,
      0b11000,
      0b10111,
      0b10101,
      0b10111,
      0b11000,
      0b10000,
      0b00000
    }; // значок динамика в левую сторону
    byte Bar8[8] = {
      0b00000,
      0b00000,
      0b00000,
      0b11111,
      0b00000,
      0b00000,
      0b00000,
      0b00000
    }; // "-----"

    void setup()
    {
      lcd.init();                      // initialize the lcd
      lcd.backlight();
      Wire.begin();
      pinMode(POT, INPUT);
      pinMode(POT_HIGH, INPUT);
      pinMode(POT_LOW, INPUT);
      pinMode(VSS, OUTPUT);
      digitalWrite(VSS, HIGH);
      lcd.createChar(1, Bar1);  // 1 вертикаль
      lcd.createChar(2, Bar2);  // 2 вертикаль
      lcd.createChar(3, Bar3);  // 3 вертикаль
      lcd.createChar(4, Bar4);  // 4 вертикаль
      lcd.createChar(5, Bar5);  // 5 вертикаль
      lcd.createChar(6, Bar6);  // значок динамика в правую сторону
      lcd.createChar(7, Bar7);  // значок динамика в левую сторону
      lcd.createChar(0, Bar8);  // "-----"
    }

    void loop()
    {
      // НЧ/ВЧ
      valueLH = map(analogRead(POT_LOW), 0, 1025, -1025, 1025);
      int high = map(analogRead(POT_LOW), 0, 1023, -9, 9);
      int possize = maxvalue / (size / 2);
      lcd.setCursor(x, y);
      if (valueLH < 0)
      {
        for (int i = 1; i <= size / 2 - (-valueLH / possize) - 1; i++) // незаполненная часть слева
        {
          lcd.write(0); // "-----"
        }
        // частично заполненная часть
        if (-valueLH / possize + 1 <= size / 2)
        {
          int dotcolumns = map(-valueLH % possize, 0, possize, 0, 6);
          switch (dotcolumns) // отражаем остаток неучтенной части value на 6 точек знакоместа
          {
            case 0: //пусто, остатка нет (пренебрежимо мал)
              lcd.write(0);
              break;
            case 1:; // 1,2,3,4 колонок точек
            case 2:;
            case 3:;
            case 4:
              lcd.write(dotcolumns);
              break;
            case 5:; //5 колонок точек
            case 6: //5 колонок точек+зазор между позициями знаков на экране
              lcd.write(0xFF);
              break;
          }
        }
        for (int i = size / 2 - (-valueLH / possize) + 1; i <= size / 2; i++) // заполненная часть
        {
          lcd.write(0xFF);
        }
        for (int i = 1; i <= size / 2; i++) // незаполненная вся часть справа
        {
          lcd.write(0); // 0x20 "-----"
        }
      }
      else
      {
        for (int i = 1; i <= size / 2; i++) // незаполненная вся часть слева
        {
          lcd.write(0); // "-----"
        }
        for (int i = 1; i <= valueLH / possize; i++) // заполненная часть (от 1 до value/possize)
        {
          lcd.write(0xFF);
        }
        // частично заполненная часть (value/possize+1)
        if (valueLH / possize + 1 <= size / 2)
        {
          int dotcolumns = map(valueLH % possize, 0, possize, 0, 6);
          switch (dotcolumns) // отражаем остаток неучтенной части value на 6 точек знакоместа
          {
            case 0: //пусто, остатка нет (пренебрежимо мал)
              lcd.write(0);
              break;
            case 1:; // 1,2,3,4 колонок точек
            case 2:;
            case 3:;
            case 4:
              lcd.write(dotcolumns);
              break;
            case 5:; //5 колонок точек
            case 6:  //5 колонок точек+зазор между позициями знаков на экране
              lcd.write(0xFF);
              break;
          }
        }
        for (int i = valueLH / possize + 2; i <= size / 2; i++) // незаполненная часть (от value/possize+2 до size)
        {
          lcd.write(0); // "------"
        }
      }
      lcd.setCursor(9, 3);
      lcd.write(7);
      lcd.write(6);
      lcd.write(0);
      lcd.setCursor(5, 0);
      lcd.print("<< HIGH >>");
      lcd.setCursor(0, 1);
      lcd.print("-");
      lcd.setCursor(19, 1);
      lcd.print("+");
      if (high > 0 && high != 0)
      {
        lcd.setCursor(7, 2);
        lcd.print(" ");
        lcd.print("+");
        lcd.print(high);
      }
      if (high < 0 && high != 0)
      {
        lcd.setCursor(7, 2);
        lcd.print(" ");
        lcd.print(high);
      }
      if (high == 0)
      {
        lcd.setCursor(8, 2);
        lcd.print(high);
      }
      lcd.print("dB");
      lcd.print(" ");
    }
    [​IMG][​IMG][​IMG][​IMG]
    Ещё столкнулся с таким нюансом - мой дисплейчик, оказывается, поддерживает всего 8 дополнительных (собственных) символов (bar0 - bar7). Попытки создать больше с собственным символом - не удачны, экран вместо желаемого символа выводит какие-то свои.Что можно предпринять :) А то я уже во вкус вошел, наштамповал кучу символов и вот облом ...
     
    Последнее редактирование: 13 апр 2015
  8. geher

    geher Гуру

    На частично заполненные квадратики хватит как раз 8 символов.
    По поводу заполнения при отклонении полоски влево, согласен, недоработка.
    У меня нет сейчас свободного дисплея. Моделирую в выдаче монитора последовательного порта.
    Измененный вариант (не проверял):
    Код (Text):

    // где-то в начале
    byte Bar1[8] = {
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000
    };
    byte Bar2[8] = {
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000
    };
    byte Bar3[8] = {
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100
    };
    byte Bar4[8] = {
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110
    };
    byte BarM1[8] = { // M - это минус
      0b00001,
      0b00001,
      0b00001,
      0b00001,
      0b00001,
      0b00001,
      0b00001,
      0b00001
    };
    byte BarM2[8] = {
      0b00011,
      0b00011,
      0b00011,
      0b00011,
      0b00011,
      0b00011,
      0b00011,
      0b00011
    };
    byte BarM3[8] = {
      0b00111,
      0b00111,
      0b00111,
      0b00111,
      0b00111,
      0b00111,
      0b00111,
      0b00111
    };
    byte BarM4[8] = {
      0b01111,
      0b01111,
      0b01111,
      0b01111,
      0b01111,
      0b01111,
      0b01111,
      0b01111
    };

    //Где-то в Setup()
    lcd.createChar(0, Bar1);
      lcd.createChar(1, Bar2);
      lcd.createChar(2, Bar3);
      lcd.createChar(3, Bar4);
    lcd.createChar(4,BarM1);
      lcd.createChar(5, BarM2);
      lcd.createChar(6, BarM3);
      lcd.createChar(7, BarM4);


    // Где-то дальше
    void printleftrightpolzun( int x, //столбец
                      int y, //строка
                      int size, //размер в позициях на экране
                      int value, //значение
                      int maxvalue //максимальное значение
                    )
    {
        int possize=maxvalue/(size/2);
        if (value <0 )
        {
          for (int i=1;i<=size/2-(-value/possize)-1;i++) // незаполненная часть слева
          {
              lcd.write(0x20);
          }
          // частично заполненная часть
          if (-value/possize+1<=size/2) {
            int dotcolumns=map(-value%possize,0,possize,0,6);
            switch(dotcolumns)  // отражаем остаток неучтенной части value на 6 точек знакоместа "левыми кусками квадрата"
            {
                case 0: //пусто, остатка нет (пренебрежимо мал)
                    lcd.write(0x20);
                    break;
                case 1:; // 1,2,3,4 колонок точек
                case 2:;
                case 3:;
                case 4:
                    lcd.write(dotcolumns+3);
                    break;
                case 5:; //5 колонок точек
                case 6: //5 колонок точек+зазор между позициями знаков на экране
                    lcd.write(0xFF);
                    break;
            }
          }
          for (int i=size/2-(-value/possize)+1;i<=size/2;i++) // заполненная часть
          {
              lcd.write(0xFF);
          }
          for (int i=1;i<=size/2;i++) // незаполненная вся часть справа
          {
              lcd.write(0x20);
          }
        }
        else
        {
          for (int i=1;i<=size/2;i++) // незаполненная вся часть слева
          {
              lcd.write(0x20);
          }
            for (int i=1;i<=value/possize;i++) // заполненная часть (от 1 до value/possize)
          {
              lcd.write(0xFF);
          }
          // частично заполненная часть (value/possize+1)
          if (value/possize+1<=size/2) {
            int dotcolumns=map(value%possize,0,possize,0,6);
            switch(dotcolumns-1)  // отражаем остаток неучтенной части value на 6 точек знакоместа "правыми кусками квадрата"
            {
                case 0: //пусто, остатка нет (пренебрежимо мал)
                    lcd.write(0x20);
                    break;
                case 1:; // 1,2,3,4 колонок точек
                case 2:;
                case 3:;
                case 4:
                    lcd.write(dotcolumns);
                case 5:; //5 колонок точек
                case 6: //5 колонок точек+зазор между позициями знаков на экране
                    lcd.write(0xFF);
                    break;
            }
          }
          for (int i=value/possize+2;i<=size/2;i++) // незаполненная часть (от value/possize+2 до size)
          {
              lcd.write(0x20);
          }
        }
    }
    Символ с пятью колонками не нужен, он есть в знакогенераторе (0xFF для первой таблицы).
    Если очень необходимо выкроить генерируемые символы для других целей, можно попробовать создавать их по необходимости "на лету". Не уверен, что поможет, но попробовать можно.
    Код (Text):

    // где-то в начале
    byte Bar1[8] = {
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000,
      0b10000
    };
    byte Bar2[8] = {
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000,
      0b11000
    };
    byte Bar3[8] = {
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100,
      0b11100
    };
    byte Bar4[8] = {
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110,
      0b11110
    };
    byte BarM1[8] = { // M - это минус
      0b00001,
      0b00001,
      0b00001,
      0b00001,
      0b00001,
      0b00001,
      0b00001,
      0b00001
    };
    byte BarM2[8] = {
      0b00011,
      0b00011,
      0b00011,
      0b00011,
      0b00011,
      0b00011,
      0b00011,
      0b00011
    };
    byte BarM3[8] = {
      0b00111,
      0b00111,
      0b00111,
      0b00111,
      0b00111,
      0b00111,
      0b00111,
      0b00111
    };
    byte BarM4[8] = {
      0b01111,
      0b01111,
      0b01111,
      0b01111,
      0b01111,
      0b01111,
      0b01111,
      0b01111
    };

    // Где-то дальше
    void printleftrightpolzun( int x, //столбец
                      int y, //строка
                      int size, //размер в позициях на экране
                      int value, //значение
                      int maxvalue //максимальное значение
                    )
    {
       static int leftright=0
        int possize=maxvalue/(size/2);
        if (value <0 )
        {
           if (leftright!=-1)
          {
                lcd.createChar(1,BarM1);
                lcd.createChar(2, BarM2);
                lcd.createChar(3, BarM3);
                lcd.createChar(4, BarM4);
               leftright=-1;
          }
          for (int i=1;i<=size/2-(-value/possize)-1;i++) // незаполненная часть слева
          {
              lcd.write(0x20);
          }
          // частично заполненная часть
          if (-value/possize+1<=size/2) {
            int dotcolumns=map(-value%possize,0,possize,0,6);
            switch(dotcolumns)  // отражаем остаток неучтенной части value на 6 точек знакоместа "левыми кусками квадрата"
            {
                case 0: //пусто, остатка нет (пренебрежимо мал)
                    lcd.write(0x20);
                    break;
                case 1:; // 1,2,3,4 колонок точек
                case 2:;
                case 3:;
                case 4:
                    lcd.write(dotcolumns);
                    break;
                case 5:; //5 колонок точек
                case 6: //5 колонок точек+зазор между позициями знаков на экране
                    lcd.write(0xFF);
                    break;
            }
          }
          for (int i=size/2-(-value/possize)+1;i<=size/2;i++) // заполненная часть
          {
              lcd.write(0xFF);
          }
          for (int i=1;i<=size/2;i++) // незаполненная вся часть справа
          {
              lcd.write(0x20);
          }
        }
        else
        {
           if (leftright!=1)
          {
                lcd.createChar(1,Bar1);
                lcd.createChar(2, Bar2);
                lcd.createChar(3, Bar3);
                lcd.createChar(4, Bar4);
               leftright=1;
          }
          for (int i=1;i<=size/2;i++) // незаполненная вся часть слева
          {
              lcd.write(0x20);
          }
            for (int i=1;i<=value/possize;i++) // заполненная часть (от 1 до value/possize)
          {
              lcd.write(0xFF);
          }
          // частично заполненная часть (value/possize+1)
          if (value/possize+1<=size/2) {
            int dotcolumns=map(value%possize,0,possize,0,6);
            switch(dotcolumns-1)  // отражаем остаток неучтенной части value на 6 точек знакоместа "правыми кусками квадрата"
            {
                case 0: //пусто, остатка нет (пренебрежимо мал)
                    lcd.write(0x20);
                    break;
                case 1:; // 1,2,3,4 колонок точек
                case 2:;
                case 3:;
                case 4:
                    lcd.write(dotcolumns);
                case 5:; //5 колонок точек
                case 6: //5 колонок точек+зазор между позициями знаков на экране
                    lcd.write(0xFF);
                    break;
            }
          }
          for (int i=value/possize+2;i<=size/2;i++) // незаполненная часть (от value/possize+2 до size)
          {
              lcd.write(0x20);
          }
        }
    }
     
    Последнее редактирование: 13 апр 2015
  9. geher

    geher Гуру

    Также можно сэкономить, если не использовать символы с частичным заполнением, выводя в этом месте в зависимости от dotcolumns полностью заполненный при >2 и пробел при <3
     
  10. geher

    geher Гуру

    По поводу "раздвинуть и вставить" могу заметить только, что поскольку дисплеи обычно с четным числом колонок, то и размер ползунка лучше делать четным. Соответственно, и вставка должна быть из четного количества символов, например "><".
    Тогда примерно так (всего лишь сокращаем правую и левую часть на одну позицию для вставки разделителя):
    Код (Text):
    void printleftrightpolzun( int x, //столбец
                      int y, //строка
                      int size, //размер в позициях на экране
                      int value, //значение
                      int maxvalue //максимальное значение
                    )
    {
      static int leftright=0
        int possize=maxvalue/(size/2-1);
        if (value <0 )
        {
          if (leftright!=-1)
          {
                lcd.createChar(1,BarM1);
                lcd.createChar(2, BarM2);
                lcd.createChar(3, BarM3);
                lcd.createChar(4, BarM4);
              leftright=-1;
          }
          for (int i=1;i<=(size/2-1)-(-value/possize)-1;i++) // незаполненная часть слева
          {
              lcd.write(0x20);
          }
          // частично заполненная часть
          if (-value/possize+1<=(size/2-1)) {
            int dotcolumns=map(-value%possize,0,possize,0,6);
            switch(dotcolumns)  // отражаем остаток неучтенной части value на 6 точек знакоместа "левыми кусками квадрата"
            {
                case 0: //пусто, остатка нет (пренебрежимо мал)
                    lcd.write(0x20);
                    break;
                case 1:; // 1,2,3,4 колонок точек
                case 2:;
                case 3:;
                case 4:
                    lcd.write(dotcolumns);
                    break;
                case 5:; //5 колонок точек
                case 6: //5 колонок точек+зазор между позициями знаков на экране
                    lcd.write(0xFF);
                    break;
            }
          }
          for (int i=(size/2-1)-(-value/possize)+1;i<=(size/2-1);i++) // заполненная часть
          {
              lcd.write(0xFF);
          }
         // разделитель
         lcd.print("><");
          for (int i=1;i<=(size/2-1);i++) // незаполненная вся часть справа
          {
              lcd.write(0x20);
          }
        }
        else
        {
          if (leftright!=1)
          {
                lcd.createChar(1,Bar1);
                lcd.createChar(2, Bar2);
                lcd.createChar(3, Bar3);
                lcd.createChar(4, Bar4);
              leftright=1;
          }
          for (int i=1;i<=(size/2-1);i++) // незаполненная вся часть слева
          {
              lcd.write(0x20);
          }
         // разделитель
         lcd.print("><");
            for (int i=1;i<=value/possize;i++) // заполненная часть (от 1 до value/possize)
          {
              lcd.write(0xFF);
          }
          // частично заполненная часть (value/possize+1)
          if (value/possize+1<=(size/2-1)) {
            int dotcolumns=map(value%possize,0,possize,0,6);
            switch(dotcolumns-1)  // отражаем остаток неучтенной части value на 6 точек знакоместа "правыми кусками квадрата"
            {
                case 0: //пусто, остатка нет (пренебрежимо мал)
                    lcd.write(0x20);
                    break;
                case 1:; // 1,2,3,4 колонок точек
                case 2:;
                case 3:;
                case 4:
                    lcd.write(dotcolumns);
                case 5:; //5 колонок точек
                case 6: //5 колонок точек+зазор между позициями знаков на экране
                    lcd.write(0xFF);
                    break;
            }
          }
          for (int i=value/possize+2;i<=(size/2-1);i++) // незаполненная часть (от value/possize+2 до size)
          {
              lcd.write(0x20);
          }
        }
    }
     
  11. КвазИ

    КвазИ Нерд

    сорри за офф) но респект тебе за тему, вскоре и мне твоя и не только твоя помощь понадобится
    хочу реализовать похожее) вот: регулятор громкости на 6тиканальном http://www.analog.com/media/en/technical-documentation/data-sheets/AD5204_5206.pdf
    для домашнего кинотеатра) т.е. фронт тыл центр и саб, все это регулировать с помощью IR и(или) энкодера с кнопкой (для переключения каналов) и всё это отображать на дисплее с 4мя цифрами (мне хватит)
     
  12. Salk

    Salk Гик

    КвазИ
    Польщен, не думал, что это тема ещё кого-то заинтересует. Т.к. по сути - это заново изобретенный велосипед.
    Мне очень не хотелось терять великолепный аналоговый темброблок, поэтому я прибегнул к цифровым потенциометрам. А так уже давно есть аудиопроцессоры, типа: TDA7313, TDA7318, TDA7439, TDA8425 и другие.
    При выборе цифровых потенциометров, тоже изначально ориентировался на пятую серию AD52**. Они хороши тем, что в одном корпусе прячут сразу несколько потенциометров и пример кода уже был в видео Джереми, но я не смог их найти. Для стерео вам понадобится 12 каналов, т.е. 2х AD5206.
    Кстати будет любопытно узнать, будут ли у Вас "мистические" щелчки при отправке данных в цифровые потенциометры :) Может это особенность только моих ЦП.
    Ещё одна неприятная особенность, которая может у Вас возникнуть, это искажения звука при большой входной амплитуде сигнала. В начале темы я об этом упоминал (поэтому перешел на AD7376), правда я там тестировал на AD84**.
    В остальном - главное желание, а насчет помощи, тут всегда помогают :) Я начинал с полного нуля. И нисколько не жалею о времени, которое затратил на изучение arduino.
    По сути с момента написания первого сообщения этой темы - это и есть время затраченное на создание этого проекта. Приятно будет если тема продолжит жить. Пост сдал-пост принял :)
     
  13. КвазИ

    КвазИ Нерд

    12 каналов??? зачем мне нужно лишь 6) 2тыла + 2 фронта + саб+ центр и все..)

    на счет щелчков.. проверим)) а вот на счет искажения я в курсе... там же в даташите написано что входное напряжение на самом потенциометре не должно превышать напряжения питания... т.е. не более 5В) поэтому я поставлю его до предусилителя.. а как известно все девайсы типа тюнеры телевизоры и даже комп не выдают на выходе более 5В так что я думаю все ок должно быть..
     
  14. Salk

    Salk Гик

    geher
    Спасибо большое! Но, опять, есть небольшая помарка:
    когда регулировку ВЧ/НЧ оставил на левой стороне, и после этого меняешь громкость, то bar1,2,3,4 запоминаются с минусом (М) и заполнение квадрата начинается с право-налево :) Если ВЧ оставил на правой стороне, то с громкостью все в порядке :)

    Как сделать, чтобы при регулировании громкости, он стирал предыдущие бары и вставлял свои.. как-то так... Не знаю поняли Вы или нет меня, но суть в том, что сейчас в скетче я сделал: если крутанули ручку громкости, то выскакивает бар с громкостью, если НЧ/ВЧ то соответственно. И вот если ползунок ВЧ/НЧ оставить в левой стороне (bar1M, Bar2,M и т.д.), то и громкость работает с этими барами.
    [​IMG][​IMG][​IMG][​IMG][​IMG]
    PHP:
    // С пульта
          value = constrain(value + VOLUME_STEP, 0, 1023);
          // Громкость
          vol = map(value, 0, 1023, 0, 101); // на LCD
          possize = maxvalue / size;
          if (lcdclear == 1)
          {
            lcd.clear();
            lcdclear = 0;
          }
          lcd.setCursor(x, y);
          static int volume = 0;
          if (volume != 1)
          {
            lcd.createChar(1, Bar1);
            lcd.createChar(2, Bar2);
            lcd.createChar(3, Bar3);
            lcd.createChar(4, Bar4);
            volume = 1;
          }
          for (int i = 1; i <= value / possize; i++) // заполненная часть (от 1 до value/possize)
          {
            lcd.write(0xFF);
          }
          // частично заполненная часть (value/possize+1)
          int dotcolumns = map(value % possize, 0, possize, 0, 6);
          switch (dotcolumns) // отражаем остаток неучтенной части value на 6 точек знакоместа
          {
            case 0: //пусто, остатка нет (пренебрежимо мал)
              lcd.print("-"); // lcd.write(0);
              break;
            case 1:; // 1,2,3,4 колонок точек
            case 2:;
            case 3:;
            case 4:
              lcd.write(dotcolumns);
              break;
            case 5:; //5 колонок точек
            case 6:  //5 колонок точек+зазор между позициями знаков на экране
              lcd.write(0xFF);
              break;
          }
          for (int i = value / possize + 2; i <= size; i++) // незаполненная часть (от value/possize+2 до size)
          {
            lcd.print("-");
          }
          lcd.setCursor(4, 0);
          lcd.print("<< VOLUME >>");
          lcd.setCursor(0, 1);
          lcd.write(7);
          lcd.setCursor(19, 1);
          lcd.print(" ");

          while (vol > oldVol)
          {
            lcd.setCursor(19, 1);
            lcd.print("+");
            oldVol = vol;
          }
          while (vol < oldVol)
          {
            lcd.setCursor(19, 1);
            lcd.print("-");
            oldVol = vol;
          }

          lcd.setCursor(9, 2);
          lcd.print(vol);
          lcd.print("%");
          lcd.print(" ");
        }
        irrecv.resume(); // Получаем следующее значение
      }

      // Если крутанули ручку громкости
      if (regulatorsChangedVol())
      {
        // "Крутилки"
        value = analogRead(VOLUME_POT);
        // Громкость
        vol = map(value, 0, 1023, 0, 101); // на LCD
        possize = maxvalue / size;
        if (lcdclear == 1)
        {
          lcd.clear();
          lcdclear = 0;
        }
        lcd.setCursor(x, y);
        static int volume = 0;
        if (volume != 1)
        {
          lcd.createChar(1, Bar1);
          lcd.createChar(2, Bar2);
          lcd.createChar(3, Bar3);
          lcd.createChar(4, Bar4);
          volume = 1;
        }
        for (int i = 1; i <= value / possize; i++) // заполненная часть (от 1 до value/possize)
        {
          lcd.write(0xFF);
        }
        // частично заполненная часть (value/possize+1)
        int dotcolumns = map(value % possize, 0, possize, 0, 6);
        switch (dotcolumns) // отражаем остаток неучтенной части value на 6 точек знакоместа
        {
          case 0: //пусто, остатка нет (пренебрежимо мал)
            lcd.print("-"); // lcd.write(0);
            break;
          case 1:; // 1,2,3,4 колонок точек
          case 2:;
          case 3:;
          case 4:
            lcd.write(dotcolumns);
            break;
          case 5:; //5 колонок точек
          case 6:  //5 колонок точек+зазор между позициями знаков на экране
            lcd.write(0xFF);
            break;
        }
        for (int i = value / possize + 2; i <= size; i++) // незаполненная часть (от value/possize+2 до size)
        {
          lcd.print("-");
        }
        lcd.setCursor(4, 0);
        lcd.print("<< VOLUME >>");
        lcd.setCursor(0, 1);
        lcd.write(7);
        lcd.setCursor(19, 1);
        lcd.print(" ");

        while (vol > oldVol)
        {
          lcd.setCursor(19, 1);
          lcd.print("+");
          oldVol = vol;
        }
        while (vol < oldVol)
        {
          lcd.setCursor(19, 1);
          lcd.print("-");
          oldVol = vol;
        }

        lcd.setCursor(9, 2);
        lcd.print(vol);
        lcd.print("%");
        lcd.print(" ");
      }

      // Если крутанули ручку НЧ
      if (regulatorsChangedLow())
      {
        // НЧ/ВЧ
        valueLH = map(analogRead(LOW_POT), 0, 1025, -1025, 1025);
        int high = map(analogRead(LOW_POT), 0, 1023, -9, 10);
        possizeLH = maxvalue / (size / 2 - 1);
        if (lcdclear == 0)
        {
          lcd.clear();
          lcdclear = 1;
        }
        lcd.setCursor(x, y);
        static int leftright = 0;
        if (valueLH < 0)
        {
          if (leftright != -1)
          {
            lcd.createChar(1, BarM1);
            lcd.createChar(2, BarM2);
            lcd.createChar(3, BarM3);
            lcd.createChar(4, BarM4);
            leftright = -1;
          }
          for (int i = 1; i <= (size / 2 - 1) - (-valueLH / possizeLH) - 1; i++) // незаполненная часть слева
          {
            lcd.print("-");
          }
          // частично заполненная часть
          if (-valueLH / possizeLH + 1 <= (size / 2 - 1)) {
            int dotcolumns = map(-valueLH % possizeLH, 0, possizeLH, 0, 6);
            switch (dotcolumns) // отражаем остаток неучтенной части value на 6 точек знакоместа "левыми кусками квадрата"
            {
              case 0: //пусто, остатка нет (пренебрежимо мал)
                lcd.print("-");
                break;
              case 1:; // 1,2,3,4 колонок точек
              case 2:;
              case 3:;
              case 4:
                lcd.write(dotcolumns);
                break;
              case 5:; //5 колонок точек
              case 6: //5 колонок точек+зазор между позициями знаков на экране
                lcd.write(0xFF);
                break;
            }
          }
          for (int i = (size / 2 - 1) - (-valueLH / possizeLH) + 1; i <= (size / 2 - 1); i++) // заполненная часть
          {
            lcd.write(0xFF);
          }
          lcd.print("><");
          for (int i = 1; i <= (size / 2 - 1); i++) // незаполненная вся часть справа
          {
            lcd.print("-");
          }
        }
        else
        {
          if (leftright != 1)
          {
            lcd.createChar(1, Bar1);
            lcd.createChar(2, Bar2);
            lcd.createChar(3, Bar3);
            lcd.createChar(4, Bar4);
            leftright = 1;
          }
          for (int i = 1; i <= (size / 2 - 1); i++) // незаполненная вся часть слева
          {
            lcd.print("-"); // "-----"
          }
          lcd.print("><");
          for (int i = 1; i <= valueLH / possizeLH; i++) // заполненная часть (от 1 до value/possizeLH)
          {
            lcd.write(0xFF);
          }
          // частично заполненная часть (value/possizeLH+1)
          if (valueLH / possizeLH + 1 <= (size / 2 - 1))
          {
            int dotcolumns = map(valueLH % possizeLH, 0, possizeLH, 0, 6);
            switch (dotcolumns) // отражаем остаток неучтенной части value на 6 точек знакоместа
            {
              case 0: //пусто, остатка нет (пренебрежимо мал)
                lcd.print("-");
                break;
              case 1:; // 1,2,3,4 колонок точек
              case 2:;
              case 3:;
              case 4:
                lcd.write(dotcolumns);
                break;
              case 5:; //5 колонок точек
              case 6:  //5 колонок точек+зазор между позициями знаков на экране
                lcd.write(0xFF);
                break;
            }
          }
          for (int i = valueLH / possizeLH + 2; i <= (size / 2 - 1); i++) // незаполненная часть (от value/possizeLH+2 до size)
          {
            lcd.print("-"); // "------"
          }
        }
        lcd.setCursor(7, 3);
        lcd.write(7);
        lcd.print("x"); // Mute

        lcd.setCursor(5, 0);
        lcd.print("<< HIGH >>");
        lcd.setCursor(0, 1);
        lcd.print("-");
        lcd.setCursor(19, 1);
        lcd.print("+");
        if (high > 0 && high != 0)
        {
          lcd.setCursor(7, 2);
          lcd.print(" ");
          lcd.print("+");
          lcd.print(high);
        }
        if (high < 0 && high != 0)
        {
          lcd.setCursor(7, 2);
          lcd.print(" ");
          lcd.print(high);
        }
        if (high == 0)
        {
          lcd.setCursor(8, 2);
          lcd.print(high);
        }
        lcd.print("dB");
        lcd.print(" ");
      }
     
    Последнее редактирование: 14 апр 2015
  15. Salk

    Salk Гик

    КвазИ
    А да-да. Понял :) 2 - тыла, 2- фронта, центр и сабвуфер. Сорри затупил.
     
  16. geher

    geher Гуру

    В вашем коде есть некоторая логическая неувязка.
    В двух местах для маркирования того, какие блоки ("правые" или "левые") загружены в знакогенератор вы используете переменную volume, которая устанавливается один раз, после чего на данном участке кода программа постоянно считает, что загружены блоки, заполняющиеся в левой части.
    Более того, вы используете две совершенно разные переменные, объявленные в разных областях видимости.
    В другом месте вы используете для того же переменную leftright, которая уже переустанавливается в зависимости от того, какие блоки были загружены. В результате получается взаимное влияние нескольких участков кода, когда символы реально загружаются только при самом первом отображении первых двух ползунков и при каждом переходе плюс-минус у третьего (как бы это сказать по русски).
    Для того, чтобы исправить проблему, достаточно объявить одну общую переменную (пусть это будет, например, leftright, не принципиально), показывающую, какие именно символы загружены в знакогенератор. Причем объявить ее так, чтобы она была видима во всех частях программы, где используются эти символы. Например, глобально или в самом начале функции. Остальные объявления этой переменной убрать. И при загрузке символов использовать только данную глобальную.
    Иначе говоря, применительно к данному конкретному участку кода:
    1. В самом начале программы, вне функций, сразу после директив "#include", объявить переменную
    int leftright=0;
    2. Все вхождения
    static int leftright = 0;
    и
    static int volume = 0;
    убрать, чтобы не плодить новые ненужные сущности.
    3.
    if (volume != 1)
    заменить на
    if (leftright != 1)

    4.
    volume = 1;
    заменить на
    leftright = 1

    В результате теоретически должно произойти объединение сигнализации о том, что загружено в знакогенератор дисплея с исправлением некорректного поведения программы.
     
    Salk нравится это.
  17. geher

    geher Гуру

    А еще правильнее будет вынести это дело в функцию загрузки символов-блоков.
    что-то вроде
    Код (Text):

    // Где-то в начале программы
    // если блоки заполняются слева
    #define BLOCK_DIRECTION_LEFT 0
    // если блоки заполняются справа
    #define BLOCK_DIRECTION_RIGHT 1

    // Где-то потом
    void loadBlocks(int direction)
    {
        static int leftright=0; // переменная-индикатор текущих загруженных блоков, поскольку static, значение между вызовами функции сохраняется
        // 0 - не определено, -1 - правые, в смысле заполняются справа, а используются слева в двустороннем ползуне (при отрицательных значениях), 1 - левые
         if (direction) // надо грузить правые блоки
         {
              if (leftright != -1) // верно, если правые блоки не загружены
             {
                   lcd.createChar(1, BarM1);
                   lcd.createChar(2, BarM2);
                   lcd.createChar(3, BarM3);
                   lcd.createChar(4, BarM4);
                   leftright = -1; // теперь загружены правые блоки
             }
         }
         else // надо грузить левые блоки
         {
              if (leftright != 1) // верно, если левые блоки не загружены
              {
                   lcd.createChar(1, Bar1);
                   lcd.createChar(2, Bar2);
                   lcd.createChar(3, Bar3);
                   lcd.createChar(4, Bar4);
                   leftright = 1; // теперь загружены левые блоки
              }
         }
    }
     
    Надеюсь, не напутал, где право, а где лево. :)

    Теперь везде, где надо использовать блоки Bar1-Bar4, вызывать перед тем
    loadBlocks(BLOCK_DIRECTION_LEFT);
    А везде, где надо использовать блоки BarM1-BarM4, вызывать перед тем
    loadBlocks(BLOCK_DIRECTION_RIGHT);
    Оно само проверит, что было до того загружено, и загрузит то, что просят.
    Естественно, при таком раскладе одновременно (в одной картинке) блоки разных типов на экране присутствовать не могут, только по очереди.
     
    Salk нравится это.
  18. geher

    geher Гуру

    Кстати, можно еще сэкономить генерируемые символы.

    Поскольку генерируемый блок-символ на самом деле в конкретный момент времени нужен только один, то его можно попробовать грузить в знаконегератор непосредственно перед отображением.
    Вообще не проверялось и проверяться не будет. Дисплея нет.
    Следует понимать, что одновременно на экране при этом можно будет использовать только один из восьми наших самопальных символов-блоков
    Код (Text):

    // num - 0-7, номер генерируемого символа в таблице знакогенератора
    // charmap - битовая карта символа
    void writeSpecialChar(int num, byte charmap[])
    {
          static void* currentChar[8]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};  // указатели на картинки текущего символа для каждого генерируемого
          if (currentChar[num]!=(void*)&charmap[0]) // текущий не тот?
         {
               lcd.createChar(num, charmap); // грузим
              currentChar[num]= (void*)&charmap[0]; // сохраняем указатель на картинку нового текущего
         }
         lcd.write(num); // рисуем
    }

    ...
    //Дальше во всех местах, где switch (dotcolumns), естественно, не забывая, какие именно Bar-символы там нужны, BarX или BarMx
    switch (dotcolumns) // отражаем остаток неучтенной части value на 6 точек знакоместа
        {
          case 0: //пусто, остатка нет (пренебрежимо мал)
            lcd.print("-"); // lcd.write(0);
            break;
          case 1:
                writeSpecialChar(1,Bar1);
                break;
          case 2:
                writeSpecialChar(1,Bar2);
                break;
          case 3:
                writeSpecialChar(1,Bar3);
                break;
          case 4:
                writeSpecialChar(1,Bar4);
                break;
          case 5:; //5 колонок точек
          case 6:  //5 колонок точек+зазор между позициями знаков на экране
            lcd.write(0xFF);
            break;
        }
     
     
    Последнее редактирование: 14 апр 2015
    Salk нравится это.
  19. Salk

    Salk Гик

    Круто! Огромное спасибо, все получилось и работает, как нужно.
    Уже начал интеграцию в основной скетч, чуть позже покажу, что получилось :)

    С дополнительными символами, у меня получилось вывести на экран два дополнительных (значки динамиков, смотрящие в разные стороны). Пока на этом остановился :)
     
  20. Salk

    Salk Гик

    Добрый.
    Что можно придумать с этим куском кода:
    PHP:
    switch (st)
        {
          case 0:
            lcd.setCursor(1, 1);
            lcd.print("<< Radio Zvezda >>");
            break;
          case 1:
            lcd.setCursor(1, 1);
            lcd.print("<<    Xit FM    >>");
            break;
          case 2:
            lcd.setCursor(1, 1);
            lcd.print("<< Silver  rain >>");
            break;
          case 3:
            lcd.setCursor(1, 1);
            lcd.print("<<  Deti  FM  >>");
            break;
          case 4:
            lcd.setCursor(1, 1);
            lcd.print("<<    NRJ      >>");
            break;
          case 5:
            lcd.setCursor(1, 1);
            lcd.print("<<  Radio SK  >>");
            break;
          case 6:
            lcd.setCursor(1, 1);
            lcd.print("<<  Maximum    >>");
            break;
          case 7:
            lcd.setCursor(1, 1);
            lcd.print("<<  Echo Msk  >>");
            break;
          case 8:
            lcd.setCursor(1, 1);
            lcd.print("<<  Intervolna  >>");
            break;
          case 9:
            lcd.setCursor(1, 1);
            lcd.print("<<  Radio KP  >>");
            break;
          case 10:
            lcd.setCursor(1, 1);
            lcd.print("<<  Sport FM  >>");
            break;
          case 11:
            lcd.setCursor(1, 1);
            lcd.print("<<  Radio Vera  >>");
            break;
          case 12:
            lcd.setCursor(1, 1);
            lcd.print("<< Nashe  radio >>");
            break;
          case 13:
            lcd.setCursor(1, 1);
            lcd.print("<< FM romantika >>");
            break;
          case 14:
            lcd.setCursor(1, 1);
            lcd.print("<<  Vesti FM  >>");
            break;
          case 15:
            lcd.setCursor(1, 1);
            lcd.print("<<  Love Radio  >>");
            break;
          case 16:
            lcd.setCursor(1, 1);
            lcd.print("<< Dorognoe  FM >>");
            break;
          case 17:
            lcd.setCursor(1, 1);
            lcd.print("<< Business  FM >>");
            break;
          case 18:
            lcd.setCursor(1, 1);
            lcd.print("<<  Retro FM  >>");
            break;
          case 19:
            lcd.setCursor(1, 1);
            lcd.print("<< Radio  Pilot >>");
            break;
          case 20:
            lcd.setCursor(1, 1);
            lcd.print("<< Radio  Mayak >>");
            break;
          case 21:
            lcd.setCursor(1, 1);
            lcd.print("<< Europa  plus >>");
            break;
          case 22:
            lcd.setCursor(1, 1);
            lcd.print("<<  Umor  FM  >>");
            break;
          case 23:
            lcd.setCursor(1, 1);
            lcd.print("<< Radio  Jamfm >>");
            break;
          case 24:
            lcd.setCursor(1, 1);
            lcd.print("<<  Chanson FM  >>");
            break;
          case 25:
            lcd.setCursor(1, 1);
            lcd.print("<<  Radio Si  >>");
            break;
          case 26:
            lcd.setCursor(1, 1);
            lcd.print("<< Radio  Dasha >>");
            break;
          case 27:
            lcd.setCursor(1, 1);
            lcd.print("<< Rock Arsenal >>");
            break;
          case 28:
            lcd.setCursor(1, 1);
            lcd.print("<<  Auto Radio  >>");
            break;
          case 29:
            lcd.setCursor(1, 1);
            lcd.print("<<  Rusradio  >>");
            break;
          case 30:
            lcd.setCursor(1, 1);
            lcd.print("<<  Radiola    >>");
            break;
          case 31:
            lcd.setCursor(1, 1);
            lcd.print("<<  Sputnik FM  >>");
            break;
          case 32:
            lcd.setCursor(1, 1);
            lcd.print("<<  Gorod FM  >>");
            break;
        }
    В проект добавил FM-радио на TEA5767, не нашел, как заставить FM приемник самому писать название станций. Поэтому решил сделать массив из станций, так сказать "фиксированные" и листать их по кругу с пульта, а уже к ним привязать названия. Все хорошо, но вот данная выше конструкция кода жуть, как жрет память у Arduino:
    Без конструкции:
    И с (здесь уже начинаются проблемы со стабильностью всей работы скетча):
    Я так и не понял, что такое:
    На старых версиях Arduino IDE, вроде бы, всегда была одна память.

    Очень жалко отказываться от названий станций :(
     
    Последнее редактирование: 5 июн 2015