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

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

?

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

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

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

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

    acos Официальный гик Администратор

    Про eeprom http://www.atmel.com/ru/ru/Images/A...8PA-168A-168PA-328-328P_datasheet_Summary.pdf
    Там написано Write/Erase Cycles: 10,000 Flash/100,000 EEPROM
    100 000 раз можно стереть-записать. Не смотря на то что число достаточно большое, все-таки не стоит писать в eeprom раз в секунду. Потому что 100 000 секунд это всего 28 часов) А вот сделать запись по нажатию на специальную кнопку пульта - самое то.

    Код (C):

    #define VOLUME_STEP 4; // шаг приращения
    #define LOW_STEP 4;
    #define HIGH_STEP 4;
    #define VOL A3 // пины подключения крутилок
    #define LOW A4
    #define HIGH A5
    // переменные, в которых будут хранится значения с обычных крутилок
    int POT_VOL;  // Мы не определили значение. Сейчас в этой переменной мусор
    int POT_LOW; // Мы не определили значение. Сейчас в этой переменной мусор
    int POT_HIGH; // Мы не определили значение. Сейчас в этой переменной мусор

    byte volume = POT_VOL; // Мы определили значение приравняв к переменной в которой мусор
    byte low = POT_LOW;      // Мы определили значение приравняв к переменной в которой мусор
    byte high = POT_HIGH;   // Мы определили значение приравняв к переменной в которой мусор

    void setup()
    {
      POT_VOL = analogRead(VOL) / 8; // считываем значения крутилок (значения от 0 до 127)
      POT_LOW = analogRead(LOW) / 8;
      POT_HIGH = analogRead(HIGH) / 8;
      digiPotInit(volume, low, high);  // и отправляем на потенциометры случайный мусор:)))
    ...}

    // можно было б сделать так
    void setup()
    {...
      volume = POT_VOL = analogRead(VOL) >> 3; // POT_VOL мог бы быть и byte
    ...}
     
     
  2. Salk

    Salk Гик

    Ну точно же, Вы абсолютно правы :) Т.е. в моем случае, как изначально я сделал, процесс происходил бы так:
    переменную назначили, значение ей не присвоили и тут же отправили на ЦП.
    А если сделать тогда так:
    Код (Text):
    // Зададим шаг приращения
    #define VOLUME_STEP 4;
    #define LOW_STEP 4;
    #define HIGH_STEP 4;
    // пины подключения крутилок
    #define VOL A3
    #define LOW A4
    #define HIGH A5

    // а если мы создадим переменную и сразу же присвоим ей значение с крутилки (0-127). Будет толк?
    int POT_VOL = analogRead(VOL) / 8;
    int POT_LOW = analogRead(LOW) / 8;
    int POT_HIGH = analogRead(HIGH) / 8;

    // Мы определили значение, приравняв к переменной в которой, надеюсь, не мусор
    byte volume = POT_VOL;
    byte low = POT_LOW;
    byte high = POT_HIGH;

    void setup()
    {//...
      digiPotInit(volume, low, high);  // и отправляем на потенциометры, надеюсь, уже не мусор :)))
    //...}
    Или можно было сделать, как Вы предложили:
    Код (Text):
    #define VOLUME_STEP 4; // шаг приращения
    #define LOW_STEP 4;
    #define HIGH_STEP 4;
    #define VOL A3 // пины подключения крутилок
    #define LOW A4
    #define HIGH A5
    // переменные, в которых будут хранится значения с обычных крутилок
    int POT_VOL;  // Мы не определили значение. Сейчас в этой переменной мусор
    int POT_LOW; // Мы не определили значение. Сейчас в этой переменной мусор
    int POT_HIGH; // Мы не определили значение. Сейчас в этой переменной мусор

    byte volume = POT_VOL;// Мы определили значение приравняв к переменной в которой мусор
    byte low = POT_LOW;     // Мы определили значение приравняв к переменной в которой мусор
    byte high = POT_HIGH;// Мы определили значение приравняв к переменной в которой мусор

    // можно было б сделать так
    void setup()
    {...
      volume = POT_VOL = analogRead(VOL) >> 3; // POT_VOL мог бы быть и byte
      low = POT_LOW = analogRead(LOW)   ; //не понял насчет ">>"
      high = POT_HIGH = analogRead(HIGH)   ;
    ...}
    >> - это оператор - "побитовый правый сдвиг".
    Но для чего он применен тут ">>" ?
     
  3. Salk

    Salk Гик

    А вот на Ваш суд, как и обещал предстает плод моих потугов, попытка №1 создать цикл с регулировкой громкостями, обычными потенциометрами :cool:
    Пока, как пример, только Volume:
    Код (Text):

    // Где-то вверху Void loop. Сюда записываются значения, которые постоянно будут обновляться
      int realVol = analogRead(VOL) / 8;
      int realLow = analogRead(LOW) / 8;
      int realHigh = analogRead(HIGH) / 8;

    // Управление громкостями
      // Если текущее значение равно начальному (мы не крутим ручку потенциометра), то можем менять громкость с пульта:
      if (realVol = POT_VOL)
        {
          if (results.value == 444) //Код кнопки (пусть это громкость плюс)
          {
            volume = volume + VOLUME_STEP;
            setVolume(volume);
          }
          if (results.value == 555) //Код 2 кнопки (пусть это громкость минус)
          {
            volume = volume - VOLUME_STEP;
            setVolume(volume);
          }
          irrecv.resume(); // Получаем следующее значение
        }
      // Если текущее значение крутилки изменилось (мы крутанули ручку), то это значение отправляем в ЦП
      if (realVol != POT_VOL)
    {
      byte volume = realVol;
      digiPotInit(volume, low, high);
      realVol = POT_VOL; // приравниваем текущее значение к POT_VOL, для того чтобы цикл мог снова повториться.
    }
    Не стал использовать оператор "else".
    Похоже на истину или ложь ? :D
     

    Вложения:

    Последнее редактирование: 2 ноя 2014
  4. acos

    acos Официальный гик Администратор

    про сдвиг: Например есть у нас двоичное число
    0b00001000 = 8
    сдвигаем вправо
    0b00000100 = 4
    еще раз
    0b00000010 = 2
    еще раз
    0b00000001 = 1
    Деление - дорогая операция для микроконтроллера. Выполняется за кучу тактов. А сдвиг - нет, выполняется за один такт. При этом сдвиг на одну позицию для целых чисел дает тот же результат что и целочисленное деление на 2. Если сдвинуть вправо 3 раза, то получим целочисленное деление на 8. Хотя в этом конкретном случае так хитристь и не стоит. Скорее всего компилятор увидит, что вы делаете целочисленное деление на степень двойки, сам все поймет и заменит в бинарнике деление на сдвиги.

    Далее.
    Соврал насчёт мусора при инициализации глобальных переменных. Глобальные переменные всегда инициализируются константой. Если программист эту константу не указал, то переменная инициализируется нулём. Мусор появляется в неинициализированных локальных переменных.

    Нельзя инициализировать глобальную переменную результатом выполнения функции (а analogRead() - это функция), только константой.


    код мне, честно признаюсь, не нравится. В нём всё смешалось - кони, люди) При такой организайии кода, очень скоро вы будете постоянно думать: "блин, где я"?
    На примере. Вы просите контроллер пожарить яичницу. При вашей организации кода вы ему говорите:

    Открой холодильник
    проверь - есть ли яйца?
    Если яиц нет
    возьми деньги
    оденься
    выйди на улицу
    дойди до магазина
    ... // тут много про то как открыть дверь магазина и найти яйца
    возьми яйца
    ...//тут много про то как дойти до кассы и расплатиться
    отдай деньги
    забери чек
    ... /// тут много про то как вернуться домой
    возьми яйца
    поставь сковородку на плиту
    // тут много про то как жарить яйца

    А вот как мог бы выглядеть код:
    Если яицНет();
    {
    купиЯйца();
    }
    ПожарьЯйца();


    Такой подход не всегда применим, но часто выручает. Я воспользовался именно им, когда делал работу с цифровыми потенциометрами. Представьте, что вся работа с потенциометрами была бы написана у вас точно там же - в loop()
    А теперь вспомните, что у вас еще будет работа с LCD и термометром и часами и тд и тп)
    А так вы можете просто сказать - выставьГромкость()

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

    Вернемся к коду. Если мы крутим ручку потенциометра - почему мы должны перестать реагировать на ик-сигналы?

    Код (C):
      // Если текущее значение равно начальному (мы не крутим ручку потенциометра),
    //то можем менять громкость с пульта:
      if (realVol = POT_VOL)
        // А если не равно, то не можем?
    //То есть, мы крутанули ручку, значение изменилось,
    //и все? Пульт перестал работать до перезагрузки?
    ///.......

    // Если текущее значение крутилки изменилось (мы крутанули ручку), то это значение отправляем в ЦП
      if (realVol != POT_VOL)
    {
      byte volume = realVol;
      digiPotInit(volume, low, high); // у нас же есть функция setVolume() для этого) Хотя можно и так
      realVol = POT_VOL; // приравниваем текущее значение к POT_VOL, для того чтобы цикл мог снова повториться.

    // Наверное тут должно быть POT_VOL = realVol; Иначе, после кручения ручки ИК-пульт перестанет работать
    }
     
    Желаю вам скорейшего изготовления всего железа, чтобы вы могли отлаживать код непосредственно на устройстве - так гораздо интереснее)
     
    Salk нравится это.
  5. Salk

    Salk Гик

    Спасибо, огромное !!! :) Пример с яичницей уяснил, но мне пока проще каждое действие описывать, чтобы понимать, что происходит и быть уверенным, что это выполниться :) А чтобы не запутаться помогут комментарии :)
    Т.е. первый вариант был больше похож на правду. Странно, что компилятор не выдал ошибку или предупреждение, что нельзя к глобальной переменной присваивать выполнение функции.
    Тогда код должен быть таким:
    Код (Text):
    #define VOLUME_STEP 4; // шаг приращения
    #define LOW_STEP 4;
    #define HIGH_STEP 4;
    // пины подключения крутилок
    #define VOL A3
    #define LOW A4
    #define HIGH A5
    // переменные, в которых будут хранится значения с обычных крутилок
    // если к глобальным переменным не присваивается значение, то оно автоматически = "0"
    int POT_VOL = 0; // можно и так записать
    int POT_LOW = 0;
    int POT_HIGH = 0;

    //зачем то сначала bool решил применить

    byte volume = POT_VOL;
    byte low = POT_LOW;
    byte high = POT_HIGH;

    void setup()
    {
    // в setup мы один раз должны считать значения с потенциометра
    // и присвоить значения глобальным переменным
    // чтобы после их передать на ЦП. Такая механика?
      POT_VOL = analogRead(VOL) / 8; // считываем значения крутилок (значения от 0 до 127)
      POT_LOW = analogRead(LOW) / 8;
      POT_HIGH = analogRead(HIGH) / 8;
      digiPotInit(volume, low, high);  // и отправляем на потенциометры
      pinMode(VOL, INPUT);
      pinMode(LOW, INPUT);
      pinMode(HIGH, INPUT);

    void loop()
    {
      // сюда записываются значения, которые постоянно будут обновляться
      int realVol = analogRead(VOL) / 8;
      int realLow = analogRead(LOW) / 8;
      int realHigh = analogRead(HIGH) / 8;

    if (realVol = POT_VOL)
      {
          if (results.value == 444) //Код кнопки (пусть это громкость плюс)
          {
            {
              volume = volume + VOLUME_STEP;
              setVolume(volume);
            }
            if (results.value == 555) //Код 2 кнопки (пусть это громкость минус)
            {
              volume = volume - VOLUME_STEP;
              setVolume(volume);
            }
          }
    // решил реализовать через оператор else.
    // Иначе (если крутим ручку, значение изменилось), то значение крутилки отправляем на ЦП
          else
          {
            volume = realVol;  // можно и так ?
            setVolume(volume);
            POT_VOL = realVol; // точно, мы должны "старое" значение приравнять к текущему, чтобы дальше его же и сравнивать, а не наоборот. Спасибо :)
          }
        irrecv.resume(); // Получаем следующее значение
      }
    ...}
    Да, только не до перезагрузки, а до того момента, пока текущее значение с потенциометра не сравняется со "старым", т.е. тогда когда мы перестанем крутить ручку (в данном коде я использовал оператор else, который "говорит" нам, если значение не равно POT_VOL ("старому значению"), то мы текущее считанное значение отправляем в ЦП. Когда мы оставим ручку в покое :) , то значения сравняются, цикл обновится и мы снова сможем менять громкости с пульта. Нам же и не зачем, да и не удобно, одновременно крутить и ручки и нажимать на кнопки пульта. Или я чего-то недопонимаю.
    Насчет сдвига понял, возьму на заметку, а как сделать так, чтобы компилятор не пронюхал, что мы делим числа? :)
    Спасибо, я постараюсь на днях, за праздники успеть. Кстати с праздником, с Днем народного единства, так вроде :)
    Всю плату ТБ целиком пока переделывать не буду, а ЦП размещу пока просто на отдельном небольшом кусочке текстолита (как с AD8402) и подключу к уже имеющемся ТБ. И будем мучить ЦП :D

    Не хочу показаться занудой, но для успокоения души :) Насчет "RS" и "SHDN", на них подать +5 В (можно от +15 В питания через гасящий резистор) и забыть про них на всегда, так? :rolleyes:
     
    Последнее редактирование: 3 ноя 2014
  6. acos

    acos Официальный гик Администратор

    Очень похоже на то.
    По коду - давайте уже отлаживать на железе)
     
  7. Salk

    Salk Гик

    Доброго времени суток. Простите за задержку. Эх... Целый день сегодня потратил на опыты :) Вот только недавно закончил. Вердикт - пока неудача. Отчет:
    Не ведомо почему, но скетч на ардуино стал загружаться раз через раз, а то и через два/три, выдавая такие вот ругательства:
    42.jpg da.jpg dasdasd.jpg Безымянныsaasй.jpg hdhs.jpg

    Я сделал отдельную плату под ЦП, т.к. на макетку их не установить, SOIC корпус. Все SS (CS) и CLK (SCK) соединил вместе, SDI первого потенциометра к arduino (вот 3 пина, идущих на arduino), далее SDO этого же первого ЦП на SDI второго, SDO второго на SDI третьего и т.д. Питание ±15 В (от ТБ), RS/SHDN посадил на + 5 В, через подстроечный резистор от + 15 В питания ЦП. Да, плата конечно, не эталон получилась, куча перемычек (29 шт., мой рекорд :D), распиновка сложная, и хотелось уже поскорее проверить, перед тем, как уже делать на чистовую. Ножки ЦП несколько раз прозванивал, пропаивал, "непропаев" недолжно быть, хотя завтра ещё раз все перепроверю.
    В общем, ЦП напрочь отказываются что-либо регулировать :) , но звук через них проходит и играет музыка, даже без искажений. Я хоть и запаял все 6 ЦП, но задействовал только 4, т.е. только громкость и ВЧ. Оставшиеся пара была подключена так же, как и все (CS, CLK, SDI), но на сами потенциометры (к A, B, W) ничего не подавалось. А то ещё прибавилось бы +10 перемычек :D

    Хотя когда я загружал скетч, который был рассчитан на применение обычных потенциометров (где в loop был analogRead() ), то ЦП не "играли", а постоянно щелкали (имеется ввиду, из динамиков шли щелкания), и крутя ручку потенциометра, эти щелкания становились, то чаще, то реже (музыки не было). И как я не пытался, в данном скетче снять показания с обычного потенциометра не выходило. Значения просто не снимались, их нельзя было увидеть ни в сериал мониторе, ни на LCD дисплее, в лучшем случае в монитор "падал" - "y".

    Упростил задачу, убрал обычные крутилки, присвоил стартовые значения и они, по идее, должны отправляться на ЦП. Когда убрал крутилки из loop, щелкания прекратились и появилась музыка. Громкость была всегда на каком-то фиксированном уровне (видимо это начальное состояние ЦП), и этот уровень нельзя было изменить ни пультом, ни изменением стартовых значений, т.е. никак не зависела от стартовых значений.
    В скетче нашел и исправил несколько мелких ошибок, касательно приема и декодирования ИК сигналов. В итоге сам механизм заработал, т.е. я нажимаю кнопку пульта, к примеру, громкость "+" и формула volume + VOLUME_STEP работает, на экране и в мониторе я вижу изменение громкостей, но ЦП так равнодушно и скептически, на это все смотрят :) . А самое интересное, что диапазон изменения громкостей от 0 - 250, а должно же быть 0-127 ?. Тут несколько фотографий с места пыток ЦП и скетч без крутилок, слегка измененный.
    MOSI, CSK, CS к Arduino подключены, вроде бы верно, я переназначил их на 10, 11, 12 пины, а 4, 5, 6 заняты LCD.
    Это старый скрин, когда ещё не исправил ошибки в декодировании ИК. Забыл сделать, новый. Но они меняются :) и это видно и в мониторе и на LCD, меняются с шагом, который я указал, но диапазон от 0 - 250, после 250 снова 0. Но ЦП не вносят в звук никаких изменений.
    dsaad.jpg
    [​IMG]
    [​IMG]
    [​IMG]
    Много вопросов, в первую очередь, конечно, это про ошибки, с чем может быть это связано? При компилировании никаких ошибок никогда не возникает. Когда заливал скетч на проверку кнопок пульта или отдельный скетч на управлением кулером, ошибок не наблюдал. Даже не знаю, завтра проверю пайку и попробую ещё поиграться :) Скорее всего составлю отдельный скетч только для ЦП, без дисплея, термодатчика и т.д.
    Спасибо, что проявляете интерес к моей работе, даже не знаю что бы без Вас делал! :)

    А можно сделать простенькую задачку, для того чтобы проверить ЦП на работоспособность? У шестого ЦП остался SDO свободный, может его подключить к arduino, и прогнать биты по кругу - от arduino по ЦП и обратно на arduino, а в serial попробовать увидеть вернулись ли наши биты ? Так сказать произвести диагностику :)

    Маленькая ремарка - оказывается, обычные потенциометры не имели прямой контакт с arduino, вот почему я не смог считать данные с них. Хотя странно, потенциометры вставлял в макетную плату (BreadBoard) и как мне казалось они хороша там себя чувствовали. Сейчас повторил пример "изменение яркости светодиода с помощью обычного потенциометра" и пришлось провода непосредственно к потенциометру цеплять.
     

    Вложения:

    • alLsktch.zip
      Размер файла:
      2 КБ
      Просмотров:
      105
    Последнее редактирование: 5 ноя 2014
  8. acos

    acos Официальный гик Администратор

    От чего запитана ардуина? Связаны ли GND ардуины и ЦП?

    нашел ошибку в digiPot.h
    Было:

    Код (C):

    void sendPotData(byte data)
    {
      digitalWrite(D_POT_SCK, LOW);

      for (int i = 0; i < D_POT_BITS; ++i)
        digitalWrite(D_POT_MOSI, bitRead(data, i));

      digitalWrite(D_POT_SCK, HIGH);
    }
    должно быть так

    Код (C):

    void sendPotData(byte data)
    {

      for (int i = 0; i < D_POT_BITS; ++i) {
        digitalWrite(D_POT_SCK, LOW);

        digitalWrite(D_POT_MOSI, bitRead(data, i));

        digitalWrite(D_POT_SCK, HIGH);  
      }

    }
     
    Пофиксил вроде. Можете заново скопировать всё отсюда https://github.com/acosinwork/analogAmp/archive/master.zip

    Чтобы проверить работоспособность, отключите все кроме потенциометров, и запилите простой скетч в котором просто по кругу раз в 100 милисекунд на потенциометры подается все возрастающее значение - от 0 до 127 и больше ничего не делается.
     
  9. Salk

    Salk Гик

    Пока без положительных результатов.:(
    Arduino запитана через USB от PC. ЦП от ТБ (±15 В и Gnd).
    По началу arduino никак не была связана с ТБ/ЦП, т.е. не было общей земли, только 3 пина (SDI, SS, CLK) шли от ардуино к ЦП. Соединил все общей землей, ничего не изменилось.

    Или нужно было GND ЦП только на ардуино кидать? :eek: В шите на 8 стр. GND обзывается, как "Digital Ground".
    Нужно было ±15 В на ЦП, а GND c CS, SDI, CLK на Arduino?
    А звук, получается, подводить к A, снимать с W, а B на землю ТБ, ну как обычный потенциометр.
    Попробую переделать, если ещё живые ЦП.

    Изменения внес в вашей библиотеке digiPot.h. У Вас ещё появилась новая "volume.h", когда её include, вылезает ошибка:
    Код (Text):
    In file included from analogAmp.ino:6:
    volume.h:14: error: ISO C++ forbids declaration of 'setPotent' with no type
    volume.h:16: error: expected ';' before 'private'
    Я так понимаю, что библиотека SPI.h не нужна больше, т.к. весь процесс работы с ЦП вы написали с нуля? :)

    Цикл только завелся, шаг приращения работает.
    Ну хоть ошибок больше не возникало, как вчера при загрузке скетча, и то радует.
     

    Вложения:

    Последнее редактирование: 6 ноя 2014
  10. acos

    acos Официальный гик Администратор

    spi.h не нужна в данном случае

    насчет volume.h - там была недоделанная версия. Я сейчас обнаружил, что на другом компе уже написал её реализацию и забабашил пример использования в ino-файле. Можешь скачать заново по той же ссылке, ну или глянь все файлы тут https://github.com/acosinwork/analogAmp
    На счет железа - пока лень разбираться. Я бы попробовал подключить для начала цп только к ардуине и все, все плюсы - к 5 вольтам ардуино. и мультиметром проверить - меняется ли сопротивление, если сделать изменение сопротивления в скетче? Ну можешь даже попробовать присоединить потенциометры и залить последний сакетч с гитхаба для теста
     
    Последнее редактирование: 6 ноя 2014
    Salk нравится это.
  11. acos

    acos Официальный гик Администратор

    тоесть отключить от ардуины все, и включить только потенциометры. Отладка обычно так и идет - заставляем работать периферию по одному устройству за раз - если работает, то ок - ищем что ещё не так.
     
    Salk нравится это.
  12. Salk

    Salk Гик

    Да уж, со мной кашу быстро не сваришь ...
    Эксперименты продолжаются. Мне кажется я нащупал больное место :)
    Это второй ЦП (нумеруется, как "1"), отвечающий за правый канал громкости.
    Код (Text):
    #define VOLUME_LEFT  0
    #define VOLUME_RIGHT  1

    #define LOW_LEFT      2
    #define LOW_RIGHT    3

    #define HIGH_LEFT    4
    #define HIGH_RIGHT    5
    Земли все соединил воедино, т.е. GND БП и ТБ с GND arduino и ЦП. Все вместе.
    Опробовал Ваш последний скетч с крутилкми, подсоединил потенциометры и о чудо, самый первый ЦП (нумеруется, как "0" - левый канал громкости) стал изменять своё сопротивление, в зависимости от "крутилки" (от ~0.1 до 50 кОм).
    Круто. Печально то, что больше никакие ЦП не реагирует, сопротивление их всегда максимальное (50 кОм, между A и W). А ещё более странно, то что изменять своё сопротивление первый ЦП, заставляет "крутилка", отвечающая за High (ВЧ), а не за Volume. Т.е. заработал только самый первый ЦП, SDI, которого подключен к arduino.

    Я подозреваю, что что-то не в порядке со вторым ЦП, он не передает дальше цепочку битов (от SDO к SDI). Я правильно понимаю, что сначала цепочка битов начинается с High (ВЧ) и дальше "распределяется" по всем ЦП, языком дилетанта. А тут дальше первого ЦП ничего не передаётся. Пайку на 100 раз перепроверил. От SDO к SDI каждого ЦП, особенно проверял от первого ко второму. RS, SHDN на +5 В.
    Я думаю переделать, сделать нормальную плату, уменьшить в разы кол-во перемычек. И этот второй ЦП заменить хотя бы на, предполагаемо рабочий, шестой ЦП, т.е. поменять местами. Если второй ЦП заработает, то цепочка битов "пройдет" дальше, и я уже увижу это, смогу управлять, как минимум вторым ЦП. Мысля правильная ? :)

    В Вашем скетче добавилась новая библиотека "volume.h". Которая служит для работы только с обычными потенциометрами. Сложный код. Впервые знакомлюсь с "классами" - полное описание работы устройства его поведение, свойства.
    Эх, мне бы сейчас с "железом" разобраться :rolleyes: После уже скетч. Надеюсь что-то изменится, когда поменяю местами ЦП.
     

    Вложения:

    Последнее редактирование: 7 ноя 2014
  13. acos

    acos Официальный гик Администратор

    да уж, тут бы пригодился логический анализатор.

    Скорее всего в том что когда вы крутите high и меняется volume ошибки нет, просто из-за особенностей spi это поведение не очевидно сразу) То есть данные, которые передаются первыми оказываются в самом последнем потенциометре - и это нормально) Проведите мысленный эксперимент с мясорубкой и сами поймёте почему так происходит. Видимо вы считали, что раз мы передаем громкость первой, то и окажутся эти значения в самом первом потенциометре. Это не так.
    С железом мне пришла в голову такая мысль - а если передать во все потенциометры нули, они все равно будут показывать 50 кОм? А если только единицы слать? Блин, надо мне посерьезней этот даташит прочитать. Пока не могу этого сделать.

    Проверить второй потенциометр можно без выпайки. Перережте дорожку между первым и вторым потенциометром (sdo -sdi) и подайте сигнал с ардуины сразу на второй потенциометр - будет работать? Но сделайте это только после проверки на нули, о которой я выше писал. Если заработает - значит я не врубился в даташит.
     
    Salk нравится это.
  14. Salk

    Salk Гик

    Хм... К счастью или нет, пока не знаю, но "железо" рабочее :)
    Верно, я думал именно так :) просто, видимо, не правильно выразился.
    Когда Вы написали сообщение, я уже выпаял ЦП :) И приступил к "разработке" новой платы.
    Сделал. ЦП взял, теперь, на пробу пятый и шестой. Результат тот же, что и был раньше.
    Т.е. работает только первый ЦП, SDI которого подключен к arduino. Поставил опыт, который Вы мне посоветовали: разорвал связь SDO-SDI между ЦП и SDI второго подключил к arduino. Он заработал. Пока распаял только два ЦП.
    1.jpg 2.jpg
    К сожалению, не понял, насчет "нулей и единиц", что нужно сделать? Восстановить перемычку (sdo-sdi) не проблема.
    Хм, в даташите на 14 стр. (рис.28) между SDO-SDI потенциометров, ещё стоит подтягивающий резистор к +5 В.
    Безымявыфывнный.jpg
    Мне говорили, что это цепочка должна уже стоять внутри ЦП, как я понял, но все же..
    Чуть выше рисунка написано:
    Если попытаться перевести:
    Может добавить резистор?
    Шит - AD7376
     

    Вложения:

    Последнее редактирование: 8 ноя 2014
  15. acos

    acos Официальный гик Администратор

    Блин. вот я слепой) Вы молодец - сами во всем разобрались. Да, все правильно, нужен резистор к 5 вольтам. Там SDO это просто транзистор, который умеет притягивать к земле и больше ничего. Поэтому ему нужно что-то, что можно притягивать. Емкость на той картинке - это паразитная ёмкость входа. Она заряжается и разряжается за какое - то время. Резистор может быть не только 2.2 кОм, можно и больше, если тех под рукой нет. Но чем больше тот резистор, тем дольше будет переключение уровней. В принципе это не страшно - если потенциометры не будут успевать переключиться, то можно будет просто поставить задержку между переключениями SCK небольшую - одной миллисекунды за глаза хватит. Но раньше времени этого не стоит делать - только если переключиться не будет успевать.
     
    Salk нравится это.
  16. Salk

    Salk Гик

    Да, верно! Заработал второй ЦП. Спасибо, acos !!!
    Добавил резистор 2.2 кОм к SDO-SDI и на +5 В. Сопротивление изменятся в зависимости от "крутилки" (отвечающая за ВЧ), но как то не так плавно, как хотелось бы, но об этом ниже. Скетч Ваш последний. Распаял пока, четыре ЦП, все работает, теперь я могу менять ВЧ и НЧ. Сопротивления правого и левого каналов ВЧ и НЧ меняются синхронно, тут все гуд :)

    Сопротивление ЦП меняется как то странно, я реализовал в скетче приращение шага с помощью пульта, шаг приращения я сделал "1" для наглядности. Оно изменяется большими скачками, если к 0 прибавить 1, то сопротивление резко возрастет с 0 Ом до 25 кОм, следующий шаг до ~40 кОм, последующие шаги будут сумбурно изменять сопротивление, строгой закономерности я найти не смог, шаг может быть и 10 и 20 и 40 кОм. А должно же быть 390 Ом, т.к. 50000 Ом / 128 позиций.
    Тут несколько фото, где попытался отобразить, как изменяется реальное сопротивление ЦП от тех показаний, которые мы шлем им:
    Low - 0; 50k.jpg Low - 1; 25k.jpg Low 2 - 37k.jpg Low - 3; 12.6k.jpg Low - 4; 44k.jpg Low - 5; 18k.jpg
    Очень странно, не могу понять где ошибка и в чем она заключается. Я что-то не правильно делаю в основном скетче? Сопротивления верны только в крайних положениях: 0 Ом и 50 кОм, т.е. если мы пошлем 0 и 127, все что между этими цифрами - какой-то корейский рандом :)

    Буду с нетерпением ждать ответа, спасибо ;)
    [​IMG]
    [​IMG]
     
    Последнее редактирование: 30 ноя 2014
  17. Salk

    Salk Гик

    Распаял до конца все цифровые потенциометры, все 6 шт. Подсоединил подтягивающие резисторы 2.2 кОм к SDO-SDI, железо работает. "Громкость/НЧ/ВЧ" распределяются, как нужно и реагируют на данные, которые мы им посылаем. Но нужной стабильности/правильных показаний я так и не смог добиться. По прежнему, что громкость, что НЧ или ВЧ изменяют свои сопротивления рандомно, в пределах 0-50 кОм, т.к. сами ЦП на 50 кОм. Они буд-то не правильно "понимают", то что мы им посылаем или я не правильно посылаю им эти данные..
    Поигрался с кол-вом битов и ЦП, ничего не дало.., да и не должно наверное было ..
    Код (Text):
    #define D_POT_BITS    7
    // Количество цифровых потенциометров
    #define D_POT_COUNT  6
    В общем где копать, что делать? :(
    Прилагаю скетч, в нем реализовано управление с пульта, с шагом приращения 1.
    Стартовые значения ЦП устанавливаются от показаний "крутилок", а уже к ним прибавляются шаги. Я также, просто, напрямую отсылал значения byte 1-127 без цикла, точно так же, рандомное изменение сопротивления.
    1 шаг всегда почему-то изменяет сопротивление ЦП на 25 кОм, последующие, как угодно..
    [​IMG]
     

    Вложения:

    Последнее редактирование: 30 ноя 2014
  18. acos

    acos Официальный гик Администратор

    Пишет "сжатая zip папка пуста".
    Я что-то не понял - скачки на всех цп, или на конкретных?
    Можно попробовать поиграться с временем задержки между переключениями уровней SDO.
     
  19. Salk

    Salk Гик

    Скачки на всех ЦП: громкость/нч/вч, левый и правый каналы.
    А куда лучше задержку поставить?

    Основной скетч:
    Код (Text):
    // by acos
    // http://amperka.ru

    // Здесь назначаем пины
    #include "pinMap.h"
    //Здесь работаем с цифровыми потенциометрами
    #include "digiPot.h"
    // работа с ИК
    #include <IRremote.h>
    //Здесь работаем с громкостью
    #include "volume.h"

    #define VOLUME_STEP 1;
    #define LOW_STEP 1;
    #define HIGH_STEP 1;

    //IR_PIN
    IRrecv irrecv(IR_PIN);
    decode_results results;

    uint32_t val; // пакет ИК

    byte vol;
    byte low;
    byte high;

    void setup()
    {
      Serial.begin(9600);
      pinMode(IR_PIN, INPUT);
      irrecv.enableIRIn(); // Включаем ресивер
      regulatorsInit();
      vol = rVol.value(); // присвоили показания с "крутилок"
      low = rLow.value();
      high = rHigh.value();
      digiPotInit(vol, low, high); // и отправили их на ЦП, как стартовые
    }

    void loop()
    {
      Serial.print("Key code - ");
      Serial.println(results.value);
      Serial.print("Vol - ");
      Serial.print(vol);
      Serial.print("      ");
      Serial.print("Low - ");
      Serial.print(low);
      Serial.print("      ");
      Serial.print("High - ");
      Serial.print(high);

      if (irrecv.decode(&results))
      {
        // реализация длительного нажатия кнопки пульта
        if (results.value != 4294967295)
        {
          val = results.value; // сохраняем правельный пакет в переменную
        }
        // громкости
        if (val == 587783) //Код кнопки (пусть это громкость плюс)
        {
          // ограничили значение до 127, некое подобии фиксатора, чтобы не перескакивать с 0 на 127 и наоборот
          if (vol < 127)
            vol = vol + VOLUME_STEP;
          setVolume(vol);
        }
        if (val == 525053) //Код 2 кнопки (пусть это громкость минус)
        {
          if (vol > 0)
            vol = vol - VOLUME_STEP;
          setVolume(vol);
        }

        if (val == 534743) // Код кнопки, пусть будет плюс НЧ
        {
          if (low < 127)
            low = low + LOW_STEP;
          setLow(low);
        }
        if (val == 542903) // Код кнопки, пусть будет минус НЧ
        {
          if (low > 0)
            low = low - LOW_STEP;
          setLow(low);
        }

        if (val == 526583) // Код кнопки, пусть будет плюс ВЧ
        {
          if (high < 127)
            high = high + HIGH_STEP;
          setHigh(high);
        }
        if (val == 585743) // Код кнопки, пусть будет минус ВЧ
        {
          if (high > 0)
            high = high - HIGH_STEP;
          setHigh(high);
        }
        irrecv.resume(); // Получаем следующее значение
      }
    }
     

    Вложения:

    • analogAmpF.zip
      Размер файла:
      2,9 КБ
      Просмотров:
      92
  20. ANV

    ANV Гуру

    MSb/LSb не попутали, раз "1" дает сразу половинку?
     
    Salk и acos нравится это.