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

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

Начнем-с…Вот некоторые характеристики аналого-цифрового преобразователя в STM32f10x:

  • АЦП является 12-ти битным
  • Возможна генерация прерывания по окончанию преобразования, по окончанию преобразования с инжектированного канала, а также возможно прерывание от Analog Watchdog (что это такое расскажу чуть ниже)
  • Возможно одиночное преобразование и преобразование в непрерывном режиме
  • Самокалибровка
  • Запуск преобразования от внешнего события
  • Работа с ПДП (DMA, прямой доступ к памяти)

Вот структурная схема из даташита, полюбуйтесь)

Пока не забыл про Analog Watchdog, опишу его работу.
Он нужен для того, чтобы следить, что напряжение попадает в определенные пределы. Причем он может сканировать как конкретный канал, так и группу каналов. В регистры ADC_HTR и ADC_LTR заносим значения верхнего и нижнего порога соответственно. И в случае, если проверяемое напряжение выходит за эти пределы, генерируется прерывание. Полезнейшая вещица!

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

Как и в микроконтроллерах AVR возможно выравнивание результата по правому или по левому краю. Тут правда результат 12-ти битный. Но суть та же. Вот как все это выглядит в регистрах:

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

Нужно сначала разобраться с компонентами, которые использовались нами для создания прошивки. А использовался нами только один компонент - PWM8. PWM расшифровывается как Pulse Width Modulator, что значит Широтно-импульсный модулятор. Суть прибора в том, что он позволяет изменять широту импульсов, генерируемых микроконтроллером. Тем самым, меняя выходное напряжения для устройств, не чувствительных к частоте.
Например: рабочая частота микроконтроллера 1Гц (то есть, период генерации импульсов 1с), ширина импульса 0.5с, напряжение импульса 5В.

Тогда среднее выходное напряжение за секунду равно 2.5 вольта. А получается эта величина просто: сложением подимпульсных площадей и делением их на общий промежуток времени. На всякий случай распишу подробней. Допустим, мы взяли промежуток времени в 1 секунду, из рисунка видно первый импульс длился 0.5. Умножаем 0.5с*5В (напряжение импульса) и все это делим на интервал времени. 0.5с*5В/1с = 2.5В. Если нам понадобится выходное напряжение в 3.33В, мы должны будем увеличить подимпульсную площадь до 75%. В литературе ещё часто фигурирует термин скважность. Так вот, скважность и есть отношений длительности импульса к длительности нулевого потенциала, например, для первого случая, она была 50%, для второго - 75%.

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

Clock - это рабочая частота ШИМа, любой цифровой или аналогово-цифровой блок должен работать на определённой тактовой частоте. Для этого и придуманы делители частоты и поле Clock. SysClk - это системная частота, выставленная в закладке Global Resources. Интересно заметить то, что в выпадающем списке Clock присутствуют такие поля, как Row_0_Input_0. Это значит, что тактовый генератор модуля может быть снаружи чипа и синхронизироваться они будут через шину Row_0_Input_0.

Enable - уровень логической единицы данного блока. Обычно используются два стандарта: High = 5В и Low = 3В. Сам микроконтроллер, кстати, можно так же перевести на один из режимов High или Low.

CompareOut - выход широтно-импульсного модулятора.

Может возникнуть вопрос: зачем была дана выше приведенная теория, если на практике мы это нигде не использовали? А ответ в том, что мы использовали дефолтные значения для длинны импульса и времени периода (поля Period и PulseWidth) 0 0. При таких значениях на выходе PWM будет сплошной сигнал, равный по величине логической единице. Менять время периода и значения ширины импульса можно так же программно в режиме работы микроконтроллера, функциями PWM8_1_WritePeriod() и PWM8_1_WritePulseWidth().

ADC или АЦП

АЦП - аналого-цифровой преобразователь (или ADC Analog-to-digital converter) - это устройство, позволяющие преобразовать аналоговый сигнал в цифровой. Любые физические величины (давление, скорость, угол поворота, напряжение, ток, сила света) являются аналоговыми, и задача ADC - переводить их в цифровой сигнал. На практике же, для перевода в цифровой сигнал обычно используется величина напряжения.
Из многочисленных характеристик АЦП следует выделить три основных:

  1. Разрядность - это наименьшая единица аналогового сигнала, изменение которой может зафиксировать ADC, обычно измеряется в битах.
  2. Частота преобразования - количество измерений в секунду, измеряется в SPS (samples per second)
  3. Рабочий диапазон - диапазон величин, в котором работает данный преобразователь.

Так как АЦП уже не такой простой прибор, как PWM. Придется разобрать ещё некоторые теоретические аспекты микроконтроллера и некоторые фичи самого АЦП.

Общие характеристики микроконтроллера

Перечень некоторых понятий и обозначений о которых нужно знать при работе c чипами PSoC(кстати и не только всё ниже сказанное будет верно и для микроконтроллеров AVR)

В описаниях и на принципиальных схемах в даташитах часто фигурируют такие обозначения как Vcc, Vdd, Vss, AGND. И разница между ними порой не самая очевидная. Vcc - это напряжение питания микроконтроллера (сс - collector-to-collector), то же самое что и Vdd, так уж исторически сложилось что одна и та же величина имеет 2 обозначения. Vss - минимальный потенциал на микроконтроллере, очень часто бывает, что эта величина эквивалентна AGND. Буква "A" в аббревиатуре AGND указывает на что, это artificial граунд или искусственная земля. Стоит упомянуть про такое напряжение на схеме, которое обычно называется как BandGap. BandGrap - это опорное напряжения. Опорное напряжение означает то что оно остаётся постоянным не зависимо от напряжения питания МК, температуры и других внешних показателей. Vref - опорное напряжения отдельно рассматриваемого модуля. Очень долго я не мог врубиться, что такое Rail-to-Rail. А попадалась мне эта фраза в контекстах типа: "Данный модуль может работать в режиме Rail-to-Rail". Так вот Rail-to-Rail означает то, что элемент может работать на всем размахе напряжений от Vcc до AGND.

Пример 2. Voltage Measuring

Задача: Измерить напряжение на потенциометре, зашитом в отладочную плату и вывести значение на экран.

Вот тут уже будет по интересней. Как обычно запускаем дизайнер, создаем проект. Идем в User Modules -> Misc Data -> LCD и левой кнопкой перетягиваем его на микроконтроллер. LCD очень полезный и простой модуль, да к тому же ещё и не занимающий место на цифровых блока. Увидеть его можно в закладке Workspace Explorer. Из настоек ему нужно выбрать только LCDPort = Port_2. Теперь заходим в файл main.c, напомню, что он лежит в Workspace Explorer -> [Имя проекта] -> Source Files -> main.c. И добавляем в функцию main() следующий код.

LCD_Start(); LCD_Position(0,0); LCD_PrCString("Measured Voltage");

Компилируем код, прошиваем микроконтроллер. Если всё было правильно сделано, получим на экране строку которая была прописана выше. Более простого управления экраном, и придумать не могли. И это радует. Теперь дело осталось за ADC. Выбираем User Modules -> Legacy -> ADCINC12 и выкидываем его на контроллер. Может возникнуть вопрос "Почему мы не выбрали просто ADCINC, а ADCINC12 да и ещё в придачу из папки Legacy? Причина кроется в сложности инициализации модулей. ADCINC более сложный и гибкий модуль, который требует более тщательной и доскональной настройки. В папке Legacy, что значит унаследованные, уже храниться модуль который менее гибкий, зато более простой в реализации. Далее не думая заходим в папку, amplifers и выкидываем на схему PGA(Programmable Gain Amplifier). Программируемый операционный усилитель. Он нужен не столько для усиления, сколько для повышения входного сопротивления. Что бы величина текущего тока в цепи не влияла на точность измерения.
Выставляем настройки PWM как на скриншоте.

  1. Gain - коэффициент усиления.
  2. Input - вход прибора.
  3. Reference - опорное напряжение.

Настройки ADC выставляем так:

  1. TMR Clock - тактовая частота таймера.
  2. Input - вход прибора (подключен к PGA).
  3. CNT Clock - частота счетчика.

Последнее, что понадобиться нам для нормальной работы, это глобальный ресурс называемый Ref Mux. Ref Mux - это рабочий диапазон напряжений аналоговых блоков. Если мы выставим значение (Vdd/2)+/-(Vdd/2) то получим полную разбежку напряжений от 0 до 5В. Но в этом есть один определённый минус. Так как за опорное напряжение принимается напряжение питания. Если будет плавать напряжение Vdd, это повлияет на правдивость результатов. В таком случае нам и пригодился бы BandGap. Но пока не будем париться, и выставляем (Vdd/2)+/-(Vdd/2).
Для перепроверки скину скрин получившейся коммутации аналоговых блоков.

Переходим в main.c и добавляем в функцию main() следующий код:

PGA_Start(PGA_HIGHPOWER); //запуск PGA ADCINC12_Start(ADCINC12_HIGHPOWER); //запуск АЦП ADCINC12_GetSamples(0); //установка АЦП на песперерывную работу M8C_EnableGInt ; // Uncomment this line to enable Global Interrupts while(1) // главный цикл прошивки { if (ADCINC12_fIsDataAvailable() != 0) //проверка на данных в ADC { result = ADCINC12_iGetData() + 2048; ADCINC12_ClearFlag(); LCD_Position(1,0); //установка позиции для вывода LCD_PrHexInt(result); //вывод результата в хексе } }

К данным функции iGetData() прибавляется 2048 для того что перевести данные в беззнаковый эквиваленте (если интересно смотреть google "c++ знаковые и беззнаковые переменные").

Соединяем потенциометр с платой следующим образом.

Прошиваем микроконтроллер и оцениваем результат работы.

Осталось только перевести хексы в напряжение и проверить корректность данных тестером. Добиваться этой цели будем чисто опытным путём. Облегчим себе ситуацию, и примем нулевой потенциал за 0x0000 значение на выходе ADC. Затем запускаем нашу уже написанную программу, выкручиваем потенциометр на максимум и смотрим получившиеся значения. У меня, например, получилось 0х0FEC. Затем берём тестер и измеряем реальное напряжение на потенциометре. У меня получилось 4.78В. Теперь делим 4.78/0х0FEC (у кого проблемы с системами исчисления, советую подкачаться) и получаем шаг квантования, то есть единицу напряжения, которой соответствует одно значение выхода АЦП. У меня получилась 0.0011727183513248 вот такое вот число. Теперь просто результат с АЦП перемножаем на эту величину и выводим на экран. Для этого добавим переменные в глобальное поле видимости (это всё то что вне функции main()).

В статье приведено описание аналого-цифрового преобразователя 32-разрядных ARM-микроконтроллеров серии STM32 от компании STMicroelectronics. Рассмотрена архитектура и состав его регистров,
а также приведены практические примеры программ.

Введение
Одним из наиболее важных и востребованных блоков для микроконтроллера является его цифровой преобразователь (АЦП), именуемый в технической англоязычной литературе как Analog-to-Digital
Converter (ADC).

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

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

Микроконтроллеры серии STM32 также имеют встроенный 12-разрядный АЦП последовательного приближения с тактовой частотой до 14 МГц. Некоторые модели STM32 имеют даже два или три блока АЦП.

Структурная схема АЦП микроконтроллеров STM32

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

  • разрядность – 12 бит;
  • минимальное время преобразования – 1 мкс;
  • количество каналов – 16 внешних и 2 внутренних;
  • количество значений времени преобразования для каждого канала – 8;
  • возможность задания одиночного или непрерывного преобразования;
  • автоматическая калибровка;
  • наличие оконного компаратора;
  • возможность запуска преобразования от внешних источников;
  • работа с блоком прямого доступа к памяти (ПДП).

АЦП питается от источника с напряжением от 2,4 В до 3,6 В. Источник опорного напряжения (ИОН) АЦП соединён либо внутренне с напряжением питания АЦП, либо со специальными внешними выводами в зависимости от модели и количества выводов кристалла. Структурная схема АЦП микроконт­роллеров серии STM32 приведена на рисунке. Как видно из рисунка, АЦП имеет 16 внешних аналоговых каналов
и 2 внутренних, которые коммутируются с помощью мультиплексора входов. Внешние каналы подключены к выводам микроконтроллера. Перед использованием этих выводов в качестве аналоговых необходимо сконфигурировать их как аналоговые входы. Дополнительные два канала задействованы под внутренние сигналы. Один – для контроля внутреннего опорного напряжения, а второй – для датчика
температуры, который расположен на кристалле.
Для данного АЦП введены такие специальные термины, как регулярные и инжектированные каналы. Суть этих понятий заключается в способе опроса каналов. Регулярные каналы опрашиваются и преобразуются с определённой периодичностью, то есть регулярностью. Инжектированные, то есть внедрённые каналы, опрашиваются по специальному запросу от программы между регулярными опросами.
Если необходимо опрашивать периодически несколько каналов, то для АЦП можно сформировать список этих каналов и записать его в специальные регистры. После этого АЦП будет поочерёдно­ преобразовывать сигналы из каналов данного списка последовательно друг за другом. Например, для поочерёдного измерения напряжения в каналах 3, 7, 5 и 1 необходимо записать эту последовательность в специальные регистры и запустить процесс преобразования АЦП. В результате данные каналы будут последовательно опрашиваться и преобразовываться,
а результат этих преобразований записываться в регистры данных. При этом порядок следования каналов не имеет значения. Более того, один и тот же канал может опрашиваться несколько раз за цикл. Количество измерений в группе регулярных каналов может достигать 16. Допускается непрерывное измерение выбранных каналов, то есть по окончании измерения автоматически запускается новый цикл.

Максимальное количество измерений в группе инжектированных каналов равно четырём. Если запустить измерение инжектированных каналов, то измерение регулярных каналов будет приостановлено. Затем будет выполнено измерение заданных инжектированных каналов и вновь восстановлено измерение каналов регулярной группы.
Рассмотрим пример того, как можно применить на практике использование регулярных и инжектированных каналов. Допустим, необходимо постоянно измерять напряжение на пяти выводах в определённой последовательности. Для этого необходимо включить эти каналы в регулярную группу и запустить преобразование. АЦП начнёт последовательно опрашивать их и преобразовывать сигналы в цифровые значения. При необходимости по окончании преобразования будут формироваться прерывания. Таким образом, можно обрабатывать аналоговые сигналы и сохранять данные преобразования АЦП в автоматическом режиме. Если в это время возникает необходимость измерить температуру кристалла или аналоговый сигнал на каком либо другом канале, то для того, чтобы не нарушать измерение в регулярном канале, можно запустить измерение инжектированного канала. При этом обработка регулярных каналов будет автоматически приостановлена на некоторое время, а после окончания
измерения инжектированной группы – автоматически восстановлена.
Сохранение результата преобразования для четырёх инжектированных каналов производится в соответствующих регистрах данных. АЦП имеет для каждого инжектированного канала отдельный регистр, то есть всего четыре регистра данных. Однако для 18 регулярных каналов в АЦП имеется всего один регистр данных. С целью сохранения результатов преобразования для каждого канала можно по окончании измерения в каждом канале формировать прерывание и переписывать данные из этого регистра в блок памяти процессора. Кроме того, можно воспользоваться специальным каналом ПДП, который позволит пересылать результаты каждого преобразования в заранее организованный в памяти буфер данных без участия процессора. Использование данного метода позволяет сократить частоту формирования прерываний до одного по завершении каждого цикла преобразования группы регулярных каналов. Кроме того, можно задействовать двойной буфер. Это позволит после заполнения АЦП первого буфера
сформировать прерывание и приступить к обработке результатов процессором. В это время АЦП начнёт заполнять с помощью­ ПДП второй буфер. Затем очерёдность поменяется и т.д. В нижней части схемы, изображённой на рисунке, приведены источники, которые могут запускать процесс преобразования отдельно для регулярной и инжектированной группы каналов. Это могут быть сигналы от таймеров, внешний сигнал или два специальных разряда управляющих регистров, установив которые, можно программ но запустить преобразование в регулярной или инжектированной группе.
Отличительной особенностью данного АЦП является наличие в нём аналогового сторожевого таймера (AWD, от англ. Analog Watch Dog), представляющего собой оконный компаратор. Он имеет в своём составе два регистра для задания границ сравнения. В регистр нижней границы и регистр верхней границы программно записываются соответствующие значения для контроля уровня измеряемого сигнала. Номер канала, к которому нужно подключить компаратор, записывается в специальный регистр. Если измеряемое напряжение заданного канала выйдет за указанные границы, то в АЦП будет установлен соответствующий флаг и сформируется запрос на прерывание.
Данный оконный компаратор может оказаться очень полезным для автоматического контроля определённого параметра. С его помощью можно, например, следить за температурой контроллера, во избежание его перегрева. Для этого можно регулярно, скажем ежесекундно, измерять уровень сигнала от датчика температуры. Если он превысит заданный порог, будет необходимо предпринять определённые действия. Например, снизить тактовую частоту, сформировать предупреждающий сигнал и тому подобное. Оконный компаратор позволяет выполнять подобную процедуру без отвлечения процессора от выполнения основной программы, экономя при этом ресурсы процессора и памяти программ. Для запуска оконного компаратора необходимо выполнить его инициализацию путём записи уровней границ, включить контролируемый канал в список регулярных каналов и разрешить прерывание от него. Если уровень контролируемого сигнала выйдет за границы заданного диапазона, компаратор сработает и будет вызвана функция обработчика прерывания данного события.
АЦП способен формировать три сигнала прерывания: конец преобразования, конец преобразования инжектированной группы и сигнал от оконного компаратора.

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

●● регистр состояния ADC_SR – содержит биты, указывающие на состояние АЦП;
●● регистры управления ADC_CR1 и ADC_CR2 – определяют режим работы АЦП;
●● регистры ADC_SMPR1 и ADC_SMPR2 – задают время преобразования АЦП;
●● регистры ADC_JOFR1…ADC_JOFR4 – определяют смещение данных в инжектированной группе каналов;
●● регистры ADC_HTR и ADC_LTR – задают верхнюю и нижнюю границы для оконного компаратора;
●● регистры ADC_SQR1…ADC_SQR3 – задают последовательность каналов регулярной группы;
●● регистр ADC_JSQR – задаёт последовательность каналов инжектированной группы;
●● регистры данных ADC_JDR1…ADC_JDR4 – содержат результат преобразования для регистров инжектированной группы каналов;
●● регистр данных DR – содержит результат преобразования для регулярной группы каналов.

Рассмотрим назначение разрядов в каждой из представленных групп регистров АЦП подробнее. Регистр ADC_SR содержит биты, которые устанавливаются аппаратно. Обнуляются они программно или при сбросе. Бит EOC сбрасывается автоматически после чтения регистра ADC_DR. Назначение бит следующее:
●● бит 4 STRT устанавливается при старте преобразования регулярного канала;
●● бит 3 JSTRT устанавливается при старте преобразования инжектированного канала;
●● бит 2 JEOC указывает на окончание преобразования инжектированного канала;
●● бит 1 EOC обозначает окончание преобразования регулярного или инжектированного канала;
●● бит 0 AWD устанавливается при срабатывании оконного компаратора.

Регистр ADC_CR1 содержит следующие биты управления:
●● бит 23 AWDEN управляет оконным компаратором регулярного канала;
●● бит 22 JAWDEN управляет оконным компаратором инжектированного канала;
●● биты 15…13 DISCNUM определяют количество регулярных каналов, преобразование которых будет выполняться в прерывистом режиме, по приходу события внешнего запуска;
●● бит 12 JDISCEN запрещает и разрешает прерывистый режим для инжектированных каналов;
●● бит 11 DISCEN запрещает и разрешает прерывистый режим для регулярных каналов;
●● бит 10 JAUTO запрещает и разрешает режим автоматического преобразования для инжектированных каналов;
●● бит 9 AWDSGL разрешает работу оконного компаратора для всех каналов или для того канала, который определён битами AWDCH;
●● бит 8 SCAN запрещает и разрешает режим сканирования каналов, заданных регистрами ADC_SQRx или ADC_JSQRx;
●● бит 7 JEOCIE запрещает и разрешает прерывания по окончании преобразования инжекционных каналов;
●● бит 6 AWDIE запрещает и разрешает прерывания от оконного компаратора АЦП;
●● бит 5 EOCIE запрещает и разрешает прерывания по окончании преобразования в регулярной или инжектированной группе;
●● биты 4…0 AWDCH определяют номер канала, к которому подключён оконный компаратор.
Регистр ADC_CR2 содержит биты, имеющие следующее назначение:
●● бит 23 TSVREFE подключает канал опорного напряжения и датчика температуры, расположенного на кристалле;
●● бит 22 SWSTART запускает преобразование регулярных каналов;
●● бит 21 JSWSTART запускает преобразование инжектированных каналов;
●● бит 20 EXTTRIG запрещает и разрешает использование внешнего запуска для регулярных каналов;
●● биты 19…17 EXTSEL определяют источник, который будет запускать преобразование в регулярном канале (000 = TIM1_CH1, 001 = TIM1_CH2, 010 = TIM1_CH3, 011 = TIM2_CH2, 100 = TIM3_TRGO, 101 =T IM4_CH4, 110 = EXTI_11, 111 = SWSTART);
●● бит 15 JEXTTRIG запрещает и разрешает использование внешнего запуска для инжектированных каналов;
●● биты 14…12 JEXTSEL определяют источник, который будет запускать преобразование в инжектированном канале (000 = TIM1_TRGO, 001 = TIM1_CH4, 010 = TIM2_TRGO, 011 = TIM2_CH1, 100 = TIM3_СH4, 101 = TIM4_TRGO, 110 = EXTI_15, 111 = JSWSTART);
●● бит 11 ALIGN задаёт выравнивание результата преобразования в регистре данных по правому (0) или левому (1) краям;
●● бит 8 DMA запрещает и разрешает использование блока ПДП (DMA);
●● бит 3 RSTCAL сбрасывает калибровку;
●● бит 2 CAL запускает калибровку АЦП путём записи 1, которая по окончании процесса сбрасывается аппаратно;
●● бит 1 CONT запускает непрерывное преобразование;
●● бит 0 ADON отключает и включает модуль АЦП.

Регистры ADC_SMPR1 и ADC_SMPR2 задают время преобразования в каждом канале. Для каждого канала выделены по три разряда, что позволяет задать 8 значений времени преобразования
в циклах (000 = 1,5 цикла, 001 = 7,5 цикла, 010 = 13,5 цикла, 011 = 28,5 цикла, 100 = 41,5 цикла, 101 = 55,5 цикла, 110 = 71,5 цикла, 111 = 239,5 цикла).
Регистры ADC_JOFR1…ADC_JOFR4 служат для задания смещения каждого канала инжектированной группы (JOFR1, JOFR2, JOFR3, JOFR4). В эти регистры можно записывать 12-битное значение, которое автоматически вычитается из результата преобразования АЦП. Если результирующее значение станет отрицательным, то регистр результата инжектированной группы дополнится битом знака отрицательного значения.

Регистры ADC_LTR и ADC_HTR имеют по 12 разрядов, в которые записываются значения верхней и нижней границ оконного компаратора.
Регистры ADC_SQR1… ADC_SQR3 служат для задания номеров каналов, которые будут опрашиваться в регулярной группе, и общее количество каналов. Разряды SQx этих регистров задают номер канала, где х – это номер позиции для преобразования от 1 до 16. Количество каналов в группе задаётся разрядами L регистра ADC_SQR1.

Например, необходимо регулярно опрашивать 7 каналов в очерёдности 1, 3, 1, 5, 9, 9, 1. Для этого нужно записать
в регистр ADC_SQR3 следующие значения: SQ1 = 1, SQ2 = 3, SQ3 = 1, SQ4 = 5, SQ5 = 9, SQ6 = 9. В регистр ADC_SQR2 требуется записать номер последнего седьмого опрашиваемого канала: SQ7 = 1. После этого следует задать количество опрашиваемых каналов регулярной группы для регистра ADC_SQR1: L = 7. Из приведённой информации видно, что каналы можно опрашивать в любой последовательности. Кроме того, любой канал можно опрашивать несколько раз.
Регистр ADC_JSQR, подобно регистрам ADC_SQRx, задаёт последовательность опрашиваемых каналов и их количество для инжектированной группы каналов. Как видно из структуры регистра, максимальное количество преобразований в инжектированной группе равно четырём. Количество каналов задаётся в разрядах JL.

Регистры ADC_JDR1…ADC_JDR4 хранят данные каналов инжектированной группы. Максимальное количество каналов в инжектированной группе равно четырём, соответственно имеется четыре регистра данных. В эти регистры помещается результат преобразований в каждом выбранном канале. Поскольку регистры 16-разрядные, а АЦП 12-разрядный, предусмотрена возможность выравнивания результата измерения по левому или по правому краю этих регистров.

Регистр ADC_DR содержит результат преобразования АЦП в регулярной группе. В отличие от инжектированной группы, в которой четыре регистра данных, он – один на всю группу. Его структура подобна регистрам JDRx, за исключением старших разрядов 16…31. Эти разряды используются при работе АЦП в сдвоенном режиме, совместно со вторым АЦП, именуемым ADC2.

Режимы работы АЦП
АЦП позволяет использовать нес­колько режимов работы. Рассмотрим их поочерёдно, начиная с режима одиночного преобразования. В этом режиме АЦП выполняет всего одно преобразование. Оно запускается после установки разряда ADON в регистре ADC_CR2 для регулярных каналов, или от внешнего сигнала для регулярного и инжектированного каналов. При этом разряд CONT регистра ADC_CR2 должен быть равен нулю. После окончания преобразования в выбранном регулярном канале результат преобразования сохраняется в регистре ADC_DR и устанавливается флаг EOC. Если установлен разряд EOCIE, генерируется прерывание. Для инжектированного канала результат преобразования сохраняется в регистре ADC_DRJ1 и устанавливается флаг JEOC. Если установлен разряд JEOCIE, генерируется прерывание. После этого работа АЦП останавливается.
В режиме непрерывного преобразования АЦП начинает очередное преобразование после завершения текущего. Этот режим запускается от внешнего источника или путём установки разряда ADON регистра ADC_CR2. При этом разряд CONT регистра ADC_CR2 должен быть равен единице. После каждого преобразования выполняется результат преобразования и сохраняется аналогично режиму одиночного преобразования.
В режиме сканирования АЦП выполняет поочерёдное преобразование группы каналов. Этот режим выбирается установкой разряда SCAN регистра ADC_CR1. Если этот разряд установлен, АЦП сканирует все каналы, выбранные в регистрах ADC_SQRx для регулярных каналов или в регистре ADC_JSQR для инжектированных каналов. Если разряд CONT установлен, то преобразование не останавливается на последнем канале, а вновь запускается с первого канала. Если установлен разряд DMA, контроллер прямого доступа к памяти используется для передачи результата в память по окончании каждого преобразования после установки разряда EOC. Если в регулярной группе используется более одного канала, то для сохранения результата рекомендуется использовать DMA. Это позволяет избежать потерь данных, которые уже хранятся в регистре ADC_DR. В конце преобразования регулярная группа формирует запрос DMA для сохранения результата из регистра ADC_DR в место, заданное пользователем. Режимы работы АЦП с инжектированными каналами также разно­ образны. Чтобы использовать запуск инжекционного канала, надо чтобы бит JAUTO был обнулён, а бит SCAN в регистре ADC_CR1 – установлен. Запуск преобразования сигналов для группы регулярных каналов производится либо внешним сигналом, либо установкой бита ADON в регистре ADC_CR2. Если внешний запуск инжектированных каналов происходит во время преобразования сигналов группы регулярных каналов, то текущее преобразование приостанавливается и запускается преобразование последовательности инжекционных каналов в режиме однократного сканирования.

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

Если установлен бит JAUTO, то после завершения преобразования группы регулярных каналов автоматически запускается преобразование группы инжекционных каналов. Это можно использовать, чтобы преобразовать последовательность из 17–20 каналов, заданных в регистрах ADC_JSQR и ADC_SQRx. В этом режиме механизм запуска внешним событием должен быть отключён. Если в дополнение к биту JAUTO установлен бит CONT, то сразу после преобразования группы инжекционных каналов вновь запускается преобразование группы регулярных каналов. Использовать одно-временно оба режима, автоматический запуск и запуск внешним событием, невозможно.

Калибровка АЦП
АЦП имеет встроенный механизм автоматической калибровки. Калибровка значительно уменьшает погрешность оцифровки, которая вызывается неоднородностью внутренних конденсаторов выборки и хранения сигналов. Во время калибровки вычисляется цифровое значение АЦП для каждого конденсатора в виде корректирующего кода. Во время всех последующих преобразований этот код используется для компенсации ошибки преобразования сигналов.
Перед началом калибровки АЦП должен находиться в отключённом состоянии, то есть бит ADON должен быть равен нулю, по крайней мере в течение двух циклов тактового АЦП.
Запуск калибровки производится установкой бита CAL в регистре ADC_CR2. Как только калибровка закончена, бит CAL сбрасывается аппаратно, после чего может быть выполнено нормальное преобразование. Рекомендуется калибровать АЦП один раз при подаче питания. Коды калибровки сохраняются в ADC_ DR при завершении фазы калибровки.

Время преобразования АЦП
АЦП поддерживает возможность раздельного программирования времени преобразования в каждом из каналов. Предусмотрена возможность выбора 8 дискретных значений из диапазона 1,5…239,5 циклов. Для каждого канала время задаётся индивидуально с помощью разрядов SMPx регистров ADC_SMPR1 и ADC_SMPR2.
Полное время преобразования Tconv вычисляется по формуле: Tconv = Tsmt + 12,5 циклов, где Tsmt – это программно заданное время выборки. Например, частота ADCCLK задана равной 14 МГц,
а время выборки – 1,5 цикла. Тогда Tconv = =1,5 + 12,5 = 14 циклов = 1мкс.

Датчик температуры АЦП
Встроенный в кристалл микроконтроллера датчик температуры позволяет измерять температуру самого кристалла. Датчик подключён к 16-му входу АЦП. Рекомендуемое время выборки
при опросе датчика составляет 17,1 мкс.
Когда датчик не используется, его можно отключить. Напряжение на выходе датчика изменяется линейно с температурой. В разных кристаллах эта линия смещается до 45 градусов, что связано
с технологией изготовления. Внутренний датчик больше подходит не для измерения абсолютного значения температуры, а для контроля её изменения. Для чтения температуры необходимо
выбрать канал 16, задать время выборки не менее 17,1 мкс и установить раз-ряд TSVREFE в регистре ADC_CR2 для включения датчика. После этого можно запустить преобразование АЦП установкой разряда ADON или внешним событием и прочитать результат преобразования.
Вычисляется значение температуры по формуле: Т[C] = (V25 – Vsense) / Avg_ Slope + 25, где V25 – значение измерения при 25 градусах, имеющее типовое значение 1,41В, Vsense – текущее измеренное значение, а Avg_Slope – коэффициент из таблицы на кристалл, имеющий типовое значение 4,3 мВ/C.

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

Флаг AWD устанавливается, если цифровое значение канального сигнала, измеренного с помощью АЦП, больше или меньше заданного уровня. Этот уровень задаётся регистрами ADC_HTR и ADC_LTR. Прерывание может быть разрешено разрядом AWDIE регистра ADC_CR1. Каналы АЦП, контролируемые оконным компаратором, задаются согласно таблице 2.
Разряд AWDSGL задаёт количество контролируемых каналов. Если он равен 0, то контролируются все каналы, а если 1 – то один канал. Номер канала при этом задаётся с помощью раз-рядов AWDCH.
Разряд AWDEN разрешает конт­роль каналов регулярной группы, а JAWDEN – контроль каналов инжектированной группы.

Таблица 2. Каналы АЦП контролируемые оконным компаратором

Примеры программ

Рассмотрим примеры программ для работы с АЦП. Начнём с простейшего варианта: измерение уровня сигнала на одном канале с программным запуском. Для этого используем вывод порта PORTA.6 микроконтроллера. Пример программы приведён в листинге 1.

Листинг 1 //========================= // Функция инициализации АЦП //========================= void Init_ADC(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Разрешить тактирование порта PORTA // Сконфигурировать PORTA.6 как аналоговый вход GPIOA->CRL &= ~GPIO_CRL_MODE6; // Очистить биты MODE GPIOA->CRL &= ~GPIO_CRL_CNF6; // Очистить биты CNF RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // Включить тактирование АЦП RCC->CFGR &= ~RCC_CFGR_ADCPRE; // Задать значение делителя тактовой частоты ADC1->CR1 = 0; // Обнулить регистр управления ADC1->SQR1 = 0; // Обнулить регистр SQR1 ADC1->CR2 |= ADC_CR2_CAL; // Пуск калибровки while (!(ADC1->CR2 & ADC_CR2_CAL)){}; // Ждать окончания калибровки ADC1->CR2 = ADC_CR2_EXTSEL; // Выбрать источником запуска разряд SWSTART ADC1->CR2 |= ADC_CR2_EXTTRIG; // Разрешить внешний запуск регулярного канала ADC1->CR2 |= ADC_CR2_ADON; // Включить АЦП } //====================================================== // Функция запуска преобразования АЦП и чтение выбранного канала // Вход - номер канала для преобразования // Выход - результат преобразования //====================================================== uint16_t RD_ADC(uint8_t nk) { ADC1->SQR3 = nk; // Задать номер канала ADC1->CR2 |= ADC_CR2_SWSTART; // Пуск преобразования while(!(ADC1->SR & ADC_SR_EOC)){}; // Ждать окончания преобразования return ADC1->DR; // Считать результат преобразования } //========================= // Главный модуль программы //========================= void main(void) { unsigned int ai; // Инициализация переменных // Другие команды … while(1) // Бесконечный цикл { Init_ADC(); // Выполнить инициализацию и пуск АЦП ai = RD_ADC(6); // Считать данные АЦП для канала 6 // Другие команды … } }

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

Листинг 2 //========================= // Функция инициализации АЦП //========================= void Init_ADC(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Разрешить тактирование порта PORTA // Сконфигурировать PORTA.6 как аналоговый вход GPIOA->CRL &= ~GPIO_CRL_MODE6; // Очистить биты MODE GPIOA->CRL &= ~GPIO_CRL_CNF6; // Очистить биты CNF RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // Включить тактирование АЦП RCC->CFGR &= ~RCC_CFGR_ADCPRE; // Задать значение делителя тактовой частоты ADC1->CR1 = 0; // Обнулить регистр управления ADC1->SQR1 = 0; // Обнулить регистр SQR1 ADC1->CR2 |= ADC_CR2_CAL; // Пуск калибровки while (!(ADC1->CR2 & ADC_CR2_CAL)){}; // Ждать окончания калибровки ADC1->CR2 = ADC_CR2_EXTSEL; // Выбрать источником запуска разряд SWSTART ADC1->CR2 |= ADC_CR2_EXTTRIG; // Разрешить внешний запуск регулярного канала ADC1->CR2 |= ADC_CR2_CONT; // Включить режим непрерывного преобразования ADC1->CR2 |= ADC_CR2_ADON; // Включить АЦП ADC1->CR2 |= ADC_CR2_SWSTART; // // Пуск преобразования } //========================= // Главный модуль программы //========================= void main(void) { unsigned int ai; // Инициализация переменных Init_ADC(); // Выполнить инициализацию и пуск АЦП // Другие команды … while(1) // Бесконечный цикл { ai=ADC1->DR; // Считать результат преобразования // Другие команды … } }

Данная программа запускает режим непрерывного преобразования заданного канала, и АЦП постоянно опрашивает выбранный канал, помещая результат в регистр данных. Поэтому
в основной программе не требуется регулярно запускать АЦП. При таком способе в регистре ADC_DR информация об уровне сигнала на входе канала будет постоянно обновляться. Обновление будет происходить с периодичностью, которую можно изменять.
В рассмотренных примерах можно запустить непрерывное преобразование для одного канала. Если нужно сделать это для нескольких каналов, то без использования прерываний или блока ПДП не обойтись, так как для регулярной группы предусмотрен всего один регистр данных. Однако если количество каналов не превышает четырёх, то подобным образом можно использовать и преобразование инжектированных каналов.
Максимальное количество каналов для инжектированной группы равно четырём. Для каждого такого канала предусмотрен свой регистр для хранения результата преобразования.
Допустим, необходимо опрашивать четыре канала с номерами: 3, 4, 5 и 6. Для этого можно запустить непрерывное измерение группы из четырёх инжектированных каналов. При этом АЦП будет автоматически сканировать четыре заданных канала, и помещать результат в регистры данных ADC_ JDR1, ADC_JDR2, ADC_JDR3 и ADC_JDR4. При этом можно будет считывать данные из нужного канала в любое время. Пример такой программы приведён в листинге 3.

Листинг 3 //========================= // Функция инициализации АЦП //========================= void Init_ADC(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Разрешить тактирование порта PORTA //Сконфигурировать PORTA.3 как аналоговый вход GPIOA->CRL &= ~GPIO_CRL_MODE3; // Очистить биты MODE GPIOA->CRL &= ~GPIO_CRL_CNF3; // Очистить биты CNF //Сконфигурировать PORTA.4 как аналоговый вход GPIOA->CRL &= ~GPIO_CRL_MODE4; // Очистить биты MODE GPIOA->CRL &= ~GPIO_CRL_CNF4; // Очистить биты CNF //Сконфигурировать PORTA.5 как аналоговый вход GPIOA->CRL &= ~GPIO_CRL_MODE5; // Очистить биты MODE GPIOA->CRL &= ~GPIO_CRL_CNF5; // Очистить биты CNF //Сконфигурировать PORTA.6 как аналоговый вход GPIOA->CRL &= ~GPIO_CRL_MODE6; // Очистить биты MODE GPIOA->CRL &= ~GPIO_CRL_CNF6; // Очистить биты CNF RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // Включить тактирование АЦП RCC->CFGR &= ~RCC_CFGR_ADCPRE; // Задать значение делителя тактовой частоты ADC1->CR1 = 0; // Обнулить регистр управления ADC1->CR2 |= ADC_CR2_CAL; // Пуск калибровки while (!(ADC1->CR2 & ADC_CR2_CAL)){}; // Ждать окончания калибровки ADC1->CR2 = ADC_CR2_JEXTSEL; // Выбрать источником запуска разряд JSWSTART ADC1->CR2 |= ADC_CR2_JEXTTRIG; // Разрешить внешний запуск инжектированной группы ADC1->CR2 |= ADC_CR2_CONT; // Включить режим непрерывного преобразования ADC1->CR1 |= ADC_CR1_SCAN; // Включить режим сканирования нескольких каналов ADC1->CR1 |= ADC_CR1_JAUTO; // Автоматический запуск инжектированной группы ADC1->JSQR = (uint32_t)(4-1)<<20; // Задать количество каналов в инжектированной группе=4 ADC1->JSQR |= (uint32_t)3<<(5*0); // Номер первого канала для преобразования=3 ADC1->JSQR |= (uint32_t)4<<(5*1); // Номер второго канала для преобразования=4 ADC1->JSQR |= (uint32_t)5<<(5*2); // Номер третьего канала для преобразования=5 ADC1->JSQR |= (uint32_t)6<<(5*3); // Номер четвертого канала для преобразования=6 ADC1->CR2 |= ADC_CR2_ADON; // Включить АЦП ADC1->CR2 |= ADC_CR2_JSWSTART; // Пуск преобразования } //========================= // Главный модуль программы //========================= void main(void) { unsigned int ai; // Инициализация переменных Init_ADC(); // Выполнить инициализацию и пуск АЦП // Другие команды … while(1) // Бесконечный цикл { //Считать результат преобразования ai=ADC1->JDR1; // Канал 3 ai=ADC1->JDR2; // Канал 4 ai=ADC1->JDR3; // Канал 5 ai=ADC1->JDR4; // Канал 6 //Другие команды … } }

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


Описание работы Аналого-цифрового преобразователя.
Прерывания от АЦП

ATMega16 содержит в себе 10-битовый АЦП, вход которого может быть соединён с одним из восьми выводов Port A. АЦП Mega16, как и любому другому АЦП, нужно опорное напряжение для целей сравнения со входным (если измеряемое равно опорному, то получаем максимальный код в двоичном виде). Опорное напряжение подаётся на вывод ADRef или может использоваться внутренний генератор с фиксированным напряжением 2,65 В. Полученный результат можно представить в таком виде:

АЦП включается установкой бита ADEN в регистре ADCSRA. После преобразования, 10-битный результат оказывается в 8-битных регистрах ADCL и ADCH. По умолчанию, младший бит результата находится справа (то есть в bit 0 регистра ADCL, так называемое правое ориентирование). Но порядок следования битов на левое ориентирование можно сменить установив бит ADLAR в регистре ADMUX. Это удобно, если требуется получить 8-битовый результат. В таком случае требуется прочитать только регистр ADCH. В противном случае, Вы должны сначала прочитать регистр ADCL первым, а ADCH вторым, чтобы быть уверенным в том, что чтение этих двух регистров относится к результату одного преобразования.

Одиночное преобразование может быть вызвано записью бита ADSC в регистр ADCSRA. Этот бит остаётся установленным всё время, занимаемое преобразованием. Когда преобразование закончено, бит автоматически устанавливается в 0. Можно также начинать преобразования по событиям из разных источников. Модуль АЦП также может работать в режиме "свободного полёта". В таком случае АЦП постоянно производит преобразование и обновляет регистры ADCH и ADCL новыми значениями.

Для выполнения преобразования модулю АЦП необходима тактовая частота. Чем выше эта частота, тем быстрее будет происходить преобразование (оно, обычно, занимает 13 тактов, первое преобразование занимает 25 тактов). Но чем выше частота (и выше скорость преобразования), тем менее точным получается результат. Для получения максимально точного результата, модуль АЦП должен тактироваться частотой в пределах от 50 до 200 КГц. Если необходим результат с точностью менее 10 бит, то можно использовать частоту больше 200 КГц. Модуль АЦП содержит делитель частоты, чтобы получать нужную тактовую частоту для преобразования из частоты процессора.

Регистр ADMUX задаёт входной контакт порта A для подключения АЦП, ориентирование результата и выбор опорной частоты. Если установлен бит ADLAR, то результат лево-ориентирован. Опорная частота от внутреннего генератора задаётся выставленными в 1 битами REFS1 и REFS0. Если оба бита сброшены, то опорная частота берётся от контакта AREF. В случае, если REFS1=0 а REFS0=1, опорная частота берётся от AVCC с внешним конденсатором, подключенным к AREF. Выбор контакта ввода выполняется следующим образом:

Регистр контроля и статуса АЦП ADCSRA :

Бит ADEN=1 включает модуль АЦП.
Запись единицы в ADSC запускает цикл преобразования. В режиме "свободного полёта" запись единицы запускает первое преобразование, последующие запускаются автоматически.
ADIF - флаг прерывания АЦП. Этот бит устанавливается в 1 когда АЦП завершено преобразование и в регистрах ADCL и ADCH находятся актуальные данные. Этот флаг устанавливается даже в том случае, если прерывания запрещены. Это необходимо для случая программного опроса АЦП. Если используются прерывания, то флаг сбрасывается автоматически. Если используется программный опрос, то флаг может быть сброшен записью лог.1 в этот бит.
ADIE - Если в этом бите установлена единица, и прерывания разрешены глобально, то при окончании преобразования будет выполнен переход по вектору прерывания от АЦП.
Биты ADPS2..0 задают коэффициенты предделителя частоты: