Все мы знаем, что микроконтроллеры умеют работать только с цифровыми значениями, однако в реальном мире нам приходится иметь дело с налоговыми сигналами. Поэтому для того, чтобы микроконтроллеры могли обрабатывать эти сигналы, их необходимо преобразовать в цифровую форму с помощью аналогово-цифрового преобразователя (АЦП). В английском языке они называются ADC — Analog to Digital Converter. Но если цифровые значения, хранящиеся в микроконтроллерах, необходимо конвертировать в аналоговую форму, используются цифро-аналоговые преобразователи (ЦАП). В английском языке они называются DAC — Digital to Analog Converter.
Простейшим примером необходимости использования ЦАП является воспроизведение какой-либо песни, хранящейся в цифровой форме. В свое время певец записал песню в студии используя микрофон. Затем эта песня была преобразована в цифровой формат и хранилась в виде файла с цифровыми данными. Чтобы затем воспроизвести эту песню в аналоговом виде с цифрового носителя данных и нужен ЦАП.
Цифро-аналоговые преобразователи (ЦАП) могут использоваться в различных приложениях, например, для управления двигателями и яркостью свечения светодиодов, в аудио усилителях, в видео-кодерах и т.п.
Во многих микроконтроллерах есть встроенные ЦАП, однако в платах Arduino, построенных на основе микроконтроллеров ATmega328/ATmega168, нет встроенного ЦАП (хотя есть АЦП). Поэтому в данной статье мы рассмотрим подключение цифро-аналогового преобразователя (ЦАП) MCP4725 к плате Arduino. Данную статью можно считать пособием для начинающих по использованию цифро-аналогового преобразования в Arduino.
Необходимые компоненты
- Плата Arduino Uno или Arduino Nano (купить на AliExpress).
- MCP4725 DAC IC (микросхема цифро-аналогового преобразователя) (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Потенциометр 10 кОм — 2 шт. (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
MCP4725 DAC Module (модуль цифро-аналогового преобразователя)
Микросхема (IC) MCP4725 представляет собой 12-битный ЦАП и используется для формирования аналогового сигнала в диапазоне от 0 до 5V. Взаимодействие с MCP4725 осуществляется по протоколу I2C. Также микросхема MCP4725 имеет в своем составе энергонезависимую память EEPROM.
ЦАП MCP4725 имеет разрешение 12 бит, то есть он может оперировать со значениями от 0 до 4096. С помощью этих значений на его выходе можно формировать аналоговое напряжение по отношению к опорному напряжению. Максимальное опорное напряжение для него составляет 5V.
Формула для расчета напряжения на его выходе выглядит следующим образом:
O/P Voltage = (Reference Voltage / Resolution) x Digital Value
Reference Voltage – опорное напряжение;
Resolution – разрешение (разрешающая способность) ЦАП;
Digital Value – цифровое значение.
К примеру, пусть мы используем опорное напряжение 5V, рассчитаем напряжение на выходе ЦАП для цифрового значения равного 2048:
O/P Voltage = (5/ 4096) x 2048 = 2.5V
Назначение контактов (распиновка) MCP4725
На следующих рисунке и таблице представлено назначение контактов ЦАП MCP4725.
Контакты ЦАП MCP4725 | Их назначение |
OUT | выходное аналоговое напряжение |
GND | земля для выходного аналогового напряжения |
SCL | линия синхронизация протокола I2C |
SDA | линия передачи данных протокола I2C |
VCC | входное опорное напряжение 5V или 3.3V |
GND | земля для опорного напряжения |
Интерфейс I2C в ЦАП MCP4725
Микросхемой ЦАП MCP4725 можно управлять с любого микроконтроллера используя интерфейс (протокол) I2C. Для функционирования протокола I2C необходимо только два провода (линии) — SCL и SDA. По умолчанию I2C адрес для MCP4725 равен 0x60, 0x61 или 0x62. В нашем варианте — 0x61. Используя шину I2C можно объединить несколько микросхем MCP4725, но в этом случае необходимо будет изменить их адреса. Более подробно работа с протоколом I2C в плате Arduino описана в следующей статье, здесь не будем на ней подробно останавливаться.
В этом проекте мы будем соединять микросхему ЦАП MCP4725 с платой Arduino. Аналоговое входное напряжение, регулируемое с помощью потенциометра, будет подаваться на аналоговый контакт A0 платы Arduino. Затем с помощью встроенного в плату АЦП это аналоговое напряжение будет преобразовываться в цифровую форму. Затем это цифровое значение будет передаваться к микросхеме MCP4725 через шину I2C и в ЦАП MCP4725 оно будет преобразовываться в аналоговую форму. Контакт A1 платы Arduino будет использоваться для проверки сигнала с аналогового выхода MCP4725. Затем значения с АЦП и ЦАП будут отображаться на экране ЖК дисплея.
Схема проекта
Схема подключения цифро-аналогового преобразователя (ЦАП) MCP4725 к плате Arduino представлена на следующем рисунке.
MCP4725 | Arduino Nano | Мультиметр |
SDA | A4 | NC |
SCL | A5 | NC |
A0 или OUT | A1 | +ve terminal |
GND | GND | -ve terminal |
VCC | 5V | NC |
Соединения между ЖК дисплеем 16×2 и платой Arduino Nano представлены в следующей таблице.
ЖК дисплей 16×2 | Плата Arduino Nano |
VSS | GND |
VDD | +5V |
V0 | к центральному контакту потенциометра для регулировка контрастности ЖК дисплея |
RS | D2 |
RW | GND |
E | D3 |
D4 | D4 |
D5 | D5 |
D6 | D6 |
D7 | D7 |
A | +5V |
K | GND |
Центральный контакт потенциометра подключен к аналоговому контакту A0 платы Arduino Nano, остальные два его контакта подключены к питанию и земле соответственно.
Объяснение программы для Arduino
Вначале в программе нам необходимо подключить библиотеки для работы с протоколом I2C (wire.h) и ЖК дисплеем (liquidcrystal.h).
1 2 |
#include<Wire.h> #include <LiquidCrystal.h> |
Затем необходимо сообщить плате Arduino контакты, к которым подключен ЖК дисплей.
1 |
LiquidCrystal lcd(2,3,4,5,6,7); //Define LCD display pins RS,E,D4,D5,D6,D7 |
Затем необходимо инициализировать адрес I2C для микросхемы ЦАП MCP4725.
1 |
#define MCP4725 0x61 |
Далее в функции void setup() необходимо инициализировать связь по протоколу I2C на контактах A4 (SDA) и A5 (SCL) платы Arduino Nano.
1 |
Wire.begin(); //Begins the I2C communication |
Затем мы зададим режим 16×2 для ЖК дисплея и покажем на его экране приветственное сообщение.
1 2 3 4 5 6 7 8 9 10 |
lcd.begin(16,2); //Sets LCD in 16X2 Mode lcd.print("CIRCUIT DIGEST"); delay(1000); lcd.clear(); lcd.setCursor(0,0); lcd.print("Arduino"); lcd.setCursor(0,1); lcd.print("DAC with MCP4725"); delay(2000); lcd.clear(); |
В функции void loop()
1. Запишем в buffer[0] значение контрольного байта (0b01000000). 010 – переводит MCP4725 в режим записи.
1 |
buffer[0] = 0b01000000; |
2. Следующая команда считывает аналоговое значение с контакта A0 и преобразует его в цифровое значение в диапазоне (0-1023). Разрешение АЦП платы Arduino составляет 10 бит, поэтому мы умножаем полученное значение на 4, в результате получим диапазон изменения цифрового значения 0-4096 – это будет соответствовать 12-битному разрешению нашего ЦАП.
1 |
adc = analogRead(A0) * 4; |
3. Следующей командой мы вычисляем значение аналогового напряжения при опорном напряжении 5V и диапазоне изменений цифрового значения от 0 до 4096.
1 |
float ipvolt = (5.0/4096.0)* adc; |
4. Первая из представленных ниже команд записывает самые значимые биты в buffer[1] при помощи сдвига вправо на 4 разряда (бита) значения переменной adc. А вторая команда записывает наименее значащие биты в buffer[2] при помощи сдвига влево на 4 разряда (бита) значения переменной adc.
1 2 |
buffer[1] = adc >> 4; buffer[2] = adc << 4; |
5. Следующая команда считывает аналоговое значение с контакта A1, на который подается значение с выхода ЦАП (MCP4725 DAC IC’s OUTPUT pin). Этот контакт можно также подключить к мультиметру чтобы контролировать значение напряжения на нем.
1 |
unsigned int analogread = analogRead(A1)*4 ; |
6. Затем значение напряжения из переменной analogread рассчитывается с помощью следующей формулы:
1 |
float opvolt = (5.0/4096.0)* analogread; |
7. Следующая команда предназначена для начала передачи (установления связи) в ЦАП MCP4725.
1 |
Wire.beginTransmission(MCP4725); |
Передаем контрольный байт.
1 |
Wire.write(buffer[0]); |
Передаем MSB (наиболее значащие биты).
1 |
Wire.write(buffer[1]); |
Передаем LSB (наименее значащие биты).
1 |
Wire.write(buffer[2]); |
Заканчиваем передачу.
1 |
Wire.endTransmission(); |
Отображаем полученные результаты на экране ЖК дисплея.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
lcd.setCursor(0,0); lcd.print("A IP:"); lcd.print(adc); lcd.setCursor(10,0); lcd.print("V:"); lcd.print(ipvolt); lcd.setCursor(0,1); lcd.print("D OP:"); lcd.print(analogread); lcd.setCursor(10,1); lcd.print("V:"); lcd.print(opvolt); delay(500); lcd.clear(); |
Тестирование работы проекта
После сборки аппаратной части проекта и загрузки программы в плату Arduino вы можете вращать ручку потенциометра и наблюдать как при этом изменяются показания на ЖК дисплее. На первой строчке дисплея будут показываться значение с выхода АЦП и значение напряжения, а на второй строчке будут показываться значение с выхода ЦАП и значение напряжения.
Также вы можете проверить значение напряжения с помощью мультиметра, подсоединив его к контактам OUT и GND микросхемы MCP4725.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#include<Wire.h> // библиотека для работы с протоколом I2C #include <LiquidCrystal.h> //библиотека для работы с ЖК дисплеем #define MCP4725 0x61 //устанавливаем для MCP4725 адрес 0x61, для своего АЦП вы можете использовать свой адрес LiquidCrystal lcd(2,3,4,5,6,7); //контакты, к которым подключен ЖК дисплей - RS,E,D4,D5,D6,D7 unsigned int adc; byte buffer[3]; void setup() { Wire.begin(); //старт связи по протоколу I2C lcd.begin(16,2); //устанавливаем ЖК дисплей в режим 16х2 lcd.print("CIRCUIT DIGEST"); delay(1000); lcd.clear(); lcd.setCursor(0,0); lcd.print("Arduino"); lcd.setCursor(0,1); lcd.print("DAC with MCP4725"); delay(2000); lcd.clear(); } void loop() { buffer[0] = 0b01000000; //записываем в buffer0 контрольный байт (010-Sets in Write mode) adc = analogRead(A0) * 4; //считываем аналоговое значение с контакта A0, преобразуем его в цифровое значение в диапазоне (0-1023) и умножаем его на 4 чтобы преобразовать его к диапазону (0-4096) float ipvolt = (5.0/4096.0)* adc; //формула для расчета значения напряжения (A0) buffer[1] = adc >> 4; //записываем наиболее значимые биты buffer[2] = adc << 4; //записываем наименее значимые биты unsigned int analogread = analogRead(A1)*4 ; //считываем аналоговое напряжение с контакта A1 float opvolt = (5.0/4096.0)* analogread; // формула для расчета значения напряжения (A1) Wire.beginTransmission(MCP4725); //присоединяемся к шине I2C с MCP4725 с адресом 0x61 Wire.write(buffer[0]); //передаем контрольный байт с помощью протокола I2C Wire.write(buffer[1]); //передаем наиболее значимые биты с помощью протокола I2C Wire.write(buffer[2]); // передаем наименее значимые биты с помощью протокола I2C Wire.endTransmission(); //окончание передачи lcd.setCursor(0,0); lcd.print("A IP:"); lcd.print(adc); // выводим на экран значение с выхода АЦП контакта A0 lcd.setCursor(10,0); lcd.print("V:"); // выводим на экран значение напряжения на контакте A0 lcd.print(ipvolt); lcd.setCursor(0,1); lcd.print("D OP:"); lcd.print(analogread); // выводим на экран значение с контакта A1 (с ЦАП) lcd.setCursor(10,1); lcd.print("V:"); lcd.print(opvolt); // выводим на экран значение напряжения на контакте A1 (From DAC) delay(500); lcd.clear(); } |
Видео, демонстрирующее работу схемы
Также можете посмотреть еще весьма наглядное видео про принцип работы ЦАП и работу с ним с помощью платы Arduino (на английском языке, но очень доступно).
8 ответов к “Подключение цифро-аналогового преобразователя (ЦАП) MCP4725 к Arduino”
Добрый день. Спасибо за статью. Если подать на модуль опорное напряжение 3.3v, а управлять i2c с Ардуины с 5-ти вольтовым опорным напряжением, модуль будеть выдавать сигнал 0-3.3 вольта? Или не будет работать? Кто нибудь так делал? Или опорное напряжение на ардуине с i2c тоже должено быть 3.3v?
А, простите, извините, уже спрашивали, вижу 🙂
Такой модуль надо бы запитать от индивидуального стаба по типу MCP1541. Тогда и выход почище и расчет коэффициентов деления не дробный.
Ну в идеале да, но в минимальном варианте можно как в статье
Здравствуйте, у меня такой вопрос. При питании MCP4725 от 3.3В а ардуинки от 5В нужно ставить конвертер уровней или резисторы на линию данных? Или же с ЦАП ничего не случится если на I2C в таком случае будет 5В?
Добрый вечер. У меня на сайте несколько аналогичных проектов, в некоторых из них есть подобный конвертер уровней, а в некоторых нет (и при этом на видео видно что проект все равно работает). Но лично я поставил бы конвертер уровней из резисторов если для вас это не сложно
Аудио можно воспроизвести ?
Например: Сместить с помощью двух резисторов аудио сигнал с выхода телефона или компа выше нуля. Так чтоб убрать минус составляющую.
Потом подать на ацп на ардуино на А0. Хранить в переменной. Потом подать это на цап. С выхода цап подключить к усилителю. Компьюторным колонкам.
Если нет в чем проблема будет?
1. Ацп самой ардуино
2. Быстродействия ардуино
3. Скорость i2c в ардуино
4. В самом цап мср 4725.
Я так питался сделать. Только хрип в колонках. Даже обычный голос не воспроизводить.
Теоретически вроде на всех этапах этих должно скорости хватать для обработки аудио. А вы задержку в 500 мс не забыли убрать из кода программы? А то ведь она может тормозить весь процесс