Amateur Radio Station R9AL

ЦАП

      Цифро-аналоговые преобразователи (ЦАП) - предназначены для преобразования цифровых сигналов в аналоговые. Такое преобразование необходимо, например, при восстановлении аналогового сигнала, предварительно преобразованного в цифровой для передачи на большое расстояние или хранения (таким сигналом, в частности, может быть звук). Другой пример использования такого преобразования - получение управляющего сигнала при цифровом управлении устройствами, режим работы которых определяется непосредственно аналоговым сигналом, например при управлении электродвигателями.

В отличии от АЦП, Arduino не содержит встроенных ЦАП-ов. Но его легко можно создать, используя резисторы.

На прошлом уроке мы преобразовали аналоговый сигнал в цифровой:



который записали в цифровом виде:
010
101
111
101
001
000
011
110
101
100
010
011
110


      Попробуем теперь преобразовать этот код обратно в аналоговый сигнал. Для этого соберем простейший ЦАП, который представляет собой набор резисторов:



      Так как при преобразовании аналогового сигнала в цифровой мы использовали три разряда, то и для обратного преобразования наш ЦАП имеет три разряда (входы in1, in2, in3).

Смоделируем эту схему в Tinkercad и посмотрим как будет работать наш резисторный ЦАП. Сигнал будем формировать с помощью платы Ardiuno, задействовав пины D0-D3, и добавим в схему еще три светодиода, для индикации состояния соответствующих пинов. Сразу загрузим простую программу, которая будет перебирать последовательно все возможные состояния на этих пинах: 000, 001, 010, 011, 100 101, 110, 111. Таких состояний возможно 8 (2 в третьей степени, так как у нас три разряда). Программу не привожу, так как она очень простая и вы легко сможете написать её сами.



Каждому цифровому значению соответствует некоторое аналоговое значение на выходе. Подключенный параллельно вольтметру осциллограф позволяет наглядно посмотреть как меняется значение напряжения на выходе.

Теперь загрузим программу, которая будет выводить цифровые значения нашего оцифрованного сигнала:
void setup() {
  pinMode(0, OUTPUT); 
  pinMode(1, OUTPUT); 
  pinMode(2, OUTPUT); 
}

void loop() {
  digitalWrite(0,0);
  digitalWrite(1,1);
  digitalWrite(2,0);
  delay(1);
  digitalWrite(0,1);
  digitalWrite(1,0);
  digitalWrite(2,1);
  delay(1);
  digitalWrite(0,1);
  digitalWrite(1,1);
  digitalWrite(2,1);
  delay(1);
  digitalWrite(0,1);
  digitalWrite(1,0);
  digitalWrite(2,1);
  delay(1);
  digitalWrite(0,1);
  digitalWrite(1,0);
  digitalWrite(2,0);
  delay(1);
  digitalWrite(0,0);
  digitalWrite(1,0);
  digitalWrite(2,0);
  delay(1);
  digitalWrite(0,1);
  digitalWrite(1,1);
  digitalWrite(2,0);
  delay(1);
  digitalWrite(0,0);
  digitalWrite(1,1);
  digitalWrite(2,1);
  delay(1);
  digitalWrite(0,1);
  digitalWrite(1,0);
  digitalWrite(2,1);
  delay(1);
  digitalWrite(0,0);
  digitalWrite(1,0);
  digitalWrite(2,1);
  delay(1);
  digitalWrite(0,0);
  digitalWrite(1,1);
  digitalWrite(2,0);
  delay(1);
  digitalWrite(0,1);
  digitalWrite(1,1);
  digitalWrite(2,0);
  delay(1);
  digitalWrite(0,0);
  digitalWrite(1,1);
  digitalWrite(2,1);
  delay(1);
}


      Сигнал на экране осциллографа полностью соответствует нашему оцифрованному сигналу, а чтобы он был больше похож на исходный аналоговый сигнал - добавим на выходе простой фильтр, из резистора и конденсатора:



      Конечно, сигнал не очень точно повторяет исходный сигнал, но чем больше разрядов будет использовано при преобразовании, и чем выше будет скорость преобразования, тем больше восстановленный сигнал будет соответствовать исходному.

COVOX



Рассмотрим еще одну схему ЦАП, с использованием резисторной матрицы (R-2R), такая схема получила название Covox:



      Достоинство данной схемы в том, что для создания многоразрядного ЦАП, используются резисторы всего двух номиналов. На заре компьютерной эры именно эта схема получила широкое распространение, заменяя собой дорогие звуковые карты. Восемь бит (или один байт) - это стандартный размер параллельного порта, к которому и подключался covox.

Точно также смоделируем эту схему в Tinkercad:



      У этого ЦАП уже 256 состояний выхода (2 в восьмой степени, так как теперь у нас восемь разрядов). С помощью этого ЦАП уже можно довольно точно воспроизводить оцифрованный сигнал, но для этого он должен быть соответствующим образом и оцифрован. Конечно, писать программу для такого ЦАП, используя функцию digitalWrite(); довольно громоздко, поэтому применим другой способ.

      Сначала разберемся с таким понятием как "порт". Порт - это совокупность пинов. В ардуино есть три такие совокупности:

В одном порте обычно до 8 пинов, и за одно действие мы можем установить нужный уровень на всех пинах одного порта.

Мы будем использовать PORTD, так как это полный 8-ми битный порт. И, так же как при работе с отдельными пинами, нужно запрограммировать пины этого порта как входные или как выходные. Конечно, мы можем использовать вот такую конструкцию:
void setup() {
  pinMode(0, OUTPUT); 
  pinMode(1, OUTPUT); 
  pinMode(2, OUTPUT); 
  pinMode(3, OUTPUT); 
  pinMode(4, OUTPUT); 
  pinMode(5, OUTPUT); 
  pinMode(6, OUTPUT); 
  pinMode(7, OUTPUT); 
}
И это будет работать, но можно сделать проще:
void setup() 
{
    DDRD = B11111111;    // все 8 пинов порта D программируем на выход
}
Или даже так:
void setup() 
{
    DDRD = 0xFF;   // FF - это шестнадцатеричное написание бинарного 11111111
}
DDRx - регистр направления порта, в нашем случае все пины на выход (8 единиц в двоичной системе исчисления), но если бы нам нужно было установить все пины порта на вход, то потребовалось бы восемь нулей. Можно также часть пинов запрограммировать на вход, а часть на выход, например:
DDRD = B11111110;        // назначает выводы Arduino 1-7 выходными, вывод 0 - входным
Теперь нужно записать в регистр порта данные. Сделать это можно командой PORTx - регистр данных порта, например так:
PORTD = B10101011;  // Выводим значение 10101011 в порт D
Вместо конкретного значения можно вывести в порт также значение какой-либо переменной. Рассмотрим следующую программу:
uint8_t value = 0;  // Переменная типа Byte, можно было бы написать byte value = 0;

void setup() 
{
    DDRD = 0xFF;    // все 8 пинов порта D программируем на выход
}

void loop()
{
  PORTD = value++;  // Выводим значение переменной value в порт D
  delay(100);
}
Введенная переменная value, может принимать значения от 0 до 255, в порт последовательно выводятся все значения переменной по порядку, увеличиваясь каждый раз на единицу.

Точно также, используя работу с портами, мы можем вывести и оцифрованный нами сигнал:
uint8_t value = 0; // Переменная типа Byte

void setup() 
{
    DDRD = 0xFF;    // все 8 пинов порта D на выход
}
void loop()
{
    PORTD = B00000010; // можно написать PORTD = 2; выводим значения в порт D
delay(10);
    PORTD = B00000101; // можно написать PORTD = 5; выводим значения в порт D
delay(10);
    PORTD = B00000111; // можно написать PORTD = 7; выводим значения в порт D
delay(10);
    PORTD = B00000101; // можно написать PORTD = 5; выводим значения в порт D
delay(10);
    PORTD = B00000001; // можно написать PORTD = 1; выводим значения в порт D
delay(10);
    PORTD = B00000000; // можно написать PORTD = 0; выводим значения в порт D
delay(10);
    PORTD = B00000011; // можно написать PORTD = 3; выводим значения в порт D
delay(10);
    PORTD = B00000110; // можно написать PORTD = 6; выводим значения в порт D
delay(10);
    PORTD = B00000101; // можно написать PORTD = 5; выводим значения в порт D
delay(10);
    PORTD = B00000100; // можно написать PORTD = 4; выводим значения в порт D
delay(10);
    PORTD = B00000010; // можно написать PORTD = 2; выводим значения в порт D
delay(10);
    PORTD = B00000011; // можно написать PORTD = 3; выводим значения в порт D
delay(10);
    PORTD = B00000110; // можно написать PORTD = 6; выводим значения в порт D
delay(10);
  }








Copyright © R9AL 2021 Все права защищены

Рейтинг@Mail.ru Яндекс цитирования