Ацп в групповом режиме

STM32 АЦП

Давайте рассмотрим какими особенностями обладает АЦП в STM32.

  • Разрядность 12 бит
  • Опорное напряжение от 2.4 до 3.6 Вольта
  • Скорость оцифровки до 1MSPS
  • 18 каналов(16 внешних и 2 внутренних – опорное напряжение и температурный датчик)
  • Прерывание по окончании регулярных и инжектированных преобразований
  • Прерывание от оконного компаратора(Analog watchdog)
  • Отправка данных по DMA для регулярных преобразований
  • Одиночное и непрерывное преобразование
  • Режим сканирования каналов по заданному списку
  • Самокалибровка
  • Выравнивание результата по выбранному краю
  • Время преобразования –12.5 цикла, время захвата – программируемое

Режим регулярных преобразований.В этом режиме задаётся группа от 1 до 16 каналов, обработка которых производится последовательно, а результат помещается в один-единственный 12-разрядный регистр, подразумевается, что данные будут сохраняться с помощью DMA. Ещё раз хотелось бы подчеркнуть, что нельзя просто выбрать один канал, надо задать группу, а в ней выбрать количество каналов. Преобразования могут быть циклическими и периодическими, запускаться по таймеру или внешнему прерыванию. 

Режим инжектированных преобразований.

В последовательность инжектированных преобразований может входить до 4 каналов, они имеют собственные регистры для сохранения результата.

Сразу после запуска инжектированных преобразований, приостанавливается оцифровка регулярных, затем по окончании инжектированных, возобновляется оцифровка регулярных.

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

Оконный компаратор.

В специальных регистрах ADC_HTR и ADC_LTR мы задаём верхнее и нижнее значение результата преобразования, при выходе за которые устанавливается флаг AWD

Для работы с АЦП в STM32 выделен 1 регистр статуса — SR и два регистра настройки CR1, CR2.

 

SR(Status Register)

 

AWD(Analog watchdog flag) — флаг оконного компаратора, устанавливается в 1, когда результат преобразования пересёк ADC_HTR и ADC_LTR.

 

EOC (End of conversion) – флаг окончания группового преобразования, устанавливается в 1 по окончании регулярного или инжектированного преобразования.

 

JEOC(Injected channel end of conversion) — флаг окончания инжетированного преобразования, устанавливается в 1 по окончании инжектированого преобразования.

 

JSTRT(Injected channel Start flag) — флаг запуска инжектированного преобразования, устанавливается в 1 при старте инжектированного преобразования.

 

STRT(Regular channel Start flag) — флаг запуска регулярного преобразования, устанавливается в 1 при старте регулярного преобразования.

Описанные выше флаги выставляются аппаратно, а сбрасывать их надо программно!!! 

ADC_CR1(ADC control register 1)

 

AWDCH[4:0] (Analog watchdog channel select bits) — выбор канала для оконного компаратора, при условии, что битAWDSGL=1.

00000: Канал № 0.00001: Канал №1.………10001: Канал №17. 

EOCIE(Interrupt enable for EOC) — разрешение прерывания по окончании преобразования, 1 — разрешить, 0 — запретить.

 

AWDIE(Analog watchdog interrupt enable) — разрешение прерывания по сигналу оконного компаратора, 1 — разрешить, 0 — запретить.

 

JEOCIE(Interrupt enable for injected channels) — разрешение прерывания по окончании инжектированного преобразования, 1 — разрешить, 0 — запретить.

 

SCAN(Scan mode) — разрешить сканирование каналов по списку указанному в регистрах ADC_SQRx, 1 — разрешить, 0 — запретить.

 

AWDSGL(Enable the watchdog on a single channel in scan mode) — задаёт режим  сканирования оконного компаратора, 0 — все каналы, 1 — только канал указанный в AWDCH[4:0].

 

JAUTO(Automatic Injected Group conversion) — непрерывное преобразование инжектированных каналов, 1 — разрешить, 0 — запретить.

 

DISCEN(Discontinuous mode on regular channels) — дискретный(прерывистый) режим преобразования регулярных каналов, 1 — разрешить, 0 — запретить.

 

JDISCEN(Discontinuous mode on injected channels) — дискретный(прерывистый) режим преобразования инжектированных каналов, 1 — разрешить, 0 — запретить.

 

DISCNUM[2:0](Discontinuous mode channel count) — количество каналов регулярного преобразования.

000: 1 канал001: 2 канала…..111: 8 каналов 

DUALMOD[3:0](Dual mode selection) — определяет режим совместной работы двух АЦП.

 

JAWDEN(Analog watchdog enable on injected channels) — подключение оконного компаратора к инжектированным каналам, 1 — разрешить, 0 — запретить.

 

AWDEN(Analog watchdog enable on regular channels) — подключение оконного компаратора к регулярным каналам, 1 — разрешить, 0 — запретить.

  

ADC_CR2(ADC control register 2)

 

ADON(A/D converter ON / OFF) — управление АЦП, 1 — разрешает работу АЦП, 0 — прерывает преобразование/калибровку и переводит АЦП в режим пониженного энергопотребления.

 

CONT(Continuous conversion) — режим преобразования, 0 — однократный, 1 — непрерывный.

 

CAL(A/D Calibration) — запуск калибровки, 1 — запустить калибровку, 0 — устанавливается аппаратно по завершении калибровки. Производить до включения АЦП, каждый раз после подачи питания.

 

RSTCAL(Reset calibration) — сброс значений калибровки, 1 — сбросить, 0 — устанавливается по завершении сброса.

 

DMA(Direct memory access mode) — разрешает работу DMA, 1 – разрешает, 0 — запрещает.

 

ALIGN(Data alignment) — выравнивание данных, 1 — по правому краю, 0 — по левому. Здесь хорошо будет посмотреть на картинку, так как при инжектированных преобразованиях появляется ещё и знак, на картинке ячейки со знаком обозначены как SEXT.

  

JEXTSEL[2:0](External event select for injected group) – выбор внешнего источника запуска инжектированных каналов.

 

JEXTTRIG(External trigger conversion mode for injected channels) — разрешение запуска инжектированного преобразования внешним сигналом, 1 — разрешить, 0 — запретить.

 

EXTSEL[2:0](External event select for regular group) — выбор внешнего источника запуска регулярных каналов.

 

EXTTRIG(External trigger conversion mode for regular channels) — разрешение запуска регулярного преобразования внешним сигналом, 1 — разрешить, 0 — запретить.

 

JSWSTART(Start conversion of injected channels) — запуск преобразования инжектированных каналов, 1 — запустить преобразование, сбрасывается после запуска преобразования аппаратно. Также для запуска в JEXTSEL[2:0] источником запуска должен быть выбран JSWSTART.

 

SWSTART(Start conversion of regular channels) — запуск преобразования регулярных каналов, 1 — запустить преобразование, сбрасывается после запуска преобразования аппаратно. Также для запуска в EXTSEL[2:0] источником запуска должен быть выбран SWSTART.

 

TSVREFE(Temperature sensor and VREFINT enable) — включает измерение температуры и ИОН, 1 — включить, 0 — выключить. Есть только в ADC1.

  

SMPR[2:1](Channel x Sample time selection).

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

В SMPR1 с 10 по 17-й канал.

 
В SMPR2 с 0 по 9-й канал.

Длительность преобразования составляет 12.5 цикла, для того чтобы найти период выборок надо к длительности преобразования прибавить значение SMPx[2:0].

Т = время между выборки + 12.5 циклаПолучается минимальный период выборок равен

Т = 12.5 + 1.5 = 14 тактов

Максимальная частота, с которой может тактироваться АЦП составляет 14MHz, таким образом, минимальный период выборок равен 1uS. 

JOFRx(x=1..4)

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

HTR и LTR

Верхний и нижний предел оконного компаратора. 

SQRх[3:1] – этот регистр можно условно разделить на две части: биты L[3:0] и биты SQx[4:0].

Номер секции SQx определяет номер в группе регулярных преобразований, а число записанное в секцию определяет номер канала.
Узнать какому выводу соответствует канал можно из даташита в разделе Pinouts and pin description.

А битами L[3:0] в регистре SQR1 задаётся длина регулярной последовательности0000: 1 преобразование0001: 2 преобразования……….1111: 16 преобразованийНапримерL = 0010SQ1=00000, SQ2=00100, SQ3=00010Означает что длина последовательности равна 3 и выполняться она будет в следующем порядке 1-й , 5-й , 3-й канал. 

JSQR — в этих регистрах задаётся длина инжектированной последовательности и порядок преобразований. Битами JL[1:0] задаётся длина  последовательности

00: 1 преобразование01: 2 преобразования10: 3 преобразования11: 4 преобразования

Номер секции JSQx определяет номер в группе инжектированных преобразований, а число записанное в секцию определяет номер канала.

Узнать какому выводу соответствует канал можно из даташита в разделе Pinouts and pin description.Если количество преобразований меньше 4, например 3, то порядок преобразования для записиADC_JSQR[21:0] = 10 00011 00011 00111 00010Будет 7-й,3-й,3-й, а не 2-й,7-й,3-й.

JDR(x = 1…4)

Регистры данных инжектированных преобразований. 

DR

Регистр данных регулярных преобразований.Ниже пример кода для запуска АЦП. #include “stm32f10x.

h” unsigned temp; void ADC1_2_IRQHandler(void) { if(ADC1->SR & ADC_SR_EOC) { //записываем результат в переменную temp =ADC1->DR; } //сбрасываем все флаги в регистре статуса ADC1->SR=0; } int main(void) { //разрешаем тактирование порта А RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //настраиваем вывод для работы АЦП в режим аналогового входа GPIOA->CRL &= ~GPIO_CRL_CNF1; //так как тактовая частота АЦП не должна превышать 14MHz RCC->CFGR |= RCC_CFGR_ADCPRE_DIV8; //разрешаем тактирование АЦП RCC->APB2ENR |= RCC_APB2ENR_ADC1EN ; //в комментах подсказали, что в 17 ревизии указано, что перед калибровкоц АЦП надо включить ADC1->CR2 = | ADC_CR2_ADON; //запускаем калибровку и ждем пока завершится, в симуляторе это не работает, в железе делать обязательно /* ADC1->CR2 |= ADC_CR2_CAL; while (ADC1->CR2 & ADC_CR2_CAL)*/ //разрешаем прерывание от АЦП NVIC->ISER[0] |= NVIC_ISER_SETENA_18; //для первого канала между выборками 7.5 цикла ADC1->SMPR2 = ADC_SMPR2_SMP1_0; //разрешаем прерывания по окончанию преобразования ADC1->CR1 = ADC_CR1_EOCIE; //разрешаем запуск от SWSTAR, разрешаем работу АЦП, разрешаем запуск внешним сигналам, непрерывное преобразования ADC1->CR2 = ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT ; //длина последовательности равна 1, первый канал ADC1->SQR1 = 0x00000000; ADC1->SQR2 = 0x00000000; ADC1->SQR3 = 0x00000001; //запускаем АЦП ADC1->CR2 |= ADC_CR2_SWSTART; while(1) { /*остановить проект, в командную строку записать include sine.ini затем записать ADC1_IN1_Sine ()*/ } } Понятно, что проверить работает ли проект, в симуляторе не получится, так как на вход АЦП ни чего не приходит. Также возникает вопрос, что за строчки закомментированы в цикле while. Проверить проект в симуляторе можно, а закомментированые строчки напоминают как это сделать.

Для начала создаём текстовый документ, записываем в него следующий код и сохраняем его с названием sine.ini

SIGNAL void ADC1_IN1_Sine (void) { float volts; // peak-to-peak voltage float frequency; // output frequency in Hz float offset; // voltage offset float duration; // duration in Seconds float val; long i, end; volts = 1.5; offset = 1.5; frequency = 50; duration = 0.01; printf (“Sine Wave Signal on AD Channel 1.
“); end = (duration * 1000000000); for (i = 0 ; i < end; i++) { val = __sin (2 * 3.1415926 * frequency * (((float) STATES) / STCLK)); ADC1_IN1 = (val * volts) + offset; swatch (0.00001); // in 10 uSec steps } } DEFINE BUTTON "ADC1_IN1 Sin","ADC1_IN1_Sine()" Перемещаем sine.ini в папку проекта, после запуска отладки выполняем то, что написано в закомментированной строчке, в итоге на входе АЦП получаем синус, теперь данные АЦП будут меняться. Картинку можно увеличить кликнув по ней.

Источник: https://hubstub.ru/stm32/66-stm32-acp.html

Аналого-цифровое преобразование для начинающих

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

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

Введение

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

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

Под измерением понимается процесс сравнения измеряемой величины с некоторым эталоном, при аналого-цифровом преобразовании происходит сравнение входной величины с некоторой опорной величиной (как правило, с опорным напряжением).

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

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

АЦП имеет множество характеристик, из которых основными можно назвать частоту преобразования и разрядность. Частота преобразования обычно выражается в отсчетах в секунду (samples per second, SPS), разрядность – в битах.

Современные АЦП могут иметь разрядность до 24 бит и скорость преобразования до единиц GSPS (конечно, не одновременно). Чем выше скорость и разрядность, тем труднее получить требуемые характеристики, тем дороже и сложнее преобразователь.

Скорость преобразования и разрядность связаны друг с другом определенным образом, и мы можем повысить эффективную разрядность преобразования, пожертвовав скоростью.

Типы АЦП

Существует множество типов АЦП, однако в рамках данной статьи мы ограничимся рассмотрением только следующих типов:

  • АЦП параллельного преобразования (прямого преобразования, flash ADC)
  • АЦП последовательного приближения (SAR ADC)
  • дельта-сигма АЦП (АЦП с балансировкой заряда)

Существуют также и другие типы АЦП, в том числе конвейерные и комбинированные типы, состоящие из нескольких АЦП с (в общем случае) различной архитектурой. Однако приведенные выше архитектуры АЦП являются наиболее показательными в силу того, что каждая архитектура занимает определенную нишу в общем диапазоне скорость-разрядность. Наибольшим быстродействием и самой низкой разрядностью обладают АЦП прямого (параллельного) преобразования. Например, АЦП параллельного преобразования TLC5540 фирмы Texas Instruments обладает быстродействием 40MSPS при разрядности всего 8 бит. АЦП данного типа могут иметь скорость преобразования до 1 GSPS. Здесь можно отметить, что еще большим быстродействием обладают конвейерные АЦП (pipelined ADC), однако они являются комбинацией нескольких АЦП с меньшим быстродействием и их рассмотрение выходит за рамки данной статьи. Среднюю нишу в ряду разрядность-скорость занимают АЦП последовательного приближения. Типичными значениями является разрядность 12-18 бит при частоте преобразования 100KSPS-1MSPS. Наибольшей точности достигают сигма-дельта АЦП, имеющие разрядность до 24 бит включительно и скорость от единиц SPS до единиц KSPS. Еще одним типом АЦП, который находил применение в недавнем прошлом, является интегрирующий АЦП. Интегрирующие АЦП в настоящее время практически полностью вытеснены другими типами АЦП, но могут встретиться в старых измерительных приборах.

АЦП прямого преобразования

АЦП прямого преобразования получили широкое распространение в 1960-1970 годах, и стали производиться в виде интегральных схем в 1980-х. Они часто используются в составе «конвейерных» АЦП (в данной статье не рассматриваются), и имеют разрядность 6-8 бит при скорости до 1 GSPS. Архитектура АЦП прямого преобразования изображена на рис. 1Рис.

1. Структурная схема АЦП прямого преобразования Принцип действия АЦП предельно прост: входной сигнал поступает одновременно на все «плюсовые» входы компараторов, а на «минусовые» подается ряд напряжений, получаемых из опорного путем деления резисторами R. Для схемы на рис.

1 этот ряд будет таким: (1/16, 3/16, 5/16, 7/16, 9/16, 11/16, 13/16) Uref, где Uref – опорное напряжение АЦП. Пусть на вход АЦП подается напряжение, равное 1/2 Uref. Тогда сработают первые 4 компаратора (если считать снизу), и на их выходах появятся логические единицы.

Приоритетный шифратор (priority encoder) сформирует из «столбца» единиц двоичный код, который фиксируется выходным регистром. Теперь становятся понятны достоинства и недостатки такого преобразователя. Все компараторы работают параллельно, время задержки схемы равно времени задержки в одном компараторе плюс время задержки в шифраторе.

Компаратор и шифратор можно сделать очень быстрыми, в итоге вся схема имеет очень высокое быстродействие. Но для получения N разрядов нужно 2^N компараторов (и сложность шифратора тоже растет как 2^N). Схема на рис. 1.

содержит 8 компараторов и имеет 3 разряда, для получения 8 разрядов нужно уже 256 компараторов, для 10 разрядов – 1024 компаратора, для 24-битного АЦП их понадобилось бы свыше 16 млн. Однако таких высот техника еще не достигла.

АЦП последовательного приближения

АЦП последовательного приближения реализует алгоритм «взвешивания», восходящий еще к Фибоначчи. В своей книге «Liber Abaci» (1202 г.

) Фибоначчи рассмотрел «задачу о выборе наилучшей системы гирь», то есть о нахождении такого ряда весов гирь, который бы требовал для нахождения веса предмета минимального количества взвешиваний на рычажных весах.

Решением этой задачи является «двоичный» набор гирь. Подробнее о задаче Фибоначчи можно прочитать, например, здесь: http://www.goldenmuseum.com/2015AMT_rus.html.

Аналого-цифровой преобразователь последовательного приближения (SAR, Successive Approximation Register) измеряет величину входного сигнала, осуществляя ряд последовательных «взвешиваний», то есть сравнений величины входного напряжения с рядом величин, генерируемых следующим образом: 1.

на первом шаге на выходе встроенного цифро-аналогового преобразователя устанавливается величина, равная 1/2Uref (здесь и далее мы предполагаем, что сигнал находится в интервале (0 – Uref). 2. если сигнал больше этой величины, то он сравнивается с напряжением, лежащим посередине оставшегося интервала, т.е., в данном случае, 3/4Uref.

Если сигнал меньше установленного уровня, то следующее сравнение будет производиться с меньшей половиной оставшегося интервала (т.е. с уровнем 1/4Uref). 3. Шаг 2 повторяется N раз. Таким образом, N сравнений («взвешиваний») порождает N бит результата.Рис. 2. Структурная схема АЦП последовательного приближения.

Таким образом, АЦП последовательного приближения состоит из следующих узлов: 1. Компаратор. Он сравнивает входную величину и текущее значение «весового» напряжения (на рис. 2. обозначен треугольником). 2. Цифро-аналоговый преобразователь (Digital to Analog Converter, DAC). Он генерирует «весовое» значение напряжения на основе поступающего на вход цифрового кода. 3.

Регистр последовательного приближения (Successive Approximation Register, SAR). Он осуществляет алгоритм последовательного приближения, генерируя текущее значение кода, подающегося на вход ЦАП. По его названию названа вся данная архитектура АЦП. 4. Схема выборки-хранения (Sample/Hold, S/H).

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

Достоинством устройства является относительно высокая скорость преобразования: время преобразования N-битного АЦП составляет N тактов. Точность преобразования ограничена точностью внутреннего ЦАП и может составлять 16-18 бит (сейчас стали появляться и 24-битные SAR ADC, например, AD7766 и AD7767).

Дельта-сигма АЦП

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

Его суть в том, что входное напряжение сравнивается со значением напряжения, накопленным интегратором. На вход интегратора подаются импульсы положительной или отрицательной полярности, в зависимости от результата сравнения.

Таким образом, данный АЦП представляет собой простую следящую систему: напряжение на выходе интегратора «отслеживает» входное напряжение (рис. 4).

Результатом работы данной схемы является поток нулей и единиц на выходе компаратора, который затем пропускается через цифровой ФНЧ, в результате получается N-битный результат. ФНЧ на рис. 3. Объединен с «дециматором», устройством, снижающим частоту следования отсчетов путем их «прореживания».Рис. 4.

Сигма-дельта АЦП как следящая система Ради строгости изложения, нужно сказать, что на рис. 3 изображена структурная схема сигма-дельта АЦП первого порядка. Сигма-дельта АЦП второго порядка имеет два интегратора и две петли обратной связи, но здесь рассматриваться не будет.

Интересующиеся данной темой могут обратиться к [3]. На рис. 5 показаны сигналы в АЦП при нулевом уровне на входе (сверху) и при уровне Vref/2 (снизу).Рис. 5. Сигналы в АЦП при разных уровнях сигнала на входе.

Более наглядно работу сигма-дельта АЦП демонстрирует небольшая программа, находящаяся тут: http://designtools.analog.com/dt/sdtutorial/sdtutorial.html.

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

Структурная схема сигма-дельта модулятора Здесь компаратор представлен как сумматор, который суммирует непрерывный полезный сигнал и шум квантования. Пусть интегратор имеет передаточную функцию 1/s.

Тогда, представив полезный сигнал как X(s), выход сигма-дельта модулятора как Y(s), а шум квантования как E(s), получаем передаточную функцию АЦП: Y(s) = X(s)/(s+1) + E(s)s/(s+1) То есть, фактически сигма-дельта модулятор является фильтром низких частот (1/(s+1)) для полезного сигнала, и фильтром высоких частот (s/(s+1)) для шума, причем оба фильтра имеют одинаковую частоту среза. Шум, сосредоточенный в высокочастотной области спектра, легко удаляется цифровым ФНЧ, который стоит после модулятора.Рис. 7. Явление «вытеснения» шума в высокочастотную часть спектра Однако следует понимать, что это чрезвычайно упрощенное объяснение явления вытеснения шума (noise shaping) в сигма-дельта АЦП. Итак, основным достоинством сигма-дельта АЦП является высокая точность, обусловленная крайне низким уровнем собственного шума. Однако для достижения высокой точности нужно, чтобы частота среза цифрового фильтра была как можно ниже, во много раз меньше частоты работы сигма-дельта модулятора. Поэтому сигма-дельта АЦП имеют низкую скорость преобразования. Они могут использоваться в аудиотехнике, однако основное применение находят в промышленной автоматике для преобразования сигналов датчиков, в измерительных приборах, и в других приложениях, где требуется высокая точность. но не требуется высокой скорости.

Немного истории

Самым старым упоминанием АЦП в истории является, вероятно, патент Paul M. Rainey, «Facsimile Telegraph System,» U.S. Patent 1,608,527, Filed July 20, 1921, Issued November 30, 1926. Изображенное в патенте устройство фактически является 5-битным АЦП прямого преобразования.Рис. 8. Первый патент на АЦПРис. 9. АЦП прямого преобразования (1975 г.

) Устройство, изображенное на рисунке, представляет собой АЦП прямого преобразования MOD-4100 производства Computer Labs, 1975 года выпуска, собранный на основе дискретных компараторов. Компараторов 16 штук (они расположены полукругом, для того, чтобы уравнять задержку распространения сигнала до каждого компаратора), следовательно, АЦП имеет разрядность всего 4 бита.

Скорость преобразования 100 MSPS, потребляемая мощность 14 ватт. На следующем рисунке изображена продвинутая версия АЦП прямого преобразования.Рис. 10. АЦП прямого преобразования (1970 г.

) Устройство VHS-630 1970 года выпуска, произведенное фирмой Computer Labs, содержало 64 компаратора, имело разрядность 6 бит, скорость 30MSPS и потребляло 100 ватт (версия 1975 года VHS-675 имела скорость 75 MSPS и потребление 130 ватт).

Литература

W. Kester. ADC Architectures I: The Flash Converter. Analog Devices, MT-020 Tutorial. www.analog.com/static/imported-files/tutorials/MT-020.pdf

Источник: https://habr.com/post/125029/

Аналого-цифровой преобразователь микроконтроллеров AVR

Автор: AntonChip. Дата публикации: 16 мая 2011.

Рейтинг:  5 / 5

Разряд Название Описание
7 ADEN Разрешение АЦП (1 – включено, 0 – выключено)

Режим непрерывных измерений активизируется установкой бита ADFR (бит 5) этого же регистра.

В ряде моделей Mega этот бит носит наименование ADATE, и управление режимом работы производится сложнее: там добавляются несколько режимов запуска через различные прерывания (в т. ч. прерывание от компаратора, при наступлении различных событий от таймера и т. п.

), и выбирать их следует, задавая биты ADTS регистра SFIOR, а установка бита ADATE разрешает запуск АЦП по этим событиям.

Разряд Название Описание
5 ADFR(ADATE) Выбор режима работы АЦП

Так как нулевые значения всех битов ADTS (по умолчанию) означают режим непрерывного преобразования, то в случае, когда вы их значения не трогали, функции битов ADATE и ADFR в других моделях будут совпадать.

ADTS2 ADTS1 ADTS0 Источник стартового сигнала
Режим непрерывного преобразования
1 Прерывание от аналогового компаратора
1 Внешнее прерывание INT0
1 1 Прерывание по событию “Совпадение” таймера/счетчика Т0
1 Прерывание по переполнению таймера/счетчика Т0
1 1 Прерывание по событию “Совпадение” таймера/счетчика Т1
1 1 Прерывание по переполнению таймера/счетчика Т1
1 1 1 Прерывание по событию “Захват” таймера/счетчика Т1

Если выбран режим запуска не от внешнего источника, то преобразование запускается установкой бита ADSС (бит 6). При непрерывном режиме установка этого бита запустит первое преобразование, затем они будут автоматически повторяться.

В режиме однократного преобразования, а также независимо от установленного режима при запуске через прерывания (в тех моделях, где это возможно) установка бита ADSС просто запускает одно преобразование. При наступлении прерывания, запускающего преобразование, бит ADSС устанавливается аппаратно.

Отметим, что преобразование начинается по-фронту первого тактового импульса (тактового сигнала АЦП, а не самого контроллера!) после установки ADSС. По окончании любого преобразования (и в одиночном, и в непрерывном режиме) устанавливается бит ADIF (бит 4. флаг прерывания).

Разрешение прерывания АЦП осуществляется установкой бита ADIE (бит 3) все того же регистра ADCSR/ADCSRA.

Разряд Название Описание
6 ADSC Запуск преобразования (1 – начать преобразование)
4 ADIF Флаг прерывания
3 ADIE Разрешение прерывания

Для работы с АЦП необходимо еще установить его тактовую частоту. Это делается тремя младшими битами регистра ADCSR/ADCSRA под названием ADPS0..2. Коэффициент деления частоты тактового генератора МК устанавливается по степеням двойки, все нули в этих трех битах соответствуют коэффициенту 2, все единицы — 128.

Оптимальная частота преобразования лежит в диапазоне 50-200 кГц, так что, например, для тактовой частоты МК, равной 4 МГц, коэффициент может иметь значение только 32 (состояние битов ADPS0..2 = 101, частота 125 кГц) или 64 (состояние битов ADPS0..2 = 110, частота 62,5 кГц).

При тактовой частоте 16 МГц в допустимый диапазон укладывается только коэффициент 128.

ADPS2 ADPS1 ADPS0 Коэффициент деления
2
1 2
1 4
1 1 8
1 16
1 1 32
1 1 64
1 1 1 128

Ниже приведена таблица с описанием регистра ADMUX.


Выборка источника опорного напряжения производится битами REFS1..0 регистра ADMUX (старшие биты 7 и 6), причем их нулевое значение (по умолчанию) соответствует внешнему источнику.

Напряжение этого внешнего источника может лежать в пределах от 2 В до напряжения питания аналоговой части AVcc (а оно, в свою очередь, не должно отличаться от питания цифровой части более чем на 0,3 В в большую или меньшую сторону).

Можно выбрать в качестве опорного и питание самой аналоговой части, причем двояким способом: либо просто соединить выводы AREF и AVcc микросхемы, либо установить биты REFS1..

0 в состояние 01 (тогда соединение осуществляется внутренними схемами, но заметим, что внешний опорный источник при этом должен быть отключен). Предусмотрен и встроенный источник (задается REFS1..0 в состоянии 11, при этом к выводу AREF рекомендуется подключать фильтрующий конденсатор), имеющий номинальное напряжение 2,56В с большим разбросом от 2,4 до 2,7 В.

REFS1 REFS0 Источник опорного напряжения
Внешний ИОН, подключенный к выводу AREF, внутренний ИОН отключен
1 Напряжение питания AVcc*
1 Зарезервировано
1 1 Внутренний ИОН напряжением 2,56V, подключенный к ввыводу AREF*
*Если к выводу AREF подключен источник напряжения, данные варианты использоваться не могут

Результат преобразования АЦП оказывается в регистрах ADCH:ADCL. Поскольку результат 10-разрядный, то по умолчанию старшие 6 битов в регистре ADCH оказываются равными нулю. Чтение этих регистров производится, начиная с младшего ADCL, после чего регистр ADCH блокируется, пока не будет прочитан.

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

Но бит ADLAR (бит 5 регистра ADMUX) предоставляет интересную возможность: если его установить в 1, то результат преобразования в регистрах ADCH:ADCL выравнивается влево: бит 9 результата окажется в старшем бите ADCH, а незначащими будут младшие 6 битов регистра ADCL.

В этом случае, если хватает 8-разрядного разрешения результата, можно прочесть только значение ADCH.

Выбор каналов и режимов их взаимодействия в АЦП производится битами MUX0..3 в регистре ADMUX. Их значения выбирают нужный канал в обычном (недифференциальном) режиме, когда измеряемое напряжение отсчитывается от “земли”.

Последние два значения этих битов для семейства Mega (11110 и 11111 в большинстве моделей или 1110 и 1111 для ATmega8) выбирают режимы, когда вход АЦП подсоединяется к опорному источнику компаратора (1,22 В) или к “земле” соответственно, что может использоваться для автокалибровки устройства.

Управление входным мультиплексором в моделях Atmega8x

MUX3-MUX0 Несимметричный вход
0000 ADC0
0001 ADC1
0010 ADC2
0011 ADC3
0100 ADC4*
0101 ADC5*
0110 ADC6**
0111 ADC7**
1000-1101 Зарезервировано
1110 1,22V
1111 0V(GND)
*8-ми разрядное преобразование**Имеются только в корпусах TQFP-32 и MLF-32.

Остальные комбинации разрядов MUX предназначены для установки различных дифференциальных режимов — в тех моделях, где они присутствуют, в других случаях эти биты зарезервированы (как в моделях Atmega8, ATmega163 и др.).

В дифференциальном режиме АЦП измеряет напряжение между двумя выбранными выводами (например, между ADC0 и ADC1), причем не все выводы могут быть в таком режиме задействованы.

В том числе дифференциальные входы АЦП можно подключать к одному и тому же входу для коррекции нуля. Дело в том, что в ряде моделей на входе АЦП имеется встроенный усилитель, с коэффициентом 1х, 10х и 200х (коэффициент выбирается теми же битами MUX0..

4), и такой режим используется для его калибровки — в дальнейшем значение выхода при соединенных входах можно просто вычесть.

После завершения преобразования (при установке в «1» флага ADIF регистра ADCSR) его результат сохраняется в регистре данных АЦП.

Поскольку АЦП имеет 10 разрядов, этот регистр физически размещен в двух регистрах ввода/вывода ADCH:ADCL, доступных только для чтения.

По умолчанию результат преобразования выравнивается вправо (старшие 6 разрядов регистра ADCH — незначащие). Однако он может выравниваться и влево (младшие 6 разрядов регистра ADCL — незначащие).

Для управления выравниванием результата преобразования служит разряд ADLAR регистра ADMUX. Если этот разряд установлен в «1», результат преобразования выравнивается по левой границе 16-разрядного слова, если сброшен в «0» — по правой границе.

Обращение к регистрам ADCH и ADCL для получения результата преобразования должно выполняться в определенной последовательности: сначала необходимо прочитать регистр ADCL, а затем ADCH.

Это требование связано с тем, что после обращения к регистру ADCL процессор блокирует доступ к регистрам данных со стороны АЦП до тех пор, пока не будет прочитан регистр ADCH.

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

С другой стороны, если результат преобразования выравнивается влево и достаточно точности 8-разрядного значения, для получения результата можно прочитать только содержимое регистра ADCH.

Для недифференциального режима АЦП, когда напряжение отсчитывается от “земли”, результат преобразования определяется формулой:

Ка = 1024Uвх/Uref

, где Ка — значение выходного кода АЦП, Uвх и Uref — входное и опорное напряжения.

Дифференциальному измерению соответствует такая формула:

Ка = 512(Upos – Uneg)/Uref

, где Upos и Uneg — напряжения на положительном и отрицательном входах соответственно. Если напряжение на отрицательном входе больше, чем на положительном, то результат в дифференциальном режиме становится отрицательным и выражается в дополнительном коде от $200 (-512) до $3FF (-1). Реальная точность преобразования в дифференциальном режиме равна 8 разрядам.

Делаем светодиодный индикатор напряжения

Для практического изучения АЦП напишем программу светодиодного индикатора напряжения. Как и в прошлых примерах будем использовать микроконтроллер Atmega8.

Восемь индикаторов подключаем к порту D контроллера, это будет линейная шкала уровня сигнала от 0 до 5V.

Входом АЦП у нас будет вывод PC0(ADC0), к которому через переменный резистор сопротивлением 10кОм подается напряжение. Схема устройства представлена ниже:

К точности АЦП в этом устройстве предъявляются наименьшие требования.

Источником опорного напряжения служит напряжение питания микроконтроллера – 5 Вольт, для этого вывод AREF соединяем с выводом Vcc микроконтроллера, также поступаем с выводами питания аналоговой части AVcc и AGND, подключаем их к плюсу и минусу соответственно, в программе битами REFS1 и REFS0 задаем источник ИОН.

Режим индикации работает следующим образом: после окончания преобразования, которое работает в непрерывном режиме, считываем биты ADCH и ADCL.

Это значение потом сравниваем с предварительно расчитанными константами.

Если значение ADC больше константы загорается один светодиод, если значение ADC больше второй константы загораются уже два светодиода и т.д.

Константы высчитываются так: так как АЦП 10-ти битный, число 1024 раскладываем на 8 равных частей, а по формуле уже вычисляем эти значения в Вольтах.

128…0,625V

256…1.25V

384…1.875V

512…2.5V

640…3.125V

768…3.75V

896…4.375V

1020…5V(приблизительно)

Полный код программы показан ниже. Частота тактового генератора контроллера 8MHz.

/*** Использование АЦП. Светодиодная шкала ***/ #include #include int main (void) { DDRD = 0xFF; PORTD = 0x00; /*** Настройка АЦП ***/ ADCSRA |= (1

Источник: https://radioparty.ru/programming/avr/c/285-lesson-adc-avr

Урок 10. АЦП в AVR микроконтроллерах. Простой вольтметр на AVR

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

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

Сигнал всегда измеряется относительно точки называемой опорное напряжение, эта же точка является максимумом который можно измерить.

В качестве источника опорного напряжения (ИОН), рекомендуется выбирать высокостабильный источник напряжения, иначе все измерения будут плясать вместе с опорным.

Одной из важнейших характеристик является разрешающая способность, которая влияет на точность измерения. Весь диапазон измерения разбивается на части. Минимум ноль, максимум напряжение ИОН. Для 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вхR2/(R1 + R2)

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

5 = 10*R2/(R1+R2)

(R1+R2)=2*R2

R1=R2

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

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

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

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

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

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

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

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

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

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

lcd_puts(lcd_buffer);                          //выводим на экран

Источник: http://avr-start.ru/?p=590

ZiB

Сегодня по плану АЦП.

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

Модуль АЦП

Кратенько рассмотрим что же “может” АЦП:

  • разрешение 12-бит
  • минимальное время преобразования 1,17 мкс (при частоте системной шины 24 МГц)
  • встроенный ИОН и датчик температры
  • встроенный механизм самокалибровки
  • режимы однократного и циклического преобразования
  • режим “сканирования” для последовательного преобразования нескольких каналов
  • время преобразования устанавливается индивидуально для каждого канала
  • инициировать преобразования возможно от внешних или внутренних сигналов
  • и  это ещё не всё 😉 читать подробнее в документции к МК

Функциональная схема блока АЦП:

И так приступим.

Для работы модуля АЦП необходимо:

  • разрешить тактирование модуля
  • сконфигурировать необходимый режим работы

Максимальная тактовая частота для модуля АЦП составляет 12 МГц, при частоте системной шины 24 МГц, на данном этапе выжимать по полной нет необходимости, поэтому продолжим работать от встроенного RC генератора частотой 8 МГц, при этом максимальная частота модуля может быть 4 Мгц, так как предварительный делитель имеет минимальный коэффициент деления двойку:

Установим предварительный делитель и разрешим тактирование модуля:

RCC->CFGR &= ~RCC_CFGR_ADCPRE;
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV2;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;

Примечание: ранее я не сделал акцент на одном моменте, как только вы разрешаете тактирование того или иного блока микроконтроллера, путем установки соответствующего бита в блоке управлением сбросом и тактированием RCC, то все регистры выбранного блока автоматически инициализируются значениями по умолчанию  (если не ошибаюсь это касается всех модулей МК).

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

#define ADC_INPUT10 C, 0, HIGH, ANALOG,

PIN_CONFIGURATION(ADC_INPUT10);

Модуль позволяет производить последовательное преобразование до 16 каналов, порядок каналов может быть любой, нам необходимо установить преобразование одного десятого канала.

Для этого устанавливаем длину последовательности преобразований равной единице (значение после сброса АЦП) и десятый номер канала в первую ячейку (не уверен в правильности терминологии, так как английский знаю на три с минусом):

ADC1->SQR3 = ADC_SQR3_SQ1_1 | ADC_SQR3_SQ1_3;

На каждый канал выделено пяти битное поле, соответственно для 16 каналов необходимо три регистра (SQR1-SQR3), ячейка для первого преобразования занимает с 0 по 4 бит в регистре SQR3, соответственно для десятого канала необходимо установить 1 и 3 бит (ADC_SQR3_SQ1_1, ADC_SQR3_SQ1_3).

Далее необходимо выбрать источник запуска, нам нужен программный запуск:

ADC1->CR2 = ADC_CR2_EXTSEL_0 | ADC_CR2_EXTSEL_1 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTTRIG;

Ну вот теперь можно вывести АЦП из режима пониженного энергопотребления:

ADC1->CR2 |= ADC_CR2_ADON;

произвести калибровку АЦП:

ADC1->CR2 |= ADC_CR2_RSTCAL;
while ((ADC1->CR2 & ADC_CR2_RSTCAL) == ADC_CR2_RSTCAL)
{
} ADC1->CR2 |= ADC_CR2_CAL;
while ((ADC1->CR2 & ADC_CR2_RSTCAL) == ADC_CR2_CAL)
{
}

и всё 😉 можно пользоваться.

Функция целиком:

void mcu_adc_init(void)
{ RCC->CFGR &= ~RCC_CFGR_ADCPRE; RCC->CFGR |= RCC_CFGR_ADCPRE_DIV2; RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; ADC1->SQR3 = ADC_SQR3_SQ1_1 | ADC_SQR3_SQ1_3; ADC1->CR2 = ADC_CR2_EXTSEL_0 | ADC_CR2_EXTSEL_1 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTTRIG; ADC1->CR2 |= ADC_CR2_ADON; ADC1->CR2 |= ADC_CR2_RSTCAL; while ((ADC1->CR2 & ADC_CR2_RSTCAL) == ADC_CR2_RSTCAL) { } ADC1->CR2 |= ADC_CR2_CAL; while ((ADC1->CR2 & ADC_CR2_RSTCAL) == ADC_CR2_CAL) { }
}

Для примера я использовал прерывания от таймера 17 (описан ранее), точнее прописал в обработчике: запуск – ожидание – считывание результата:

void mcu_adc_channel_10_convert(void)
{ ADC1->CR2 |= ADC_CR2_SWSTART; while ((ADC1->SR & ADC_SR_EOC) != ADC_SR_EOC) { } mcu_adc_channel_10_value = ADC1->DR;
}

Результат преобразования вывожу на ЖКИ индикатор, ну и для тех у кого нет индикатора меняю частоту “мигания” зеленого светодиода в зависимости от результата преобразования:

void handler_tim1_trigger_and_communication_and_tim17(void)
{ if (TIM17->SR & TIM_SR_UIF) { TIM17->SR &= ~TIM_SR_UIF; mcu_adc_channel_10_convert(); if (test_count == 0) { PIN_ON(LED_GREEN); } else if (test_count == (1 + (mcu_adc_channel_10_value >> 4))) { PIN_OFF(LED_GREEN); } if (++test_count >= ((1 + (mcu_adc_channel_10_value >> 4)) * 2)) test_count = 0; }
}

Напряжение на вход АЦП подаю используя обычный делитель напряжения выполненный на переменном резисторе:

Резистор R2 необходим для защиты линии ввода-вывода в случае неправильной конфигурации.

Небольшое видео, сори за тряску 😉

Всю необходимую информацию вы можете найти на офф стайте:

STM32F100RB – STM32 Value Line 32-bit Microcontrollers

Проект с примером:

[download id=”30”]

Источник: http://ziblog.ru/2011/01/15/stm32-chast-9-ndash-analogo-tsifrovoy-preobrazovatel-atsp.html

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}