Отличительные особенности:

  • Рассмотрены характеристики аналогово-цифровых преобразователей
  • Измерение описанных характеристик АЦП
  • Влияние температуры, частоты и напряжения питания на результат преобразования
  • Компенсация погрешностей смещения и коэффициента передачи

Введение

В данных "Рекомендациях…" объясняется снятие характеристик различных АЦП, приведенных в документации, и как они влияют на результат измерений АЦП. Также описывается, как определить данные параметры в процессе тестирования приложения на стадии производства и как выполнить реально-временную компенсацию некоторых измеренных отклонений.

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

1. Сведения из теории

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

1.1. Основные характеристики АЦП

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

Рисунок 1. Передаточная функция идеального АЦП

Чтобы дать определение совершенного АЦП необходимо предварительно рассмотреть понятие квантование. В связи с тем, что АЦП имеет цифровую основу, то генерация им непрерывных значений невозможна. Выходной диапазон может быть представлен в виде множества интервалов, каждому из которых соответствует собственное цифровое значение. Это означает, что одно выходное значение соответствует не конкретному уровню входного напряжения, а небольшому диапазону входных значений. Передаточная функция такого преобразования имеет лестничную форму. Например, АЦП с 8 интервалами имеет разрешающую способность 8 уровней или иными словами 3 разряда. На рисунке 2 представлен пример передаточной функции 3-хразрядного совершенного АЦП вместе с передаточной функций идеального АЦП. Как следует из рисунка совершенный АЦП эквивалентен идеальному точно посредине каждого интервала квантования. Это означает, что совершенный АЦП по существу округляет входные значения к ближайшему выходному значению.


Рисунок 2. Передаточная функция 3-разрядного совершенного АЦП

Максимальная погрешность совершенного АЦП составляет ±1/2 интервала дискретизации. Иными словами, максимальная погрешность квантования всегда ±1/2 мл.разр., где мл. разр. - приращение входного напряжения, при котором изменяется значение младшего разряда выходного кода. Реальный АЦП характеризуется другими источниками погрешностей, которые будут рассмотрены далее.

1.2. Диапазоны преобразования

АЦП в микроконтроллерах AVR можно сконфигурировать на несимметричное и на дифференциальное преобразование. Несимметричный режим используется для измерения уровней входных напряжений в одном входном канале, а дифференциальный режим предназначен для измерения разности напряжений между двумя каналами. Независимо от режима преобразования, входные напряжения на любом из каналов должны находиться между GND и AVCC.

При использовании несимметричного режима напряжение относительно общего (GND) преобразовывается в цифровое значение. Если же используется дифференциальный режим, то в цифровое значение преобразовывается напряжение с выхода дифференциального усилителя (с опциальным усилением). На рисунке 3 показана упрощенная схема входного каскада АЦП.


Рисунок 3. Упрощенная схема входного каскада АЦП

Для задания диапазона преобразования в схеме необходим источник опорного напряжения (Vион), который задает, какому уровню входного напряжения соответствует выходное значение. В соответствии с документацией напряжение Vион должно быть не менее 2,0В для стандартных микроконтроллеров и не менее 1,0В для микроконтроллеров с напряжением питания от 1,8В. Данное распространяется на оба режима преобразования: несимметричный и дифференциальный. Подробности необходимо выяснить в документации.

1.2.1. Несимметричный диапазон преобразования

В несимметричном режиме входной сигнал поступает непосредственно к схеме преобразования (см. рисунок 3а). 10-разрядный АЦП микроконтроллера AVR, таким образом, преобразовывает непрерывные входные напряжения в диапазоне от GND до Vион в дискретные выходные значения от 0 до 1023, соответственно.

1.2.2. Дифференциальный диапазон преобразования

В дифференциальном режиме преобразования два входных канала подключаются к дифференциальному усилителю с опциональным усилительным каскадом. Затем напряжение с выхода усилителя поступает к логике преобразования, как показано на рисунке 3б. В этом случае разности напряжений в диапазоне от -Vион до +Vион соответствуют выходные значения в диапазоне от -512 до +511. Выходное значение представляется в формате двоичного дополнения. Несмотря на возможность образования отрицательного напряжения на выходе дифференциального усилителя входные напряжения должны быть в диапазоне GND…AVCC.

Обратите внимание, что некоторые микроконтроллеры не могут измерить отрицательного приращения, как, например, ATtiny26.

1.3. Необходимость калибровки

Общая погрешность реального АЦП складывается не только из погрешности квантования. В данном документе рассматриваются погрешности смещения и коэффициента передачи и методы их компенсации. Кроме того, рассматривается измерение двух нелинейностей, а именно дифференциальной и интегральной нелинейности.

В большинстве приложений нет необходимости выполнять калибровку АЦП при использовании несимметричного режима преобразования. Типичная погрешность в этом случае составляет 1-2 мл.разр., что зачастую удовлетворяет требованиям приложения и исключает необходимость калибровки.

Однако, при использовании дифференциального преобразования ситуация меняется, особенно при использовании внутреннего усилительного каскада с большим усилением. Незначительные отклонения, вызванные особенностями производства микроконтроллеров, умножаются усилительным каскадом и, поэтому, у разных микроконтроллеров могут наблюдаться существенные отличия в результате измерения при прочих равных условиях. Некомпенсированная погрешность может достигать 20 мл. разр. и выше. Данные отклонения могут быть определены для каждого микроконтроллера, а затем компенсированы программно.

Значение 20 мл. разр. на первый взгляд может показаться большим значением, но это не означает, что дифференциальный режим непрактичен в использовании. С помощью простого калибровочного алгоритма возможно достичь точность 1-2 мл.разр.

1.4. Абсолютная погрешность

Абсолютная погрешность - максимальное отклонение между идеальной прямолинейной и реальной передаточными функциями, в т.ч. внутри интервалов квантования. Минимальная абсолютная погрешность, таким образом, равна погрешности квантования 1/2 мл. разр.

Абсолютная погрешность или абсолютная точность - общая некомпенсированная погрешность, которая включает погрешность квантования, погрешность смещения, погрешность коэффициента передачи и нелинейность. Смещение, коэффициент передачи и нелинейность будут описаны далее.

Абсолютная погрешность может быть измерена с помощью пилообразного входного напряжения. В этом случае все выходные значения сравниваются с входным напряжением, а по максимальному отклонению определяется абсолютная погрешность.

Обратите внимание, что абсолютная погрешность не может быть компенсирована непосредственно, без использования таблиц преобразования или полиноминальной аппроксимации. Однако, наиболее весомые составляющие общей погрешности - передаточная погрешность и погрешность смещения - могут быть компенсированы.

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

1.5. Погрешность смещения

Погрешность смещения - отклонение фактической передаточной функции АЦП от прямолинейной передаточной функции идеального АЦП при нулевом входном напряжении.

Когда выходное значение изменяется от 0 к 1, но при этом входное напряжение не достигло уровня 1/2 мл.разр., то говорят, что имеет место погрешность смещения. Если ошибка смещения положительная, то выходное значение будет больше 0, когда входное напряжение приближается к 1/2 мл.разр. снизу. Если ошибка смещения отрицательная, то входное значение будет больше 1/2 мл.разр. при первом изменении выходного кода. Другими словами, если фактическая передаточная функция становится ниже идеальной линии, то погрешность смещения отрицательная и наоборот. Отрицательные и положительные смещения показаны на рисунке 4.


Рисунок 4. Примеры положительного (а) и отрицательного (б) смещений

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

1.5.1. Погрешность смещения в несимметричных каналах

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

На рисунке 5а первый переход возникает при уровне 1 мл.разр. При изменении выходного кода с 2 к 3 у совершенного АЦП эквивалентное входное напряжение будет равно 2 1/2 мл. разр. Разница равна +1 1/2 мл. разр. и является погрешностью смещения. Данная разница показана на рисунке размерной линией. Такие же рассуждения применимы и к рисунку 5б. Первое изменение возникает при 2 мл.разр. У совершенного АЦП переход от 0 к 1 возникает при входном напряжении 1/2 мл.разр. Таким образом, погрешность смещения равна разнице: - 1 1/2 мл. разр.


Рисунок 5. Положительная (а) и отрицательная (б) погрешности смещения в режиме несимметричного преобразования

Процедура измерения может быть формализована в виде блок-схемы (см. рисунок 6).


Рисунок 6. Блок-схема измерения несимметричных погрешностей смещения

Для компенсации погрешностей смещения в несимметричных каналах необходимо из каждого измеренного значения вычесть погрешность смещения. Необходимо, помнить, что погрешности смещения ограничивают диапазон преобразования АЦП. Большие положительные погрешности смещения вызывают установку на выходе максимального значения еще до достижения входным напряжением максимума. В свою очередь отрицательные погрешности смещения приводят к появлению на выходе 0 при минимальных входных напряжениях.

1.5.2. Погрешность смещения в дифференциальных каналах

Погрешность смещения в дифференциальных каналах вычисляется более просто, т.к. в этом случае не требуется регулировка входного напряжения. Два дифференциальных входа необходимо подключить к одному и тому же напряжению, а результирующее выходное значение и будет погрешностью смещения. Поскольку при данном способе не дается точная информация при каком именно уровне возник первый переход, то его погрешность равно от 1/2 до 1 мл.разр. в худшем случае.

Для компенсации погрешностей смещения при использовании дифференциальных каналов необходимо из каждого измеренного значения вычесть погрешность смещения.

1.6. Передаточная погрешность

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

При реально-временной компенсации часто используется целочисленная арифметика, т.к. вычисления с плавающей точкой выполняются гораздо дольше. Таким образом, для достижения наилучшей точности измерения отклонения наклона оно должно быть выполнено как можно далее от нулевого значения. Чем выше значения, тем лучше точность измерения. Это более подробно описано далее. Пример передаточной функции 3-разрядного АЦП с передаточной погрешностью показан на рисунке 7. Приведенное далее описание распространяется на оба режима преобразования: несимметричный и дифференциальный.


Рисунок 7. Примеры положительной (а) и отрицательной (б) передаточных погрешностей

Для измерения передаточной погрешности необходимо увеличивать входное напряжение от 0 до достижения последнего интервала преобразования. Масштабирующий коэффициент для компенсации передаточной погрешности равен отношению идеального выходного значения посредине последнего интервала дискретизации и фактического значения в этой же точке.

На рисунке 7а выходное значение достигло предела еще до достижения максимума входным напряжением. Вертикальная размерная линия показывает середину последнего выходного интервала дискретизации. Идеальное выходное значение для данного входного напряжения равно 5,5, таким образом, масштабирующий коэффициент равен 5,5/7. На рисунке 7б выходное значение достигло только 6 при достижении входным напряжением максимума. В итоге присутствует отрицательное отклонение от фактической передаточной функции. Для этого случая идеальное выходное значение посередине последнего интервала преобразования равно 7,5, а масштабирующий коэффициент 7,5/6. Процедура измерения представлена на рисунке 8.


Рисунок 8. Блок-схема измерения передаточных погрешностей

1.7. Нелинейность

После компенсации погрешности смещения и передаточной погрешности фактическая передаточная функция должна совпадать с передаточной функцией совершенного АЦП. Однако ввиду нелинейности АЦП фактическая кривая может слегка отклоняться от совершенной кривой, даже если обе кривые совпадают в районе 0 и в точке измерения передаточной погрешности. Имеется два способа измерения нелинейности; оба метода описаны ниже. На рисунке 9 показаны примеры для обоих методов измерения.


Рисунок 9. Пример нелинейной кривой преобразования АЦП

1.7.1. Дифференциальная нелинейность

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

Для измерения ДНЛ на вход подается пилообразное напряжение и записываются все изменения выходных значений. Ширина интервала определяется как расстояние между двумя переходами и большинство отрицательных и положительных отклонений от 1 мл.разр. используются для определения максимальной и минимальной ДНЛ.

Интегральная нелинейность

Интегральная нелинейность (ИНЛ) - максимальное отклонение по вертикали между фактической и совершенной кривыми преобразования АЦП.

ИНЛ можно интерпретировать как сумму ДНЛ. Например, несколько последовательных отрицательных ДНЛ поднимают фактическую кривую над совершенной, как показано на рисунке 9а. Отрицательные ИНЛ сигнализируют о снижении фактической кривой ниже совершенной. Максимальная и минимальная ИНЛ измеряются с помощью того же пилообразного входного напряжения, что и при измерении ДНЛ. Для этого записываются отклонения посередине каждого интервала преобразования, а затем определяются максимальное и минимальное значения, соответствующие максимальной и минимальной ИНЛ.

Измерения и компенсация

Очень важно, что бы измерение ИНЛ и ДНЛ выполнялось после компенсации погрешности смещения и передаточной погрешности. В противном случае в результат измерения будут входить указанные погрешности и, следовательно, полученные значения ДНЛ и ИНЛ не будут соответствовать действительности.

Нелинейность не может быть компенсирована с помощью простых вычислений. Для этого необходима либо полиноминальная аппроксимация, либо таблицы преобразования. Однако типичные значения ИНЛ и ДНЛ для 10-разрядных АЦП микроконтроллеров AVR составляют 1/2 мл. разр. и редко влияют на жизнеспособность приложений.

1.8. Влияние температуры, частоты и напряжения питания

При использовании внутреннего ИОН совместно с АЦП необходимо уточнить его точность. Технические характеристики внутреннего ИОН приводятся в документации на интересующий тип микроконтроллера. Из них следует, что напряжение ИОН слегка зависит от напряжения питания и рабочей температуры.

Точность работы АЦП также связана с его синхронизацией. Рекомендованная максимальная частота синхронизации АЦП ограничивается характеристиками внутреннего ЦАП в схеме преобразования. Для достижения оптимальных характеристик частота синхронизации АЦП не должна превышать 200 кГц. Однако частоты до 1 МГц не приводят к существенному ухудшению разрешающей способности.

Характеристики работы АЦП с частотами синхронизации выше 1МГц не определялись.

1.9. Частотный диапазон и входное сопротивление

В несимметричном режиме работы АЦП частотный диапазон ограничивается частотой синхронизации АЦП. Одно преобразование длиться 13 тактов, поэтому, при максимальной тактовой частоте 1 МГц достигается частота преобразования 77 тысяч преобразований в секунду. Таким образом, в соответствии с теоремой Котельникова частотный диапазон для несимметричного режима преобразования ограничивается частотой 38,5 кГц.

В дифференциальном режиме частотный диапазон ограничивается частотой 4 кГц за счет дифференциального усилителя. Частотные составляющие выше частоты 4 кГц должны быть удалены с помощью внешнего аналогового фильтра, что позволить избежать нелинейностей.

Входное сопротивление по отношению к VCC и GND составляет 100 МОм (типичное значение). Совместно с внутренним сопротивлением источника сигнала образуется делитель напряжения. Таким образом, для получения корректного результата преобразования необходимо, чтобы внутреннее сопротивление источника сигнала было намного меньше входного сопротивления АЦП.

2. Реализация

На рисунке 10 показан пример установки для выполнения калибровки.


Рисунок 10. Установка для калибровки в производственных условиях

На этапе тестирования выполняется определение характеристик АЦП каждого микроконтроллера с помощью подобной приведенной испытательной установки. После подключения тестового блока к калибруемому микроконтроллеру AVR его тестовые сигналы выполняют самокалибровку автоматически. В состав тестового блока входит высокоточный ЦАП (например, с 16-разрядным разрешением) для генерации входных напряжений в соответствии с калибровочным алгоритмом. По завершении калибровки определенные значения погрешности смещения и передаточной погрешности записываются в ЭСППЗУ для дальнейшего использования, а затем AVR сигнализирует о готовности к следующей фазе тестирования.

Обратите внимание, что в данном случае требуется, чтобы бит EESAVE был запрограммирован. В этом случае выполнение операции стирания всей памяти, которая предшествует программированию флэш-памяти, не затрагивает содержимое ЭСППЗУ. В противном случае, параметры АЦП должны быть временно запомнены программатором перед стиранием памяти микроконтроллера.

2.1. Арифметика с фиксированной точкой для коррекции погрешности смещения и передаточной погрешности

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

Поскольку коэффициент компенсации передаточной погрешности никогда не превысит значения 2, то можно отмасштабировать с коэффициентом 2 14 , чтобы точно вписаться в 16-разрядное слово. Иными словами, масштабирующий коэффициент может быть представлен двумя байтами как число с фиксированной точкой и знаком 1:14.

Ниже приведено выражение для одновременной компенсации передаточной погрешности и погрешности смещения.

Фактическое_значение = (Код_АЦП - Смещение) · Км, (1)

где Км- масштабирующий коэффициент передаточной погрешности.

При преобразовании результата вычисления к целочисленной форме он всегда округляется к наибольшему целочисленному значению, которое меньше или равно результату. Чтобы добиться корректного округления к ближайшему целому перед преобразованием необходимо добавить 0.5. Прибавление 0.5, масштабирование на 214 и смещение представим в виде выражения (2).

2 14 · Фактическое_значение = 2 14 · Код_АЦП · Км + 2 14 · 0,5 - 2 14 · Смещение · Км (2)

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

Введя две отмасштабированные константы factor и correction, которые используются в программе, получаем итоговые выражения:

factor = 2 14 · Км,

correction = 2 14 · (0,5 - Смещение · Км), (3)

2 16 · Фактическое_значение = 2 2 · (Код_АЦП · factor + correction).

С помощью данного метода калибровочная программа вычисляет константы factor и correction, а затем сохраняет их в ЭСППЗУ. Время выполнения программы компенсации составляют одно целочисленное умножение, одно сложение и два сдвига влево. При использовании компилятора Си компании IAR C с максимальной оптимизацией быстродействия на эти действия потребуется 42 такта ЦПУ.

2.1.1. Калибровка

Разработка тестового блока не рассматривается в рамках данных "Рекомендаций…". Однако блок-схема калибровки с помощью микроконтроллера AVR приведена. В ней подразумевается использование в тестовом блоке внешнего ЦАП и работа по собственному калибровочному алгоритму.

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

Программа должна быть реализована, как показано на рисунке 11.

Рисунок 11. Блок-схема калибровочной программы

Данная часть программного обеспечения записывается в AVR до начала калибровки, а по ее завершении заменяется программным кодом фактического приложения. Еще раз необходимо обратить внимание, что программирование конфигурационного бита EESAVE позволит заблокировать действие команды стирания всей памяти относительно ЭСППЗУ во время перепрограммирования флэш-памяти и, таким образом, калибровочные данные будут незатронутыми.

2.1.2. Компенсация

Программный код реально-временной компенсации реализован как небольшая функция. Каждый результат измерения АЦП пропускается через эту функцию, в который используются константы factor и correction .

Рисунок 12. Блок-схема программы компенсации погрешности смещения и передаточной погрешности

Вычисления на рисунке 12 могут быть реализованы с помощью следующей Си-функции или альтернативно с помощью макроса:

Signed int adc_compensate(signed int adcvalue, signed int factor, signed long correction) { return (((((signed long)adcvalue*factor)+correction)<<2)>>16); }

Константы хранятся в ЭСППЗУ и перед началом работы должны быть скопированы в ОЗУ для ускорения доступа к ним.

Использованная литература:

  1. Robert Gordon - A Calculated Look at Fixed-Point Arithmetic (Прагматичный взгляд на арифметику с фиксированной точкой)
    http://www.embedded.com/98/9804fe2.htm
  2. Рекомендации по применению AVR210: Использование аппаратного умножающего устройства микроконтроллеров AVR

Микроконтроллер общается с внешним миром посредством портов ввода/вывода. В общем случае он может “воспринимать” только цифровые сигналы – логический ноль или логическую единицу. Например, для микроконтроллера ATmega8535 при напряжении питания 5 В логический ноль – это напряжение от 0 до 1,3 В, а логическая единица – от 1,8 до 5 В. Довольно часто возникает потребность измерять напряжения, которые могут принимать любое значение в диапазоне от 0 до напряжения питания. Для этих целей в составе микроконтроллеров AVR есть аналого-цифровой преобразователь (АЦП).

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

Разрешающая способность (разрешение) – это способность АЦП различать два значения входного сигнала. Определяется как величина обратная максимальному числу кодовых комбинаций на выходе АЦП. У AVRа АЦП 10-ти разрядный. Максимальное число кодовых комбинаций будет равно 2 10 = 1024. Разрешающая способность равна 1/1024 от всей шкалы допустимых входных напряжений.

Для работы АЦП необходим источник опорного напряжения (ИОН). Для него это эталон, по отношению к которому он измеряет входные сигналы. Микроконтроллеры AVR позволяют в качестве ИОНа использовать напряжение питания, внутренний опорный источник на 2,56 В и напряжение на выводе AREF (внешний ИОН).

Напряжение питания в нашей схеме 5 В, тогда 1/1024 от всей шкалы это 5 * 1/1024 = 0,0048 В или примерно 5 мВ. С таким шагом (это называется шаг квантования) АЦП будет измерять входное напряжение. Если два ближайших значения сигнала на входе АЦП будут отличаться между собой на величину < 5 мВ, АЦП воспримет их как одинаковые. На практике разрешающая способность АЦП ограничена его шумами.

Абсолютная точность – отклонение реального преобразования от идеального. Это составной результат нескольких погрешностей АЦП. Выражается в количестве младших значащих разрядов (LSB - least significant bit) АЦП. Для AVRа абсолютная погрешность АЦП = ±2LSB. Для нашего примера абсолютная точность будет равна 2 * 5 мВ = ±10 мВ.

Предельная частота дискретизации определяет быстродействие АЦП и измеряется в герцах или количестве выборок в секунду (SPS – samples per second). Для микроконтроллеров AVR эта величина равна 15 kSPS (килло семплов в секунду). Практически АЦП AVRа работает и быстрее, но при этом его точность ухудшается.

Теорема Котельникова (теорема Найквиста-Шеннона, теорема о выборке) гласит, что аналоговый сигнал имеющий ограниченный спектр, может быть восстановлен однозначно и без потерь по своим дискретным отсчётам, если частота выборки (дискретизации) превышает максимальную частоту спектра сигнала более чем в 2 раза. Выражаясь по-простому - если вам нужно оцифровать аналоговый сигнал с полосой спектра 0 - 7 КГц, то в идеальном случае частота дискретизации должна быть > удвоенной максимальной частоты спектра этого сигнала, то есть > 14 КГц. На практике все намного сложнее. Перед входом АЦП всегда ставят НЧ фильтр, чтобы ограничить спектр сигнала, а частота дискретизации выбирается еще более высокой.

Диапазон входных напряжений – это минимальное и максимальное значение напряжения, которое можно подавать на вход АЦП. Для микроконтроллера AVR он равен 0 – Vcc (напряжение питания)


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

Пояснения к схеме

Для знакомства с модулем АЦП микроконтроллера AVR я выбрал простую, но интересную схему. Взгляните на рисунок. Четыре кнопки подключены к делителю напряжения (резисторы R8…R11). При нажатии они коммутируют на вход нулевого канала АЦП разные напряжения. Измеряя эти напряжения в прерывании АЦП и определяя в какой диапазон они попадают, микроконтроллер будет распознавать номер нажатой кнопки.

Резистор R7 нужен чтобы вход АЦП не “болтался в воздухе”, когда все кнопки отпущены. Если этого не сделать АЦП будет ловить помехи. Номинал резистора R7 выбран большим, чтобы не оказывать влияние на делитель напряжения.

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

Для индикации номера нажатой кнопки в схеме используются 4 светодиода.
Микроконтроллер - ATMega8535. Описание регистров АЦП ниже по тексту приводится именно для него. Для других микроконтроллеров могут быть некоторые отличия.

Задача

Для приведенной выше схемы, написать программу определяющую номер нажатой кнопки.

Алгоритм программы такой:

Основная программа
Инициализация портов
Инициализация АЦП
Разрешение прерываний
Бесконечный цикл
{
Если кнопка нажата, зажечь нужный светодиод
Если нет, погасить все светодиоды
}

Обработчик прерывания АЦП
Считать напряжение на входе АЦП
Определить в какой диапазон оно попадает
Записать номер кнопки в буфер

Начальный код программы

//программирование микроконтроллеров AVR на Си - осваиваем АЦП

#include
#include

//макрос для запуска преобразования
#define StartConvAdc() ADCSRA |= (1<

int main(void )
{

ADMUX = (0<

//вкл. ацп, режим одиночного преобр., разрешение прерывания,частота преобр. = FCPU/128

ADCSRA = (1<


__enable_interrupt
();
StartConvAdc();
while (1)
{

//какой-нибудь код

}
return 0;
}

//обработчик прерывания АЦП
#pragma vector=ADC_vect
__interrupt void adc_my(void )
{
unsigned char AdcBuf = ADCH;

//какой-нибудь код

StartConvAdc();
}

Пояснения к коду

Макрос для запуска преобразования

StartConvAdc() – это макрос для запуска преобразования АЦП. Он устанавливает бит ADSC в регистре управления и состояния ADCSRA.

Инициализация АЦП

Чтобы запустить модуль АЦП, его нужно предварительно настроить. За это отвечают три регистра:
Регистр управления мультиплексором - ADMUX
Регистр управления и состояния - ADCSRA
Регистр специальных функций - SFIOR

Регистр ADMUX

Модулю АЦП для работы нужен источник опорного напряжения (ИОН). За выбор ИОНа отвечают биты REFS1, REFS0. В нашем случае опорное напряжение это напряжение питания (именно поэтому мы завели вывод AVcc на +5В) поэтому REFS1 - 0, REFS0 - 1

АЦП микроконтроллера AVR 10-ти разрядный, а сам камень 8-ми. Поэтому результат преобразования хранится в двух регистрах (ADCH, ADCL). Бит ADLAR задает направление выравнивания результата преобразования. 0 – выравнивание вправо (в ADCH заняты 2 младших бита, ADCL занят весь), 1 – выравнивание влево (ADCH занят весь, в ADCL только 2 старших бита). В нашем примере не требуется высокой точности преобразования, поэтому было бы удобно выровнять результат влево и работать только с регистром ADCH. Устанавливаем ADLAR - 1

Чисто физически в микроконтроллере AVR всего один АЦП. Но перед ним стоит мультиплексор, который позволяет подключать любой из 8-ми выводов порта к входу АЦП. Номер выбранного в данный момент канала задается битами ADMUX3, ADMUX2, ADMUX1, ADMUX0. Мы используем нулевой канал, поэтому все биты равны 0.

//ион - напряжение питания, выравнивание влево, нулевой канал
ADMUX = (0<

Регистр ADCSRA

Чтобы АЦП заработал его надо включить, то есть установить бит ADEN – 1

Запуск преобразования осуществляется установкой бита ADSC -1. Во время инициализации мы не будем запускать АЦП, поэтому ADSC – 0

АЦП может работать в двух режимах: одиночное преобразование - когда каждое преобразование запускается программно и непрерывное - когда преобразование запускается один раз программно, а перезапускается автоматически. В нашем примере преобразование одиночное, бит ADATE – 0.

Когда АЦП закончил преобразование, он подает запрос на прерывание. Чтобы разрешить прерывание нужно установить бит ADIE – 1

Модулю АЦП для работы требуется тактовый сигнал. Он формируется из тактового сигнала микроконтроллера путем деления на фиксированные коэффициенты. Для установки коэффициентов предделителя предназначены биты ADSP2, ADSP1, ADSP0. Поскольку мы будем опрашивать с помощью АЦП кнопки, а это очень медленное устройство, выбираем самый большой коэффициент (то есть самую низкую частоту). Все биты в 1.

//вкл. ацп, режим одиночного преобр., разрешение прерывания, F преобр. = FCPU/128
ADCSRA = (1<

Про все биты рассказал, кроме ADIF. ADIF - это флаг прерывания. Он устанавливается аппаратно, когда преобразование завершено.

Регистр SFIOR

Биты ADTS2, ADTS1, ADTS0 определяют источник, запускающий процедуру преобразования. Устанавливать эти биты нужно только в режиме непрерывного преобразования. У нас режим одиночный, поэтому регистр не трогаем.

Обработчик прерывания АЦП

#pragma vector=ADC_vect
__interrupt void adc_my(void )
{
unsigned char AdcBuf = ADCH;

//какой-нибудь код

Любой микроконтроллер общается с периферийными устройствами при помощи портов ввода/вывода. При этом он способен “воспринимать” только цифровые сигналы – логический ноль или единицу. Например, у МК ATmega8 при напряжении питания 5 В логический ноль – это напряжение лежащие в интервале от 0 до 1,3 В, а единица – от 1,8 до 5 В. Довольно часто в радиолюбительской практике возникает необходимость измерять напряжения, которое может принимать любое значение в диапазоне от нуля до уровня напряжения питания. Для этих задач в составе всех микроконтроллеров AVR имеется аналого-цифровой преобразователь.


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

Разрешающая способность или разрешение – эта характеристика АЦП помогает различать два значения входного сигнала. Определяется как величина обратная наибольшему числу кодовых комбинаций АЦП на выходе. У нашего МК АЦП десяти разрядный, поэтому максимальное число возможных кодовых комбинаций будет равно 2 10 = 1024 , а его разрешающая способность равна 1/1024 от полной шкалы допустимых входных напряжений.

Для правильной работы АЦП требуется источник опорного напряжения (ИОН). По отношению к которому, АЦП измеряет сигналы поступающие на его вход. МК AVR позволяют в роли ИОН применять напряжение питания, их внутренний опорный источник на 2,56 В, а напряжение на выходе AREF (внешний ИОН).

Так как наша схема запитана от 5 В, тогда 1/1024 от всей шкалы получится 0,0048 В или около 5 мВ. С таким шагом АЦП будет определять уровень входного напряжения. Если два ближайших значения на входе преобразователя будут отличаться друг от друга на величину менее 5 мВ, АЦП будет считать равными. На практике разрешающая способность любого АЦП ограничена шумами.

Абсолютная точность АЦП это отклонение реального преобразования от идеального. Это составной результат нескольких погрешностей преобразователя. Математически описывается в количестве младших значащих разрядов (LSB). Максимальная абсолютная погрешность АЦП «Atmega8» равна 1.5 LSB. Для нашего случая абсолютная точность равна 2 × 5 мВ = ±10 мВ

Предельная частота дискретизации это есть быстродействие АЦП, которое измеряется в Гц или количестве выборок за секунду (SPS – samples per second). Для МК AVR она равна15 kSPS (килло семплов за секунду).

На порт В - МК AVR подключен типовой ЖК дисплей 16х2. Выводы AREF и AVCC подключены к питающему напряжению 5В. Это и есть ИОН. На порт С Atmega к нулевому разряду подключен контакт с вольтметром и переменным сопротивлением для изменения уровня входного напряжения. Наша задача в этом учебном примере следующая: Мы хотим вывести на ЖК экран величину напряжения, аналогичную измерению вольтметра.

Переходим к программированию запускаем новый проект в программе . В настройках Chip выбираем МК Atmega8, частоту выставляем 4,00000000 MHz. (см. пример с мигающим светодиодом). Переходим во вкладку LCD выбираем PORTB. И сохраняем проект под названием ADC (аббревиатура АЦП на забугорном языке). Вначале необходимо добавить две директивы препроцессора для работы с текстом и задержкой. Для этого после директивы LCD вставим две строки.

#include
#include

Первая строка необходима для задержек, а вторая для работы дисплея с текстом. Далее создаем массив для промежуточного хранения форматированного текста. После текста в коде, пишем.

Затем после открытия главной функции main, мы должны добавить еще две переменных. Одна из них используется для хранения значения после выборки, а другая для хранения выводимого на экран значения.

Теперь настроим сам АЦП. Для этого после настройка компаратора запишем следующее.

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off

ACSR=0x80;
SFIOR=0x00;

ADMUX=0; // Первая строка, № порта.
ADCSR=0x85; // Вторая строка настройка АЦП. (в двоичной системе x85=10000101)

Для того чтоб начать работу с АЦП у МК имеется регистр ADCSR. Вот, что в нем находится.

0-й бит ADPS0 Настройка частоты преобразования
1-й бит ADPS1 -/-/-
2-й бит ADPS2 -/-/-
3-й бит ADIE Разрешение прерывания
4-й бит ADIF Флаг прерывания
5-й бит ADFR Выбор работы АЦП. 1-непрерывный либо 0-по запуску ADSC
6-й бит ADSC Запуск преобразование 1-старт. После преобразования сбрасывается в ноль аппаратно.
7-й бит ADEN Разрешение работы АЦП 1-да 0-нет

Для включения в АЦП записываем 1 в 7-й разряд, 0 в 6-й, 5-й, 3-й и 4-й разряды. Теперь подбираем частоту, т.к у нас кварц на 4000 кГц, то нам его надо поделить (для стабильной работы АЦП его требуется тактировать частотой в диапазоне 50 кГц - 200 кГц), чуть ниже представлена таблица коэффициентов деления.

Возьмем коэффициент делителя на 32, получим частоту 125 кГц, что вполне достаточно для стабильной работы АЦП. Итак, в регистр ADCSR нам надо записать значение 10000101.

С настройками АЦП надеюсь понятно. Теперь давайте выведем в первой строке на экране наши намерения. Для этого после инициализации LCD дисплея запишем строчку. lcd_putsf("Work with ADC");

// LCD module initialization
lcd_init(16);
lcd_putsf("Work with ADC"); // Выводим запись

Теперь при старте программы В МК увидим эту надпись. Далее в бесконечном цикле пишем тело основной программы.

while (1)
{
delay_ms(20); // Задаем задержку в 20 миллисекунд
ADCSR |= 0x40; // Записываем 1 в ADSC
data = ADCW; // Вычитываем значение
V = (float) data*0.0048828; // Переводим в вольты
sprintf(string, "Data: %1.2f", V); // форматируем
lcd_gotoxy(0,1); // Выставляем курсор
lcd_puts(string); // Выводим значение

delay_ms(20); задержку на 20 миллисекунд.
ADCSR |= 0x40; битное ИЛИ. Число 0х40 в бинаре выглядит так 0b01000000. Если мы проведем по битное ИЛИ с 0х85 (0b10000101), то у нас в 6-й разряд запишется 1. Для того, чтобы началось преобразование в 6-й разряд нужно записать 1. А после преобразование он сбросится в 0 аппаратно.
data = ADCW; После преобразования микроконтроллер записывает полученное значение в ADCW. Вот оттуда мы его и возьмем
V = (float) data*0.0048828; Преобразуем полученное значение в вольты, т.к ИОН=5В, а значение регистра 1024, то мы 5/1024=0.0048828 получим коэффициент напряжения. Минимальная величина напряжения будет при минимальном значении регистра ADCW. То есть если в нем будет значение 1, то напряжение будет 0.0048828 В. Поэтому в строке, данные ADCW перемножаем на это значение - 0.0048828. Слово float в скобке используется для того чтобы преобразовать переменную data из целочисленной в вещественную с плавающей точкой.
sprintf(string, "Data: %1.2f", V); Заносим значение напряжения в массив string с последующим форматированием. Сначала впишем Data: . После ставим знак процента. 1.2f - говорит о том что мы хотим вывести на экран один знак до запятой и два знака после, а буква f означает, что это значение вещественным с плавающей точкой.
lcd_gotoxy(0,1); Курсор в нулевую позицию во второй строке.
lcd_puts(string); Выводим значение на дисплей.

Перед тем как собрать проект нужно сделать небольшие настройки в CodeVisionAVR. В меню нажимаем "Project->Configure" и в открывшемся окне переходим во вкладку "C Compiler", затем в левом нижнем углу меняем значение (s)printf Features: с int, width на float, width, precision.

Результат работы программы на рисунке ниже:


Архив с проектом для CodeVisionAVR и Proteus вы можете скачать по зеленой ссылке выше. Затем распакуйте архив в корень диска С и проект можно запускать.

АЦП — Аналого-цифровой преобразователь. Из названия можно догадаться, что на вход подается аналоговый сигнал, который преобразуется в число.

Первое о чем нужно сказать — АЦП микроконтроллера умеет измерять только напряжение. Чтобы произвести измерение других физических величин, их нужно вначале преобразовать в напряжение. Сигнал всегда измеряется относительно точки называемой опорное напряжение, эта же точка является максимумом который можно измерить. В качестве источника опорного напряжения (ИОН), рекомендуется выбирать высокостабильный источник напряжения, иначе все измерения будут плясать вместе с опорным.

Одной из важнейших характеристик является разрешающая способность, которая влияет на точность измерения. Весь диапазон измерения разбивается на части. Минимум ноль, максимум напряжение ИОН. Для 8 битного АЦП это 2^8=256 значений, для 10 битного 2^10=1024 значения. Таким образом, чем выше разрядность тем точнее можно измерять сигнал.

Допустим вы измеряете сигнал от 0 до 10В. Микроконтроллер используем Atmega8, с 10 битным АЦП. Это значит что диапазон 10В будет разделен на 1024 значений. 10В/1024=0,0097В — с таким шагом мы сможем измерять напряжение. Но учтите, что микроконтроллер будет считать, величину 0.0097, 0.0098, 0.0099… одинаковыми.

Тем не менее шаг в 0,01 это достаточно неплохо. Однако, есть несколько рекомендаций, без которых эта точность не будет соблюдена, например для измерения с точностью 10бит, частота на которой работает АЦП должна быть 50-200 кГц. Первое преобразование занимает 25 циклов и 13 циклов далее. Таким образом, при частоте 200кГц мы сможем максимум выжать
200 000/13 = 15 384 измерений.

В качестве источника опорного напряжения можно использовать внутренний источник и внешний. Напряжение внутреннего источника (2,3-2,7В) не рекомендуется использовать, по причине низкой стабильности. Внешний источник подключается к ножке AVCC или Aref, в зависимости от настроек программы.

При использовании АЦП ножка AVCC должна быть подключена. Напряжение AVCC не должно отличаться от напряжения питания микроконтроллера более чем на 0,3В. Как было сказано, максимальное измеряемое напряжение равно опорному напряжению(Vref), находится оно в диапазоне 2В-AVCC. Таким образом, микроконтроллер не может измерить более 5В.

Чтобы расширить диапазон измерения, нужно измерять сигнал через делитель напряжения. Например, максимальное измеряемое напряжение 10В, опорное напряжение 5В. Чтобы расширить диапазон измерения, нужно уменьшить измеряемый сигнал в 2 раза.

Формула для расчета делителя выглядит так:

U вых = U вх R 2 /(R 1 + R 2)

Подставим наши значения в формулу:

5 = 10*R2/(R1+R2)

т.е. можно взять любые два одинаковых резистора и подключить их по схеме

Следовательно, когда мы измеряем напряжение через делитель, нужно полученное значение АЦП умножить на коэффициент=Uвых/Uвх.

Полная формула вычисления измеряемого напряжения будет выглядеть так:
U=(опорное напряжение*значение АЦП*коэффициент делителя)/число разрядов АЦП

Пример: опорное 5В, измеренное значение АЦП = 512, коэффициент делителя =2, АЦП 10разрядный.

(5*512*2)/1024=5В — реальное измеренное значение напряжения.

Некоторые программисты пишут программу так, чтобы микроконтроллер автоматически вычислял коэффициент делителя, для этого выходной сигнал измеряют образцовым прибором и заносят это значение в программу. Микроконтроллер сам соотносит истинное напряжение каждому значению АЦП, сам процесс однократный и носит название калибровки.

Перейдем к программной реализации. Создаем проект с указанными параметрами. Также подключим дисплей на порт D для отображения информации.

Измерение будет производиться в автоматическом режиме, обработка кода в прерывании, опорное напряжение подключаем к ножке AVCC. По сути нам нужно только обрабатывать получаемые данные. Измеренные данные хранятся в переменной adc_data. Если нужно опрашивать несколько каналов, то выбираем какие каналы сканировать, а данные будут для ножки 0 в adc_data, для ножки 1 в adc_data и т.д.

В основном цикле добавим строки:

result=((5.00*adc_data)/1024.00); //пересчитываем значение АЦП в вольты
sprintf(lcd_buffer,»U=%.2fV»,result); //помещаем во временную переменную результат
lcd_puts(lcd_buffer); //выводим на экран

Небольшое замечание, чтобы использовать числа с плавающей точкой, нужно в настройках проекта изменить (s)printf Features: int, width на float, width, precision. Если этого не сделать десятые и сотые мы не увидим.

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

Резистором можно менять напряжение, измеряемое напряжение выведено на дисплей. При сборке на реальном железе к ножке Aref нужно подключить конденсатор на 0,1мкФ. Урок получился немного сложным, но думаю он вам понравится.

Файл протеуса и прошивка:

Update:
Измерение тока:

На прошлом уроке мы собрали свой первый программатор и прошили с его помощью МК. Ну что, поздравляю вас с первым реальным проектом. Мигание светодиодом это конечно хорошо, но давайте займемся чем-нибудь по интереснее. Сегодня я расскажу как работать с АЦП(аналогово-цифровой преобразователь). Ну поехали. Перед тем как браться за программирование, давайте вернемся в школу. Да, да именно в школу, на урок алгебры и вспомним что же такое график. Из своего детства я помню, что при построении графика по той или иной функции многие из класса выпадали в осадок. Да, да именно графики были не понятны как и векторы. Хотя что там не понять. А может просто преподаватель плохо объяснял. Ну я попробую удалить это белое пятно. Те кто могут с ходу нарисовать график Х = У могут не читать эту часть текста. Для тех кто не понимает как это делать, лучше внимательно прочесть. Давайте рассмотрим выражение Х = У . У нас есть неизвестная Х и неизвестная У . Если мы возьмем любое число и подставим скажем под Х , то соответственно У примет то же значение. Ну это само собой, ведь у нас знак равенства. А как теперь по этому уравнению построить график. А очень просто. Первое что нужно понять, так это то что любой график является прямой или кривой состоящие из множества точек. Что это значит. А значит это то, что если вы возьмете фломастер и попытаетесь нарисовать прямую, только не проведя по листу, а ставя точки одну за другой, то вы получите некую прямую или кривую. Вот она больше всего подходит к понятию график. Но просто нарисованная линия на листе это еще не все. Ведь нам надо строить линию точно по уравнению. А как это сделать? Вот тут нам поможет координатная ось. Что это такое. Вот что можно сделать при помощи простой деревянной линейки? Правильно, измерить длину. А в чем? Конечно в мм или см . Глупый вопрос скажите вы, но будете не правы. Та шкала на которую вы смотрите для определения длины и есть координатная ось. А в каких единицах она, это все равно. Ведь у англичан она в дюймах. Теперь давайте представим что наша линейка имеет значения в Х -ах. И равна она от 0 до скажем 20. Это означает что на всю длину линейки мы имеем 20 рисок от 0 до 20 соответственно. И назовем ее ось Х . Так же возьмем еще одну линейку на 20 рисок и назовем ее ось У . Теперь соединим эти линейки нулевыми рисками так чтобы линейка Х лежала горизонтально, а У вертикально. Рисунок 1. И так мы получили координатную сетку. Теперь давайте попробуем с помощью данной координатной сетки нарисовать наш график по уравнению Х = У . Подставим под Х число 2. Теперь проведем от риски 2 оси Х вверх линию. Так как у нас икс равен игрику, то проведем еще одну линию от риски 2, но уже от оси У . Теперь посмотрев на эти две линии, найдем место их пересечения. Таким образом мы нашли одну из множества точек нашего будущего графика. Давайте найдем еще одну точку. Скажем что Х равен 4. Значит и У равен 4. Чисто теоретически мы можем на этом закончить. Так как видно, то что, при любом значении Х , У принимает то же значение, и график будет выглядеть простой прямой. Но мы не верим. Давайте проверим. Давайте найдем еще три точки. К примеру 6, 8 и ну скажем 18. Найдя все точки давайте соединим их прямой. Вот что у меня получилось. Рисунок 2. Как видите, прямая оказалось прямой. И если внимательно присмотреться, то можно сделать вывод, что эта прямая наклонена от обеих осей на 45°. Это вытекает из равенства обеих неизвестных. А давайте по химичим. Ну к примеру удвоим значение X . Теперт наше равенство примет вид Y = 2X . Попробуем построить график. Возьмем к примеру значения Х равным 2, 4 и 9. Вот что у меня получилось. Рисунок 3. Отсюда вытекает замечание, чем больше коэффициент переменной, тем больше он удаляет от себе прямую. Ну это видно из построенного графика. Видите как прямая прижалась к оси У. Ну с прямыми вроде как разобрались. Давайте теперь построим что-нибудь кривое. Это не в смысле плохого здания. Берем классическое квадратное уравнение. Y = X² . (Квадратное, это не потому что выглядит как квадрат, а потому что имеет одну из неизвестных во второй степени.) Теперь давайте найдем четыре точки со значением Х равным 1, 2, 3 и 4. Не пугайтесь, график получится большой не смотря на такие маленькие иксы. Ведь они у нас в квадрате. Вот что у меня получилось. Рисунок 4. Ничего не напоминает? Конечно, ветвь параболы. Если мы возьмем еще иксы и с отрицательным значением, то получим полноценную параболу. Теперь давайте построим более сложную вещь. Синусойду. Уравнение имеет вид У = sinХ . Здесь надо помнить лишь одно, что значение икса есть угол, который меняется от 0° до 360°. То есть полный оборот. Значение может быть и больше, но это будет лишь следующий оборот, а за ним следующий и так далее. Теперь давайте подставим под Х значения 0°, 90°, 180°, 270° и 360°. Да, да, это полный оборот. Вот что у меня получилось. Рисунок 5.
Ну на этом с графиками мы закончим. Я надеюсь что все было понятно. Что такое отцифровка сигнала? Сразу отмечу, мы не будем разбирать теорему Котельникова, так как это займет очень много времени и появятся много вопросов. Будем разбирать все на пальцах. И так, отцифровка - это разбитие некого сигнала на множество маленьких прямых. Вспомним нашу параболу, она была построена из четырех прямых. Это маловато, оно и видно. Ветвь какая-то ломаная. А вот если взять не пять точек, а скажем сто, то понятно что ветвь будет выглядеть более менее плавная. А если взять тысячу точек? Хорошо, ну разбили мы наш сигнал на прямые и что? А тут нам понадобятся знания которые мы получили выше. Только мы пойдем от обратного. Если мы имеем график и одно из неизвестных, то мы можем смело найти второе неизвестное графическим путем. Для наглядности смотрим на рисунок ниже. Рисунок 6.
Что мы здесь видим. По оси Х отложено время в секундах, а по оси У напряжение в вольтах. Нам известна форма сигнала и время. Теперь мы договариваемся что через каждую секунду будем узнавать величину напряжения. Что собственно и видно из графика. Теперь собрав в последовательность наши напряжения, а именно: 0.3, 0.9, 1.9, 4, 6, 7.9, 8.9, 9.5, 10, 9.9, 9.6, 9.1, 8.1, 6. Мы можем в принципе заявить, что мы отцифровали сигнал. Ведь мы знаем несколько точек находящихся на кривой сигнала. Но вот если мы обратно попробуем собрать наш сигнал, то вот что получим. Рисунок 7.
Но как вы видите это не совсе то что мы хотели увидеть. А почему так получилось? А потому что мы очень редко снимали значение напряжения. Чтобы график был более плавным, нужно уменьшить период времени опроса. То есть смотреть не через 1 секунду, а через 1 сотую секунды. И тогда у нас будет не 13 точек, а 1300. Есть разница? Теперь давайте перейдем к аппаратной части. Как реализована данная схема в железе. АЦП не может запоминать напряжение. А как же тогда, спросите вы. А я скажу что достаточно просто. Вот смотрите. Берем конденсатор и подаем на него наш сигнал. Пока конденсатор заряжается, мы отсчитываем время, ну например 1 миллисекунду. По истечении времени прекращаем подавать сигнал. Теперь все наоборот, начинаем разряжать наш конденсатор, а в это время считаем от нуля до конца разряда конденсатора. Получившееся число и есть та точка которая попадает на график по истечении 1 миллисекунды. В МК эта процедура называется "выборка". Ну с теорией мы вроде закончили, переходим к практике. Нам понадобится МК Atmega8. Данный МК имеет 6 каналов 10-ти разрядных АЦП, два из которых 8-ми разрядные. Для того чтобы начать работать с АЦП, нам понадобиться лишь опорное напряжение. Для начала возьмем 5 вольт. Это означает что отцифровка сигнала возможна от 0 до 5 вольт. Так как канал 10-ти разрядный то получается 5/2 10 = 0.0048 В на единицу. Значит если у нас АЦП выдаст при выборке число 482, то напряжение будет равно 482*0.0048 = 2.3136 В. В принципе неплохая точность. По заявленным параметрам, МК делает 15000 выборок в секунду. Отсюда наш график можно разбить на 14999 прямых. Давайте для начала соберем схему чтоб было немного по понятнее. Рисунок 8.
Немного пояснений. На порт В МК подсоединен LCD 16х2. Сейчас я вдаваться в подробности как он работает не буду, это не в этом уроке. Просто подсоедините как на рисунке. Выводы AREF и AVCC присоединены к 5В. Это как раз есть то самое апорное напряжение. На порт С к нулевому разряду подсоединен контакт с вольтметром и переменным резистором для изменения входного напряжения. Наша задача такова. Мы должны вывести на экран величину напряжения ту которую показывает вольтметр. Приступаем к программированию. Запускаем новый проект. В настройках Chip выбираем Atmega8, 4,00000000 MHz. Во вкладке LCD выбираем PORTB. И сохраняем проект под названием, в моем случае, ADC. Вы можете его назвать как вам угодно. Первым делом мы добавляем две директивы препроцессора для работы с текстом и задержки. Для этого после директивы LCD добавим эти две строки. #include #include Первая из них нужна для создания задержек, а вторая для работы с текстом. Далее нам нужно создать массив для временного хранения форматированного текста. После надписи "// Declare your global variables here" пишем char string;. // Declare your global variables here char string; Теперь после открытия главной функции main, мы должны объявит две переменные. Одна для хранения значения после выборки, а другая для хранения выводимого значения. Для этого запишем так. void main(void) { // Declare your local variables here int data; // Переменная для хранения данных выборки. int так как регистр 10 разрядов. float V; // Переменная для выводимого значения. float так как у нас точность до 2 знаков. Теперь давайте займемся настройкой самого АЦП. Для этого после настройка компаратора сразу запишем две строчки. // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; ADMUX=0; // Первая строка, № порта. ADCSR=0x85; // Вторая строка настройка АЦП. Ну с номером порта все ясно, какой номер прописан с тем и работаем, а вот с настройкой тут давайте по подробнее. Для того чтоб начать работу с АЦП у МК есть такой регистр который называется ADCSR . Что в нем находится. 0-й бит ADPS0 Выбор частоты преобразования 1-й бит ADPS1 Выбор частоты преобразования 2-й бит ADPS2 Выбор частоты преобразования 3-й бит ADIE Разрешение прерывания 4-й бит ADIF Флаг прерывания 5-й бит ADFR Выбор работы АЦП. 1-непрерывный 0-по запуску ADSC 6-й бит ADSC Запуск преобразование 1-старт. После преобразования сбрасывается в ноль аппаратно. 7-й бит ADEN Разрешение работы АЦП 1-да 0-нет Теперь давайте его настроим. Чтобы включить АЦП нам надо выставить в 1 7-й разряд. Далее выставим 0 для старта преобразования. Мы его потом дергать будем. После выставим в 0 5-й разряд. Будем сами запускать преобразование. 3-й и 4-й разряды выставим в 0. Мы не будем работать с прерыванием. Теперь осталось подобрать частоту. Если почитать мануал на МК, то там сказано что для более стабильной работы АЦП его необходимо тактировать частотой в пределах 50 кГц - 200 кГц. Так как у нас кварц на 4000 кГц, то нам его надо поделить. Вот для этого мы и воспользуемся первыми тремя разрядами. Смотрим ниже на таблицу коэффициентов деления. Что нам выбрать. Берем нашу частоту кварца и делим на коэффициент. 4000 кГц делим на 8, получаем 500 кГц. Много. Давайте теперь на 16, получим 250 кГц, тоже многовато. Делим на 32 и получаем 125 кГц. Во то что надо. Мы уложились в заданные пределы. Смотрим в таблицу и видим что коэффициент 32 задается значением разрядов 101. Ну вроде все собрали. теперь давайте посмотрим на наш регистр. Вот его значения. 10000101 здесь собраны все ранее рассмотренные значения всех разрядов. Если перевести это число в HEX то получим 0х85. Теперь вам понятно почему я записал в регистр ADCSR значение 0х85. С настройками АЦП закончено. Теперь давайте выведем в первой строке наши намерения. Для этого после инициализации LCD запишем строчку. lcd_putsf("Work with ADC"); // LCD module initialization lcd_init(16); lcd_putsf("Work with ADC"); // Выводим запись Теперь при старте программы мы в первой строке увидим нашу надпись. Далее в бесконечном цикле пишем тело самой программы. while (1) { delay_ms(20); // Задаем задержку в 20 миллисекунд ADCSR |= 0x40; // Записываем 1 в ADSC data = ADCW; // Вычитываем значение V = (float) data*0.0048828; // Переводим в вольты sprintf(string, "Data: %1.2f", V); // форматируем lcd_gotoxy(0,1); // Выставляем курсор lcd_puts(string); // Выводим значение }; Как вы заметили вся программа состоит из семи строк. Давайте все по порядку. delay_ms(20); Эта функция которая создаст задержку на 20 миллисекунд. ADCSR |= 0x40; Здесь мы делаем по битное ИЛИ. Число 0х40 в бинаре выглядит так 0b01000000. Если мы проведем по битное ИЛИ с 0х85 (0b10000101), то у нас в 6-й разряд запишется 1. Помните, что надо сделать чтобы началось преобразование. Да, да, именно в 6-й разряд нужно записать 1. А после преобразование он сбросится в 0 аппаратно. data = ADCW; После преобразование МК записывает полученное значение в регистр ADCW. Вот мы от туда его и выдергиваем. V = (float) data*0.0048828; Здесь мы преобразуем полученное число в вольты. Так как у нас опорное напряжение 5В, а значение регистра 1024, то мы 5/1024=0.0048828 Это коэффициент напряжения. Ну или минимальная величина напряжения при минимальном значении регистра ADCW. То есть если в регистре будет значение 1, то велечина напряжения будет равна 0.0048828 В. Поэтому мы в строке, данные ADCW перемножаем с 0.0048828. Слово float в скобке нужно для того чтобы преобразовать переменную data из целочисленной в вещественную с плавающей точкой. sprintf(string, "Data: %1.2f", V); Здесь мы заносим значение напряжения в массив string с форматированием. Сначала мы впишем Data: . После ставится знак процента. Он говорит о том сколько знаков будет выведено. 1.2f говорит о том что мы хотим вывести один знак до запятой и 2 знака после, а буква f говорит что мы имеем дело со значением вещественным с плавающей точкой. lcd_gotoxy(0,1); Ну тут все ясно. Выставляем курсор в нулевую позицию во второй строке. lcd_puts(string); Выводим значение на экран. Перед тем как собрать проект нужно сделать небольшие настройки. Зайдите в настройки проекта "Project->Configure" и в открывшемся окне перейдите во вкладку "C Compiler" Далее в левом нижнем углу поменяйте значение (s)printf Features: с int, width на float, width, precision . Зачем это нужно я расскажу в статье по работе с ЖК дисплеями, а сейчас просто поменяйте. Вот и вся программа. Ниже на рисунке видно как это работает. Рисунок 9.