Рейтинг@Mail.ru

Как подключить АЦП ADT7411 к Arduino

автор:
Be the first to comment! Arduino
Print Friendly, PDF & Email
Аналогово-цифровой преобразователь ADT7411 фирмы Analog Devices совмещает в себе 8-канальный 10-разрядный АЦП со встроенным термодатчиком. Научимся подключать его и считывать показания по интерфейсам SPI и I2C с помощью Arduino и микросхемы FT2232/FT2242.

Для проекта нам понадобятся:

1 Описание аналого-цифрового перобразователя ADT7411

Диапазон измеряемых напряжений АЦП – либо от 0 до 2,25 В, либо от 0 до напряжения питания. АЦП ADT7411 питается напряжением от 2,7 до 5,5 В. Встроенный датчик температуры позволяет измерять температуру в диапазоне от -40° до +120°C с точностью четверть градуса. Также имеется возможность подключить один внешний термодатчик.

Управление преобразователем возможно по цифровым последовательным интерфейсам SPI и I2C.

Назначение выводов микросхемы 7411 представлено на рисунке.

Назначение выводов АЦП ADT7411
Назначение выводов АЦП ADT7411
Назначение выводов АЦП ADT7411
НазваниеНазначениеПримечание
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.

Структура конфигурационного регистра 0x18 АЦП ADT7411
Структура конфигурационного регистра 0x18 АЦП ADT7411
Структура конфигурационного регистра 0x19 АЦП ADT7411
Структура конфигурационного регистра 0x19 АЦП ADT7411
Структура конфигурационного регистра 0x1A АЦП ADT7411
Структура конфигурационного регистра 0x1A АЦП ADT7411

Начнём изучение с того, что подключим АЦП к отладочной плате с микросхемой FT2232H и с помощью программы SPI via FTDI изучим нюансы информационного обмена с данным АЦП, а затем на основе этих данных реализуем алгоритм на Arduino.

2 Подключение и работа микросхемы ADT7411 в режиме SPI

Подключение стандартное для SPI.

Типичная схема подключения ADT7411 в режиме SPI
Типичная схема подключения ADT7411 в режиме SPI
Подключение АЦП ADT7411 к плате с FT2232H
Подключение АЦП ADT7411 к плате с FT2232H

Питание 3,3 В подадим на ножку VDD, землю – на ножку GND. Импульсы синхронизации возьмём с ADBUS0 микросхемы FT2232H и подадим на ножку SCL/SCLK ADT7411. Выходные данные возьмём с ADBUS1 и подадим на SDA/DIN, а входные – с ADBUS2 и подадим на DOUT/ADD. Сигнал выбора ведомого будет подан с ADBUS3 на CS. На канал AIN6 (1-ую ножку микросхемы) подадим 3,3 В для тестирования аналогового канала АЦП.

Подключение ADT7411 к FT2232
Вывод ADT7411Вывод FT2232H
SCL/SCLKADBUS0
SDA/DIN ADBUS1
DOUT/ADDADBUS2
CSADBUS3
GNDGND
AIN63.3 V

Теперь запустим программу SPI via FTDI, в меню «Устройство» выберем интерфейс SPI. Подключимся к микросхеме через меню "Устройство" или щёлкнув по вкладке устройства правой кнопкой мыши. Настройки режима должны быть как на скриншоте ниже. В поле записи наберём команду 90 4D и трижды нажмём кнопку «Записать».

Почему трижды? Дело в том, что АЦП ADT7411 при подаче питания находится в режиме I2C. Чтобы перевести его в режим SPI, необходимо сгенерировать на его ножке CS три импульса с активным низким уровнем. Трижды посланная команда сделает в том числе как раз это.

Команда 0x90 показывает микросхеме ADT7411, что далее мы будем передавать ей данные, 0x4D – это передаваемые данные, а именно – адрес регистра DeviceID.

Чтение идентификатора устройства, кода производителя и версии микросхемы ADT7411
Чтение идентификатора устройства, кода производителя и версии микросхемы ADT7411

После этого в поле чтения наберём команду 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, которое можно скачать в приложении к статье.

Структура конфигурационного регистра 0x18 АЦП ADT7411
Структура конфигурационного регистра 0x18 АЦП ADT7411
Структура конфигурационного регистра 0x19 АЦП ADT7411
Структура конфигурационного регистра 0x19 АЦП ADT7411
Структура конфигурационного регистра 0x1A АЦП ADT7411
Структура конфигурационного регистра 0x1A АЦП ADT7411

Для запуска измерений подадим команду 90 18 01. После этого АЦП запустит непрерывный цикл измерений.

Теперь прочитаем значения регистров устройства. Для этого сначала запишем (в разделе «Запись») адрес 0-го регистра: 90 00, а затем прочитаем 64 байта, указав команду 91 и число байтов для чтения – 64.

Чтение карты регистров АЦП ADT7411 по SPI
Чтение карты регистров АЦП ADT7411 по SPI

В окне принимаемых значений отобразится 64 байта, которые нам вернул АЦП ADT7411. Это значения его 64-х регистров. Давайте посмотрим, что нам вернулось.

Значение встроенного термодатчика содержится в регистрах с адресами 0x03 и 0x07, а данные аналогового входа AIN6 – в регистрах с адресами 0x05 и 0x0D.

В соответствии со скриншотом выше, в регистре 3 содержится значение 0x0B (или 0000_1011 в двоичном виде), в регистре 7 содержится значение 0x1C (или 0001_1100 в двоичном виде). Для ясности можно записать в таблицу:

Регистр 0x03Регистр 0x07
D7D6D5D4D3D2D1D0 D7D6D5D4D3D2D1D0
------T1T0 T9T8T7T6T5T4T3T2
00001011 00011100

Соединив все разряды с 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
D7D6D5D4D3D2D1D0 D7D6D5D4D3D2D1D0
----A1A0-- A9A8A7A6A5A4A3A2
01110011 11010000

Из разрядов 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);
}    

В результате загрузки данного скетча в память Ардуино, в мониторе последовательного порта будет примерно следующее:

Чтение показаний АЦП ADT7411 по SPI
Чтение показаний АЦП ADT7411 по SPI

Пример временной диаграммы запроса и чтения регистров идентификаторов устройства, производителя и версии чипа приведена на рисунке:

Диаграмма чтения регистров ID АЦП ADT7411 по SPI
Диаграмма чтения регистров ID АЦП ADT7411 по SPI

Полную временную диаграмму работы скетча можно скачать в приложении к статье. Она открывается бесплатной программой Saleae Logic 2.

Разумеется, это лишь пример, демонстрирующий основы работы с данным АЦП по интерфейсу SPI, содержащий однако все необходимые для обмена с микросхемой функции.

3 Подключение и работа микросхемы ADT7411 в режиме I2C

Теперь сделаем то же самое, только управлять АЦП будем по шине I2C (или IIC). Здесь есть несколько нюансов.

АЦП подключается по следующей схеме.

Типичная схема подключения ADT7411 в режиме I2C
Типичная схема подключения ADT7411 в режиме I2C

Питание 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 в режиме I2C
Вывод ADT7411Вывод FT2232H
SCL/SCLKADBUS0
SDA/DIN ADBUS1 и ADBUS2
DOUT/ADDVDD или GND
CSVDD
GNDGND
AIN6Источник напряжения от 0 до VDD

При обмене по шине I2C АЦП может передавать только по одному байту. Ведущее устройство (мастер) сначала должно передать АЦП адрес интересующего регистра и затем прочитать ответ от АЦП. Например, чтобы прочитать значение регистра DeviceID, нужно передать АЦП адрес 0x4D, а затем вычитать 1 байт. Но вот от мастера ведомому можно передавать несколько байтов.

Запустим программу SPI via FTDI, переключимся в режим I2C (меню «Устройство» – «Интерфейс» – I2C). Оставим настройки по умолчанию. Просканируем шину I2C. При правильно собранной схеме програма обнаружит на шине одно устройство и добавит его в выпадающий список. Выберем его. Укажем в поле записи адрес 4D и нажмём кнопку «Записать». Далее в поле чтения укажем количество байт – 1 – и нажмём кнопку «Прочитать». В окне принятых результатов должно появиться число 2. Это и есть постоянное значение регистра DeviceID, как мы уже знаем.

Чтение регистров идентификаторов АЦП ADT7411 в режиме I2C
Чтение регистров идентификаторов АЦП ADT7411 в режиме I2C

Совершенно аналогично будет проводиться запись и чтение и в другие регистры. Например, для записи в конфигурационный регистр 0x18 значения 0x08 осуществляется так:

Запись в регистр конфигурации 0x18 АЦП ADT7411 в режиме I2C
Запись в регистр конфигурации 0x18 АЦП ADT7411 в режиме I2C

Соответственно, перепишем скетч на применение интерфейса 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 в режиме I2C
Подключение АЦП ADT7411 к Arduino в режиме I2C

Временная диаграмма опроса регистров идентификаторов представлена на рисунке, а полная диаграмма – в приложении к статье.

Временная диаграмма чтения регистров идентификаторов АЦП ADT7411 в режиме I2C
Временная диаграмма чтения регистров идентификаторов АЦП ADT7411 в режиме I2C

Итак, мы научились управлять АЦП ADT7411 без использования специальных библиотек с помощью Arduino по интерфейсам SPI и I2C.

☆∘☆∘☆

Last modified onЧетверг, 28 Июль 2022 22:40 Read 1936 times
Ключевые слова: :

Поблагодарить автора:

Поделиться

Print Friendly, PDF & Email

Leave a comment

  1. Arduino это...
  2. Arduino это...
  3. Arduino это...
Отличный способ начать знакомство с электроникой, микроконтроллерами и программированием!
Замечательное средство для создания собственных электронных устройств, которые пригодятся в быту или для развлечения!
Уникальный конструктор, для которого разработаны десятки совместимых датчиков и модулей!
next
prev