ЦАП для Arduino: виды и работа с микросхемой MCP4921

Чем настоящий аналоговый выход отличается от ШИМ, почему параллельные ЦАП неудобны и как подключить к Arduino 12-разрядный MCP4921 по SPI.
Зачем нужен ЦАП, если есть ШИМ
Аналоговые входы Arduino (A0, A1 и далее) — это аналого-цифровые преобразователи, АЦП: они измеряют напряжение и выдают его в виде числа. Обратной операции — превратить число в напряжение — плата не выполняет. Обычно её имитируют широтно-импульсной модуляцией, но ШИМ остаётся прямоугольным сигналом: светодиод не горит вполнакала, а быстро мерцает на полной яркости. Для ряда задач такая имитация не годится: она не подходит для плавного управления некоторыми типами коллекторных двигателей, ШИМ-подсветка на малой яркости и частоте неприятна для глаз, а получить на цифровом выводе пилу, треугольник или синусоиду невозможно вовсе.
Эти задачи решает цифро-аналоговый преобразователь — ЦАП, или DAC. Проще всего использовать готовую специализированную микросхему.
Параллельные ЦАП и их недостатки
По интерфейсу ЦАП делятся на параллельные и последовательные, по разрядности чаще всего встречаются 8, 10 и 12 бит. Разрядность определяет размер шага, с которым задаётся напряжение: чем больше шагов, тем они мельче и тем выше точность.
Параллельный ЦАП по сути представляет собой управляемый резистивный делитель: подключая и отключая отдельные ветви, меняют суммарное сопротивление плеч и получают нужное напряжение. К каждому разряду подводится свой вывод контроллера, а на выходе ставится операционный усилитель, чтобы нагрузка не искажала результат.

Достоинство такой схемы — быстродействие: вычислений внутри нет, всё происходит на физическом уровне. Недостатков больше:
- требуется много выводов контроллера — распространённому десятиразрядному КР572ПА нужно 10 линий;
- вклад каждого разряда в выходное напряжение различен, и зависимость нелинейна;
- обычные двоичные числа в качестве комбинаций не работают: при переборе от 0 до 1023 вместо ровной линии получается хаотичная ступенчатая кривая, поэтому комбинации приходится вычислять особым алгоритмом, что замедляет и разработку, и работу контроллера;
- при разрядности более восьми выводы переключаются группами не одновременно даже при прямой записи в порты, отчего между шагами появляются выбросы;
- сложная обвязка: настроечные резисторы и конденсаторы, а также два-три разных напряжения — логическое, опорное и зачастую отрицательное опорное.



Параллельные преобразователи достались в наследство от аналоговой техники. Их разумно применять там, где нужно выставить несколько редко меняющихся уровней без строгих требований к точности, — например, режимы светильника «максимум», «полумрак», «ночник».
Последовательные ЦАП на примере MCP4921
Последовательный ЦАП — составное устройство с собственной логикой и делителем напряжения. Внутреннее устройство пользователю знать не обязательно, достаточно передать число нужной разрядности. Чаще всего используется протокол SPI — простой, быстрый и достаточно помехоустойчивый.
Микросхема MCP4921 — компактный 12-разрядный преобразователь, который подходит для большинства любительских проектов. Диапазон выходного напряжения разбит на 4096 шагов; при максимуме 5 В (без усиления) один шаг теоретически равен 0,0012 В, причём все шаги одинаковы. Чтобы получить требуемое напряжение, его значение умножают на 4096/5, то есть на 819, и отправляют результат в микросхему.
| Микросхема | MCP4921 |
| Интерфейс | SPI |
| Разрядность | 12 бит (4096 шагов) |
| Максимальное выходное напряжение без усиления | 5 В |
| Теоретический шаг | 0,0012 В |
| Шум на выходе | порядка 10 мВ |
| Реальная точность | около 10 бит |
Подключение к Arduino
Документация рекомендует полную схему включения, но для проверки достаточно минимальной, даже без операционного усилителя. Используется аппаратный SPI: к микросхеме подводят линию данных MOSI (вывод 11), линию синхроимпульсов SCK (вывод 13) и линию выбора, для которой подойдёт практически любой вывод — в примере это 9. К выходу OUT подключают осциллограф, а при его отсутствии вольтметр или светодиод.
Что показывает осциллограф
Тестовый скетч подключает библиотеку SPI.h, вызывает SPI.begin() и в бесконечном цикле с отключёнными прерываниями перебирает значения от минимума до максимума и обратно, формируя треугольный сигнал. Каждое значение передаётся двумя байтами через SPI.transfer(): в старшем байте к четырём старшим битам числа добавляются служебные биты (маска B00110000), затем идёт младший байт. Линия выбора на время передачи опускается прямой записью в порт PORTB.
При шаге в единицу и размахе от 1 до 4090 получается практически идеальный треугольник частотой почти 20 Гц. Если перескакивать через четыре шага, форма остаётся такой же ровной, а частота вырастает вчетверо. Точность при этом практически не теряется: выход шумит примерно на 10 мВ, так что реальная точность микросхемы — порядка 10 бит, и шаг 10 можно использовать без потерь. С шагом 10 и диапазоном от 10 до 4086 пила на полной амплитуде достигает почти 200 Гц.
Если добавить между сменами уровней задержку delayMicroseconds() в 2000 мкс и подключить к выходу светодиод с резистором, яркость будет плавно нарастать и убывать без мерцания. Форма сигнала может быть любой — вычисленной по формуле или заданной таблицей.
Практические замечания
- Синусоиду и другие сложные функции лучше выводить по заранее рассчитанной таблице: считать их на ходу контроллер не успевает.
- ЦАП с разрядностью выше 10 для бытовых задач смысла не имеет: дополнительную точность поглощают шумы, а на вывод уходит больше времени.
- Другие диапазоны напряжения, например 0–24 В или симметричные относительно нуля, получают с помощью операционных усилителей, которые масштабируют и сдвигают сигнал.