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

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

?

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

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

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

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

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

    А так?
    Код (C):
    #include <SPI.h>
    #include <IRremote.h>

    #define START_VOLUME 20; //стартовое значение громкости
    #define VOLUME_STEP 5; //шаг приращения громкости


    //When Using the SPI library, you only have to worry
    //about picking your slave select
    //By Default, 11 = MOSI, 12 = MISO, 13 = CLK
    int SS_pin = 10;  //SPI Slave Select

    int RECV_PIN = 3; //пин подключения IR приёмника
    IRrecv irrecv(RECV_PIN);
    decode_results results;

    byte volume = START_VOLUME;
    byte volumeOld = 0;

    void setup()
    {
      Serial.begin(9600);

      //Set Pin Direction
      //Again, the other SPI pins are configured automatically
      pinMode(SS_pin, OUTPUT);

      //Initialize SPI
      SPI.begin();

    /// А так?
      irrecv.enableIRIn(); // Start the receiver

    }

    //This will set 1 LED to the specififed level
    void setVolume(int reg, int level)
    {
      digitalWrite(SS_pin, LOW);
      SPI.transfer(reg);
      SPI.transfer(level);
      digitalWrite(SS_pin, HIGH);
    }


    void loop()
    {

      if (irrecv.decode(&results))
      {
       Serial.print("Key code - ");
        Serial.println(results.value);
        if (results.value == 573503) //Код кнопки (пусть это громкость плюс)
        {
          volume = volume + VOLUME_STEP;
          Serial.println(volume);
        }

        if (results.value == 532703) //Код 2 кнопки (пусть это громкость минус)
        {
          volume = volume - VOLUME_STEP;
          Serial.println(volume);
        }

        irrecv.resume(); // Получаем следующее значение
      }

      if (volume != volumeOld)
      {
        for (int i = 0; i <= 1; i++)
        {
          setVolume(i, volume);
        }
        volumeOld = volume;
      }
    }
     
    Последнее редактирование: 14 окт 2014
  2. Salk

    Salk Гик

    Странное происходит. Действительно, коды кнопок не падают в монитор. Однако ИК-приемник подключен верно к пин =3 .Если загрузить скетч проверки кодов кнопок пульта, то там все работает, все коды всех кнопок отображаются, как на фото:
    [​IMG]
    По такому принципу у меня переключается реле.
    Если вставить строчку: Serial.println("ready"); даже это не выводится в монитор, он всегда пустой. CLK, CS, MOSI подключены верно к 13, 10 и 11 пинам соответственно. Странно, может виной всему отсутствующий пин MISO (SDO), который должен идти к 12 пину? :(
    А на что влияет, указанное сопротивление цифрового потенциометра "1 кОм, 10 кОм, 50 кОм", думал на плавность регулировки/кол-во шагов, но нет, это мы можем задать программно. Значит это сопротивление влияет лишь на цепь, куда подключается потенциометр, входное/выходное сопротивление каскадов?
     
    Последнее редактирование: 14 окт 2014
  3. acos

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

    упс. случайно изменил камент, вместо нового. Забыли вот это
    irrecv.enableIRIn();// Start the receiver
     
    Salk нравится это.
  4. Salk

    Salk Гик

    acos я на седьмом небе от счастья :D Перед Вами в долгу. Круто, очень круто, получилось все заработало. Я тоже проверял код ИК-приемника, но как-то тоже не обратил внимания на эту строчку включение рессивера. Фуф. Если позволите пару фоток с "места преступления" :p
    Скетч, изменил начальную громкость на комфортную и шаг, тут надо сказать, что громкость ПК 50%, т.к. при такой громкости не слышно хрипы, какие-то призвуки, я почти уверен, что дело именно в сопротивлении потенциометра - 1 кОм, его нужно поднять, как минимум до 20-50 кОм, в регулировку ВЧ или НЧ, такой потенциометр на 1 кОм лучше не ставить. :
    [​IMG]

    И фото "вид сверху" :):
    [​IMG]
    Все это пока выглядит не очень "аппетитно", т.к. на стадии проектирования; плата ТБ (верх тормашками, истыканная конденсаторами :rolleyes:) будет переделываться и на ней уже разместятся цифровые потенциометры, а вместо проводов к "крутилкам" будут "управляющие" провода к Arduino (тут пока "вход и выход" громкости идут к цифровому потенциометру, а все остальное пока к обычным резисторам).
    Ещё раз ОГРОМНОЕ СПАСИБО! Позвольте ещё несколько уточняющих вопросов:
    * Для чего же тогда используются этот интерфейс -
    Вы так и не ответили, я Вам уже надоел с этим? :)
    * И касательно нужного сопротивления цифровых потенциометров. Я смогу достать на 50 кОм, но только одноканальные (AD8400), которые фигурировали в самом начале темы. По видеоуроку Джереми, как я понял можно каждый потенциометр соединить вместе SS, MOSI, CLK между собой, используя такое же кол-во пинов Arduino, что и с двухканальным или четырех и т.д., т.е. всего 3 пина. Получится, для реализации трех стерео регулировок - громкость, НЧ, ВЧ, мне понадобится 6 шт. одноканальных AD8400, включенных, как бы параллельно на 3 пина Arduino. А в прошивке это учесть, присвоив 6 регистров, добавив 3 макроопределений на Volume, НЧ и ВЧ, ну и разумеется кнопки пульта.
    Правильно?
     
    Последнее редактирование: 14 окт 2014
  5. acos

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

    SDO нужен, когда периферийное устройство должно отдавать данные в контроллер.
    В шине SPI есть устройство Master - оно управляет передачей, выбирает, с каким устройством общаться (ножка CS или Chip Select она же SS или Slave Select нужна именно для этого), ведь на одних и тех же проводах может сидеть несколько SPI-устройств (О! Хлоп себя по лбу! Точно, вы же можете все свои потенциометры посадить на MISO SCK параллельно, а отдельными ножками CS выбирать, с кем общаться! Для шести потенциометров - MISO и SCK параллельно, и шесть ног на CS для каждого. Вылетело из головы).
    Есть устройство Slave, оно слушает CS, и если тот опущен, общается с Master через контакты MOSI и MISO.

    Короче говоря, SDO, он же MISO — Master Input, Slave Output здесь не нужен совсем, потому что данные передавать в сторону микроконтроллера незачем. Если б это был http://amperka.ru/product/74hc165-shift-in-register входной сдвиговый регистр, то у него входа MOSI нет, потому что ему не нужно принимать данные от микроконтроллера - не за чем. Но вот иногда, когда имеешь дело со сдвиговыми регистрами, которых нужно очень много, так вот иногда их ставят каскадом. Таким образом, чтобы на вход SDI регистра шло значение из SDO предыдущего регистра, которое равно значению SDI этого регистра за восемь циклов SCK до того. Что-то у меня получается долго запутанно и непонятно)

    Давайте так: У вас есть мясорубка. у неё есть один вход - туда кладут мясо. У нее есть выход - оттуда падает мясо. Рубящим механизмом пренебрегём:) У вас есть мясобайт - восемь мисок под мясо. В каких то мисках есть мясо - это логическая «1», в каких-то нет - «0». Вам нужно переложить это мясо в том же порядке внутрь мясорубки. В мясорубку помещается ровно 8 кусков мяса. Вы берете первую миску - там мясо. Не глядя переворачиваете миску в мясорубку и проворачиваете ручку (SCK), мясо проезжает по мясорубке вперёд, находясь в пазу. Берете вторую миску - там мяса нет, поэтому вы кладете пустоту в мясорубку и крутите ручку. И так 8 раз. Теперь у вас внутри мясорубки сидит тот же самый байт на винте - паз с мясом, паз без, и т.д. Всё - вы передали мясобайт в мясорубку. А теперь мы хотим передать этот мясобайт в другую мясорубку, а в первую мясорубку передать новый мясобайт! Мы ставим выход первой мясорубки над входом второй мясорубки, кладём новый мясобит в первую мясорудку и одновременно крутим обе ручки сразу двух мясорубок. Самый наш первый мясобит падает из первой мясорубки во вторую, кладем новый мясобит в первую мясорубку и опять проворачиваем обе ручки. Самый первый мясобит продвигается по второй мясорубке на паз вперёд, второй мясобит падает во вторую мясорубку и т.д. Итого, после 16-и оборотов ручки мясорубки с момента начала передачи, у нас в двух мясорубках лежит два мясобайта! И мы получили каскад из двух мясорубок.
    Так вот, подозревая, что в данном случае SDO - это выход мясорубки.
     
    Salk нравится это.
  6. acos

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

    На счёт потенциометра нужно глянуть схему всю.
     
  7. Salk

    Salk Гик

    Вы имели в виду схему подключения потенциометров или полную схему всего ТБ, немного не понял?
    Вы меня извините за назойливость и тупость. Надоел уже, знаю ... :(
    Я правильно понял, как подключать ЦП (цифровые потенциометры) друг к другу ?
    Безымянный.jpg Безымянный1.jpg
    MISO (SDO) можно и вовсе пренебречь и не занимать лишний пин на Arduino ?
    Проблем с AD7376 быть не должно (у него единственное отличие, что имеет 128 позиций, а не 256). Скорее всего я смогу их приобрести к концу следующей недели.
    Шит на AD7376:
    http://www.analog.com/static/imported-files/Data_Sheets/AD7376.pdf

    А удастся ли подключить не все ЦП к СS отдельно (6 шт.), а попарно (т.к. все равно сигнал стерео; по 2 ЦП на каждую регулировку). Тем самым можно получить тот же сдвоенный ЦП в одном корпусе.
    Или все же придется каждый ЦП цеплять на свой CS (все 6 шт.) ?
    Для AD8402 есть внутри "DAC Select" и регистры A0, A1, точно! (Вы говорили про них), тем самым идет переключение ЦП внутри одного корпуса. Наверное подцепить два ЦП на одну шину CS все же не получиться ? Значит придется для каждого подключать отдельно, занимая при этом все 8 пинов Arduino, ладно это не страшно.
    Я могу ещё обращаться к Вам за поддержкой?
     
    Последнее редактирование: 16 окт 2014
  8. Salk

    Salk Гик

    Добрый время суток. Я попытался написать скетч для управления AD7376 (все 6 шт, подключаем параллельно, а CS (SS) отдельно для каждого). Сделал пример пока для двух ЦП (они одноканальные и будут занимать два пина CS), чтобы понять как ими можно управлять и сделать так, чтобы они работали синхронно, т.к. сигнал стерео (остальные регулировки можно будет добавить по аналогии). Соответственно можно сделать так: управлять одним каналом, а второй будет "смотреть" на первый и подстраиваться, идеология верна?
    Вот что у меня получилось, проверить пока нет возможности, т.к. забрать заказ смогу лишь через, примерно, неделю (жаль, что в вашем магазине нет подобного).

    Код (Text):
    #include <SPI.h>
    #include <IRremote.h>

    #define START_VOLUME 10; //стартовое значение громкости 1 канала
    #define VOLUME_STEP 2; //шаг приращения громкости 1 канала
    #define START_VOLUME1 10; //стартовое значение громкости 2 канала
    #define VOLUME1_STEP 2; //шаг приращения громкости 2 канала

    //When Using the SPI library, you only have to worry
    //about picking your slave select
    //By Default, 11 = MOSI, 12 = MISO, 13 = CLK
    int SS_pin = 10;  //SPI Slave Select
    int SS_pin1 = 9; //cS 1 пока на примере одноканальных ЦП, остальные добавлю по аналогии

    int RECV_PIN = 3; //пин подключения IR приёмника
    IRrecv irrecv(RECV_PIN);
    decode_results results;

    byte volume = START_VOLUME;  // 1 канал
    byte volume1 = START_VOLUME1;  // 2 канал

    void setup()
    {
      Serial.begin(9600);

      //Set Pin Direction
      //Again, the other SPI pins are configured automatically
      pinMode(SS_pin, OUTPUT);
      pinMode(SS_pin1, OUTPUT);

      //Initialize SPI
      SPI.begin();
    }

    //This will set 1 LED to the specififed level
    void setVolume(int reg, int level)
    {
      digitalWrite(SS_pin, LOW);
      SPI.transfer(reg);
      SPI.transfer(level);
      digitalWrite(SS_pin, HIGH);
     
     
      digitalWrite(SS_pin1, LOW);
      SPI.transfer(reg);
      SPI.transfer(level);
      digitalWrite(SS_pin1, HIGH);
      irrecv.enableIRIn();// Start the receiver
    }


    void loop()
    {

      if (irrecv.decode(&results))
      {
      Serial.print("Key code - ");
        Serial.println(results.value);
        if (results.value == 587783) //Код 1 кнопки (пусть это громкость плюс)
        {
          volume = volume + VOLUME_STEP;
          Serial.println(volume);
          delay(20);
        }

        if (results.value == 525053) //Код 2 кнопки (пусть это громкость минус)
        {
          volume = volume - VOLUME_STEP;
          Serial.println(volume);
          delay(20);
        }

        irrecv.resume(); // Получаем следующее значение
      }

      if (volume != volume1) // Выставляем значение 2 канала равному первому
      {
        for (int i = 0; i <= 1; i++)
        {
          setVolume(i, volume);
        }
        volume1 = volume;
      }
    }
    Acos, если я Вас чем-то оскорбил, простите, я далеко не специально, Вы просто так внезапно исчезли, или просто надоело возиться с нубом? :D
     
  9. acos

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

    Я про вас не забыл, просто отвечаю по-возможности.
    судя по даташиту, AD7376 вполне можно подключить так
    потенциометры.png
    Помните про мясорубки? вот - это они. И кормить эти мясорубки нужно очень длинной последовательностью бит - 7*6=42 бита, в которых хранятся все значения громкостей всех потенциометров.
     
  10. Salk

    Salk Гик

    Добрый день. В данный момент изучаю азы SPI - http://suli-company.org.ua/electro/arduino/1111-spi-i-arduino.html
    Там есть пример подключения сдвиговых регистров, как одного, так и двух. Первое подключение: независимое (отдельно для каждого регистра свой SS), второе: каскадное подключение (ещё называют его кольцевое подключение, которое указано в даташите на AD7376, как "гирляндное" подключение, в переводе :) ), так вот сразу возник вопрос. Я не совсем понимаю, как получится при каскадном подключении, раздельное управление трех независимых регулировок - Громкость/НЧ/ВЧ. Мы же будем "вертеть" биты по кругу, "из одной мясорубки в другую", крутя ручки всех мясорубок одновременно (т.к. SS общая), а что если нам понадобится разное кол-во мясобитов на выходе мясорубок ? Как будет происходить выборка?
    Может тогда разделить по три пары SS (по два на каждую регулировку, т.к. стерео) - SS1 (по два ЦП для НЧ), SS2 (по два ЦП для ВЧ) и SS3 (по два ЦП для громкости), а шины данных распределить между всеми. Чушь? :)

    С кодом все ещё сложнее, с MISO (SDO) мы ещё не работали. Давайте, для простоты подключим пока всего два ЦП, для регулировки стерео громкости, каскадным способом подключения. Тут все будет, как на Вашей картинке, только SDO последнего ЦП будет висеть в воздухе:
    потенциометры.png
    Я так понял, что enum - это что-то вроде int, только может содержать несколько перечислений в одной строчке, для упрощения написания кода ?
    В нашем случае мы должны будем передать 14 бит, так?:
    Код (Text):
    void writeShiftRegister14(int ss_pin, uint14_t value)
    {
    digitalWrite(ss_pin, LOW);  /* Фокус вот в чём: сначала шлём старший байт */
    SPI.transfer(highByte(value));  /* А потом младший */
    SPI.transfer(lowByte(value));
    digitalWrite(ss_pin, HIGH);
    }
    Боюсь мне самому тут не разобраться, можете набросать часть кода, чтобы я мог отталкиваться дальше. Спасибо.
     
  11. acos

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

    enum это перечисление. Вот здесь про enum http://wiki.amperka.ru/программирование:конечный-автомат?s[]=enum
    и ещё
    http://valera.asf.ru/cpp/book/c03_8.html

    С каскадированием все просто - у вас есть под каждую задачу своя переменная, когда нужно изменить только одно значение, например НЧ, вы изменяете только одну эту переменную, а все остальные значения у вас остаются старые. Потом вы обновляете все мясорубки одновременно. В мясорубку с НЧ попадает новое значение, а в остальные - старые. Так как изменение сопротивления происходит только после окончания передачи (т.е. после того как CS стал HIGH), то изменяется только НЧ, а громкость и ВЧ остаются теми же самыми.
     
  12. Salk

    Salk Гик

    Да, вот полная схема, собираемого устройства:
    Безымянный.jpg
    Это - трехканальная акустическая система, формата 2.1, собирается на замену старенькой компьютерной, покупной, акустики тоже 2.1 формата. Изюминкой такой системы, я считаю, микроконтроллерное управление на базе Arduino Uno. О цифровой части расскажу чуть позже, пока про аналоговую :)

    Усилители на микросхемах, средней мощности, суммарная мощность ~114 W (если верить даташитам) - 2 х 22W (стерео) + 70 W (саб) при искажения не выше 0.1 % (THD). Сетевой БП, регулируемый. Имеется защита самих динамиков от постоянного напряжения на выходе усилителей (если они неисправны), а так же задержка подключения динамиков на 3 сек после подачи питания, что избавит от прослушивания бабахов, бухов и т.п. при первом включении питания всего устройства. Дальше собирался ТБ (темброблок). Довольно качественный ТБ, активный с применением ОУ (операционных усилителей) TL072, но их в легкую можно поменять на более качественные, малошумящие, ну и дорогостоящие ОУ, типа NE5532 или OPA2134 и т.д. В самой схеме ТБ имеется возможность регулировать НЧ, но т.к. система формата 2.1, то был собран отдельный ФНЧ на TL074, а тот регулятор НЧ можно либо исключить из схемы, или (что я сделаю) оставить и применить не переменные резисторы (и тем более цифровые потенциометры), а обычные подстроечные резисторы, тем самым согласовать сателлиты (стерео) с сабвуфером, иными словами разгрузить стерео от НЧ, что-то вроде :) Вот поэтому сама основная идея заключается в оцифровывании этого аналогового ТБ, я не очень доверю аудио процессорам, да там уже есть функции ТБ, т.к. сказать все в одном, но по качеству они наверняка проигрывают. Собственно, ничего сложного тут нет. В качестве ЦП (цифровых потенциометров) я буду использовать AD7376, которые и предназначены для управления громкостью, имеют низкие вносимые искажения и большую входную амплитуду сигнала. Но беда в том, что они одноканальные, и если их подключать по такому же принципу, как AD8402 (пример скетча выше, работает ! ), то тогда пины на Arduino будут заняты только ими, а у меня на них ещё свои планы :) Поэтому возникла загвоздка, в том, как подключить 6 ЦП в каскадном подключении , задействовав всего три пина Arduino. Поэтому я прошу помощи в написании скетча, сам боюсь, не смогу осилить. ЦП встанут вместо сдвоенных переменных резисторов на Громкость/НЧ/ВЧ (по два на каждую настройку).

    Теперь пару слов о цифровой части проекта, основанной на Arduino. Тут немного:
    • управление блоками реле (их 2 шт) по команде с пульта ДУ, один для вкл/выкл сети, основного питания всего устр-ва. Второй блок реле, скорее всего будет отвечать, так же вкл/выкл подсветки корпуса, пока не знаю что это будет точно, т.к. корпус и его оформление будет делаться на последнем этапе.
    • кулер, который будет обдувать все сверху :) а регулировка его оборотами будет зависеть от показания термодатчика (LM35), управление кулером простое - напряжением, не ШИМ, просто и со вкусом.
    • LCD дисплей (16х2), на котором будет отображаться текущая температура датчика и скорость кулера, а так же в планах сделать отображение текущей настройки. Идея: главное меню - время/дата, температура и скорость кулера. Жмем на кнопку пульта, изменяем, к примеру Громкость, на 3 сек на дисплее показывается название регулировки (Volume) и шкала заполнения (знаете, как у телевизоров, больше меньше, вертикальные полоски). Если за 3 сек ничего больше не изменяется, на экране вновь появляется "главное меню".
    • ИК-датчик, управление пультом ДУ. Я даже не буду выносить, дублировать регуляторы громкости/НЧ/ВЧ, чтобы можно было регулировать помимо пульта ДУ, т.к. тут скорее всего нужно будет применить энкодеры, а лишних пинов у меня уже не осталось. Да и пустяк это.
    • Часы реального врмени (RTS) на DS1307, его куплю готовый, типа:
      http://amperka.ru/product/real-time-clock
      Время будет выводится на LCD дисплей.
    Вот такой небольшой проектик пока ещё в процессе сборки. Все скечти, кроме ЦП у меня есть и проверены на макетной плате :), объединить их в один, проблем не должно возникнуть. C LCD дисплеем, как я хотел, тоже должно получится, пример работы с LCD в интернете хватает. Но вот с цифровыми потенциометрами тупик :(
    Ведь я правильно понял про каскадное подключение: три пина на Arduino SS, CLK, SDI?
    А SDO к SDI следующего потенциометра ?
    И спасибо, огромное! ;)
     
    Последнее редактирование: 23 окт 2014
  13. acos

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

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

    Salk Гик

    acos
    Огромное спасибо! ;) Это классно, что Вы сделали для меня. Я обязательно доведу тему до логического конца, может даже видео сниму про законченную сборку. Потенциометры уже приехали :)
    Можно ещё парочку уточняющих вопросов:

    1. Подключение каскадное - 3 пина на Arduino (MOSI, SCK, CS) и SDI к SDO следующего потенциометра, все так? В pinMap.h им пины назначены 4, 5 и 6.
      [​IMG]
    2. Если нужно будет добавить, какие-либо пины или переназначить, то все это можно менять в "pinMap", т.е. в основном скетче перед void setup, назначать пины не нужно? Можно только настроить: OUTPUT или INPUT.
    3. Не много не понял, как управлять - увеличивать или уменьшать настройки, с пульта. Знаю, что код IR должен быть примерно таким:
      Код (Text):
      if (results.value == 573503) //Код кнопки (пусть это громкость плюс)
          {
            volume = volume + VOLUME_STEP;
          }

          if (results.value == 532703) //Код 2 кнопки (пусть это громкость минус)
          {
            volume = volume - VOLUME_STEP;
          }
       
      Но "шаг приращения" мы ведь не указали? Т.е. нужно будет указать что-то типа этого, как мы делали с AD8402. Только для "vol, low, high" ? :
      Код (Text):
      #define START_VOLUME 20; //стартовое значение громкости
      #define VOLUME_STEP 5; //шаг приращения громкости
      Или тут другая механика?
    4. И на счет обычных переменных резисторов. Т.е. можно их применить, но в звуковой тракт не устанавливать, а просто подать на них +5 В и Arduino просто считывает показания напряжения с потенциометра, как в примере (от 0 до 255, если разделить на 4) и на основании этих показаний будут изменятся и ЦП, соответственно звук. Такая идея?
    Ну вот пока, все что я хотел спросить. Ещё раз огромнейшее спасибо за Ваш труд, это классно!
    Тут пара фоток, экспериментов с дисплеем и датчиком температуры, пока без кулера. Полный собранный скетч я выложу вместе с отчетом, когда приведу устройство в гожий вид. :) И можно Вас будет ещё чуток в будущем помучить, разными вопросами по скетчу, которые могут со временем возникнуть? :cool:
     

    Вложения:

    • xyGIqgaj7oo.jpg
      xyGIqgaj7oo.jpg
      Размер файла:
      904,6 КБ
      Просмотров:
      993
    • xLE7v9jUKtY.jpg
      xLE7v9jUKtY.jpg
      Размер файла:
      863,1 КБ
      Просмотров:
      1.301
    Последнее редактирование: 24 окт 2014
  15. acos

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

    На самом деле это не конец. Я пока только реализовал возможность простой работы с потенциометрами, таким образом, чтоб можно было просто выставлять значение громкости из основного скетча, вызывая функции типа setVolume(volume); то есть будет как-то так

    Код (C):
    if (results.value == 573503) //Код кнопки (пусть это громкость плюс)
        {
          volume = volume + VOLUME_STEP;
        setVolume(volume);
        }

        if (results.value == 532703) //Код 2 кнопки (пусть это громкость минус)
        {
          volume = volume - VOLUME_STEP;
          setVolume(volume);
        }
     
    работа с потенциометры сейчас сделана через простой "ножкодрыг" - просто потому, что так проще и понятнее для вас будет.

    pinMap - там все ноги назначены. Если будете использовать для работы только константы, то поменять ножку можно просто изменив значение константы в pinMap.

    потенциометры-крутилки - да идея такая. При старте считываем стартовое значение с них, далее просто проверяем время от времени- если считанное значение с них изменилось - отправляем на цифровые потенциометры. Это позволит управлять и с пульта и вручную с крутилок одновременно.
    на счёт температуры и куллера - я не расчитывал на это в pinMap, мне больше понравилась идея считывать звуковой сигнал итоговый, получившийся, и при больших значениях зажигать светодиоды PEAK - что бы было видно перегруз. Эту же инфу использовать для LCD - сделать из него UV-метр такой. А больше ног не осталось)
     
    Последнее редактирование: 24 окт 2014
    Salk нравится это.
  16. Salk

    Salk Гик

    Приветствую, acos.
    Не совсем понял, что Вы имели ввиду под: :)
    Сделать VU-метр и отображать анимацию на дисплее? :) Вещь заманчивая, даже очень, но я думал сделать отдельно попроще, на подобии "цветомузыки", а входной сигнал брать непосредственно с выхода звуковой карты. И да, пины на Arduino быстро заканчились :)Думал, было бы не плохо сделать простое информативное "главное меню", где отображалась бы информация: о температуре и скорости вращения вентилятора и время. (с RTC я пока ещё не работал, но скетч есть, библиотеку скачал, проблем не должно быть) :) А при изменении какой-либо из "громкостей" на три секунды бы показывалось название текущей настройки (Volume, Low, High) и ползунок заполнения (в виде анимации, как у телевизоров). 3 сек истекли, вновь "главное меню". Думаю должно прикольно смотреться.

    По разбирался со скетчем, смог объединить все свои задумки в один (реле, датчики, экранчик, кулер, ни одного свободного пина не осталось :) ), но пока без реализации "главного меню" на LCD.
    Но вот с потенциометрами опять что-то не срастается. Пытаюсь IR приделать, вызываю функции setVolume, setLow setHigh, ругается компилятор на них. Шаг приращения указал. С обычными потенциометрами, не уверен точно, правильно ли сделал. Там ведь мы должны данные с обычных потенциометров посылать также, как и данные с ИК-пульта, вызывая setVolume, setHigh и setLow? Запутался..
    Посмотрите, пожалуйста, прикрепленный файл (скетч) "alLsktch". Спасибо!

    Ещё можно вопрос: а Arduino Uno "потянет" все это, не будут ли задержки при принятии сигналов с пульта ДУ? Можно и экран, и датчики, и RTC и реле (реле 5 В) запитать от +5 В Arduino? Или лучше будет отдельное питание реализовать?
    Я спрашиваю, потому что уже пробовал объединить реле, дисплей и датчики. Работает, в добавок ещё реализовал вкл/выкл подсветки экрана. Но было замечено, что при подключении экрана, команды с пульта срабатывали с какой-то задержкой (доли секунды, но ощущалось), а так же из 5 нажатий одно могло не сработать. Убираю экран из скетча и реле "щелкают" как нужно, мгновенно откликаясь на команды с пульта. Скетч так же прикрепляю "Cooler_Temp_IR_Rele".
     

    Вложения:

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

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

    а что компилятор то говорит по поводу функций?

    Ох, ну и код у вас) не код а забор. А должен быть - змей ;) Используйте форматирование кода (в arduino IDE в скетче нужно нажать Ctrl+T либо "Инструменты"→"Auto Format"). Так шансов запутаться в коде гораздо меньше.

    по поводу lcd - в вашем проекте нужно избегать тупых задержек вида delay(200);
    То есть вместо
    Код (C):
        lcd.setCursor(7, 0); // передвигаем курсор вправо. Слева предполагается отображение часов.
        lcd.print("Temp: ");
        lcd.print(temp); // отображение температуры
        lcd.print("C ");
        lcd.setCursor(7,1); // перевод курсора на следующую сторку
        lcd.print("Fans: ");
        lcd.print(fanLCD); // отображение скорости вращения вентилятора
        lcd.print("%");
        delay(200);
        // я так понял эта задержка, по сути, частота обновления экрана,
        // странно то, что если уменьшить или увеличить хотябы на 5 мс,
        // то кнопки пульта срабатывают раз через раз. Если LCD дисплей отключить, то работают быстро и без задержек.
        lcd.clear();
        }
    нужно делать так:

    Код (C):
    //это где-то в самом верху кода
    #define LCD_UPDATE_TIME  200
    unsigned long lcdLastUpdateTime = 0;


    // а это уже там же, где у вас

    if (millis() - lcdLastUpdateTime > LCD_UPDATE_TIME) {

        lcdLastUpdateTime = millis(); // если времени прошло больше 200 мс,
       //то выполняем, не забывая актуализировать время последнего обновления экрана

        lcd.clear();

        lcd.setCursor(7, 0); // передвигаем курсор вправо. Слева предполагается отображение часов.
        lcd.print("Temp: ");
        lcd.print(temp); // отображение температуры
        lcd.print("C ");
        lcd.setCursor(7,1); // перевод курсора на следующую сторку
        lcd.print("Fans: ");
        lcd.print(fanLCD); // отображение скорости вращения вентилятора
        lcd.print("%");
        // delay(200);
        // я так понял эта задержка, по сути, частота обновления экрана,
        // странно то, что если уменьшить или увеличить хотябы на 5 мс,
        // то кнопки пульта срабатывают раз через раз. Если LCD дисплей отключить, то работают быстро и без задержек.
      }
     
  18. Salk

    Salk Гик

    Спасибо за подсказку с LCD дисплеем. Узнал новую функцию millis, которая возвращает прошедшее время (в мс) после запуска скетча. Классная штука :)
    И спасибо за "Автоформатирование" - очень полезная вещь, заборов больше не будет :D

    Поразмыслил насчет ЦП, в общем, попытался сделать пока без обычных потенциометров, присвоил "стартовые значения" и относительно них уже должна производится регулировка "громкостей" с пульта, как мы делали с AD8402.
    Вот, в общем добавил
    Код (Text):

    #define VOLUME_STEP 4;
    #define LOW_STEP 4;
    #define HIGH_STEP 4;
    #define START_VOLUME 20;
    #define START_LOW 50; // заранее указанное стартовое значение "value"
    #define START_HIGH 50;
    #define LCD_UPDATE_TIME  200

    // попробуем, пока без обычных потенциометров
    byte volume = START_VOLUME;
    byte low = START_LOW; // укажем от куда брать стартовое значение
    byte high = START_HIGH;
    И все "vol" заменил на "volume", чтобы не было несоответствий.
    "Ругаться" на "громкости" перестал. Изначально не внимательно проверил {}, выдавал ошибки при компиляции. Все перепроверил, исправил, теперь все должно работать, компиляцию прохожу :)
    В таком виде скетч работоспособный (скетч приложил "AllSketch")?
    Если да, то я сам попробую добавить "крутилки" :)

    Я правильно понял механизм работы "потенциометров-крутилок" - для того чтобы, потом их прикрутить (обычные потенциометры) нужно в setup один раз выставить "стартовые значения", полученные с обычных потенциометров (analogRead), а в loop сделать условие (if) и сравнивать это значение со "старым" на изменения, если значение "крутилок" не изменилось (мы не трогаем ручки потенциометра), то можно изменить громкости с пульта ДУ. Но, если значение "крутилки" изменилось (мы крутанули ручку), то это новое значение отправляем сразу же на ЦП и относительно уже этого "нового" значения мы с нова сравниваем, крутим ли мы ручку потенциометра дальше или нет.
    В итоге должно получится - Arduino запускается, ЦП выставляют значение громкостей, исходя из показателей "крутилок", после, если не трогаем их, можем менять "громкости" с пульта. Как только крутанули ручку обычного потенциометра, значение громкостей, установленные с пульта сбрасываются и назначаются "новые" значения "крутилок". Получается регулировка такими скачки, если с пульта выставим половину (0-127 = 63) и крутанем ручку потенциометра, которая, к примеру, была выставлена на минимум (пусть 10), то громкость резко уменьшится с 63 до 10?
    Не велика беда, а чтобы "синхронизировать" эти две регулировки (пульт и обычную крутилку), тут нужен уже будет энкодер (который вращается на 360*)? Только ради любопытства спрашиваю :) ?

    И поясните, пожалуйста, для чего эта функция в конце "digiPot.h" и как её правильно применить, если её вызвать в таком виде в setup, то получим ошибку
    Код (Text):
    // Это нужно будет вызать в setup()
    // и передать сюда значения с потенциометров-крутилок
    void digiPotInit(byte volume, byte low, byte high)
    {
      pinMode(D_POT_MOSI, OUTPUT);
      pinMode(D_POT_SCK, OUTPUT);
      pinMode(D_POT_CS, OUTPUT);
      setAllVolumes(volume, low, high);
    }
    ошибка:
    Спасибо Вам за помощь, надеюсь я Вас ещё с ума не свел :)
     

    Вложения:

    • AllSketch.zip
      Размер файла:
      2,4 КБ
      Просмотров:
      295
    Последнее редактирование: 29 окт 2014
  19. acos

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

    Не вижу ничего плохого в том, чтобы значение громкости резко менялось при кручении крутилки, если громкость была изменена с пульта. Тем более, что это скорее будет использоваться просто как удобное задание стартовых настроек, которое потом редко будет меняться. Энкодеры тут ни к чему, тем более ножек на них не остается) Хотя в бытовых усилителях обычно используются именно энкодеры. В принципе можно было бы обойтись вообще без крутилок, задавать все параметры с пульта и сохранят эти значения в EEPROM - это такая энергонезависимая память в контроллере. Но это скорее для дальнейшего развития.
    Не увидел в скетче, как вы вызываете digiPotInit()
    По задумке как то так:
    Код (C):
    digiPotInit(volume, low, high);
    Это вместо вашего
    Код (C):
    //...
      pinMode(D_POT_MOSI, OUTPUT);  // укажем, что пины ЦП должны работать, как выход
      pinMode(D_POT_SCK, OUTPUT);
      pinMode(D_POT_CS, OUTPUT);
    //...
    Кстати. Не увидел в скетче - а где вы выставляете все значения громкостей в первый раз? вот эта функция digiPotInit(volume, low, high) это делает, но у вас её нет, и изменения громкостей происходят только при приёме ик-сигнаала
     
  20. Salk

    Salk Гик

    Да дурак я, думал этого будет достаточно :confused:
    Код (Text):
    #define VOLUME_STEP 4;
    #define LOW_STEP 4;
    #define HIGH_STEP 4;
    #define START_VOLUME 20;
    #define START_LOW 50; // заранее указанные стартовые значение
    #define START_HIGH 50;
    Теперь скетч должен быть рабочим?
    Код (Text):
    // Зададим шаг приращения
    #define VOLUME_STEP 4;
    #define LOW_STEP 4;
    #define HIGH_STEP 4;
    // стартовые значения
    #define START_VOLUME 20;
    #define START_LOW 50;
    #define START_HIGH 50;

    byte volume = START_VOLUME;
    byte low = START_LOW; // присвоим стартовые значения
    byte high = START_HIGH;
    ...

    void setup()
    {...
      digiPotInit(volume, low, high);
    ...}
    В данном случае идея проста - громкости должны меняться только с ИК пульта, начальные/стартовые значения мы указали (#define). Теперь у нас после выключения питания, значения громкостей всегда будут фиксированы. Все так? :)
    Теперь, для того чтобы прикрутить крутилки необходимо считать значения с них и передать на ЦП, как то так: ?
    Код (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()
    {
      POT_VOL = analogRead(VOL) / 8; // считываем значения крутилок (значения от 0 до 127)
      POT_LOW = analogRead(LOW) / 8;
      POT_HIGH = analogRead(HIGH) / 8;
      digiPotInit(volume, low, high);
    ...}
    Теперь у нас при старте Arduino каждый раз будут устанавливать значения с крутилок. Правильно?
    В принципе можно даже оставить и так :) как удобный способ выставления начального уровня громкостей. Но было бы круто и регулировать крутилками громкости :) Для этого нам нужно будет составить условие, в котором бы значение "POT_VOL" сравнивалось с значением в текущий момент времени, и если значения равны, то можно жмякать на кнопки пульта и регулировать громкости :)
    Но если значение изменилось относительно ранее установленных значений (в Setup), то мы должны считать текущее значение и отправить так же на ЦП (byte volume = ). При этом условие с ИК пультом уже не будет выполнятся. И так по кругу, каждый раз текущее значение с крутилки будет сравниваться с чуть ранее установленным значением, и если оно окажется равным, то мы сможем управлять с ИК-пульта, а иначе крутим ручку крутилки и изменяем громкости с неё. Фуф. Вроде бы ничего не упустил :) Я попробую составить код и выставить на Ваш суд. Если, конечно, не наврал.
    На счет EEPROM, вещь стоящая, с ней должно быть попроще, там просто должны будем значения, которые мы выставим с пульта, записывать каждый раз в память, чтобы после выключения питания эти значения там сохранились и относительно их продолжать регулировку. Так? Но я вычитал, здесь же на форуме про EEPROM, что память не долговечная
    Спасибо, Вам огромное за помощь и что не забываете меня ;)
    Вот в ближайшее время хочу спаять все 6 ЦП на платке (т.к. корпус SMD), как тестовый вариант и проверить.

    Я уже спрашивал на форуме, касательно ног RS и SHDN, но ради железного спокойствия -
    на них нужно подавать +5 В, не меньше и не больше, если бы я подал +15 В, я бы их сжег. Верно?
     
    Последнее редактирование: 2 ноя 2014