Samou4ka » 🐞 AVR.Начинающим » Аналого-цифровой преобразователь МК ATmega8

Аналого-цифровой преобразователь МК ATmega8

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

Итак, в МК ATmega8 имеется встроенный 10-битный АЦП. Что значит 10-битный? Это значит что входное напряжение от GND до Uвх будет линейно разбито на 210 частей. Минимальный код равен 0, максимальный 210-1 = 1023. Например, у нас максимальное входное напряжение на входе МК составляет 5В. Значит шаг измерения составляет 5/1023=0.0049, т.е. 4.9мВ. У МК имеется 6 каналов АЦП для корпуса DIP28 (PORTC) и 2 дополнительных канала АЦП для корпуса TQFP и QFN/MLF. Напряжение на одном из входов измеряется относительно опорного напряжения. Измеренное напряжение преобразуется в 10-битное число и сохраняется в регистрах ADCL и ADCH. Вот нам и встретились первые два регистра АЦП. ADCH – старший байт результата измерения, ADCL – младший байт результата измерения. В МК предусмотрено два режима работы: непрерывное и однократное преобразование. В непрерывном режиме АЦП периодически измеряет входное напряжение и по окончании преобразования записывает результат в регистры ADCL и ADCH. В режиме однократного преобразования мы должны инициировать каждое преобразование самостоятельно. Мы вкратце рассмотрели основные характеристики ATmega8. Теперь давайте разберем, как же произвести все установки, чтобы АЦП заработал так, как нам нужно.

В МК ATmega8 номер вывода подключенного к входу АЦП задается с помощью регистра ADMUX — регистр мультиплексора АЦП. Давайте посмотрим какие биты за что отвечают в этом регистре.

Биты 7:6 – REFS1:REFS0. Биты выбора опорного напряжения. Если мы будем менять эти биты во время преобразования, то изменения вступят в силу только после текущего преобразования. В качестве опорного напряжения может быть выбран AVcc (напряжение источника питания), AREF или внутренний 2.56В источник опорного напряжения.

Рассмотрим какие же значения можно записать в эти биты:

REFS1:REFS0

00 AREF

01 AVcc, с внешним конденсатором на AREF

10 Резерв

11 Внутренний 2.56В источник, с внешним конденсатором на AREF

Бит 5 – ADLAR. Определяет как результат преобразования запишется в регистры ADCL и ADCH.

ADLAR = 0

ADLAR = 1

Как можно видеть при ADLAR = 0 в ADCH записываются два старших бита (2 MSB), а остальные в ADCL. А при ADLAR = 1 в ADCH записываются 8 старших битов (8 MSB), а два младших (2 LSB) в ADCL. Это удобно, если для точности ваших измерений достаточно 8-ми старших бит преобразования.

Биты 3:0 – MUX3:MUX0 – Биты выбора аналогового канала.

MUX3:0

0000 ADC0

0001 ADC1

0010 ADC2

0011 ADC3

0100 ADC4

0101 ADC5

0110 ADC6

0111 ADC7

Если вы хотите проверить несколько каналов, то можно изменить соответствующие биты в регистре ADMUX и канал сменится сразу же по окончании текущего преобразования. Т.е. в режиме непрерывного преобразования мы можем легко произвести сканирование нужных каналов. Просто меняя номер канала во время преобразования – следующее преобразование начнется на новом канале.

Для большего понимания рассмотрим пример. У нас источником опорного напряжения является AREF (REFS7:6 — 00). И для данного измерения выбираем 0-й канал (MUX3:MUX0 – 0000). Таким образом записав в ADMUX значение 00000000 мы и получим требуемые настройки.

Остальные установки находятся в регистре ADCSR — регистр контроля и состояния АЦП. В МК ATmega8 он называется ADCSRA.

Бит 7 – ADEN. Разрешение АЦП.

0 – АЦП выключен

1 – АЦП включен

Бит 6 – ADSC. Запуск преобразования (в режиме однократного

преобразования)

0 – преобразование завершено

1 – начать преобразование

Бит 5 – ADFR. Выбор режима работы АЦП

0 – режим однократного преобразования

1 – режим непрерывного преобразования

Бит 4 – ADIF. Флаг прерывания от АЦП. Бит устанавливается, когда преобразование закончено.

Бит 3 – ADIE. Разрешение прерывания от АЦП

0 – прерывание запрещено

1 – прерывание разрешено

Прерывание от АЦП генерируется (если разрешено) по завершении преобразования.

Биты 2:1 – ADPS2:ADPS0. Тактовая частота АЦП

ADPS2:ADPS0

000 СК/2

001 СК/2

010 СК/4

011 СК/8

100 СК/16

101 СК/32

110 СК/64

111 СК/128

Рассмотрим пример. Частота нашего МК равна 4,096Мгц. Мы хотим выбрать частоту АЦП меньше 200кГц. Этому соответствует СК/32 = 128кГц (ADPS2:ADPS0 — 101). Разрешим прерывания от АЦП (ADIE = 1) и будем работать в режиме однократного преобразования (ADFR = 0). Само собой ADEN = 1, т.к. только включенный МК будет измерять напряжение на входе. Учитывая все выше сказанное в ADCSRA будет записано следующее значение – 10001101 (0х8D).

Хотелось бы отметить, что для достижения полной 10-битной точности рекомендуется использовать частоты ниже 200кГц. Частоты выше 200кГц можно использовать если точность не важна, а важна скорость. Например, при частоте 1МГц получаем 8-битное разрешение, а при 2МГц – 6-битное.

А теперь в качестве примера приведу функцию инициализации АЦП и функцию, которая будет возвращать измеренное значение на указанном канале. Мне нравится больше писать на Си, поэтому код будет приведен на Си.

//функция инициализации

void ADC_init()

{

//воспользуемся значениями регистров, определенными ранее

ADMUX = 0x00;

ADCSRA = 0x8D;

}

//функция получает в качестве аргумента номер канала и

возвращает значение на входе

unsigned int ADC_result(unsigned char adc_input)

{

ADMUX=adc_input | (ADMUX & 0xF0);

//задержка для стабилизации входного напряжения

_delay_us(10);

//начинаем преобразование (ADSC = 1)

ADCSRA | = 0x40;

while((ADCSRA & 0x10)==0); //ждем, пока АЦП закончит преобразование (ADIF = 0)

ADCSRA|=0x10;//устанавливаем ADIF

return ADCW;//ADCW — содержит ADCH и ADCL как нам нужно

}

ADCW определен в файле МК (например, iom8.h в WINAVR). Посмотрите, ради интереса, как он там определен. Чтобы получить значение в Вольтах (например для вывода на экран) нужно умножить полученное значение на шаг измерения. Для рассмотренных выше 4.9мВ:

Напряжение в Вольтах = 0.0049*ADC_result(номер канала)

Кстати, эти функции одинаково выглядят как в WINAVR, так и в CodeVisionAVR (обозначения регистров совпадают). Только в CodeVisionAVR нужно _delay_us() заменить на delay_us.

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

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

P.S. Всегда смотрите даташит!smile

Как вам статья? Ваша реакция:
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0
Расскажите друзьям:
Оцените статью:

20 комментариев

  • Отличная статья! Все кратко и доходчиво. Неделю со справочником пытался понять как конфигурировать и без толку. А тут сразу все стало на свои места. Спасибо огромное.

  • «ADCSRA|=0x10;//устанавливаем ADIF

    Це лишнє. Коли ADIF=1 проскакуєм цикл while((ADCSRA & 0x10)==0);»

  • «полезная информация

    но хотелось бы поподробнее найти про данный мк.

    просто в даташите технический английский и не все понятно»

  • Прошу прощения, но английский язык даташитов для микроконтроллеров AVR самый простой по стравнению с даташитами других микроконтроллеров. я, в своё время, с нулевыми знаниями за неделю по оригинальным даташитам сворганил нечто работающее, даже с таймерами и прерываниями. Если совсем туго, есть даташит для ATmega128(по инету полно ссылок, ответ я не нашел приравнивается к я не искал). Очень большая часть даташитов на АВР микроконтроллеры идентична, читаем вышеуказанный на русском, а особенности не тяжело понять и на английском языке. Если начинаете очень рекомендую книгу Программирование на языке С для AVR и PIC микроконтроллеров. Шпак Ю.А. Если непонятно даже после прочтения энной, либо Вам просто лень читать и разбираться, либо микроконтроллеры это не Ваше. Я не придираюся, просто не люблю когда задают вопросы и плодят ветки по темам которые в инете разжеваны до безобразия. ATmega8 Atmega16 ATtiny2313 и ещё многие очень популярны, по этому не ленитесь, а читайте и программируйте и разбирёйтесь на раз два три.

  • ADMUX=adc_input | (ADMUX & 0xFF); мм я еще нновичок и может ошибаюсь.. сразу извините….. но по мойму надо переписать это так ADMUX=adc_input | (ADMUX & 0xF0) 0xF0—обнуляет первые 4 бита

  • да, все правильно. мы же сначала обнуляем, а потом записываем номер канала операцией или. исправил в статье)) спс

  • Здравствуйте, очень хотелось бы знать, можно ли на той же атмеге8 организовать несколько АЦП, хотя бы программно? Если нет, какие вы видите решения данной проблемы?

  • «Привет. Не могли бы объяснить следующее: верно ли, что:

    AVCC — подаём Uпитания, такое же, как на VCC? Внутренний источник питания — схема, которая питается от ноги VCC и даёт 2.56В внутри самого контроллера. И вопрос, что подавать на AREF и что это вообще за нога?»

  • Читайте внимательно даташит, вы никогда не заставите работать АЦП меги8 на 1Мгц а на 2Мгц тем более… внимательно перечитайте даташит про тактирование и время преобразование!

  • При использовании АЦП, например на порту 1, то настраивать порт на вход без подтягивающего резистора?

  • Есть вопросы. Делаю подсветку приборки в авто на Меге8. Задействован канал АЦП по которому будет ШИМом регулироваться яркость. АЦП будет брать напряжение с реостата. Т.е. покрутил ручкой, яркость убавилась. Вопросы такие. Я использую 8-бит. АЦП, 125КГц. АЦП настроен опорное напряжение на AVCC. На AREF нужно конденсатор вешать? и какой номинал? От VCC на AVCC можно просто дорожку кинуть или лучше через какой то фильтр?

  • А как допустим можно узнать частоту используя АЦП .Например написали тестер меряем вольтаж а как узнать частоту ?

  • Форматирование кода УЖАСНО! Никогда так не пишите. Что это за запись «ADCSRA = 0x8D;»? Что она должна сказать человеку, пытающемуся разобраться в подобном «коде»? Нет бы написать по-человечески «ADCSRA = (1

Оставить комментарий