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

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

?

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

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

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

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

    Salk Гик

    ...:p Неужели я близок к логическому завершению.
    Начну по порядку, действительно ANV, Вы были правы, не той стороной посылали биты ;)
    Я исправил в скетче одну строчку и уже стало на что-то похоже:
    Код (Text):
    // Здесь хранятся все настройки громкостей
    byte dPotValues[D_POT_COUNT];

    // Шлём данные одного потенциометра
    void sendPotData(byte data)
    {
      for (int i = D_POT_BITS; i > 0; --i)
      {
        digitalWrite(D_POT_SCK, LOW);

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

        digitalWrite(D_POT_SCK, HIGH);
      }
    }
    А именно:
    Теперь шаг стал равен 390-400 Ом. ~140 Ом минимальный уровень, т.е. ниже не опустить, но в даташите об этом сказано, что-то для защиты самих ЦП. Все хорошо, но вылезла ещё одна проблемка, надеюсь последняя :rolleyes::
    Теперь почему-то общее сопротивление ЦП уменьшилось на половину, было 50 кОм, стало 25 кОм. И в пределах этих 25 кОм сейчас меняется сопротивление с шагом 390 Ом.

    //На следующий день.
    Аллилуйя! УРАааа, даже не верится:eek: В общем, добил, все супер, я смог сделать диапазон 50 кОм :p
    Не мытьем, так катаньем. По идее, мы должны отсылать значения от 0 до 127 и в этот диапазон должен умещаться все 50 кОм потенциометров. Но дело в том, что я искусственно ограничил в основном скетче границу до 127, чтобы сопротивления не "гуляли" по кругу, от максимума к минимуму и наоборот, поэтому вчера у меня было максимум 25 кОм. Сейчас я расширил диапазон до 255, и ... Аллилуйя! ... Все встало на свои места: шаг - ~400 Ом, сопротивления меняются на всех ЦП (громкость/НЧ/ВЧ) в диапазоне 0-50 кОм (0-255). Возможно это не совсем верное решение, если честно до сих пор не до конца понимаю такое поведение ЦП. Т.к.правильнее было бы вогнать потенциометры в 0-127...
    Спасибо, acos !!! Эпопея с цифровыми потенциометрами, надеюсь, подошла к концу :) И 100% заслуга Ваша. Сейчас осталось дело за малым, собрать все воедино, ТБ с цифровыми потенциометрами на борту и все свои задумки воплотить в жизнь. Обязательно опубликую готовое устройство в теме, как и обещал. Спасибо !!! ;)
     

    Вложения:

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

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

    :oops: Вот блин) Спасибо @ANV !
    зы, странно, почему-то пропустил оповещения с этой темы
     
  3. Salk

    Salk Гик

    Доброе время суток. Позвольте ещё вопрос :). Как можно ужесточить границы диапазона 0-255, так что бы значения не выходили за его рамки, т.е. чтобы нельзя было сделать меньше 0 и больше 255.
    К примеру: если сделать один шаг равным 15, то будет 17 градаций - от 0 до 255, все хорошо, если идти от 0.
    Код (Text):
    if (vol < 255)
            vol = vol + VOLUME_STEP; // +шаг
          setVolume(vol);

          if (vol > 0)
            vol = vol - VOLUME_STEP; // -шаг
          setVolume(vol);
    Но, дело в том что ещё есть обычные переменные резисторы, с которых считываются значения, они так же будут изменять сопротивление ЦП, эти значения могут быть любыми (0-255), четными и нечетными.
    К примеру, если считается значение 243, а после я решу прибавить к этому значению шаг (15) с пульта ИК, то получится, что условие:
    Код (Text):
    if (vol < 255)
    будет верным, тогда шаг прибавится, и получится, что общее значение станет 258, т.е. 255+3, и эта "3" будет остатком и сбросит настройку в самое начало на этот же остаток. Точно так же, если из 10 вычесть шаг (15), то станет враз 250 (остаток 5). Т.к.:
    Код (Text):
    if (vol > 0)
    Так и оглохнуть можно будет, если делать громкость тише, а после, нечаянно.. сделать громко, очень громко.. :D
    Как возможно "ужесточить" условие, чтобы избавится от "остатков" ? Спасибо. :)
     
    Последнее редактирование: 12 дек 2014
  4. acos

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

    Salk нравится это.
  5. Salk

    Salk Гик

    Огромное спасибо, не знал что есть "готовая" функция, думал придется что-то выдумывать, самому изобретать :)
     
  6. Salk

    Salk Гик

    Простите, у меня почему-то не получается верно применить constrain. Что-то видимо делаю не так. Пробовал по разному:
    Код (Text):
    if (val == 534743) // Код кнопки, пусть будет плюс НЧ
        {
          low = low + LOW_STEP;
          setLow(low = constrain(low, 0, 255));
        }
        if (val == 542903) // Код кнопки, пусть будет минус НЧ
        {
          low = low - LOW_STEP;
          setLow(low = constrain(low, 0, 255));
        }
    И
    Код (Text):
    if (val == 534743) // Код кнопки, пусть будет плюс НЧ
        {
          low = low + LOW_STEP;
          setLow(low = constrain(low, 0, 255));
          low = constrain(low, 0, 255);
        }
        if (val == 542903) // Код кнопки, пусть будет минус НЧ
        {
          low = low - LOW_STEP;
          setLow(low);
          low = constrain(low, 0, 255);
        }
    И просто, либо в loop, либо в setup
    Код (Text):
    low = constrain(low, 0, 255);
    vol = constrain(vol, 0, 255);
    high = constrain(high, 0, 255);
    Не ограничивает...
     
  7. rav_75

    rav_75 Гик

    Все дело в воздушных пузырьках... :) А именно вот здесь low = low + LOW_STEP. Вы уже присвоили переменной low новое значение, а так как тип переменной byte, то она уже приняла значение от 0 до 255. Т.е. если low = 250 и LOW_STEP = 10, то low = low + LOW_STEP даст нам low ==4. Дальнейшее использование constrain(low, 0, 255) ничего не изменит, так как low в заданном диапазоне. Попробуйте так:
    low = constrain(low + LOW_STEP, 0, 255);
    Аналогично в обратную сторону.
     
    Последнее редактирование: 12 дек 2014
    acos и Salk нравится это.
  8. Salk

    Salk Гик

    Спасибо, но именно так, компилятор выдает ошибку, что-то ему не нравится, скорее всего функция constrain должна иметь только три аргумента (переменная и диапазон "min, max"), прибавлять внутри скобок не получится. Даже если "low + LOW_STEP" выделить отдельными скобками.
    Но по моему я уловил суть и постарался исправить, код получился такой:
    Код (Text):

        if (val == 534743) // Код кнопки, пусть будет плюс НЧ
        {
          // вгоняем low в диапазон 0-255, прибавляем шаг и присваиваем это снова low
          low = constrain(low, 0, 255) + LOW_STEP;
          setLow(low); // а тут уже отправляем на ЦП
        }
        if (val == 542903) // Код кнопки, пусть будет минус НЧ
        {
          low = constrain(low, 0, 255) - LOW_STEP;
          setLow(low);
        }
    Так компилируется.
    В описание этой функции сказано:
    "Задает новое значение", означает ли это, что если, к примеру: к 243 прибавим шаг 15, значение примет максимальный диапазон 255 (хотя общая сумма будет 258)? Либо шаг вообще не прибавится и значение останется на прежнем уровне, т.е. 243?
    Проверить на практике смогу только завтра. Спасибо :)
     
  9. acos

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

    low=constrain((int) low + LOW_STEP, 0,255);
    С телефона код писать не удобно)
    По идее предложение @rav_75 должно работать, ошибки компилятора тоже лучше писать) можно еще объявить локальную int переменную, ей присвоить сумму и присваивать low результат её constrain'а. По сути под капотом кода выше именно это и должно происходить
     
    Последнее редактирование: 12 дек 2014
    Salk нравится это.
  10. rav_75

    rav_75 Гик

    Странно, проверил, у меня работает. А что за ошибка?
    и опять 25.. Тогда объявите low как int и не парьтесь
    low += LOW_STEP;
    low = constrain(low, 0, 255)
    int low = 250;
    const int LOW_STEP = 15;
    low+= LOW_STEP; // low == 265
    low = constrain(low, 0, 255); // low == 255
     
  11. Salk

    Salk Гик

    Ничего не понимаю. Если написать так:
    Код (Text):
    if (val == 542903) // Код кнопки, пусть будет минус НЧ
        {
          low = constrain(low + LOW_STEP, 0, 255);
          setLow(low);
        }
    То ошибка:
    Не нравится ему, что прибавляем внутри constrain, стоит убрать "+STEP_LOW" и все нормально.Я тут на днях обновил Arduino IDE до 1.0.6 версии..
    Тогда так: ?
    Код (Text):
    if (val == 534743) // Код кнопки, пусть будет плюс НЧ
        {
          low += LOW_STEP;
          low = constrain(low, 0, 255);
          setLow(low);
        }
        if (val == 542903) // Код кнопки, пусть будет минус НЧ
        {
          low -= LOW_STEP;
          low = constrain(low, 0, 255);
          setLow(low);
        }
     
  12. rav_75

    rav_75 Гик

    ну дык вот и грабли
    #define LOW_STEP 4;
    зачем ; ?
    после #define точка с запятой не ставится
     
    Salk нравится это.
  13. rav_75

    rav_75 Гик

    Можно так, только объявляйте low не как byte, а как int
     
  14. Salk

    Salk Гик

    ааа, понял :) Все дошло. Спасибо!
    Завтра отпишусь о результатах.
     
  15. Salk

    Salk Гик

    Спасибо, @rav_75, @acos, проверил, все работает как нужно, Классно! :)
    Код (Text):
    #define VOLUME_STEP 10
    #define LOW_STEP 10
    #define HIGH_STEP 10

    byte vol;
    byte low;
    byte high;

    void loop()
    {
        if (val == 534743) // Код кнопки, пусть будет плюс НЧ
        {
          low = constrain(low + LOW_STEP, 0, 255);
          setLow(low);
        }
        if (val == 542903) // Код кнопки, пусть будет минус НЧ
        {
          low = constrain(low - LOW_STEP, 0, 255);
          setLow(low);
        }
    }
    Сейчас "железом" вплотную займусь :)
     
    Последнее редактирование: 13 дек 2014
  16. Salk

    Salk Гик

    Всех с прошедшими праздниками !!!
    Хех, до собирал таки своё детище, изобрел велосипед заново :D
    Но обнаружились некоторые подводные камни:
    • Дело в том, что при регулировании громкостей, т.е. при изменении сопротивления ЦП, в колонках возникают сопутствующие, какие-то щелчки - одно нажатие, один щелчок. Но эти, сопутствующие регулировке, щелчки не громкие и всегда одинаковой громкости, т.е. на средней и высокой громкости музыки их не слышно, но на малой очень даже, так же слышны при изменении НЧ и ВЧ. Неприятно, как думаете, что это и возможно ли от этого избавится?

    • "Земли" я зря объединил вместе - и цифровую и аналоговую.Придется переделать, разделю "земли", будет два отдельных БП для самой акустики и Arduino. Тем самым избавлюсь от "щелчков" в колонках во время срабатывания реле и работы кулера.
    В принципе это все, что со знаком "-". В остальном... все получилось :cool:
    Качество звука, неплохое, ЦП особо звук не ухудшают. В отличии от предыдущего эксперимента c AD8402, где мне приходилось снижать громкость PC до 30%, чтобы не было сильных искажений, тут же на 100% довольно не плохо играет, не HI-EnD, конечно, но в HI-Fi, я думаю, попадает :)
    Скетч для теста был упрощен "крутилки" не подключал пока, вместо них просто задал фиксированные стартовые значения.

    Теперь немного о самой схеме, она немного изменилась:
    Вся схема.jpg Цифровая часть.jpg ЦП+LED_RING.jpg
    Прикупил LCD с I2c модулем, освободились пины, чем я и воспользовался. В схему добавится RTC (часы реального времени - I2c); готовый Fm модуль (заказал с ebay, тоже I2c); микросхема MSGEQ7, для построения графического анализатора на LCD дисплее; и "Led Ring", т.к. "крутилки" (обычные потенциометры) у меня будут, то их я решил украсить, и с помощью сдвиговых регистров создать светодиодные кольца (из SMD светодиодов) вокруг ручек потенциометров. Более подробно в этой теме:
    LED Ring
    Аналоговая часть не изменилось, она уже собрана: есть усилители, есть Блок Питания, есть защита АС.

    Ну и на последок, то что на данный момент получилось. Проект потихоньку собирается из маленьких частей в один большой. Надеюсь уже скоро смогу показать, хотя бы, приближенный итоговый вариант:
    IMG_20150110_163639.jpg IMG_20150110_171842.jpg IMG_20150110_171851.jpg IMG_20150110_171859.jpg
    Тут плата ТБ (темброблока) с ЦП на борту (они под грудой перемычек, SOIC корпус), Arduino Uno, БП, ИК-приемник.

    Буду до собирать все остальное и, надеюсь, в ближайшем обозримом будущем покажу более подробно, уже полностью функционирующий проект. :)
     
    Последнее редактирование: 14 янв 2015
  17. Salk

    Salk Гик

    Но есть и обратная сторона. По ней мне снова, нужен совет.
    ИК-приемник связан с цифровыми потенциометрами через 5 В.
    Тогда когда ИК-приемник принимает любой сигнал с пульта (с любого пульта и с любой, даже не запрограммированной кнопки), то в звуковом тракте возникают "щелчки", я так понимаю с частой несущей ИК-приемника - 36 кГц.
    Вот так напрямую подключен ИК-приемник к Arduino:
    103.jpg
    А вот так связаны цифровые потенциометры и Arduino между собой:
    302.jpg
    Т.е. явно, что эти "щелчки" передаются по линии 5 В. Они, для цифровых потенциометров, нужны для ног "RS (сброс) и SHDN (отключение)", но так же, видимо благополучно проникают и в звуковой тракт, внутри самих потенциометров. Земли аналоговая и цифровая раздельны. Между собой накоротко не звонятся, сопротивление больше 2 МОм. Точно так же между 5 В и AGND (аналоговой землей); 5 В и DGND (цифровой землей), т.е. пробоя нигде нет. потенциометры целы и работают на все 100. Но вот такой досадный дефект имеет место быть. Виной всему явно ИК. Но как его "изолировать", не могу решить и прошу помощи. Кстати есть одна, интересная особенность - когда ВЧ на цифровых потенциометрах в среднем положении (т.е. 25 кОм), на видео видно в начале - "0 dB", то щелчки малозаметны ели ели слышны, НО если начать увеличивать ВЧ ИЛИ уменьшать, то они значительно усиливаются, как-будто частоты попадают в резонанс.

    Я думал попробовать поставить опто развязку, к примеру так, но совсем не уверен, что это решит проблему:
    43212.jpg
    Где 5V (1) это один источник питания, а 5V (2) второй. По сути повторение выходного каскада самого ИК-приемника - TSOP4836
    И на всякий - шит на цифровые потенциометры - AD7376.
    Или может фильтр какой-то поставить на 5 В, идущие к потенциометрам, ставил фильтрующие емкости до 4700 мкФ на 5 В, никакого улучшения не давало.
    Огромнейшее спасибо, кто поможет разрешить наинеприятнейшее явление :)
     
    Последнее редактирование: 8 май 2015
  18. acos

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

    Глянул тут даташит http://www.vishay.com/docs/82459/tsop48.pdf
    Там на страничке 2 есть APPLICATION CIRCUIT, в котором нарисован опциональный резистор на 100 Ом и опциональный конденсатор на 0,1 мкФ. В вашем случае они видимо не опциональны а обязательны)
    Далее я бы поставил перед каждым входом питания потенциометров керамические конденсаотры на 0,1мкФ.
    Ну и плохо подключать микросхемы шлейфом, лучше б питание к потенциометрам шло от источника питания, а не после ИК-приемника.
    Рекомендую книжку Хоровиц, Хилл "Искусство схемотехники"

    P.S. Вы молодец)
     
  19. Salk

    Salk Гик

    Поставил их - конденсатор и резистор - ни как не помогли :(. Интересно, что в том даташите на TSOP4836, который я выкладывал, указан конденсатор на 4.7 мкФ. Но и с ним, и с 0.1 мкФ, и даже с 0.47 мкФ разницы нет.
    От "основного" двуполярного БП на выходе, которого ±26 В, идут напрямую на усилители и на плату темброблока. На плате темброблока стоят линейные стабилизаторы, которые понижают это напряжение до ±15 В, и этим уже напряжением питаются и ОУ NE5532 и вместе с ними так же потенциометры. При том на ЦП заходят только +15 В и - 15 В, без общего (земли). Земля к ЦП подключается только цифровая от arduino.
    ___
    В итоге потенциометры питаются от стабилизированных ±15 В от БП (так же, как и ОУ), все питающие шины разведены на ПП. Пленочные (К73-17) 0.47 мкФ стоят везде: между "+" и "-"; "+" и "общим"; "-" и "общим". Так же перед самими потенциометрами стоит ещё керамика между "+" и "-" на 0.47 мкФ.
    ___
    От Arduino к ЦП через шлейфы идут CS/CLK/SDI ("SPI"), земля, а так же 5 В - они нужны для логических единиц на ногах RS и SHDN. Для работы ЦП необходимо на них подавать 5 В ("1"), т.к. лог. "0" на RS сбросит все настройки, а SHDN не даст включить потенциометры.

    Я предполагаю, что в момент приема сигнала ИК-приемником по всей Arduino (линии 5 В) возникают "всплески", которые по линии 5 В передаются на ЦП (RS и SHDN) и как-то уже внутри самих ЦП проникают в звуковой тракт. Звук же через потенциометры проходят (A, B, W), тесно там очень :) У меня просто нет другого предположения. Между 5 В (от Arduino) и землей так же стоит керамика на 0.47 мкФ.
    Так же наблюдается странный эффект, что когда потенциометры, отвечающие за регулировку ВЧ выставлены в среднее положение (25 кОм, "0 dB"), то щелчков практически не слышно, стоит повышать или понижать (-1...-9 dB || 1...9 dB) ВЧ, то щелчки значительно усиливаются, как буд-то попадают в резонанс.
    Может какое-то ферритовое колечко поставить на 5 В, идущие от Arduino на RS и SHDN?
     
    Последнее редактирование: 12 мар 2015
  20. Salk

    Salk Гик

    Доброе время суток, надеюсь не надоел ещё :D

    Из нового:
    - Добавил "крутилки": обычные переменные резисторы, с помощью, которых так же можно регулировать громкость и тембры.
    - Подключил сабвуфер.
    - Сделал отдельный БП для Arduino Uno 9V
    - Добавил анализатор спектра на MSGEQ7, часы. FM-приемник в пути из поднебесной.
    - Немного отладил код, но большие изменения, в основном касаемые отображения на LCD дисплее, ещё впереди.
    - Добавились те же самые щелчки, только теперь при кручении обычных переменных резисторов, что развеивает "миф" о виновности ИК-приемника. И рождает "ново-старую" гипотезу о возникновении этих щелчков в момент посылки битов в цифровые потенциометры, т.е. когда мы посылаем в них данные для изменения их сопротивления, в динамиках происходят щелчки. Ну я уже с этим смирился, спишем на особенности ЦП, т.к. эти щелчки в 90% случаях абсолютно не мешают пользоваться аудиосистемой. Они не громкие, чуть заметны (без музыки) в шаге от колонок, а с музыкой и вовсе "растворяются", возникают только в момент изменения громкости или НЧ/ВЧ.

    Но возникло пара вопросов:
    1.) Я воспользовался уже написанной acos-ом библиотекой ("volume.h"), ОГРОМНОЕ СПАСИБО, ещё раз за все Ваши труды, не было бы вашей помощи, не было бы и этого проекта... ну может был, ну уж точно без всяких "цифровых прелестей" :D

    Так вот, у Вас сделано так, что при кручении хотя бы одного переменного, сбрасываются настройки остальных регулировок. К примеру, если выставили НЧ и ВЧ с пульта "+10 дБ", и крутанули ручку громкости переменного резистора, то и ВЧ и НЧ так же сбросятся до значений переменных. Как разделить их?
    В "volume.h" есть такие строки:
    PHP:
    bool regulatorsChanged()
    {
      bool needChange = false;

      needChange |= rVol.analogInChanged();
      needChange |= rLow.analogInChanged();
      needChange |= rHigh.analogInChanged();

      return needChange;
    }
    А в void loop() :
    PHP:
    {
      // если хоть одна из крутилок изменилась - мы обновим все потенциометры
      if (regulatorsChanged())
        setAllVolumes(rVol.value(), rLow.value(), rHigh.value());
    }
    Можно ли эти части кода переписать так ? :
    в "volume.h"
    PHP:
    bool regulatorsChangedVol() // Громкость
    {
      bool needChange = false;

      needChange |= rVol.analogInChanged();

      return needChange;
    }
    bool regulatorsChangedLow() // НЧ
    {
      bool needChange = false;

      needChange |= rLow.analogInChanged();

      return needChange;
    }
    bool regulatorsChangedHigh() // ВЧ
    {
      bool needChange = false;

      needChange |= rHigh.analogInChanged();

      return needChange;
    }
    А в void loop() :
    Код (Text):
      // Если крутанули ручку громкости
      if (regulatorsChangedVol())
      {
        vol = rVol.value();
        setVolume(vol);
      }
      // Если крутанули ручку НЧ
      if (regulatorsChangedLow())
      {
        low = rLow.value();
        setLow(low);
      }
      // Если крутанули ручку ВЧ
      if (regulatorsChangedHigh())
      {
        high = rHigh.value();
        setHigh(high);
      }
    Сработает?

    2.) В "volume.h" считывание показаний с переменных резисторов и преобразование их в диапазон 0-255 происходит сразу для всех:
    PHP:
        uint8_t readAInValue()
        {
          return _value = map(analogRead(_analogInput), 0, 1023, 0, 255);
        }
    Дело в том, что мне нужно изменить "полярность" одного переменного, отвечающего за ВЧ, сейчас его нужно крутить против часовой стрелки, чтобы прибавить ВЧ (так подключены ЦП на плате темброблока). Примерно так:
    PHP:
    map(analogRead(_analogInput), 1023, 0, 0, 255);
    Можно конечно, это поправить аппаратно, переделав плату под переменные резисторы и на одном переменном поменять 5В и GND местами, но.. лень снова травить.
    Не совсем могу сообразить как это сделать не "портя" такой красивый код :)
    Скетч ниже.
    3.) Не подскажите в построении различных не стандартных символов на текстовом LCD экране, а главное как "строить" ползунки громкостей, на подобии таких ? :
    123.jpg

    Пока на этом все. Предложения, дополнения приветствуются, портов свободных не осталось, но вот линия I2C может ещё пополнится (сейчас там: FM, RTC, LCD) :D
     

    Вложения:

    • analogAmp.zip
      Размер файла:
      5,7 КБ
      Просмотров:
      327
    Последнее редактирование: 8 май 2015