17.01.2010

Простое повышение точности АЦП Arduino

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

Выбор этого источника происходит при вызове функции analogReference(type), где type может принимать одно из трех значений:
  • DEFAULT: напряжение питания, около 5 Вольт (по умолчанию, после старта скетча);
  • INTERNAL: встроенный ИОН - 1.1 Вольт для ATmega168 и 2.56 Вольт для ATmega8;
  • EXTERNAL: напряжение на пине AREF.
Я не случайно написал "около 5 Вольт", потому что в действительности питание шины USB составляет 4,40 .. 5,25 В, а стабилизатора L7805 - 4,65 .. 5,35 В. Простой математический подсчет показывает, что диапазон 0,7 В "выливается" в 14% от ожидаемых 5.00 Вольт. А теперь обратите внимание, что один шаг нашего 10-битного АЦП составляет 5.00/1024 = 0,0048828, и 0,7 Вольт в пересчете analogRead составит 143 единицы.

Это подводит нас к грустному, но неотвратимому выводу - точность лучше одного вольта при использовании DEFAULT нам заказана. Может быть, нам поможет INTERNAL?

Тут нас будет ждать второе разочарование - дело в том, что внутренний источник опорного напряжения ATmega требует предварительной калибровки. Надо взять эталонный источник напряжения, подать его на аналоговый пин и сравнить с внутренним, получив таким образом поправку, компенсирующую т.н. систематическую погрешность. Полученное значение надо сохранить в EEPROM микроконтроллера, поскольку оно индивидуально для каждого конкретного чипа, а в скетче считывать после старта. Немного занудно, но ничего сложного. Но, быть может, есть более простой путь?

Надо каким-то образом подать внешнее опорное напряжение на наш АЦП, да поточнее (это вариант EXTERNAL). В этом нам могут помочь:

  • Точный резистор: если поискать, то можно найти с погрешностью 1%,  0,1% и даже 0,01%. Есть и лучше, но это уже крутая экзотика. Из закона Ома известно, что падение напряжения на резисторе равно произведению тока на сопротивление. ОК, сопротивление-то повышенной точности, но как зафиксировать ток? Вероятно, потребуется генератор тока - это небольшая схема на операционном усилителе.
  • Диод: проводя ток в прямом направлении, он попутно "съедает" вполне фиксированное напряжение. Диод ведет себя не так, как резистор - для него закон Ома не писан, но зависимость от тока все-таки есть: достаточно взглянуть на графики вольт-амперной характеристики Vf(If) в документации.
  • Стабилитрон: это модификация диода (синоним "диод Зенера" :), который изначально предназначен для стабилизации напряжения. В простых схемах, не критичных к потерям энергии, его допустимо использовать с оглядкой на мощность. К сожалению, под рукой обычно оказываются только стандартные BX55C или BX79C, а у них погрешность 5%.
Тем не менее, вот простейшая схема стабилизатора питания +5В на стабилитроне (использована в Arduino minimum):

Более продвинутый вариант стабилитрона - это микросхема LM385-1.2, которая работает подобно стабилитрону, но обеспечивает падение напряжения 1.235 Вольта с точностью 1-2% (чем меньше ток, тем выше точность). Используются они практически повсеместно, выпускаются в корпусе SO и TO-92:




Если подключить LM385 к AREF, то получится, что мы сузим диапазон измерений от 0 до 1.235 Вольт, что не всегда удобно. В этом случае надо либо искать похожий чип на другое напряжение, либо, пожертвовав одним аналоговым пином, оставить схему DEFAULT:



Этот прием я использовал в схеме SMPReaderUSB, для измерения напряжения внутренней литиевой батареи модуля МПО-10. Резистор R9 22К выбран с таким расчетом, чтобы через LM385 протекал небольшой ток, как и положено по его документации. Измеряемый вход BATT притянут через R10 22K к земле на тот случай, если модуль не подключен и вход ADC0 повис в воздухе.

Далее, происходит считывание с двух аналоговых пинов - к одному подключен измеряемый источник напряжения BATT (ADCm), к другому - LM385 (ADC385). Оба значения передаются в хост-программу на PC, которая вычисляет пропорцию:

 Um = ADCm * 1,235 / ADC385

Значение опорного напряжения в этой формуле не участвует, и хотя зависимость по-прежнему есть, выведя это значение из формулы мы понизили его влияние на пару порядков (речь про ошибку квантования). Такой способ позволяет улучшить точность до 0,03 В, что - согласитесь - для Arduino весьма неплохо!

(в статье использованы материалы из руководства по языку Arduino)

2 комментария:

  1. Спасибо за статью.
    Возник вопрос: а третья нога LM385 (FB) остается в воздухе в последней схеме ?

    ОтветитьУдалить
  2. Да, в воздухе. Он ни к чему не подключается, а нужен только для единообразия - в корпусах TO-92 положено три вывода.

    ОтветитьУдалить