Хоть я и не позиционирую свой сайт как «учебник», но частенько приходится отвечать на вопросы начинающих эмбеддеров. Народ пишет и в личку, и в комменты, некоторые даже звонят. Когда однотипных вопросов накапливается достаточно много, то, мне кажется, полезнее написать статью по теме, чем отвечать каждому товарищу по-отдельности, тем более, когда они так сильно прОсют 🙂
Тема использования АЦП описана чуть ли не на каждом микроконтроллерном сайте, но, как видим, вопросы у многих остаются. Не знаю, может народ не понимает английского для прочтения и изучения даташитов, но книга А.В. Евстифеева «Микроконтроллеры AVR семейств Tiny и Mega фирмы ATMEL», по-моему, должна быть у каждого человека, занимающегося такими (и не только такими) микроконтроллерами. Эта книга по своей сути — перевод и обобщение даташитов наиболее популярных контроллеров. ? не беда, что номенклатура последних уже существенно обогатилась — основные принципы те же.
?так, аналого-цифровой преобразователь, как следует из его названия, преобразовывает аналоговую величину (в нашем случае напряжение) в цифровой код. Управляется он в ATmega8 всего двумя регистрами. На рисунке ниже я попытался максимально просто изобразить принцип действия АЦП и его основные характеристики.

Входной аналоговый сигнал через вход мультиплексора MUX, который мы выбрали разрядами MUX3-MUX0 регистра ADMUX, поступает непосредственно на вход АЦП микроконтроллера и сравнивается с установленным REFS1,REFS0 (ADMUX) опорным напряжением (входной сигнал не может быть выше опорного — для измерения величин выше опорного следует применять делители напряжения). Весь диапазон опорного напряжения разбит на 2 в степени разрешение, т.е для нашего случая 2^10=1024 градации. При запуске АЦП установкой ADSC (ADSCRA) входной аналоговый сигнал сравнивается с опорным в течении времени t преобразования, и, по истечении этого времени в пару регистров ADCH(выделен жёлтым)—ADCL(выделен голубым) записывается цифровой выходной 10-ти разрядный код, показывающий относительную величину входного, по отношению к опорному. Например, если опорное напряжение равно 5 В, а на вход АЦП пришёл сигнал 2,5 В, то в регистры ADCH-ADCL запишется значение 512 — половина от 1024. Причём результат в пару ADCH-ADCL будет записан со сдвигом вправо или влево в зависимости от значения разряда ADLAR регистра ADCSRA. Абсолютную величину напряжения легко вычислить , зная опорное.
Все разряды регистра ADMUX на рисунке наглядно представлены. ??з ADSCRA не рассмотрены: 7-й разряд — ADEN — разрешение работы АЦП; 5-й — ADFR — включение режима непрерывного преобразования; 4-й — ADIF — флаг прерывания от АЦП; 3-й — ADIE — разрешение прерывания от АЦП.
Теперь код для простейшего примера, демонстрирующего работу АЦП. Вся логика работы здесь, как и во всех моих примерах, расписана в комментариях. Код написан на классическом Си для WinAVR, но по идее должен работать и под CodeVision (только подключаемые файлы там по другому называются). МК ATmega8 работает от внутреннего генератора на частоте 1 МГц.
/*Учебный пример написаный товарищем s_black www.embed.com.ua для товарища ВМ, который ленится читать даташиты*/ #include <avr/io.h> #include <avr/interrupt.h> #define PORT_LED PORTD /*назначение порта светодиодов*/ #define DDR_LED DDRD /*назначение регистра направления порта светодиодов*/ #define LED_1 PD0 /*первый светодиод - индикатор 1/4 максимального напряжения*/ #define LED_2 PD1 /*второй светодиод - индикатор 2/4 максимального напряжения*/ #define LED_3 PD2 /*третий светодиод - индикатор 3/4 максимального напряжения*/ #define ON_LED(LED) (PORT_LED &= ~(1< <led)) *макрос="" включения="" светодиода*="" #define="" off_led(led)="" (port_led="" |="(1<<LED))" выключения="" isr="" (adc_vect)="" прерывание="" по="" завершению="" преобразования="" АЦП="" {="" unsigned="" int="" voltage_adc="" ;="" переменная="" результата="" напряжения="" значение="" АЦ="" блок="" операторов="" ниже="" реализует="" "светящийся="" столбик"="" в="" зависимости="" от="" измеренной="" величины="" if="" (voltage_adc="">= 768) {ON_LED (LED_3);ON_LED (LED_2);ON_LED(LED_1);}//если U > или = 3/4 максимального - подсвечиваем светодиоды 3,2,1 else if (voltage_ADC >= 512) {OFF_LED(LED_3);ON_LED (LED_2);ON_LED(LED_1);}//если U > или = 2/4 и < 3/4 максимального - подсвечиваем светодиоды 2,1 else if (voltage_ADC >= 256) {OFF_LED(LED_3);OFF_LED(LED_2);ON_LED(LED_1);}//если U > или = 1/4 и < 2/4 максимального - подсвечиваем светодиод 1 else {OFF_LED(LED_3);OFF_LED(LED_2);OFF_LED(LED_1);}//если U < 1/4 максимального - ничего не подсвечиваем ADCSR |= (1<<adsc); запускаем="" очередное="" преобразование="" }="" int="" main="" (void)="" {="" ddr_led="" |="(1<<LED_3)" (1<<led_2)="" (1<<led_1);="" разряды="" порта="" светодиодов="" -="" выходы="" port_led="" изначально="" погашены="" 7="" 6="" 5="" 4="" 3="" 2="" 1="" 0="" admux="REFS1" refs0="" adlar="" –="" mux3="" mux2="" mux1="" mux0="" качестве="" опорного="" напряжение="" питания,="" результат="" выравнивается="" вправо,="" 0-й="" канал="" АЦП="" (pc0)="" adcsra="ADEN" adsc="" adfr="" adif="" adie="" adps2="" adps1="" adps0="" (1<<adsc)="" (1<<adie)="" (1<<adps1)="" (1<<adps0);="" разрешаем="" преобразование,="" его,="" прерывание="" от="" тактовую="" частоту="" делим="" на="" 8="" получаем="" преобразования="" 125="" кГц="" sei();="" общее="" разрешение="" прерываний="" for(;;);="" бесконечный="" цикл="" в="" ожидании="" прерывания="" по="" завершению="" }<="" pre=""> |
Для демонстрации работы этого кода я собрал макет по такой схеме:
Элементы с левой стороны микроконтроллера IC1 ATmega8 — это стандартная даташитовская обвязка для АЦП. В частности L1, C1 — это LC-фильтр для «аналогового» питания. Резистор R1 подтягивает вывод сброса микроконтроллера к питанию. Конденсатором С2 вывод опорного напряжения AREF рекомендуют коротить на корпус, если не используется внешнее опорное.
Теперь рассмотрим элементы с правой стороны. ?сточник измеряемого изменяемого напряжения реализован на потенциометре R2. Резистор R3 добавлен, чтобы не «посадить» питание на корпус при самом нижнем положении ползунка. ??ндикация напряжения по градациям реализована на светодиодах LED1-3 с токоограничительными резисторами R4-6. Питание — Li-ION батарея 3,7 В от мобильного телефона. В качестве отдельных светодиодов используются сегменты «a» трёхразрядного семисегментного индикатора с общим анодом.
На видео ниже демонстрация работы макета. В исходном положении ползунок R2 в верхнем по схеме положении, т.е. подключён к питанию в результате чего светятся все три светодиода. Напряжение на ползунке индицируется мультиметром DT830B.
При «движении» ползунка R2 вниз к «корпусу» (резистор используется многооборотный) мы видим погасание сначала правого (при напряжении 2,82 В), затем среднего ( при напряжении 1,88 В), и, наконец, левого (при напряжении 0,94 В). Если посчитать в столбик, то эмпирическим путём мы подтвердим практические результаты: 1 = 3,77; 3/4 = 2,8275; 2/4 = 1,885; 1/4 = 0,9425.
</adsc);></led))> |
Приветствую, а вот такой вопрос, как Вы считаете что более целесообразно применять из температурных датчиков DS18B20 или Pt100 совместно с АЦП сего МК? Я раньше думал что DS18B20 это вещь вообще безотказная.
Но по воле случая когда устроился на новую работу (ну Вы знаете) обратил внимание на что что в промышленности никаких DS18B20 или любых других законченных цифровых температурных датчиков не используют, только Pt100 или другие температурные датчики на платиновой основе.
Думаю, что причины следующие:
1. ?нертность по внедрению новых комплектующих.
2. Проще обработка (не нужно заморачиваться с цифровым обменом — простой замер напряжения).
3. БОльшая надёжность аналоговых датчиков.
4. Дешевизна.
Хотя может быть и другое…
Палка о двух концах, в тоже время с аналоговыми датчиками:
1. Не линейное сопротивление на больших температурах.
2. Большие требования к кабельной линии.
3. Большие размеры.
4. Вот не как не дешевизна (Pt100 стоит начиная от 1500 руб. за шт., в тоже время DS18B20 в гильзе начиная от 250 руб. за шт. это при приблизительно).
Если Вы говорите о инертности то тоже спорный вопрос, на большинстве температурных датчиков ставят преобразователи 4-20мА, что же не даёт ставить подобный преобразователь и для DS18B20???
ещё забыли про диапазон. платиновые датчики вне конкуренции.
Да, да и это тоже. Термостойкие платиновые датчики можно нагревать даже до 450 градусов (в некоторых паяльных станциях стоят). Но вот не задача для замера температуры этого датчика необходимо серьёзное разрешение АЦП, на мой взгляд 1024 маловато.
Могу пояснить, скажем если датчик работает в диапазоне температур от -50 до +100 градусов то 100+50=150, 150/1024=0.1464 градусов на 1 бит дискретизации, при этом мы даже не уверенные в том что этот бит будет стабилен, у DS18B20 тоже не очень период 0.125 градусов на 1 бит дискретизации.
Но пожалуй это уже другая история, не в этой теме.
а как выполнить переключение каналов ацп в прерывании
В регистре ADMUX установить необходимые значения разрядов MUX.
в симуляторе протеус симулирует последний mux предыдущий пропускает
может я что то не то делаю
меня интересует алгоритм переключения каналов ацп в прерывании по ацп
Никакой разницы, где Вы переключаете каналы нет. Протеус может показывать что угодно.
?звините что влез, но у Вас там ошибочка небольшая в исходнике.
А так в протеусе все работает. Спасибо, полезная статья.
?звините еще раз, в схеме тоже ошибка.
?звините, а Вы не могли бы указать конкретно на ошибки?
одна ошибка частота конроллера.То что я увидел
в какой среде компиляции вы работаете?
Про частоту контроллера не понял.
В WinAVR.
Atmel studio 7 похоже частота контроллера в ней прописывается иначе в железе не будет работать.Я любитель начинающий хотя уже 42.Всё равно интересно.А у вас есть примеры с динамической индикацией и вывода результата с Ацп
Почитайте статьи здесь на сайте «Трёхфазный вольтметр переменного тока» и «Управление водонагревателем».
В первом макросе включения светодиода в знаке «меньше» не должно быть пробела. ? посчитайте количество скобок. По моему в конце лишние, один штука. А в схеме светодиоды наоборот поставить. Хотя…
Вставляя сишный код исходника в HTML-код страницы сайта вордпресс иногда автоматом ставит пробелы или некоторые знаки считает за свои — такое бывает. Это насчёт пробела.
Количество скобок в макросе правильное. Светодиоды поставлены катодами к МК и включаются лог. 0 — смотрите схему и макросы. Где ещё ошибки?
?звините, какие «еще ошибки» Вы думаете что я решил к Вам «доколупаться»? Какие нашел те и назвал. Вопросы еще будут?
Кстати Ваше письмо попало в спам.
выше вопрос про 4..20мА. Токовая петля надежнее 0-10В, подверженного наводкам и помехам (если о стандартах), обеспечивает и длину сигнальных линий, отсутствие необходимости надежно экранировать/располагать вдали от силовухи и т.д. Про пт-100 и платину — чушь какая-то. Не нужно путать температуру, линейность характеристики и т.д. — каждой задаче — своё. Никель-хром-никель припомните вместо платины., иные никелевые дороже в десятки раз., зависит и от исполнения в т.ч. О преобразователях 4..20мА и 0..10В — нынче (лет 15 как и в России не проблема) у многих производителей есть такие. компактные, на дин рейку., с развязкой, с доп. опциями и т.д. (?збавляет переплачивать за датчик с головой-преобразователем — датчик живет меньше). К слову, это и о фантазиях выше относительно температур и дискретности. Почитайте о стандартах (я указал) и о дискретности., а температуру меряем и 800 гр.ц. и 1600 гр.ц. (а не тривиальные 450, на которые у автора (комментария) почему-то не хватает дискретности).
А вот если питание не 5 вольт, а скажем 4,67. То 4,67 это будет равняться 1024? Ну если опорное напряжение выбрано напряжением источника питания.
По-моему, там где написано включение светодиода нужно наоборот поставить выключение в комментарии, а где включение — выключение. ? еще не указан номер конкретного порта, так как надпись LED — не указывает какой светодиод должен загораться. Значит и величина сдвига будет неизвестна. Возможно, я что-то не так понимаю. Только начинаю работать со всеми этими штуками. ?зучаю.