Доброго времени суток, уважаемые участники форума! Пытаюсь наладить взаимодействие АЦП AD 7791 с Arduino UNO через SPI-интерфейс. Для этого подключил АЦП, как показано на схеме: Подключаю с помощью макетной платы и припаянных к ней DIP-ножек, которые вставлены в пины 8-13. Для взаимодействия между Ардуино и АЦП был написан следующий код: Код (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 (как на схеме ниже) В результате следующее: при считывании данных из регистра фильтра и регистра режима получаем нули. Из регистра данных приходят случайные величины. Если же опорное напряжение отключить, то из регистров получаем значения по умолчанию (0 для регистра данных, 2 - для регистра режима, 4 - для регистра фильтра. Интересует следующее: 1. В чем может заключаться моя ошибка? 2. Имеет ли значение тот факт, что напряжение с USB-порта, которое я подаю, составляет 5В, а напряжение на выходи из 5V-порта Ардуино составляет 4,5 В? 3. Правильно ли написана функция для чтения из регистра данных? Или же ее необходимо изменить, руководствуясь таймингами из даташита? Заранее благодарен! P.S.: Конструктивная критика и советы по улучшению схемы приветствуются! Это моя первая схема и по образованию я химик
В даташите таблица 4, реккомендуется подавать напряжения на Ref- и Ref+ так, чтобы разница уровней напряжений была равна 2.5 В. Я бы подал на Ref- землю, а на Ref+ 2.5 В, я пока обхожусь двумя резисторами для этого. В будущем, конечно, нужно фильтровать.. Интересно приоритеты операций сдвига и ИЛИ. А еще есть опечатка по коду, которая не решит проблему, но все равно - регистр mode это 1 байт, а у Вас он считывается 6 раз.(2ой аргумент в функции чтения) То что просело напряжение питания на 500 мВ мне кажется это много. Может пайка привела к такому?(первый раз?). Я думаю стоит сделать делитель напряжения так, чтобы из 4.5 В получалось бы 2.5.
http://en.cppreference.com/w/cpp/language/operator_precedence Вообще, если нет полной уверенности - просто ставьте скобки.
Unixon, спасибо за ссылку! Теперь по всему остальному. 4.5 В выдает сама Ардуина с источника опорного напряжения, установленного на ней. Дело в том, что высокие и низкие уровни должны быть на уровне земли или напряжения питания. А когда я подаю напряжение питания напрямую с USB-разъема (5v), то высокие уровни становятся ниже напряжения питания. Исходя из всего вышеизложенного, я решил подать напряжение питания 5В Ардуины, в качестве опороного напряжения взять 3,3 В с нее же. В результате схема заработала. Сегодня удалось запустить ее в паре с инструментальным операционным усилителем, подключенным к мостовой схеме. Наблюдались значения чисел, которые зависели от поворота ручки потенциометра. В тексте кода была опечатка. Перепутал местами шестерку с единицей. Записать нужно было значение 6 (00000110), а считать 1 байт. Опечатку исправил в самой теме. Побитовый сдвиг имеет более высокий приоритет, по сравнению с побитовым "ИЛИ", так что скобки не нужны.
И еще. Подскажите, пожалуйста, какую-либо программу для графического отображения данных, поступающих на COM-порт. Power Graph - аналог, но он платный.