3.12. Чтение аналогового сигнала с помощью ADC¶
До сих пор камера считывала цифровые сигналы – вывод находится либо в состоянии 0, либо 1, переключатель разомкнут или замкнут. Большинство сигналов, поступающих от реальных датчиков, являются аналоговыми: это непрерывное напряжение, которое плавно изменяется в некотором диапазоне. Фоторезистор проходит через все напряжения между шинами питания по мере изменения окружающей яркости. Выход датчика температуры смещается на несколько милливольт по мере нагрева помещения. Выход микрофона повышается и понижается вместе с окружающим звуком.
Мостом между ними служит аналого-цифровой преобразователь (ADC). Он измеряет напряжение на выводе и возвращает целое число, которое Python может прочитать как любое другое значение.
3.12.1. Квантование¶
Цифровое значение не может точно представить непрерывное напряжение. Задача ADC – квантовать, то есть привязывать каждый отсчёт к ближайшему из фиксированного набора уровней. N-битный ADC имеет 2^N уровней; 12-битный преобразователь имеет 4096 уровней, распределённых по своему входному диапазону.
Квантование: каждый отсчёт аналогового сигнала (сплошная линия) округляется до одного из конечного набора цифровых уровней (ступенчатая пунктирная линия).¶
Напряжение между двумя соседними уровнями – это шаг квантования ADC; всё, что меньше него, исчезает при округлении. 12-битный ADC в диапазоне 3,3 В имеет шаг квантования около 3.3 / 4096 ≈ 0.8 mV – достаточно мелкий, чтобы большинство сигналов выглядели в программе фактически непрерывными.
3.12.2. Класс machine.ADC¶
machine.ADC оборачивает один аналоговый входной канал. Создайте его с указанием вывода, который вы хотите считывать, затем вызовите read_u16():
from machine import ADC
adc = ADC("P6")
value = adc.read_u16()
print(value)
read_u16() всегда возвращает беззнаковое 16-битное целое число от 0 до 65535. Собственное разрешение ADC зависит от платы (12 бит на STM32, в других случаях зависит от порта); результат выравнивается по левому краю в 16 битах, так что аппаратные подробности не проникают в Python – значение 65535 соответствует полной шкале независимо от чипа.
Опорное напряжение – вход, соответствующий полной шкале, – зависит от платы. Посмотрите значение для вашей камеры в Платы OpenMV. Всё, что выше опорного напряжения, считывается как полная шкала (и может повредить вывод, если превысит абсолютно максимальное входное напряжение).
3.12.2.1. Преобразование отсчётов в напряжение¶
Отображение отсчётов в напряжение линейно, причём отсчёт полной шкалы точно соответствует Vref:
voltage = counts × Vref / 65535
В коде:
VREF = 3.3 # cam-dependent; see the quickref
counts = adc.read_u16()
voltage = counts * VREF / 65535
print(voltage, "V")
3.12.3. Делители напряжения¶
Два последовательно соединённых резистора между шиной напряжения и землёй образуют делитель напряжения. Узел между ними находится под напряжением, заданным отношением двух резисторов:
Делитель напряжения: R1 и R2, соединённые последовательно, понижают Vin до V_out.¶
V_out = Vin × R2 / (R1 + R2)
Равные резисторы дают половину напряжения шины; R2, намного меньший R1, помещает отвод близко к земле; намного больший R2 помещает его близко к шине.
Формула предполагает, что ничто иное не потребляет заметного тока с V_out. Вывод ADC обладает высоким импедансом (мегаомы, наноамперы) и легко удовлетворяет этому условию, поэтому делитель, питающий ADC, ведёт себя так, как предсказывает формула.
3.12.4. Потенциометры¶
Потенциометр – это единственный физический компонент, который представляет собой именно делитель напряжения со скользящим движком, перемещающим отвод между двумя концами. Поворот ручки изменяет R1 и R2 одновременно, сохраняя постоянной их сумму (полное сопротивление потенциометра).
Потенциометр, подключённый как ручной источник напряжения для ADC: 3,3 В на одном конце, земля на другом, движок к выводу.¶
Потенциометр – это классическое устройство ввода для испытания ADC. Подключите один конец к 3.3 V, другой к земле, а движок к выводу с поддержкой ADC; поворот ручки проводит движок через все напряжения между шинами.
import time
from machine import ADC
pot = ADC("P6")
VREF = 3.3
while True:
counts = pot.read_u16()
voltage = counts * VREF / 65535
print(voltage, "V")
time.sleep_ms(100)
3.12.5. Чтение более высоких напряжений с помощью делителя¶
Напряжение выше Vref зафиксирует ADC на полной шкале и может повредить вход, если превысит абсолютно максимальное значение. Чтобы считать более высокий источник – аккумулятор, выход датчика, выходящий за пределы Vref, – понизьте его с помощью фиксированного делителя напряжения, прежде чем он достигнет вывода:
Масштабирование высоковольтного источника под ADC: R1 и R2 образуют фиксированный делитель напряжения, отвод которого питает вывод ADC.¶
Подберите R1 и R2 так, чтобы поделённое напряжение оставалось в диапазоне ADC при наибольшем ожидаемом вами входном напряжении:
V_adc = V_in × R2 / (R1 + R2)
Для максимального V_in = 12 V и опорного напряжения 3,3 В отношение R2 / (R1 + R2) должно быть не более 3.3 / 12 ≈ 0.275. Распространённый выбор с небольшим запасом – R1 = 33 kΩ, R2 = 10 kΩ. Отношение составляет 10 / 43 ≈ 0.233, поэтому V_adc достигает максимум около 12 × 0.233 ≈ 2.79 V – безопасно ниже Vref.
Чтобы восстановить исходное V_in из показания ADC, обратите формулу делителя:
V_in = V_adc × (R1 + R2) / R2
В коде:
from machine import ADC
R1 = 33_000
R2 = 10_000
VREF = 3.3
adc = ADC("P6")
counts = adc.read_u16()
v_adc = counts * VREF / 65535
v_in = v_adc * (R1 + R2) / R2
print(v_in, "V")
Несколько практических замечаний:
Делитель непрерывно потребляет
V_in / (R1 + R2). ПриR1 + R2 = 43 kΩиV_in = 12 Vэто около 280 мкА – обычно пренебрежимо мало, но если источник работает от аккумулятора, рассмотрите более крупные резисторы (от 100 кОм до 1 МОм), чтобы сократить ток покоя.Допуск резисторов (обычно ±1 % или ±5 %) напрямую влияет на точность измерения. Два резистора с допуском ±5 % могут дать восстановленному
V_inпогрешность в худшем случае около ±10 %.Выходной импеданс делителя в сочетании с любой паразитной ёмкостью образует фильтр нижних частот для входа. Для быстро меняющихся сигналов это имеет значение; для проверки напряжения аккумулятора – нет.