AVR. Учебный курс. Использование АЦП
Автор DI HALT
Опубликовано 20 Ноя 2008
Рубрики: AVR. Учебный курс
Метки: AVR, АЦП
Многие AVR имеют на борту АЦП последовательного приближения.
АЦП это десятиразрядное, но при точности +/- 2 минимально значащих разрядов его можно смело считать восьмиразрядным :) Так как в младших двух разрядах всегда мусор какой то, не похожий на полезный сигнал. Тем не менее это неплохой инструмент для контроля напряжения, в восьмиразрядном режиме имеющий 256 отсчетов и выдающее частоту дискретизации до 15кГц (15 тысяч выборок в секунду).
Конфигурация источника
Сигнал в АЦП подается через мультиплексор, с одного из восьми (в лучшем случае, часто бывает меньше) входов. Выбор входа осуществляется регистром ADMUX, а точнее его битами MUX3…MUX0. Записанное туда число определяет выбраный вход. Например, если MUX3..0 = 0100, то подключен вывод ADC4.
Кроме того, существует несколько служебных комбинаций битов MUX, использующихся для калибровки.
Например, 1110 подключает к АЦП внутренний источник опорного напряжения на 1.22 вольта. А если записать в MUX3..0 все единицы, то АЦП будет изнутри посажено на землю. Это полезно для выявления разных шумов и помех.
У старших AVR семейства Mega (8535, 16, 32, 128) есть возможность включить АЦП в режиме дифференциального входа. Это когда на два входа приходят разные напряжения. Одно вычитается из другого, да еще может умножаться на коэффициент усиления. Зачем это нужно? А, например, когда надо замерить перекос напряжения измерительного моста. У какого-нибудь тензомоста при входном напряжении в пять вольт выходные сигналы будут различаться между собой всего лишь 30мВ, вот и поймай его. А так подал на диф вход, подогнал нужный коэффициент усиления и красота!
Таблицу значений MUX3..0 для диф включения я не буду тут приводить, она находится легко в даташите, зовется она “Input Channel and Gain Selections“. Я поясню лишь один тонкий момент. В режиме выбора диф входа встречаются такие комбинации как: первый вход ADC0 и второй вход тоже ADC0 ну и коэффициент усиления еще. Как так? Ведь для диф входа нужно два разных входа! Вначале подумал опечатка, поднял даташит на другую АВРку - та же ботва. Потом повтыкал в текст ниже и понял - это для калибровки нуля. Т.е. перед началом съема диф данных нам нужно закоротить входы, чтобы понять, что же у нас ноль. Так вот, комбинация когда два входа подключены к одной ноге это и есть та самая калибровочная закоротка входов. Делаешь первое преобразование на такой фигне, получаешь смещение нуля. А потом вычитаешь его из всех полученных значений, что резко повышает точность.
Мультиплексирование каналов осуществляется только после того, как завершится преобразование, поэтому можно смело запускать АЦП на обсчет входных значений, записывать в MUX3..0 параметры другого входа, и готовится снимать данные уже оттуда.
Выбор опорного сигнала
Это максимальное напряжение, которое будет взято за максимум при измерениях. Опорное напряжение должно быть как можно стабильней, без помех и колебаний — от этого кардинальным образом зависит точность работы АЦП. Задается он в битах REFS1..0 регистра ADMUX.
- По дефолту там стоит REFS1..0 = 00 — внешний ИОН, подключенный к входу AREF. Это может быть напряжение со специальной микросхемы опорного напряжения, или же со стабилитрона какого, если нужно замерять небольшое напряжение, заметно меньшее чем напряжение питания, скажем от 0 до 1 вольт, то чтобы было точнее, и чтобы оно не затерялось на фоне пятивольтового питания, то на AREF мы заводим опорное напряжение в 1 вольт.
- REFS1..0 = 01 - тут просто берется напряжение питания. У всех почти Мег с АЦП есть вход AVCC - вот это напряжение питания для AЦП и порта на который это АЦП повешено. Подавать туда плюс питания желательно через LC фильтр, чтобы не было искажений.
- REFS1..0 = 11 - внутренний источник опорного напряжения на 2.56 вольт. Честно говоря, качество этого источника мне сильно не понравилось. С ним показания АЦП плавают как говно в проруби. Но если невозможно обеспечить гладкую и стабильную подачу напряжения на AREF или AVCC то прокатит. Кстати, внутренний ИОН подключен к выводу AREF так что можно повесить туда кондер и попробовать его чуть чуть сгладить. Немного, но помогает.
В регистре SFIOR под АЦП отведено аж три бита. ADT2..0 которые управляют режимами запуска АЦП.
- По дефолту ADT2..0 = 000 и это значит, что преобразование идет в непрерывном режиме. Ну или по ручному запуску.
- ADT2..0 = 001 — запуск АЦП от аналогового компаратора. Удобно блин. Например, чтобы не замерять постоянно входную величину, а запрограммировать компаратор на то, что как только у него вылезет что-либо выше порога, так тут же захватывать это дело на АЦП.
- ADT2..0 = 010 — запуск от внешнего прерывания INT0
- ADT2..0 = 011 — по совпадению таймера T0
- ADT2..0 = 100 — по переполнению таймера Т0
- ADT2..0 = 101 — по совпадению с таймера Т1
- ADT2..0 = 110 — По переполнению таймера Т1
- ADT2..0 = 111 — По событию “захват” таймера Т1
Частота выборки АЦП задается в битах предделителя ADPS2…0 регистра ADCSR. Саму таблицу можно поглядеть в даташите на соответствующий МК, скажу лишь то, что самая оптимальная точность работы модуля АЦП находится в пределах 50…200кГц, поэтому предделитель стоит настраивать исходя из этих соображений. С повышением частоты точность падает.
Прерывания.
Естественно у АЦП есть прерывания. В данном случае это прерывание по окончанию преобразования. Его можно разрешить битом ADIE, а внаглую вручную палится оно по флагу ADIF (регистр ADCSRA). Флаг ADIF автоматом снимается при уходе на вектор прерывания по АЦП.
Данные с АЦП сваливаются в регистровую пару ADCH:ADCL откуда их можно забрать. Причем тут есть один прикольный момент. Регистровая пара то у нас ведь 16ти разрядная, а АЦП имеет разрядность 10бит. В итоге, лишь один регистр занят полностью, а второй занимает лишь оставшиеся два бита. Так вот, выравнивание может быть как по правому краю — старшие два бита в ADCH, а младшие в ADCL, либо по левому — старшие биты в ADCH, а два младших бита в ADCL.
Зачем это сделано? А это выборка разрядности так оригинально организована. Как я уже говорил, в младших разрядах все равно мусор и шумы (по крайней мере я от них так и не смог избавиться, как ни старался) . Так вот. Делаем выравнивание по левому краю. И загребаем старшие разряды только из регистра ADCH, а на младший забиваем. Итого, у нас число отсчетов становится 256. За выравнивание отвечает бит ADLAR в регистре ADMUX 0 — выравнивание по правой границе, 1 — по левой.
Запуск преобразования в ручном или непрерывном режиме.
Для запуска преобразования нужно вначале разрешить работу ADC, установкой бита ADEN в регистре ADCSR и в том же регистре ткнуть в бит ADSC. Для запуска непрерывного преобразование (одно за другим) нужно также выставить бит ADFR (ADATA в некоторых AVR).
Повышение точности уходом в спячку.
Для повышения точности, чтобы внутренние цепи АЦП не гадили своими шумами, можно запустить АЦП в спящем режиме. Т.е. проц останавливается, все замирает. Работает только WatchDog и блок АЦП. Как только данные сосчитаются, генерируется прерывание которое будит процессор, он уходит на обработчик прерывания от АЦП и дальше все своим чередом.
А теперь приведу парочку примеров простой инициализации и работы с АЦП. Микроконтроллер ATMega8535
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ; Мой любимый макрос для записи в порты :)))) .MACRO outi LDI R16,@1 OUT @0,R16 .ENDM ; ADC Init - Инициализурем АЦП. Это можно сунуть куда - нибудь в начало кода OUTI ADCSRA,(1<<ADEN)|(1<<ADIE)|(1<<ADSC)|(1<<ADATE)|(3<<ADPS0) ; Итак что тут у нас: ; ADEN = 1 - разрешаем АЦП ; ADIE = 1Разрешаем прерывания. ; ADSC = 1 Запускаем преобразование (первое, дальше автоматом) ; ADATE = 1 Непрерывные последовательные преобразования, одно за другим. ; ADPS2..0 = 3 Делитель частоты на 8 - так у меня получается оптимальная частота. OUTI ADMUX,0b01000101 ;А тут выбираем откуда брать будем сигнал ;REFS -- 0b[01]000101 первые два бита - напряжение с входа AVCC ;ADLAR --0b01[0]00101следующий бит выравнивание по правому краю ;MUX -- 0b010[00101]</B>Сигнал на вход идет с 5й ноги. |
А что дальше делать? А ничего! Сидеть и ждать прерывания!
Когда оно придет процессор кинет на вектор и дальше уже можно либо переписать данные из ADCH:ADCL в другое место, либо какую простенькую обработку тут же, не отходя от кассы, замутить. Вроде усреднения.
Вариант два, с уходом в спячку. В принципе, все то же самое, только нужно выключить автоматический перезапуск конвертирования. Далее в регистре MCUCR в битах SM2..0 выбрать режим ADC Noise Reduction SM2..0 = 001, а после, сразу же после запуска послать процессор в спячку командой SLEEP. Как только он уснет заработает АЦП, сделает преобразование и проснется на прерывании.
Выглядит это так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ; ADC Init - Инициализурем АЦП. Это можно сунуть куда - нибудь в начало кода OUTI ADMUX,0b01000101 ;А тут выбираем откуда брать будем сигнал ;REFS -- 0b[01]000101 первые два бита - напряжение с входа AVCC ;ADLAR --0b01[0]00101следующий бит выравнивание по правому краю ;MUX -- 0b010[00101]</B>Сигнал на вход идет с 5й ноги. OUTI MCUCR,0b10010000 ; Выставил биты спящего режима в Noise Reduction ; А это уже тело главной программы Main Prog: OUTI ADCSRA,(1<<ADEN)|(1<<ADIE)|(1<<ADSC)|(0<<ADATE)|(3<<ADPS0) ; Подготовили АЦП SLEEP ; Свалились в спячку, как только Хрюша со Степашей скажут нам ; Баю-бай так врубится молотилка АЦП, затем придет Фреди Крюг... ; в смысле запрос на прерывание и проц резко проснется |
Ну и, для повышения точности, следует соблюдать ряд правил по подключению питания к АЦП модулю, например подавать напряжение на вход AVCC через дроссель, ставить конденсаторы и земли побольше вокруг. Об этом все есть в даташите. Я же скоро выложу пример рабочей программы - примера для АЦП и UART.
Комментарии
120 комментариев на «AVR. Учебный курс. Использование АЦП»
Оставьте свой отзыв
Вы должны войти, чтобы оставлять комментарии.





На сколько я понял, АЦП - это цифровой вариант аналогового компаратора? Ведь по существу и внешнее опорное напряжение они снимают с одной ножки . Только компаратор оперирует с сравнением чистого напряжения, а АЦП - с его 8-и битным аналогом… Я правильно понял? И какие еще могут быть примеры применения АЦП ?
применение в любом роде задач, где подаётся сигнал и его надо обработать, сохранить и передать дальше в буфер.
лично я юзал для 3д-резистора, который выглядит как джойстик и менят сопр от 0 дол 10к. очень удобно изменять что-либо на индикаторе со скоростью тем большей, чем сильней повёрнут джойстик. ну или вот поставили задачу сделать гитарный тюнер, то там думается нужны спецпроцессоры со встроенным пфк, простые авры не подойдут.
АЦП - это аналог не компаратора, а цифрового вольтметра со шкалой 0-1023. Если опору взять 1,024v, цена деления будет 1mV.
Погрешность определяется погрешностью опоры и шумами, плюс +-1 младшего разряда. Например, в специальном малошумящем режиме, когда на время измерения большинство цифровой начинки на время измерения переводится в спящий режим, у PIC гарантируется погрешность преобразования +_1 последнего разряда по всей шкале. В переводе на привычный язык - это точность 0,1% !
Вы когда-нибудь видели аналоговый прибор такой точности? Даже в 8-битном режиме (0-255) точность получается 0,4% ! Аналоговые приборы 0,5 процента имели зеркальные шкалы, нехилые размеры, и использовались как образцовые, для поверки менее точных. Большинство же тестеров имеет погрешность 1 - 2,5% и более, в зависимости от вида измерений. Для точных преобразователей есть много очень стабильных микросхем - источников опорного напряжения от 1,024 до 10в. Самый простой и дешевый - TL431, регулируется от 1,2v до питающего.
Да, тока осталось сделать точный ИОН с погрешностью менее 0.1%
Нет проблем. Вот, навскидку, из тех, что я просматривал пару лет назад и легко найти в продаже:
Mикросхемы опорного напряжения:
Тип UA допуск ($)
ICL8069 1.2 +-0.01% 3,63
LH0070 10.000 -+0.02% 18,15
LM336 2.5 +-1% 3.08 ц 154-212T
LM336 5 +-1% 3.08
LM9140BYZ 2.5 +-0.5% 8.48
LM9140BYZ 5 +-0.5% 8.48
LT1021DCN 5 +-0.05% 12.37
LT1431CZ 5 +-1% 5.48
TL431C 2.5-36 30ppm/C 1.51 ц 23-38T
REF02CN8 5 +-0.3% 9.14
ZN404 2.45 +-3% 2.16
Есть куча других, просто эта шпаргалка оказалась под руками.
А еще есть TLE2426 - клевый распополамиватель напряжения. Хорошо подходит для создания виртуальных нулей в однополярных схемах.
не обязательно иметь точный ИОН. главное, что бы он был стабилен. тогда готовое устройство можно откалибровать (подстроичными элементами или программно)по внешнему образцовому прибору.
п.с. чуть выше SWG путает разрешающую способность и точность. вернее не делает разницы между ними
Если производителем гарантирована точность +-1 единица младшего разряда, то разницы между разрешающей способностью и точностью действительно нет. Главное - не потерять ее, а это уже зависит и от ИОН, и от монтажа, и от допуска и стабильности резисторов делителя, и т.д.
В своем ходовом контроллере я и использовал как раз тот факт, что хотя у интегральных стабилизаторов разброс напряжения стабилизации несколько процентов, в то же время при постоянной и неполной нагрузке, при входном напряжении намного больше выходного, (10,5-14,2v/5v), и небольшом интервале температур (работа в помещении) стабильность выходного напряжения стабилизатора вполне достаточна для моей задачи контроля состояния аккумулятора, а отклонение от 5v легко компенсируется подстройкой входного делителя.
10, а не 8 бит результата преобразования я использовал тоже не для получения высокой точности, а чтобы не потерять ее в процессе пересчета и округления. Всегда предпочитаю иметь несколько лишних разрядов, которые в конце можно отбросить, тем более что в процессе пересчета диапазон значений всегда укладывается в пределы двух байт (WORD). Конечное максимально допустимое значение (0-149) - укладывается уже в один байт, так и хранится и пересылается.
Точно!! =) А ведь так оно и есть! … и как я сразу то не выехал
Респект SWG за идеально разжеванный ответ! ))
А ещё для повышения точности и уменьшения шума, возможно будет полезным не подключать никакие нагрузки на остальные ножки порта. Т.е. если меряем на входе ADC0, то остальные выводы (PA1…PA7) - только на ввод, кнопки там, датчики.. но не светодиоды!
читал книжку по аврам.
про ацп там одна из последних глав. запомнилось, что кроме программных штучек для повышения точности и необходимой обвязки (вроде LC и прочего) требуется и разводка специальная. вроде разделения аналоговой и цифровой земли, “толстые” дорожки и прочее… вот про это хотелось бы поподробнее, т.к. там одни слова и функциональные схемы.
как это живьём выглядит, хотя бы в лайоуте?
Все довольно просто. Быстро привыкаешь, потом уже это сидит в подсознании.
Гляньте, например, плату моего ходового контроллера. Там у меня есть и силовые цепи от 2х движков с ШИМ, и задействован АЦП в 10 битном режиме для контроля напряжения аккумулятора. Дорожки короткие, достаточно широкие, шины земли и питания имеют большую площадь, движки включены на выход L293 через индуктивно-емкостные фильтры, пути протекания токов двигателей проходят далеко от малосигнальных цепей. Напряжение батареи поступает на вход АЦП через делитель 1:3, что дает макс. входное напряжение 5в при напряжении на батарее 15в. Реально оно не превысит 14,5в даже в режиме заряда, так что измерение проводится в пределах последней трети шкалы. Слишком большая точность мне не нужна, поэтому я в качестве опорного напряжения использовал напряжение питания. Нагрузка стабилизатора около 30мА и практически не меняется, стабильность его достаточно хороша, а разброс напряжения стабилизации легко компенсируется подстройкой входного делителя. Измеренное значение программно умножаю на 15, прибавляю 50 (для округления) и делю целочисленно на 100. В результате получаю, например, 127 при 12,7V на батарее. Для калибровки достаточно подключить достаточно точный цифровой вольтметр к батарее и отрегулировать делитель так, чтобы выдаваемые значения напряжения соответствовали показаниям образцового прибора. Достаточно выставить в 1 точке, линейность преобразования достаточно высока. Только и делов. Программа на Паскале - всего несколько строчек. Работает уже пару месяцев, показания достаточно точны и стабильны. По RS232 результат измерения поступает в комп, где и отображается на виртуальном отладочном пульте.
Так а где плату то глянуть? Я бы с удовольствием глянул как грамотно развести аналоговую и цифровую землю. Судя по твоим комментариям в разных статьях у тебя опыту вагон и маленькая тележка.
Сори, случайно только что наткнулся на плату то на сайте. Профессионально сделана ничего не скажешь.
Какую именно плату? Я далеко не везде делал аналоговую землю. Обычно я на точность АЦП редко заморачиваюсь.
Это я про плату которую SWG для робота сделал. Которую он выше описывает.
“Робот на контроллере PIC от swg”, сказать честно я в легком шоке. Профессионализм SWG реально впечатляет. Да человек со временем может много чего достичь в области которой он занимается постоянно.
Привет!
Спасибо за интересную статью!
Вот фраза: “Как я уже говорил, в младших разрядах все равно мусор и шумы (по крайней мере я от них так и не смог избавиться, как ни старался)” - а пробовал делать усреднение по множеству отсчетов?
Делал усреднение по 256. Както не особо заметен результат был :/ Возможно, конешн, сторонняя наводка, но провод до самого АЦП идет экранированным кабелем тупо с резистора, задающего напряжение.
не знаю как (я не программер) но коллеги из aduc814 (если не ошибаюсь там 12-разрядный АЦП последовательного приближения) программно выжимали разрешение 1/20000. я с помощью аналогового калибратора (В1-12) проводил испытания их разработки и при 2В на входе, приращение в 0,1 мВ отслеживалось великолепно.
Боюсь вопрос глупый, но может просто хватило-бы подвести питание к AVR-у отдельным толстым медным проводом, а на самом контроллере прямо поверх корпуса повесить по питанию пару из электролита на тыщи микрофарад и керамического - я подозреваю что контроллер мог сам себе помеху создавать.
Ну и кстати, меряющий резистор лучше не экранированным кабелем подключать а прямо к ногам АЦП припаять, хотя-бы ради эксперимента.
Еще встречал в правильных устройствах - на всех цифровых выводах микроконтроллера висели между выводом и внешней нагрузкой резисторы около 100 Ом - специально чтобы уменьшить токи при переключении состояния вывода и таким образом уменьшить ВЧ помехи, ну и естественно, тактовая частота была минимально возможная.
Да, и еще, коллеги советовали такие схемы по возвожности делать навесным монтажем, причем не на макетнице а именно взять кусок текстолита, посверлить где надо отверстия и соединить каким удобно проводом, потому что в плате и толщина фольги ограничена и между дорожками всегда присутствует емкостная связь, а навесным можно каждому сигналу экран и даже витую пару исполнить :)
Не знал куда написать, поэтому написал сюда.
Есть ли на сайте описание, как программно реализовать на МК что-то вроде дешифратора на микросхеме серии ИД. Вообщем, проще говоря, как к микроконтроллеру подключить семисегментный индикатор, и желательно не один, а, к примеру, 3 индикатора (три цифры)?
А что так сложно? ;) Берешь и пишешь!
Самый простой способ это сделать в памяти таблицу. В ячейке с смещением 0 - 7-код нуля, в ячейке с смещением 1 7-код 1 и так далее.
После, делаешь Bin2Dec конверсию и по таблице (косвенной адресацией по смещению) переводишь ее в 7сег код и уже гонишь в порт.
Экспериментирую с АЦП в ATMega8. Проблема в том, что порт имеет сопротивление порядка 20 Ом, соответственно, ток через него доходит до 80мА. Cконфигурирован как высокоимпедансный вход (если это имеет значение). Не сгорел, ибо меряет. Куда копать?
Не должно так быть. Раз Hi-Z конфигурация, значит сопротивление его должно быть высоко и ни о каких 20 омах не должно быть и речи. Может пробило?
Попробуй пропустить сигнал через повторитель на ОУ (подать сигнал на +вход ОУ, а на -вход подать напрямую с выхода, без всяких резисторов).
Сомневаюсь, что могло пробить - выше 5 вольт в схеме взяться просто неоткуда. Попробую на другую ногу АЦП повесить.
Может, я что-то не так понимаю, но ведь у ОУ достаточно большое внутреннее сопротивление - соответственно, падение на этих 20 омах будет около 0, разве нет?
Наводка или статика.
Входное сопротивление ОУ можно считать бесконечным, следовательно, минимальные воздействия измерительной цепи на источник напряжения. Выходной же каскад ОУ довольно мощный и возможно таки прокачает тебе этот 20омный вход. Но, повторюсь, 20ом это слишком мало! Что то не так.
Собственно у МК в режиме высокого импенданса сопротивление тоже в гигаомы.
С грустью признаю, что я осел.
Перепутал порты. Не обратил внимания, как мой порт АЦП был сконфигурирован, но сильно подозреваю, что как вывод. Теперь все работает.
Чет не понял я - внутренний ИОН на 1,22 или 2,56 вольта? а то в статье и так и так написано.
на 1.22 вольта это ИОН от аналогово компаратора. Его можно просто подать на вход. Его нельзя юзать в качестве референса. А 2.56 это ИОН от ацп. Его можно подать только на референс, но нельзя завернуть на вход.
не понял - как это? можно подать на вход, но нельзя юзать как референс.
если мы подадим на один из входов компаратора, то он и будет референсным (опорным напряжением). может я чето не понимаю?
ИОН который служит референсом для компаратора может быть входным сигналом для АЦП (например в тестовых целях), но не может быть опорным сигналом для АЦП. Равно как и наоборот. АЦП и компаратор это два разных блока. Погляди на структуру в даташите.
да, я смотрел - это 2 разных блока. а я спрашивал про компаратор и его же ИОН. теперь я понял о чем речь
Использую ATMega16.
Застрял на этапе использования АЦП в режиме с дифференциальными входами. Выставляю ADLAR = 1, т.о. выравниваниие по левому краю. Подаю результат в PortB, в итоге на 3м МК вместо 8-разрядного получается 7-разрядное число. Никак не могу разобраться в чем тут дело. Думал связано с использованием 2 входов, т.е. в целом в ADC-Data-Register вместо 10 хранится 9 разрядное число. Пытался считывать 7 гипотетических старших битов склеивать со старшим из младших - ничего хорошего не вышло: даже даташитовское “When ADCL is read, the ADC Data Register is not updated until ADCH is read.” не помогло, число в ADC-Data-Register перестало изменяться.
В даташите нарыл следующее: If differential channels are used, the result is presented in two’s complement form - после чего запутался еще больше (7-битное число хоть и было 7-битным, но с увеличением разности напряжения на PA0 и PA1 росло, после применения neg к результату в ADCH стало уменьшатся).
128 бит мне будет маловато…
растолкуйте пожалуйста что к чему…
Насколько я понял из даташита - для режима сна при АЦП нужно не только установить биты: OUTI MCUCR,0b00010000 (SM2 SM1 SM0 == 001), но и бит SE тоже должен быть уже установлен. Вот даже перевод с gaw.ru про Atmega128 (про другие мк наверняка также): “Для перевода микроконтроллера в один из шести режимов сна необходимо предварительно установить бит SE в регистре MCUCR, а затем выполнить инструкцию SLEEP. Биты SM2, SM1 и SM0 регистра MCUCR задают в какой именно режим будет переведен микроконтроллер”. А в выше приведенном примере этого вроде нет
Да, конечно же. SE не даст процессору уснуть. Забыл про этот бит совсем :) Исправил. Кстати, рекомендуется его устанавливать непосредственно перед командой sleep во избежание. =)
ошибка.в OUTI MCUCR,0b10010000
надо: OUTI MCUCR,0b01010000
т.к. SE бит - 6, а не 7. кривовато сделали нумерацию в amtel….
Если установлен бит непрерывного преобразования,оно не прекращается
даже на время обработки прерывания?
Да именно так. АЦП это же независимый от ядра блок.
Я вот тут вольтметр пробую сделать.
Использовал усреднение описанное в примере,
все получилось,показания на дисплее меняются 0-1023.
Но это я задействовал один вход ацп,а как поступить если надо
снять показания со второго канала?
ОЧевидно же. Заказал разовое преобразование. Получил результат. Сменил номер ацп в MUX регистре, заказал еще одно преобразование. Получил второй результат.
Здравствуйте.
Гонял АЦП на MEga8. Данные из АЦП читал с выравниванием по левому краю (т.е. 8 старших из десяти, соответственно бит ADLAR=1) но почему то последний бит тоже скакал на +-1 Получается, что погрешность преобразования АЦП не +-2 бита а +-3 бита, это нормально или нет?
А ты все требования по экранированию сигнальных линий, фильтрации питания, разведению аналоговой и цифровых земель выполнил? ;)))))
Не просто на макетной платке проводками прицепился :)
Ну вот. Позырь последний пост про наводки, где лампочки сами зажигались. Увидишь какое дерьмо летает в эфире. Так что 3 МЗР это еще ОЧЕНЬ круто. У меня в таких условиях плясало 5-6 разрядов.
ок спасибо!
Отличная статья. Вообще отличный портал. Можно почерпнуть много информации как теоретической, так и практической. Спасибо большое!
Только вот маленький вопросик возник, может кто вразумит:
“…неплохой инструмент для контроля напряжения…выдающее частоту дискретизации до 15кГц (15 тысяч выборок в секунду)…” и “…Частота выборки АЦП задается в битах предделителя ADPS2…0…находится в пределах 50…200кГц…”. Как это? Или 15 кГц это при использовании всех входных каналов АЦП по очереди, т.е. на каждый канал 15 кГц частота дискретизации, а если используется один канал то можно уже задать конкретную частоту? Правильно я понимаю?
Нет частота дается на один канал. Просто делится частота системного кварца. А коэффициент деления задается в битах адпс2,,0
так и все-таки. в мануале к мега8 написано что частота выборок АЦП до 15 кГц, а вручную можно установить 200 кгц. как это понимать? что имеется ввиду?
При выборке до 15кГц, как я понимаю, гарантируется точность 2МЗР, но никто не запрещает тебе разогнать ацп до предела, поставив соответствующий делитель частоты.
50…200кГц - это частота работы самого блока АЦП, по аналогии с 8-мью или, например, 16-тью мегагерцами тактовой частоты самого ядра процессора. 15 кГц - это количество 10-ти битных результатов с указанной в даташите точностью. Т.е. получается в секунду подобных результатов можно получить 15000 штук. Можно получить больше при той же частоте работы блока АЦП, но результат будет менее точным, 8 бит, а то и 6.
Кстати, я тут эксперимент провел на Меге48. При Ref в 2,8В я установил напряжение на аналоговом входе такое, что результат при 10-ти битном режиме получился равен 9-ти. И через УАРТ его на комп для наблюдения. Так вот я не заметил флуктуаций этого значения около этого результата. Все время шло 9, а ведь напряжение в вольтах получается то маленьким (кондюк на вход АЦП специально не ставил). Хотя то что я там наваял с УАРТ’ом мне не очень нравится - какие-то повторы цифр идут (скорости согласованы), и еще наверное не очень быстро как мне хотелось оно выдавало на комп результаты. Из-за этих повторов ставил delay, чтоб как-то заставить более или менее работало. Может что с буфером там получалось… Надо бы получше сделать, а то все это на скорую руку делал.
Если у меня тактовая частота МК = 4000000 Гц, то как правильно выбрать коэффициент предделителя блока АЦП битами ADPS2…0? Учитывая что нужно уложиться в оптимальную частоту преобразования от 50 до 200 кГц. Из даташита коэффициенты только такие 2,4,8,16,32,64,128. Делим 4000000 Гц на 2 = 2000 кГц, многовато. Делим на 4 = 1000кГц опять много. Делим на 16 = 250кГц, много. Делим на 32 = 125 кГц, подходит. На 64 = 62.5Кгц тоже подходит. Делим на 128 = 31.24 кГц уже мало. Получается при частоте кварца 4МГц подходят только два результата битов ADPS2…0, это 101 и 110. Так что ли? А это число 15000 выборок в секунду, от чего оно зависит? Как его можно регулировать? Делать быстрее медленнее. С помощью кода в AVR?
Ага, понял чем выше частота ядра АЦП тем больше и выборка.
15 кГц - это количество 10-ти битных результатов с указанной в даташите точностью.
——–
тогда невижу смысла в 50…200кГц если невозможно коректно увидеть импульс скажим с частотой в 30КГц в 10 разрядности (соглашусь что 8 хватит но никак не ниже)
или я непонял чтото..
тоесть мы можем использовать даже 200кГц но разрядность будет очень малым (на вскидку 4).
почему так происходит - непонимаю я… откуда такая зависимость зачем она..
я уже мечтал что максимальная частота от кварца на 16МГц получится 16МГц/10бит=1.6ЬГц (ну округлим некоторыми возможностями = 1МГц) - тоесть хотел сделать осцилограф на этом для прослушки ультразвука (импульсные источники сигнала не только 20к-200к но и более - ШИМ импульсы например которые и повыше 300к встречаются) и сверх того до 1МГц.. АнНет
Разрядность будет те же 10 бит, только в младших битах будет мусор.
А ты думал чего цифровые осциллографы такие дорогие? ;)))) Там зверские высокоскоростные АЦП стоят. Которые составляют 95% стоимости.
да.. а я еще к томуже глаз положил на атини13 (35 рублей).. мдя наивный я
Ridik911, представь себе звукою плату в компе. Ты записываешь звук через линейный вход ее. Если в настройках записывающей программы ты указываешь писать с частотой дискретизации 44100Гц, 16бит, моно (это для простоты объяснения), то ты получишь звуковую дорожку, где каждый отсчет (выборка) размером 16бит следует через каждые 1/44100 сек. При этом спектр входгого сигнала перед этим обрежется до частоты 22000Гц приблизительно, а на самом деле чуть пониже (это сделано для получения правильного преобразования) Так и здесь, достаточно точные 10бит ты получишь только неспеша, то есть если будешь получать только 15 тыс выборок в секунду. Ими можно и звук оцифровать, но верхняя частота на входе АЦП должна быть не больше 15000/2 Гц И это в лучшем случае
Уважаемый,DI HALT,у меня возникла проблема.мучаюсь над ней уже месяц.
Задача такая: моя мега8535 в цикле опрашивает 10 дискретных датчиков и один аналоговый, из этого всего лепит 11 пассылок (10 для дискр и 1 для аналогов)и пересылает их ПК. У меня же все работает только по отдельности (когда опрашиваються отдельно дискр. и отдельно аналог. датчики). Стоит только подключить АЦП ко всему этому, все начинает бочить((((. Думаю что проблема в АЦП. Пробовал два режима работы АЦП. В одиночном режиме - все работает, а аналоговые велечины не опашиваются. В циклическом режиме- АЦП рабтает,но блакирует работу всех дискретных портов.
Телепаты в отпуске, но могу предположить, что прерывание АЦП срывает стек. Причем, в постоянке это делает, вызывая перезапуск МК.
Покажи код.
А если прерывания от АЦП заглушены?
Вот то , что у меня запраграммированно в регистре ADCSRA: (1<<ADEN)|(0<<ADIE)|(1<<ADSC)|(1<<ADFR)|(3<<ADPS0) . Может тут что -то ни так?
Вопрос. Может мне стоит перед пересылкой по Уарту останавливать работу Ацп?
В глаза ничего криминального не бросается. Код топорный но явных затыков нет.
Хм. Возможно дело у тебя не в АЦП. Т.к. она тут не связана ваще. Трассировать пробовал? Прогони ее в трассировке позырь где у тебя затыки.
Единственно что я тебе советую:
Включи прерывания АЦП. И Данные с АЦП бери в прерывании и там вкладывай в какую нибудь переменную. Только внимательней. Следи чтобы эта переменная нигде не юзалась больше. А в процедуре ADC_start спокойно бери значение из этой переменной. Так правильней.
Трассировка это в смысле график с АЦП рисует? Эта та прога - Терминал, что ты приводил? То ее я пробовал. Отдельно АЦП на ней рисует безупречный график. А когда зашит вот этот код, выходит полная ерунда.
Нет, запустить в AVR Studio эмуляцию выполнения и пошагово выполнить всю программу, увидишь где у тебя что отсылается и где у тебя какой затык.
Аааааа вот это очень важно. я без отладки никуда не хожу. Это я делал. Прога в эмуляторе работает как нужно. Даст ли что нибудь, если остановить АЦП перед тем как начинать пересылку? интуиция подсказывает. или ничего это не даст?
Это странно. У тебя там единственное место где программа затыкается - ожидание уарта. И при чем тут ваще АЦП? Попробуй вместо показания АЦП просто слать в уарт произвольный байт. Эксперементируй в общем.
Я же говорю, если убрать тот кусок кода,где шлем данные из АЦП, то устройство работает как часики, без ошибок. И уарт получает все нормаль. А как только подключаем тот кусок с АЦП, начинается какашка((
Не, ты не убирай тот кусок. Оставь условия как есть. Закомментируй только строку с копированием данных из регистра АЦП. И вставь туда чо нибудь другое из той же оперы, Скажем IN из порта какого нибудь. Будет работать?
Сегодня разбрался метдом тыка с этим. Кроче из проги убрал инициализацию порта С на ввод побитово
(то есть OUT DDC0,perem
OUT DDC1,perem
OUT DDC2,perem
OUT DDC3,perem
OUT DDC4,perem
OUT DDC5,perem
OUT DDC6,perem
OUT DDC7,perem) и все зарабтало.Просто заменил на OUT DDRC,perem. Теперь не могу понять, как же оно все таки не давало нрмально рабтать?
Потому что
Какая то невьебенная хуета. Как я ее проглядел при первом просмотре :/. Сам посуди, ты пытается в БИТ засунуть БАЙТ!
А теперь смотри как это выглядело если развернуть все макроопределения:
Таким образом, ты забил совершенно левыми значением порты с 00 по 07
А конкретно в:
Побитово порты устанавливаются командами
SBI IOPORT,BIT
и
CBI IOPORT,BIT
Блин, какой ты молочага. Я прокрутил, проанализировал все это. Все так и есть. Спасибо, санцей))))
Есть еще один вопросик. Может, конечно, не в тему, но все-таки про АЦП и АВР. Вот тут http://mkeia.com/Oscyloskopy/moc1k_en.htm есть девайс со схемами и прошивкой. Вообщем суть вопроса вот в чем: указано что ацп делает 250 тысяч выборок в секунду при 10-битном разрешении. Каким образом такое может быть достигнуто?
Врут
ответ разработчиков “Yes it is possible. There is a little degradation of resolution, but works fine.”
на вопрос “Still, a final true resolution? 10-bit or 8?” был получен ответ “about 9 :)”
Ну вот о чем и речь. Теперь они уже согласны на 9бит, плюс 3МЗР на помехи. В итоге имеем 6.
Снять 10 бит на 250кгц это элементарно - взял и считал, вот только что из этих 10 бит будет ценной инфой, а что мусором?
Посоветуйте как заставить АЦП работать во free running mode, т.е. чтобы он в циклическом режиме поочереди перебирал все 8 ног. Я устанавлию нужную ногу в регистре ADMUX битами MUX3…MUX0, но он все-равно настырно берет значение только с первой ноги, хотя в регистре лежит уже другое значение. Может я еще чего забыл где включить\настроить. Контроллер AVR ATmega8535
А нельзя во фриранне перебирать ноги. Только вручную. Запустил. В прерывании переменил ногу, еще раз запустил. И так далее.
Ясно, спасибо. Непонятно только зачем он тогда нужен вообще:)
Как это зачем? Врубить непрерывный опрос одного канала. Чтобы не заморачиваться на повторный запуск.
А как тогда его запускать вручную, если в ADTS нет такого понятия, и по дефолту он в фриране?
А как тогда его запускать вручную, если в ADTS нет такого понятия, и по дефолту он в фриране? или нужно как раз во фриране его и пускать, а после выполнения первого преобразования перезапускать с новым значением MUX ???
Очевидно замучаю и мёртвого. с вопросом о ручном запуске разобрался и нарыл в даташите на 48 мегу следующий прикол
If Auto Triggering is used, the exact time of the triggering event can be indeterministic. Special
care must be taken when updating the ADMUX Register, in order to control which conversion
will be affected by the new settings.
If both ADATE and ADEN is written to one, an interrupt event can occur at any time. If the
ADMUX Register is changed in this period, the user cannot tell if the next conversion is based
on the old or the new settings. ADMUX can be safely updated in the following ways:
a. When ADATE or ADEN is cleared.
b. During conversion, minimum one ADC clock cycle after the trigger event.
c. After a conversion, before the Interrupt Flag used as trigger source is cleared.
When updating ADMUX in one of these conditions, the new settings will affect the next ADC
conversion.
Что в кратце означает, что если поменять ADMUX в во время следующего такта после начала прерывания (в фриране) то следующее вычисление будет производится с нового пина…
Я ничего не напутал ?
Проще сделать так:
Включаешь АЦП на одиночное преобразование (бит ADFR(ADATE) сбросшен) тогда АЦП делает только ОДНО преобразование и генерит прерывание. В этом прерывании ты правишь адмух и запускаешь следующее преобразование. У тебя получается как бы фриран, но со сменой каналов.
меня в варианте мучает вопрос того, что проц постоянно будет инициализировать ацп, то есть время расчета следующего значения увеличивается в 2 раза, а у меня мысль следующая, взять свободный таймер который запускать на тем же делителем что и ацп, и собственно запускать сразу после получения первого значения с значением компаратора …например 1, то есть на 2-3 такте АЦП он должен сработать. учитывая что делитель частоты на таймере АЦП у меня стоит на 1/64 я так понимаю что для обработки значений результатов вычисления 64 такта должно хватить… ну я так думаю во всяком случае )))
А какой контроллер то?
mega48p
позвольте понаглею и спрошу
как узнать какой ADC можно использовать как обычный АЦП потомучто мне непонятно это:
AD9220AR Complete 12-Bit 1.5/3.0/10.0 MSPS Monolithic A/D Converters
AD9200ARS Complete 10-Bit, 20 MSPS, 80 mW CMOS A/D Converters
а стоят до 200 руб.
как вообще понять до какой частоты.. и на какие еще штуки можно смотреть
спасибо
Любой из. Тока это внешние АЦП
Здравствуйте, господа! :) Подскажите, пожалуйста, как подключить датчик (24В, 4-20мА) к АЦП 0-5В?
Пусти ток с датчика на резистор (где то в 1к) и на землю. А падение напряжения с этого резистора заведи на АЦП.
Не так давно был пост про датчики и средства измерения. Отмотай ленту сайта от начала, думаю в пределах первых двух страниц найдешь :) ТАм более подробно.
Большое спасибо! Если я правильно посчитал, то нужно не 1 кОм, а где-то 250 Ом?
тогда 20мА = 5В.. 4мА = 1В.. Верно, или закон Ома мне повторить следует? :) Да, и еще. Нельзя ли в описание программатора на УСБ выложить его фотки сверху и снизу, и добавить номенклатуру компонентов?
Да, все верно.
Может и сделаю перечень. А фотки сверху и снизу есть там.
Добрый день! Очередной вопрос чайника. :) В чем разница между источниками опорного напряжения? У меня есть на 5 вольт и на 4.096. Какой предпочтительнее использовать? Токи и напряжения все те же: 24 В, 4-20 мА.
ИОН нужен для задания опорного (максимального) значения для АЦП. Соответственно чем он ближе к величине измеряемого напряжения тем лучше — более рационально используется шкала АЦП.
Но ИОН не может быть больше напряжения питания МК
Спасибо. Значит если АЦП меряет 0-5 В, то и ИОН нужен на 5 вольт? АЦП внешнее, если это важно.
АЦП меряет от 0 до ИОН, но не выше питания.
Если твой сигнал меняется от 0 до 5, то и ИОН должен быть не ниже 5. Если сигнал меняется от 0 до 2, то поставив ИОН на 5 ты теряешь 3/5 шкалы АЦП впустую. Т.к. мерять он может до 5, а сигнал реально только до 2х достигнет. В этом случае ион лучше сделать на 2 вольта. Либо входной сигнал снормировать на ОУ
А может так быть что на входе ацп напряжение 90миливольт (относительно земли)?По идее ноль должен быть.
А может так быть что на входе ацп напряжение 90миливольт (относительно земли)?По идее ноль должен быть.Это когда вход просто в воздухе висит ни к чему не подключен.
Ноль может быть только в одном случае — когда вход лежит на земле.
Когда же он висит в воздухе, то на нем наводится черти что. Обычно это черти что предстает в виде синуса 50Гц и амплитудой около 2.5-3вольт. Это наводки.
я подаю на вход ацп сигнал со звуковой карты.Последовательно поключены наушнеки (через штекер).Так вот,когда врублен контроллер в наушниках слышится шум даже тогда когда музыка не включена.при этом на входе ацп 1000 миливольт.
100 милливольт Ж)
Сопротивление входа АЦП мегаоммы. Сответственно последовательно с ним наушники вешать бессмысленно.
Да и нафига ты наушники туда еще втыкаешь? У них сопротивление в порядки ниже чем у АЦП. Так что либо одно либо другое.
Бля,я ошибся не последовательно а параллельно :d
Последовательно нет смысла врубать.
Здравствуйте! Написал программу для Меги 8, которая снимает показания АЦП и передает в порт B. Только в порт B она почему-то всегда выдает пятерку (0000 0101), как в АВРСтудии так и в Протеусе. Что неправильно в коде? И ещё: не запускается в симуляторе беспрерывное преобразование. Никто не сталкивался с этим? Спасибо.
;Иницализация
OUTI DDRB, 0b11111111
OUTI ADMUX, 0b01000000
OUTI ADCSRA, 0b11111011
;Основа
main: RJMP main
;Обработчик прерывания по оконч. преобразования
Gotov:
CLI
OUTI PORTB, ADCH
OUTI ADCSRA, 0b11111011
SEI
rjmp main
>OUTI ADCSRA, 0b11111011
Вот это будет работать так, как ты хочешь (запись 0b11111011 в регистр ADCSRA).
А вот это:
>OUTI PORTB, ADCH
запишет не значение регистра ADCH в регистр PORTB, а _адрес_ регистра ADCH в регистр PORTB.
Адрес ADCH и есть 00000101 (т.е. 5). Если ты пользуешь AVR Studio, то там в панели I/O View, там где черно-белые такие квардратики (биты), есть колонка Address, значение в которой отображает адрес регистра.
В твоем случае макрос OUTI должен выглядеть так:
.macro
in r16,@1
out @0,r16
.endmacro
Кури команду in. Юстировка по левому краю? А назвезда ты измеренное напряжение с ADCH пихаешь в PORTB? В r16-r31 надо пихать (например).
Вот кстати, о птичках. Заметил тут жука в АВР Студио. Если в режиме отладки отметить квадратик в ADCH руками, потом запустить Run, остановить, перекючиться посмотреть другую группу регистров, а потом полезть смотреть опять ADCH, то квардартика там уже не будет, но значение в регистре останется. То же проявляется, если квадратик руками снять. :(
Если используешь подавление шума, в обработчике прерывания АЦП надо что-то писать?
Уточняю порядок:
1 Ставим ADEN и ADIE и все настройки
2 Запускаем ADSC (у меня одиночные преобразования будут)
3 SLEEP
И вот он проснётся по прерыванию и дальше по программе замолотит, можно не волноваться?
DI HALT, подскажи пожалуйста, как посчитать, что будет в ADCH и ADCL, если знаем напряжение на входе.
Подели опорное напряжение на разрядность ацп. Получишь вес одной единицы. Дальше делишь входное напряжение на вес и получаешь искомое.
спасибо!
DI. хотел спросить на счет последовательности считывания результата. В датшите сказано
“When ADCL is read, the ADC Data Register is not updated until ADCH is read. Conse-
quently, if the result is left adjusted and no more than 8-bit precision is required, it is
sufficient to read ADCH. Otherwise, ADCL must be read first, then ADCH.”
Т.е. я так понимаю, что если уже готово новое значение измерения (непрерывное преобразование 10bit с выравниванием вправо), то пока не прочитаешь ADCH от прежнего измерения, то новый значение не запишется в ADCH:ADCL. Т.е. если сначала пытаться читать ADCH, а уже потом ADCL есть вероятность прочитать из ADCL результаты нового измерения, что уже является ошибкой. Если это так (я 10bit читаю именно так - сначала ADCL,а уже потом ADCH), то может добавите этот момент в статью (там где пишете про выравнивание результата)?
ААА ммм)) непонятно порты задействованные под АЦП настраивать как?? На выход или на вход??
На вход. Без подтяжки. т.е. DDR=0 PORT=0
И тем не менее неполучилось((((.Хотел в ATmega8 задействовать АЦП. АЦП должен измерять напряжение раз в 0,5 С на вывоже ADC0 (PC0), затем прочитав это значение из ADCH (выравнивание влево) вывести значение в остальные вывода порта C. PC1-PC5 подключены светодиоды. Почемуто непроисходит ничего , светодиоды негорят Напряжение на ADC0 беру с переменного резистора, который соиденён с источником питания МК. Помогите разобраться кто может.
.
.
.
ldi Temp,low(RamEnd) ;установка указателя стека
out SPL,Temp
ldi Temp,high(RamEnd)
out SPH,Temp
ldi Temp,0b11111110
out DDRC,Temp
ldi Temp,0b00101000
out PORTC,Temp
ldi Temp,0b11100000
out ADMUX,Temp; выбор канала, а так же выравнивание влево(бит 5),+(биты 6 и 7)
; включение опорного напряжения внутреннего источника
ldi Temp,0b10000101
out ADCSRA,Temp; старший бит вкл АЦП, младшие - предделитель
reset: sbi ADCSRA,ADSC ; уст бит “старт преобразования”
WaitADC:
sbis ADCSRA,ADIF
rjmp WaitADC
; тут отсчет готов…
in Temp1,ADCH ; ст байт
out PORTC,Temp1
ldi Temp3,0×06
ldi Temp2,0×1A
ldi Temp1,0×80
Delay: subi Temp1,1;ждём 0,5С
sbci Temp2,0
sbci Temp3,0
brcc Delay
rjmp reset
А прогон в студии что дает? Не встает флаг?
Честно говоря я непонимаю о как прогоне и о каком флаге идёт речь??
э… а как ты вообще пишешь код?
Набил десяток команд, откомпплировал, лишь бы скомпилилось без ошибок, зашил. Если не работает сидим и тупим в код. Так?
Открою тебе страшную тайну. АВР студия может пошагово выполнять программу на ассемблере, показыая содержимое всех регистров, флагов и периферии. Более того, можно брейкпоинты ставить в коде и ловить всякие редкие события, вроде срабатывания прерываний и прочее.
О флаге завершения преобразования.
Во Во!! Точно так и делаю!!!!))
Про по шаговое выполнение AVR Studio программы вы кажется писали в одной из статей, ща попробую найти.
МК потребляет ток 8…10mA-это немного?? Я АЦП никак не мог попортить?? А и ещё несовсем ясно при измерении в недиферинциальном режиме возможно ли использовать встроенный усилитель x10??
И вот ещё вы писали что посдедние 2 разряда в результате АЦП это мусор и данные там недийствительные, а есть же AVR у которых 12 разрядов, что тогда там последние 4 разряда врут чтоли??
А что там искать вторая кнопка после компиляции.
8..10мА довольно много, если конечно светодиодов не понавешано и они не горят.
Нельзя, он только для дифрежима.
Ну не то чтобы мусор, но крайне неточные, по заверениям самих же атмеловцев.
У какого из авр 12 разрядный АЦП?
ммм да ))) прикольная штука!! Надо в ней по подробней разобраться!!
С программой разобрался(ну т.е. помогли)!! метку reset нетуда воткнул((
Теперь новая проблема возникла(( Все разряды скачут,загорается то 3 то 4 светодиода, практически без остановки (только старший вроде как одекватно держиться)-это может быть вызванно слабым источником питания??
А про 12 разрядный АЦП в книге читал: Юрий Ревич стр.207, 5-я строчка :)))))
А к вам на сай попасть всё сложнее и сложнее, вечером вообще нриально, уж больше часа долблюсь))))