Использование ацп в pic

Эта статья я думаю, будет немного поинтереснее. Здесь мы сделаем АЦП на основе МК PIC16F877. АЦП этот будет 10-ти разрыдным, что очень неплохо ибо позволяет получать хорошую точность преобразования. При диапозоне входных напряжений АЦП 0−5 В получаем шаг квантования 5/(2 10 ) = 0.00488 В

Начнем, пожалуй со схемы, чтоб был более понятным код. В МК PIC16F877 есть аж целых 8 линий, на котроые, при соответствующих программных настройках, можно подавать аналоговое напряжение на вход АЦП. В этом примере я использую линию RA0/AN0 (вывод 2). Диапозон рабочих АЦП этого МК составляет 0 — 5 В . Не превышайте этот порог — можно МК сжечь. Еще одним схемным изменением стало появление еще двух светодиодов — нам же надо как-то показать результат работы АЦП. Т.к. 10-ти разрыдный, то нам и нужны 10 светодиодов для отображения результата преобразования.

Для упрощения этого примера, я решил не использовать еще один источник напряжения для входа АЦП, а запитал его через переменый резистор от общей шины питания схемы. Теперь изменяя положение движка резистора можно будет изменять подаваемое на вход АЦП напряжение — от 0 до 5 В.

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

Рассмотрим что здесь происходит. Начнем с функции main, ведь имено с нее начнется выполнение программы. Сначала мы присваиваем значение счетчику таймера равным 0 (TMR0=0). Это нужно для того, чтобы таймер не успел сработать, пока мы проводим начальную инициализацию (до входа в бесконечный цикл). Тут необходимо сказать пару слов об этом самом таймере. Это обычный 8-ми разрядный регистр, значение которго при каждом машинном такте увеличивается на еденицу. Как только значение в нем будет равно 256, он сбрасывается и в определенном регистре устанавливается флаг, говорящий о том что произошло переполнение таймера. (вот тут то управление и перейдет на нашу функцию обработчик прерывания). Перодом срабатывания таймера можно управлять, указав через сколько прошедших машинных тактов значение регистра таймера увеличивается на 1. Ругилировать можно в пределах 1:2, 1:4, 1:8, 1:16, 1:32, . 1:256. Т.е. в последнем случае, чтобы регистр увеличился на еденицу должно пройти 256 машинных тактов. Тогда для срабатывания таймера потребуется 256*256 = 65536 машинных тактов. Зная длительность машинного такта можно однозначно опрделеить период срабатывания таймера в секудах. Для МК PIC один машинный такт = 4 тактам кварца. Тогда, если у нас стоит кварц на 20 МГц, длительность одного машинного такта будет равна 1/(5 МГц) = 0.2 * 10 −6 сек = 0.2 мкс.

Слующей строчкой в коде мы как раз и настраиваем работу таймера. Для этого служит спецальный регистр, каждый бит в котором предназначен для определенной настройки какого-либо свойства. Полное описание этого регистра советую прочитать в описании к этому МК, которое можно было найти в 3-тьей статье этого раздела.

То числовое значение которое загружается в него (регистр) в это примере означает что таймер будет работать с предделителем 1:2 (увеличение счетчика таймера происходит после двух машинных тактов). Далее устанавливая спец. бит настройки T0IE в еденицу мы разрешаем прерывания от таймера. GIE=1 — разрешает обработку прерываний в МК глобально. Потом настраиваем порт B и D для работы на выход и помещаем в них 0 (светодиоды подключенные к ним будут погашены).

Далее проводим настройку работы АЦП. Для его настроек предназначенны два регистра ADCON1 и ADCON0. Более подробно про их содержимое расписано в описаниии МК.

На что хотел обратить Ваше внимание, так это на т.н. выравнивание результата преобразования. Результат то 10-ти разрядный, а регистры в МК PIC 8-ми разрядные. Значит нужны два регистра. Размещением в них этого результата (с какой сторны они выровнены, т.е. откуда начинаются) можно устанавливать самомтоянтельно. В этом примере я указал правое выравнивание. Это значит что 8 младших бит результата будут находиться в одном регистре а оставшиеся 2 будут находится в двух младших битах другогог регистра.

Читайте также:  Интерфейс флешки что это

После того как все настройки сделаны, запускаем бесконечный цикл и ждем кагда сработает таймер. Как только это происходит, управление переходит на специальнцю функцию с ключевым словом interrupt. В ней мы проверяем бит T0IF, в которм указывается что произошло прерывание таймера. Если это так, то мы его сбрасываем в ноль (чтоб таймер дальше мог работать) и запускаем процесс преобразования входного аналогового напряжения в цифровой код установкой бита управления АЦП ADGO. Как только преобразование АЦП будет сделано, этот бит станет равным 0. Поэтому с помощью while мы ждем этого события. Теперь нам нужно прочесть результат преобразования. Он храниться в двух регистрах с именами ADRESL и ADRESH. В первом из них храняться 8 младших бит результата и мы сразу же их отсылаем в порт B (красные светодиоды). В ADRESH находятся 2 старших бита результата. Т.к. на схеме я хотел чтобы эти два бита отображались на выводах 2,3 порта D (чтоб все светодиды были по одну сторону от МК) то нужно содержимое этого регистра сдвинуть на два разряда влево. После этого то что сдвинули записываем в порт D.

Внешне полученная схема может выглядеть например вот так.

На пробу вставил рабочий код (в инете нашёл), должно было откомпилировать, а всё равно ошибки вылезают!

MOVLW 0x8E ; опорное напряжение равно напряжению микроконтроллера, используется только вход AN0, правое выравнивание
MOVWF ADCON1, ab
MOVLW 0×81 ; делитель — Fosc/32, выбираем на мультиплексор канал AN0, и включаем АЦП
MOVWF ADCON0, ab
BCF PIE1, ADIE, ab ; прерывание использовать не будем

; ждем когда зарядиться конденсатор Chold (acquisition time=12,86мкс)
; на каждую команду требуется 200нсек (4/20000000), таким образом, 12,86/0,2=65 — столько команд потребуется, чтобы выдержать интервал в 12,86 мкс
; организуем программную задержку (пусть и будет погрешность, но она будет в сторону увеличения времени, а это не критично)

MOVLW 0×11
MOVWF temp, ab ; счетчик циклов

NOP
NOP
DECFSZ temp, rf, ab ; Цикл выполняется за 4−5 команд
BRA Wait_aq ; поэтому, грубо 4*17=72 команды

BSF ADCON0, GO_DONE, ab ; старт преобразования
BTFSC ADCON0, GO_DONE, ab ; ждем пока не сброситься данный бит
BRA $-2 ; возврат на одну команду назад (-2, потому что каждая команда занимает в памяти программ 2 байта)

MOVFF ADRESH, ADC_value_h
MOVFF ADRESL, ADC_value_l

; измеряемый канал один — AN0, поэтому мультиплексор не трогаем
; ждем 2 периода Tad = 1,6*2/0,2 = 16 команд, пока заряжается конденсатор

MOVLW 0×04
MOVWF temp, ab ; счетчик циклов

NOP
NOP
DECFSZ temp, rf, ab ; Цикл выполняется за 4−5 команд
BRA Wait_Chold ; поэтому, грубо 4*4=16 команд
CLRWDT
BRA Start_ADC ; начинаем следующее преобразование

Oleg674ct 27.09.2010 23:36
Vovka 27.09.2010 23:48
Oleg674ct 27.09.2010 23:53
Machine slave 28.09.2010 00:16
Symbol not previously defined (ab) и тд

Ну не знает он что такое ab, замените на 0.

rf в операндах на 1.

Определите ADC_value_h, ADC_value_l, temp.

Да вы знаете толк в извращениях. Ставьте MPLAB и пишите в нем. Хотя б в Notepad++ что ли писали и то удобнее.

Oleg674ct 28.09.2010 00:33

Ну не знает он что такое ab, замените на 0.

Действительно, незнал, каюсь! Дело в том, что с пиками, ровно как и с асмом работаю не больше двух недель!

Заменил на 0 и 1, всё заработало!

Всем большое Спасибо, разбираюсь дольше сам!:)

Machine slave 28.09.2010 00:34
atlant 28.09.2010 08:38
Oleg674ct 28.09.2010 08:52
Greg 28.09.2010 08:59
Oleg674ct 28.09.2010 09:03
Марк 28.09.2010 09:17
Oleg674ct 28.09.2010 09:21

Компилирую MPASMWIN: «C:Program FilesMicrochipMPASM SuiteMPASMWIN.exe»
Проэкт работает нормально, по крайней мере в протеусе!

Подскажите: какой функцией можно сравнить число в регистре с заданным диапазоном чисел? Скажем: если число «в диапазоне» то делаем что-то, если «нет», то сверяем со следующим диапазоном.
А то в инете не могу найти примера!

Марк 28.09.2010 09:27
atlant 28.09.2010 12:56
Machine slave 28.09.2010 15:53
Oleg674ct 28.09.2010 16:03

Вроде всё правильно написал, всё равно не работает.

MOVLW b'11101011' ; опорное напряжение равно напряжению микроконтроллера, используется только вход AN0, правое выравнивание
MOVWF ADCON1, 0
MOVLW b'11000001' ; делитель — Fosc/32, выбираем на мультиплексор канал AN0, и включаем АЦП
MOVWF ADCON0, 0
BCF PIE1, ADIE, 0 ; прерывание использовать не будем

; ждем когда зарядиться конденсатор Chold (acquisition time=12,86мкс)
; на каждую команду требуется 200нсек (4/20000000), таким образом, 12,86/0,2=65 — столько команд потребуется, чтобы выдержать интервал в 12,86 мкс
; организуем программную задержку (пусть и будет погрешность, но она будет в сторону увеличения времени, а это не критично)

Читайте также:  Как вернуть в ворде исходный документ

MOVLW 0×11
MOVWF temp, 0 ; счетчик циклов

NOP
NOP
DECFSZ temp, 1, 0 ; Цикл выполняется за 4−5 команд
BRA Wait_aq ; поэтому, грубо 4*17=72 команды

BSF ADCON0, GO_DONE, 0 ; старт преобразования
BTFSC ADCON0, GO_DONE, 0 ; ждем пока не сброситься данный бит
BRA $-2 ; возврат на одну команду назад (-2, потому что каждая команда занимает в памяти программ 2 байта)

MOVFF ADRESH, ADC_value_h
MOVFF ADRESL, ADC_value_l

; измеряемый канал один — AN0, поэтому мультиплексор не трогаем
; ждем 2 периода Tad = 1,6*2/0,2 = 16 команд, пока заряжается конденсатор

MOVLW 0×04
MOVWF temp, 0 ; счетчик циклов

NOP
NOP
DECFSZ temp, 1, 0 ; Цикл выполняется за 4−5 команд
BRA Wait_Chold ; поэтому, грубо 4*4=16 команд
CLRWDT
;Результат ставнения:
;x = y Z = 1, C = 1
;x > y Z = 0, C = 0
;x

Переходим к изучению следующего модуля контроллера PIC — ADC, я считаю, одного из самых важных модулей.

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

Как вообще работает цифровое преобразование?

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

Изобразим схематично процесс измерения

Отрезок — это диапазон измерений. Он находится между нулём и опорным напряжением. А стрелка — это измеряемое напряжение.

Данный отрезок делится пополам, и АЦП оценивает, в какой половине находится приложенное напряжение

Если оно находится в стороне нуля, то в самый старший бит результата записывается 0, а если в стороне максимального напряжения, то единица. У нас будет единица. Затем та половина отрезка, на которой находится измеряемое напряжение делится ещё пополам, и АЦП опять измеряет, в какой половинке уже данного отрезка у нас находится измеряемое напряжение

Оценка идёт по тому же принципу — в какой стороне отрезок. В нашем случае будет 0. И этот ноль записывается в следующий более младший бит.

Затем та четвертинка опять делится пополам и АЦП опять оценивает, где находится отрезок

И АЦП так и продолжает такой процесс до тех пор, пока не кончатся ячейки для битов. То есть если мы используем 10-битный режим, то. соответственно, и будет 10 подобных измерений и заполнятся 10 бит величины. Чем больше бит, тем точнее результат, но уже потребуется на это больше времени и более серьёзный и точный АЦП. Имея данный результат, нам несложно будет посчитать величину измеренного напряжения. Мы знаем. что если у нас АЦП 10-битный, то данный результат у нас лежит в промежутке от до 1023 (0xFFFF), получается всего у нас 1023 отрезка. И мы затем наш результат делим на 1024 (количество отрезков плюс 1) и умножаем на величину опорного напряжения.

Теперь посмотрим, как устроен модуль ADC в контроллере PIC16 (нажмите на картинку для увеличения изображения)

Измеряемый сигнал поступает на коммутатор входов, управляемый с помощью битов CHS2:CHS0, в A/D конвертер, в котором преобразовывается в цифровой код. Также в конвертер подаётся опорное напряжение, которое также может поступать из различных источников, что управляется тоже определёнными битами регистров настроек, с которым и сравнивается поступивший сигнал.

A/D-конвертер работает следующим образом. Сигнал, который поступил в него через коммутатор, заряжает внутренний конденсатор CHOLD. Затем модуль преобразует напряжение, удерживаемое на конденсаторе в соответствующий 10-разрядный цифровой код методом, описанным выше (данный метод называется методом последовательного приближения).

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

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

Читайте также:  Древо семьи шаблон распечатать для детей

Управляющий регистр ADCON0

Рассмотрим отдельные биты данного регистра:

ADCS1:ADCS0 (A/D Conversion Clock Select bits): Выбор источника тактового сигнала. Также есть третий бит выбора источника тактового сигнала ADCS2, который находится в регистре ADCON1. Вот как зависит выбор источника тактового сигнала, а также его частота от состояний этих трёх битов

ADCS2:ADCS0 Частота преобразователя
000 FOSC/2
001 FOSC/8
010 FOSC/32
011 FRC (Внутренний RC генератор модуля АЦП)
100 FOSC/4
101 FOSC/16
110 FOSC/64
111 FRC (Внутренний RC генератор модуля АЦП)

CHS2:CHS0 (Analog Channel Select bits): Выбор аналогового канала

000 = Канал 0 (AN0)

001 = Канал 1 (AN1)

010 = Канал 2 (AN2)

011 = Канал 3 (AN3)

100 = Канал 4 (AN4)

101 = Канал 5 (AN5)

110 = Канал 6 (AN6)

111 = Канал 7 (AN7)

GO/DONE (A/D Conversion Status bit): Статус модуля АЦП

1 — модуль АЦП выполняет преобразование (установка бита вызывает начало преобразования)

— состояние ожидания (сбрасывается аппаратно по окончанию преобразования).

ADON (A/D On bit): Бит включения модуля АЦП

1 — модуль АЦП включен

— модуль АЦП выключен. Ток модулем не потребляется.

Управляющий регистр — ADCON2

Рассмотрим биты данного регистра:

ADFM (A/D Result Format Select bit): Формат сохранения 10-битного результата

1 — правое выравнивание (два старших бита находятся в двух младших битах регистра ADRESH, остальные нули, а 8 младших битов — в регистре ADRESL)

— левое выравнивание (два младших бита находятся в двух старших битах регистра ADRESL, остальные нули, а 8 старших битов — в регистре ADRESH).

ADCS2 (A/D Conversion Clock Select bit): Старший бит выбора источника тактового сигнала

Был рассмотрен выше.

PCFG3:PCFG0 (A/D Port Configuration Control bits): Управляющие биты настройки каналов АЦП. Данные биты настраивают тип входов (цифровой или аналоговый), а также влияют на выбор источника опорного напряжения. Для этого в технической документации существует вот такая таблица

Из данной таблицы мы видим, что можно одновременно работать с несколькими каналами измеряемого сигнала. В этом случае преобразование сигнала каналов происходит не одновременно, а по очереди. Мы перед началом преобразования выбираем определённый канал, а перед началом следующего — другой канал.

Теперь поговорим о последовательности действий при работе с модулем ADC.

  1. Сначала мы настраиваем модуль, в том числе и биты PCFG3:PCFG0, выбираем направление ножек портов (ножки, участвующие в измерении сигналов, должны быть включены на вход). Затем выбираем канал, на котором будет производиться замер напряжения сигнала, выбираем источник тактирования АЦП и включаем модуль.
  2. Затем настраиваем прерывание от ADC, если необходимо. Прерывания настраиваются следующим образом: бит ADIF сбрасывается в , ADIE устанавливается в 1, также включаем глобальные прерывания с помощью битов PEIE и GIE.
  3. Выдерживаем паузу, необходимую для зарядки конденсатора.
  4. Начинаем аналого-цифровое преобразование с помощью установки бита GO/DONE.
  5. Ждём окончания преобразования путём отслеживания состояния бита GO/DONE или обрабатывая соответствующее прерывание.
  6. Считываем результат из регистров ADRESH:ADRESL, сбрасываем бит ADIF при необходимости.
  7. Чтобы начать следующее преобразование, процесс повторяется с шага 1 или 2. Минимальное время ожидания перед запуском следующего преобразования должно быть не менее двух периодов преобразования одного бита.

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

В данном занятии мы попытаемся отследить изменение напряжения на ножке AN0, а результат мы мониторить будем с помощью жидкокристаллического дисплея подключенного через переходник к шине I2C.

В качестве подопытного контроллера мы возьмём PIC16F877A, расположенный на плате от WaveShare, а в качестве источника испытуемого сигнала соберём примитивный делитель с помощью переменного резистора на 10 килоом, подключенного с одной стороны к плюсу питания контроллера, а с другой — к общему проводу. Центральный провод соединим с ножкой AN0.

Подключим резистор к плате

Подключим программатор, подключив его затем и к ПК, а также подключим внешний блок питания к плате.

В следующей части занятия мы настроим проект, АЦП, напишем код для измерения напряжения и проверим код на практике.

Купить программатор (неоригинальный) можно здесь: PICKit3

Купить программатор (оригинальный) можно здесь: PICKit3 original

Отладочную плату PIC Open18F4520−16F877A можно приобрести здесь: PIC Open18F4520−16F877A

Дисплей LCD 20×4 можно приобрести тут: Дисплей LCD 20×4

Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004

Смотреть ВИДЕОУРОК (нажмите на картинку)

">

Оцените статью
Adblock detector