AD 7791 через SPI

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем Will_1990, 1 дек 2014.

  1. Will_1990

    Will_1990 Нуб

    Доброго времени суток, уважаемые участники форума!
    Пытаюсь наладить взаимодействие АЦП AD 7791 с Arduino UNO через SPI-интерфейс.
    Для этого подключил АЦП, как показано на схеме:
    [​IMG]
    Подключаю с помощью макетной платы и припаянных к ней DIP-ножек, которые вставлены в пины 8-13.
    [​IMG]

    Для взаимодействия между Ардуино и АЦП был написан следующий код:
    Код (Text):
    #include <SPI.h>
    const int CS = 10;
    const int MOSIpin = 11;
    const int statusRegister =0x000; //Адрес регистра статуса
    const int modeRegister =0x010; // Адрес регистра режима
    const int filterRegister =0x020; // Адрес регистра фильтра
    const int dataRegister =0x030; // Адрес регистра данных
    const int readOperation =0x008; // Адерс операции чтения для записи в коммуникационный регистр
    const int READ =0x0FF; // Команда чтения для передачи по SPI

    void setup()
    {
    Serial.begin(9600);//Запускаем работу СОМ-порта
    SPI.begin();// Запускаем библиотеку SPI:
    SPI.setBitOrder (MSBFIRST);
    SPI.setClockDivider(SPI_CLOCK_DIV128);
    SPI.setDataMode(SPI_MODE3);
    pinMode(CS, OUTPUT);// Устанавливаем режим работы пинов.:
    writeRegister (modeRegister,0x06); //Режим работы АЦП - Непрерывное преобразование, униполярный режим кодирования, буфер включен
    delay (10);
    writeRegister (filterRegister,0x03); // Режим работы фильтра- Частота тактования - обычная, частота преобразования - 20 Гц
    delay (10);
    delay (1000);
    }

    void loop()
    {int mode = readRegister (modeRegister,1);
    Serial.print ("mode=");
    Serial.println (mode);
    int filter = readRegister (filterRegister,1);
    Serial.print ("filter=");
    Serial.println (filter);
      long data = readRegister (dataRegister,3);
      Serial.print ("data=");
      Serial.println (data,BIN);
    Serial.println (data);


      delay (1000);
    }

    //Функция записи в регистр
    //Необходимо указать адрес регистра и значение, которое нужно в него записать
    void writeRegister(byte regAdress, byte value)
    {
      digitalWrite (CS, LOW); //Активируем АЦП
      SPI.transfer (regAdress); //Отправляем адрес регистра
      SPI.transfer (value); //Отправляем записываемое значение
      digitalWrite (CS, HIGH); // Деактивируем АЦП
    }

    // Функция чтения данных из регистра
    // Необходимо указать адрес регистра и количество считываемых байтов

    long readRegister (byte regAdress, int bytes)
    {
      long result=0; //Обнуляем значение возвращаемого результата
      digitalWrite (CS,LOW); //Активируем АЦП
      SPI.transfer (regAdress|readOperation); //Объединяем адрес регистра с командой чтения
    if (digitalRead (MOSIpin)==LOW) // Ждем, когда на выходе из АЦП будет низкий уровень
      {
      for (int i=0; i<bytes; i++) //Повторяем операцию для заданного количества байтов
        {
          byte inByte= SPI.transfer (READ); // Присваиваем входящему байту значение, полученное после отправки команды чтения
          result = result <<8|inByte; // Сдвигаем значение результата на 8 бит влево и присоединяяем к нему значение входящего байта
        }
      digitalWrite (CS, HIGH); // Деактивируем АЦП
      }
    return (result); // Возвращаем результата функции
    }
    В результате удалось записать данные в регистр фильтра АЦП и в регистр режима, а затем считать их. С регистром данных ничего толкового не получалось, но я не слишком беспокоился по этому поводу, поскольку ни опорное напряжение, ни аналоговые вводы не были подключены.
    Решил двигаться дальше и подключил питание и опорное напряжение к 5 В шины USB (как на схеме ниже)
    [​IMG]
    В результате следующее: при считывании данных из регистра фильтра и регистра режима получаем нули. Из регистра данных приходят случайные величины. Если же опорное напряжение отключить, то из регистров получаем значения по умолчанию (0 для регистра данных, 2 - для регистра режима, 4 - для регистра фильтра.

    Интересует следующее:
    1. В чем может заключаться моя ошибка?
    2. Имеет ли значение тот факт, что напряжение с USB-порта, которое я подаю, составляет 5В, а напряжение на выходи из 5V-порта Ардуино составляет 4,5 В?
    3. Правильно ли написана функция для чтения из регистра данных? Или же ее необходимо изменить, руководствуясь таймингами из даташита?

    Заранее благодарен!

    P.S.: Конструктивная критика и советы по улучшению схемы приветствуются! Это моя первая схема и по образованию я химик :)
     

    Вложения:

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

    Daniil Гуру

    В даташите таблица 4, реккомендуется подавать напряжения на Ref- и Ref+ так, чтобы разница уровней напряжений была равна 2.5 В.
    Я бы подал на Ref- землю, а на Ref+ 2.5 В, я пока обхожусь двумя резисторами для этого. В будущем, конечно, нужно фильтровать..
    Интересно приоритеты операций сдвига и ИЛИ.
    А еще есть опечатка по коду, которая не решит проблему, но все равно - регистр mode это 1 байт, а у Вас он считывается 6 раз.(2ой аргумент в функции чтения)
    То что просело напряжение питания на 500 мВ мне кажется это много. Может пайка привела к такому?(первый раз?). Я думаю стоит сделать делитель напряжения так, чтобы из 4.5 В получалось бы 2.5.
     
    Последнее редактирование: 3 дек 2014
  3. Unixon

    Unixon Оракул Модератор

    http://en.cppreference.com/w/cpp/language/operator_precedence
    Вообще, если нет полной уверенности - просто ставьте скобки.
     
    Daniil нравится это.
  4. Will_1990

    Will_1990 Нуб

    Unixon, спасибо за ссылку!
    Теперь по всему остальному. 4.5 В выдает сама Ардуина с источника опорного напряжения, установленного на ней. Дело в том, что высокие и низкие уровни должны быть на уровне земли или напряжения питания. А когда я подаю напряжение питания напрямую с USB-разъема (5v), то высокие уровни становятся ниже напряжения питания.
    Исходя из всего вышеизложенного, я решил подать напряжение питания 5В Ардуины, в качестве опороного напряжения взять 3,3 В с нее же. В результате схема заработала. Сегодня удалось запустить ее в паре с инструментальным операционным усилителем, подключенным к мостовой схеме. Наблюдались значения чисел, которые зависели от поворота ручки потенциометра.
    В тексте кода была опечатка. Перепутал местами шестерку с единицей. Записать нужно было значение 6 (00000110), а считать 1 байт. Опечатку исправил в самой теме.
    Побитовый сдвиг имеет более высокий приоритет, по сравнению с побитовым "ИЛИ", так что скобки не нужны.
     
  5. Will_1990

    Will_1990 Нуб

    И еще. Подскажите, пожалуйста, какую-либо программу для графического отображения данных, поступающих на COM-порт. Power Graph - аналог, но он платный.