Как подключить АЦП ADT7411 к Arduino
Для проекта нам понадобятся:
- АЦП ADT7411;
- Arduino или аналог;
- макетная плата;
- плата с микросхемой FT2232 (опционально);
- осциллограф или логический анализатор;
- набор резисторов;
- соединительные провода;
- компьютер со средой разработки Arduino IDE или иной.
1 Описание аналого-цифрового перобразователя ADT7411
Диапазон измеряемых напряжений АЦП – либо от 0 до 2,25 В, либо от 0 до напряжения питания. АЦП ADT7411 питается напряжением от 2,7 до 5,5 В. Встроенный датчик температуры позволяет измерять температуру в диапазоне от -40° до +120°C с точностью четверть градуса. Также имеется возможность подключить один внешний термодатчик.
Управление преобразователем возможно по цифровым последовательным интерфейсам SPI и I2C.
Назначение выводов микросхемы 7411 представлено на рисунке.
Название | Назначение | Примечание |
---|---|---|
AIN3…AIN8 | Однопроводные аналоговые входы. | Входное напряжение от 0 до 2,25 В или от 0 до VDD |
D+,D– / AIN1, AIN2 | Или подключение внешнего термодатчика, или однопроводные аналоговые входы. | |
VDD | Питание. | 2,7…5,5 В |
GND | Земля. | Общий провод для аналоговой и цифровой части схемы. |
CS | Выбор ведомого в режиме SPI. | В режиме I2C рекомендуется подтянуть к питанию. |
SCL/SCLK | Тактовая частота для последовательных интерфейсов. | Для выводов с открытым коллектором требуется подтягивающий резистор. |
SDA/DIN | Вход последовательных интерфейсов. | Для выводов с открытым коллектором требуется подтягивающий резистор. |
DOUT/ADD | Выход данных в режиме SPI / Изменение адреса в режиме I2C. | Для выводов с открытым коллектором требуется подтягивающий резистор. |
INT/INT | Конфигурируется на прерывание превышения температуры, напряжения на аналоговых входах или питания. | Для выводов с открытым коллектором требуется подтягивающий резистор. |
Внутренняя память устройства состоит из 255-ти регистров, которые показаны на рисунке ниже. Здесь присутствуют регистры конфигурации, статуса, информации о ревизии и производителе микросхемы, а также регистры показаний аналоговых каналов и термодатчиков. Некоторые из регистров мы чуть позже рассмотрим подробно, а на рисунке представлены адреса регистров, их названия и значения по умолчанию после подачи питания на ADT7411.
Начнём изучение с того, что подключим АЦП к отладочной плате с микросхемой FT2232H и с помощью программы SPI via FTDI изучим нюансы информационного обмена с данным АЦП, а затем на основе этих данных реализуем алгоритм на Arduino.
2 Подключение и работа микросхемы ADT7411 в режиме SPI
Подключение стандартное для SPI.
Питание 3,3 В подадим на ножку VDD, землю – на ножку GND. Импульсы синхронизации возьмём с ADBUS0 микросхемы FT2232H и подадим на ножку SCL/SCLK ADT7411. Выходные данные возьмём с ADBUS1 и подадим на SDA/DIN, а входные – с ADBUS2 и подадим на DOUT/ADD. Сигнал выбора ведомого будет подан с ADBUS3 на CS. На канал AIN6 (1-ую ножку микросхемы) подадим 3,3 В для тестирования аналогового канала АЦП.
Вывод ADT7411 | Вывод FT2232H |
---|---|
SCL/SCLK | ADBUS0 |
SDA/DIN | ADBUS1 |
DOUT/ADD | ADBUS2 |
CS | ADBUS3 |
GND | GND |
AIN6 | 3.3 V |
Теперь запустим программу SPI via FTDI, в меню «Устройство» выберем интерфейс SPI. Подключимся к микросхеме через меню "Устройство" или щёлкнув по вкладке устройства правой кнопкой мыши. Настройки режима должны быть как на скриншоте ниже. В поле записи наберём команду 90 4D и трижды нажмём кнопку «Записать».
Почему трижды? Дело в том, что АЦП ADT7411 при подаче питания находится в режиме I2C. Чтобы перевести его в режим SPI, необходимо сгенерировать на его ножке CS три импульса с активным низким уровнем. Трижды посланная команда сделает в том числе как раз это.
Команда 0x90 показывает микросхеме ADT7411, что далее мы будем передавать ей данные, 0x4D – это передаваемые данные, а именно – адрес регистра DeviceID.
После этого в поле чтения наберём команду 91 (поставив галку «Команда») и число байт для чтения – 3. Откроем окно для вывода результата (кнопка в виде таблицы) и нажмём кнопку «Прочитать». В открытом окне должны появиться значения 3-х прочитанных регистров.
Обратите внимание, что каждая команда АЦП ADT7411 предваряется кодом 0x90, если мы собираемся записывать данные, и кодом 0x91, если будем запрашивать данные от АЦП.
В данном примере нам вернулись 3 байта: 0x02, 0x41, 0x05. Если заглянем в техническое описание (datasheet, находится в приложении к статье), то увидим, что так и должно быть: 0x02 – это постоянный идентификатор АЦП 7411, 0x41 – постоянный идентификатор производителя, а версия кристалла может меняться, и в данном случае она 5-ая. Значит, устройство работоспособное и подключено правильно.
Проведём конфигурирование АЦП. Дело в том, что АЦП ADT7411 может измерять в двух режимах: по запросу и непрерывно (т.н. режим round-robin). При подаче питания АЦП входит в режим непрерывных измерений, но он не активен. Его нужно активировать. Кроме того, нужно задать ещё несколько настроек.
Для этого (в разделе «Запись») нужно записать в три конфигурационных регистра (с адресами 18, 19 и 1A) определённые настройки. Это делается путём отправки устройству последовательности команд:
Команда | Расшифровка | Пояснение |
---|---|---|
90 18 08 | Записываем по адресу 18 значение 08. | Остановка опроса каналов, выводы 7 и 8 работают как AIN1 и AIN2, включение прерываний активным низким, вывод устройства из режима ожидания. |
90 19 00 | Записываем по адресу 19 значение 00. | Включаем непрерывный режим измерений и усреднение по 16-ти измерениям. |
90 1A 19 | Записываем по адресу 1A значение 19. | Быстрое измерение (частота 22,5 кГц), VDD используется как опорный уровень напряжения. |
Почему мы отправляем именно такие значения в регистры? Каждый бит в 8-битовом числе представляет собой определённый параметр. Присваивая биту значение «1» или «0», мы включаем или выключаем эти параметры. Некоторые параметры могут кодироваться не одним, а несколькими битами. Более подробно показано на рисунке ниже, а также в техническом описании ADT7411, которое можно скачать в приложении к статье.
Для запуска измерений подадим команду 90 18 01. После этого АЦП запустит непрерывный цикл измерений.
Теперь прочитаем значения регистров устройства. Для этого сначала запишем (в разделе «Запись») адрес 0-го регистра: 90 00, а затем прочитаем 64 байта, указав команду 91 и число байтов для чтения – 64.
В окне принимаемых значений отобразится 64 байта, которые нам вернул АЦП ADT7411. Это значения его 64-х регистров. Давайте посмотрим, что нам вернулось.
Значение встроенного термодатчика содержится в регистрах с адресами 0x03 и 0x07, а данные аналогового входа AIN6 – в регистрах с адресами 0x05 и 0x0D.
В соответствии со скриншотом выше, в регистре 3 содержится значение 0x0B (или 0000_1011 в двоичном виде), в регистре 7 содержится значение 0x1C (или 0001_1100 в двоичном виде). Для ясности можно записать в таблицу:
Регистр 0x03 | Регистр 0x07 | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
- | - | - | - | - | - | T1 | T0 | T9 | T8 | T7 | T6 | T5 | T4 | T3 | T2 |
0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
Соединив все разряды с T9 (старший разряд) по T0 (младший), получается, что значение внутреннего термодатчика в двоичном виде 00_0111_0011 или 115 в десятичном виде. Это код температуры. Для перевода кода температуры в градусы Цельсия:
- t = T × 0,25 если разряд T9 равен "0" (признак, что температура выше нуля);
- t = (T – 1024) × 0,25 если разряд T9 равен "1" (признак, что температура отрицательная).
Здесь T – код температуры АЦП, t – значение температуры в градусах Цельсия, коэффициент 0,25 – число градусов Цельсия на один разряд АЦП, 1024 – это 210 – максимум шкалы для 10-разрядного АЦП.
В нашем случае разряд T9 равен нулю, поэтому температура в градусах Цельсия положительна и равна 115×0,25 = 28,75°C
Теперь переведём измерения напряжения из кода АЦП в вольты. Составим аналогичную таблицу. Значение регистра 0x5 – 0x73 (или 0111_0011 в двоичном виде), значение регистра 0xD – 0xD0 (или 1101_0000 в двоичном виде).
Регистр 0x05 | Регистр 0x0D | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
- | - | - | - | A1 | A0 | - | - | A9 | A8 | A7 | A6 | A5 | A4 | A3 | A2 |
0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
Из разрядов A9…A0 получаем значение на аналоговом входе AIN6: 11_0100_0000 или 832 в десятичном виде. Для перевода кода напряжения UADC в вольты U: U = UADC × Vref / 1024 = 832×3,3 / 1024 = 2,68 В
Здесь Vref – опорное напряжение, равное напряжению питания чипа ADT7411 в вашей схеме, 1024 – опять же, максимальное значение 10-разрядного АЦП.
Расшифровку остальных регистров можно посмотреть в техническом описании АЦП и сейчас рассматривать не будем.
Теперь можно написать скетч для Arduino, который будет делать то же самое: определять температуру внутреннего термодатчика АЦП ADT7411 и напряжение на входе AIN6.
Скетч управления АЦП ADT7411 по SPI (разворачивается)
#include <SPI.h> const byte WRITE = 0x90; // команда записи const byte READ = 0x91; // команда чтения const float Vref = 3.3; // опорное напряжение равно напряжению питания АЦП void setup() { Serial.begin(9600); SPI.begin(); pinMode(SS, OUTPUT); delay(100); // задержка на время самопроверки АЦП ADT7411 lockSpiMode(); readSpiLockStatus(); readIds(); initAdt7411(); startMonitoring(); } void loop() { byte regs[64]; readAll(regs); float internalTemperature = getTemperature(regs); Serial.println("t=" + (String)internalTemperature); float ain6 = getAin6(regs); Serial.println("AIN6=" + (String)ain6); Serial.println(); delay(1000); } // Читает регистр режима SPI/I2C. byte readSpiLockStatus(){ byte regs[1]; readRegister(0x7f, 1, regs); if (regs[0] & 1 == 1){ Serial.println("Mode: SPI"); } else { Serial.println("Mode: I2C"); } } // Читает всю карту регистров АЦП ADT7411. void readAll(byte regs[]){ readRegister(0x00, 64, regs); for (int i=0; i<64; i++){ Serial.print(String(regs[i],HEX) + " "); } Serial.println(); } // Переводит АЦП ADT7411 в режим SPI. void lockSpiMode(){ for (int i=0; i<3; i++){ digitalWrite(SS, LOW); digitalWrite(SS, HIGH); } } // Инициализация АЦП ADT7411. void initAdt7411(){ byte conf[] = {0x08, 0x00, 0x19}; // значения конфигурационных регистров writeRegister(0x18, &conf[0], 1); writeRegister(0x19, &conf[1], 1); writeRegister(0x1A, &conf[2], 1); } // Читает идентификаторы и выводит в монитор последовательного порта. void readIds(){ byte ids[3]; readRegister(0x4D, 3, ids); Serial.println("Device ID = " + (String)ids[0]); Serial.println("Manufacturer ID = 0x" + String(ids[1], HEX)); Serial.println("Silicon revision = " + (String)ids[2]); Serial.println(); } // Запускает измерения. void startMonitoring(){ byte conf[1] = {0x01}; writeRegister(0x18, conf, 1); } // Читает температуру и переводит в градусы. float getTemperature(byte regs[]){ int tempCode = (regs[3] & B11) | (regs[7] << 2); if ((tempCode >> 10) & 1 == 1){ // 11-ый бит ==1 - признак отрицательной температуры tempCode -= 1024; } return tempCode * 0.25; } // Читает показания на входе AIN6 и переводит в вольты. float getAin6(byte regs[]){ int uadc = ((regs[5] >> 2) & B11) | (regs[0x0D] << 2); return uadc * Vref / 1024; } // Читает массив байтов заданной длины, начиная с заданного адреса. void readRegister(byte address, int len, byte out[]) { // записываем адрес: digitalWrite(SS, LOW); SPI.transfer(WRITE); SPI.transfer(address); digitalWrite(SS, HIGH); // читаем, начиная с этого адреса: digitalWrite(SS, LOW); SPI.transfer(READ); for(int i=0; i<len; i++){ out[i] = SPI.transfer(00); } digitalWrite(SS, HIGH); } // Записывает в регистр массив байтов, начиная с заданного адреса: void writeRegister(byte address, byte value[], int len) { digitalWrite(SS, LOW); SPI.transfer(WRITE); SPI.transfer(address); for(int i=0; i<len; i++){ SPI.transfer(value[i]); } digitalWrite(SS, HIGH); }
В результате загрузки данного скетча в память Ардуино, в мониторе последовательного порта будет примерно следующее:
Пример временной диаграммы запроса и чтения регистров идентификаторов устройства, производителя и версии чипа приведена на рисунке:
Полную временную диаграмму работы скетча можно скачать в приложении к статье. Она открывается бесплатной программой Saleae Logic 2.
Разумеется, это лишь пример, демонстрирующий основы работы с данным АЦП по интерфейсу SPI, содержащий однако все необходимые для обмена с микросхемой функции.
3 Подключение и работа микросхемы ADT7411 в режиме I2C
Теперь сделаем то же самое, только управлять АЦП будем по шине I2C (или IIC). Здесь есть несколько нюансов.
АЦП подключается по следующей схеме.
Питание 3,3 В подадим на ножку VDD, землю – на ножку GND. Импульсы синхронизации возьмём с ADBUS0 микросхемы FT2232H и подадим на ножку SCL/SCLK ADT7411 (обратите внимание, через резистор ~10 кОм). Данные возьмём с ADBUS1 и подадим на SDA/DIN (тоже через аналогичный резистор). Кроме того, вывод ADBUS2 также нужно подать на SDA/DIN (особенность работы микросхем FTDI в режиме I2C). Ножку CS подтянем к питанию. На канал AIN6 подадим 3,3 В для тестирования аналогового канала АЦП.
Ножку ADD можно подключить либо к земле, либо к питанию. Это влияет на то, каким будет адрес устройства на шине I2C. При подключении к земле адрес будет 72, при подключении к питанию – 75.
Вывод ADT7411 | Вывод FT2232H |
---|---|
SCL/SCLK | ADBUS0 |
SDA/DIN | ADBUS1 и ADBUS2 |
DOUT/ADD | VDD или GND |
CS | VDD |
GND | GND |
AIN6 | Источник напряжения от 0 до VDD |
При обмене по шине I2C АЦП может передавать только по одному байту. Ведущее устройство (мастер) сначала должно передать АЦП адрес интересующего регистра и затем прочитать ответ от АЦП. Например, чтобы прочитать значение регистра DeviceID, нужно передать АЦП адрес 0x4D, а затем вычитать 1 байт. Но вот от мастера ведомому можно передавать несколько байтов.
Запустим программу SPI via FTDI, переключимся в режим I2C (меню «Устройство» – «Интерфейс» – I2C). Оставим настройки по умолчанию. Просканируем шину I2C. При правильно собранной схеме програма обнаружит на шине одно устройство и добавит его в выпадающий список. Выберем его. Укажем в поле записи адрес 4D и нажмём кнопку «Записать». Далее в поле чтения укажем количество байт – 1 – и нажмём кнопку «Прочитать». В окне принятых результатов должно появиться число 2. Это и есть постоянное значение регистра DeviceID, как мы уже знаем.
Совершенно аналогично будет проводиться запись и чтение и в другие регистры. Например, для записи в конфигурационный регистр 0x18 значения 0x08 осуществляется так:
Соответственно, перепишем скетч на применение интерфейса IIC. Это потребует минимальных изменений.
Скетч управления АЦП ADT7411 по I2C (разворачивается)
#include <Wire.h> const float Vref = 3.3; // опорное напряжение равно напряжению питания const byte I2C_ADDR = 75; // адрес АЦП ADT7411 на шине I2C при подтяжке вывода ADD к питанию void setup() { Serial.begin(9600); Wire.begin(); delay(100); // задержка на время самопроверки АЦП ADT7411 readIds(); readSpiLockStatus(); initAdt7411(); startMonitoring(); } void loop(){ float internalTemperature = getTemperature(); Serial.println("t=" + (String)internalTemperature); float ain6 = getAin6(); Serial.println("AIN6=" + (String)ain6); Serial.println(); delay(1000); } // Читает регистр режима SPI/I2C. byte readSpiLockStatus(){ byte reg = readRegister(0x7f); if (reg & 1 == 1){ Serial.println("Mode: SPI"); } else { Serial.println("Mode: I2C"); } } // Инициализация АЦП ADT7411. void initAdt7411(){ byte conf[] = {0x08, 0x00, 0x19}; // значения конфигурационных регистров writeRegister(0x18, &conf[0], 1); writeRegister(0x19, &conf[1], 1); writeRegister(0x1A, &conf[2], 1); } // Читает идентификаторы и выводит в монитор последовательного порта. void readIds(){ byte devId = readRegister(0x4D); Serial.println("Device ID = " + (String)devId); byte manId = readRegister(0x4E); Serial.println("Manufacturer ID = 0x" + String(manId, HEX)); byte rev = readRegister(0x4F); Serial.println("Silicon revision = " + (String)rev); Serial.println(); } // Запускает измерения. void startMonitoring(){ byte conf[1] = {0x01}; writeRegister(0x18, conf, 1); } // Читает температуру и переводит в градусы. float getTemperature(){ byte reg3 = readRegister(0x03); byte reg7 = readRegister(0x07); int tempCode = (reg3 & B11) | (reg7 << 2); if ((tempCode >> 10) & 1 == 1){ // отрицательная температура tempCode -= 1024; } return tempCode * 0.25; } // Читает показания на входе AIN6 и переводит в вольты. float getAin6(){ byte reg5 = readRegister(0x05); byte regD = readRegister(0x0D); int uadc = ((reg5 >> 2) & B11) | (regD << 2); return uadc * Vref / 1024; } // Читает значение регистра с адресом addr. byte readRegister(byte addr) { // Записывает адрес регистра: Wire.beginTransmission(I2C_ADDR); Wire.write(addr); Wire.endTransmission(); // Запрашивает из регистра данные: Wire.requestFrom(I2C_ADDR, 1); byte result; while (Wire.available()) { result = Wire.read(); } return result; } // Записывает в регистр массив байтов value заданной длины len, начиная с заданного адреса address: void writeRegister(byte address, byte value[], int len) { Wire.beginTransmission(I2C_ADDR); Wire.write(address); for(int i=0; i<len; i++){ Wire.write(value[i]); } Wire.endTransmission(); }
При подключении АЦП к Arduino, нужно также помнить, что у Arduino выводы для I2C: SDA – аналоговый вывод A4, а SCL – A5.
Временная диаграмма опроса регистров идентификаторов представлена на рисунке, а полная диаграмма – в приложении к статье.
Итак, мы научились управлять АЦП ADT7411 без использования специальных библиотек с помощью Arduino по интерфейсам SPI и I2C.
☆∘☆∘☆
Download attachments:
- Скачать datasheet на АЦП ADT7411 (542 Downloads)
- Временная диаграмма работы скетча SPI (343 Downloads)
- Временная диаграмма работы скетча i2c (315 Downloads)