Задействуем АЦП. Вольтметр на AVR.

 Аналогово-Цифровой Преобразователь служит для преобразования аналогового сигнала на входе в цифровую форму, понятную для МК.  Практически во всех современных микроконтроллерах от AVR имеется 10 битный АЦП, позволяющий оцифровывать аналоговый сигнал с дискретностью 1024 значений. Этого достаточно чтобы, например, делать замеры напряжений (в разумных пределах), снимать показания с различных датчиков, таких как фотодиод и термопара, делать анализаторы спектра и многое другое.

 Примерная работа преобразования приведена на рисунке ниже; через равные промежутки времени (ось X) происходит считывание значения напряжения на входе АЦП (ось Y). Так как АЦП имеет ограниченную разрешающую способность, появляется дискретность (дробление) значений.  

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

  В Bascom-AVR конфигурирование АЦП сводится к одной строчке:

Config Adc = SINGLE , Prescaler = 128 , Reference = Avcc

 здесь Adc – режим считывания значения: Single – единичное считывание, также может быть Free (режим постоянной работы преобразователя)Prescaler = 128 – выбираем частоту дискретизации путем деления частоты кварца на определенное число (также может быть 2,4,8,16,32,64 или Auto). Если выбрать Auto, то компилятор сам выберет подходящую частоту работы АЦП

Reference – выбор источника опорного напряжения. Aref – внешний источник, Avcc – напряжение питания схемы, Internal – внутренний ИОН на 2,56 в.

  Преобразование аналога в цифру в Bascom-AVR происходит следующим образом, для примера считаем значение напряжения на первом канале АЦП и выведем результат преобразования на ЖКИ:

Start ADC         ‘ запускаем преобразование

M = GetADC(1)     ‘ приравниваем переменную М результату преобразования

Stop ADC          ‘ останавливаем работу АЦП

LCD  M           ‘ выводим значение на ЖКИ

  Считывание может быть произведено с любого пина АЦП микроконтроллера, от 0 до 7 (например для ATMEGA32). Для этого в строке GetADC(x) заместо х ставим интересующий нас канал. И все!

  В дополнение решил собрать вольтметр на ATMega8. Во-первых стало интересно как точно все это работает в железе, и во-вторых вольтметр пригодится в регулируемом блоке питания который хочу собрать.Итак, первым делом нужно определиться с диапазоном измеряемых значений.  Я выбрал пределом измерения 30 Вольт, от этого зависит коэффициент на который нужно будет умножать результат преобразования, а также расчет резисторного делителя напряжения на входе АЦП. В качестве источника опорного напряжения выбран внутренний ИОН на 2,56 В. Поэтому резисторный делитель рассчитан таким образом, чтобы при максимально измеряемом напряжении 30 В на вход АЦП заходило не более 2,56 В. Схема вольтметра приведена ниже:

  Подстроечник RV1 – многооборотный, для точной настройки делителя.  В схеме использованы семисегментные индикаторы с общим анодом, но без точки. Точку пришлось добавлять путем высверливания отверстия и вставки в него светодиода. Точку я сделал горящей постоянно, а сегменты управляются динамически.  Индикация организована в главном цикле программы. Для считывания показаний АЦП задействован Timer1, который переполняется примерно 2 раза в секунду. При переполнении вызывается подпрограмма, в которой происходит считывание данных с АЦП и их преобразование. Так как переполнение таймера происходит каждые 0,5 сек, то показания вольтметра будут обновляться 2 раза в секунду. Это сделано для того чтобы четвертая цифра отображающая сотые доли не скакала слишком быстро, размазывая показания (так как АЦП имеет свойство иногда менять показания при неизменном напряжении на входе).


    $regfile = “m8def.dat”

    $crystal = 8000000

     

    ‘ * * * переменные * * *

     

    Dim W As Integer              ‘ переменная для хранения значения АЦП

     

    Dim N1 As Integer

    Dim N2 As Integer

    Dim N3 As Integer

    Dim N4 As Integer

     

    Dim M1 As Integer

    Dim M2 As Integer

    Dim M3 As Integer

    Dim M4 As Integer

     

    Dim C1 As Integer

    Dim C2 As Integer

    Dim C3 As Integer

    Dim C4 As Integer

     

     

    ‘ * * * настройка портов * * *

     

     

    Ddrb = &B11111111

    Ddrd = &B11111111

     

     

    ‘ * * * конфигурируем таймер1 и прерывание по его переполнению * * *

     

     

    Config Timer1 = Timer , Prescale = 64

     

    On Timer1 Acp:

     

     

    ‘ * * * конфигурация АЦП * * *

     

    Config Adc = Single , Prescaler = Auto , Reference = Internal

     

     

    ‘ * * * разрешаем прерывания * * *

     

    Enable Interrupts

    Enable Timer1

     

     

    ‘ * * * основная программа * * *

     

     

    Do

     

     

    Portb = &B11101111

     

    Select Case N1

    Case 0 : Portd = &B11111111

    Case 1 : Portd = &B11111001

    Case 2 : Portd = &B10100100

    Case 3 : Portd = &B10110000

    Case 4 : Portd = &B10011001

    Case 5 : Portd = &B10010010

    Case 6 : Portd = &B10000010

    Case 7 : Portd = &B11111000

    Case 8 : Portd = &B10000000

    Case 9 : Portd = &B10010000

    End Select

    Waitms 5

     

    Portb = &B11110111

     

    Select Case N2

    Case 0 : Portd = &B11000000

    Case 1 : Portd = &B11111001

    Case 2 : Portd = &B10100100

    Case 3 : Portd = &B10110000

    Case 4 : Portd = &B10011001

    Case 5 : Portd = &B10010010

    Case 6 : Portd = &B10000010

    Case 7 : Portd = &B11111000

    Case 8 : Portd = &B10000000

    Case 9 : Portd = &B10010000

    End Select

    Waitms 5

     

    Portb = &B11111011

     

    Select Case N3

    Case 0 : Portd = &B11000000

    Case 1 : Portd = &B11111001

    Case 2 : Portd = &B10100100

    Case 3 : Portd = &B10110000

    Case 4 : Portd = &B10011001

    Case 5 : Portd = &B10010010

    Case 6 : Portd = &B10000010

    Case 7 : Portd = &B11111000

    Case 8 : Portd = &B10000000

    Case 9 : Portd = &B10010000

    End Select

     

    Waitms 5

     

    Portb = &B11111101

     

    Select Case N4

    Case 0 : Portd = &B11000000

    Case 1 : Portd = &B11111001

    Case 2 : Portd = &B10100100

    Case 3 : Portd = &B10110000

    Case 4 : Portd = &B10011001

    Case 5 : Portd = &B10010010

    Case 6 : Portd = &B10000010

    Case 7 : Portd = &B11111000

    Case 8 : Portd = &B10000000

    Case 9 : Portd = &B10010000

    End Select

     

    Waitms 5

     

    Loop

     

    ‘ * * * подпрограмма считывания показания с АЦП * * *

     

    Acp:

     

    Start Adc          ‘ считываем показания АЦП

     

     

    W = Getadc(1)      ‘ <—- число которое получили с первого канала АЦП

     

     

    M1 = W * 3         ‘ переводим значение АЦП в вольты. Так как запятая у меня

                       ‘ фиксированная, то для удобства работать будем с целыми числами 3069/1023=3;

                       ‘ где 3069 максимальное значение напряжения отображаемое вольтметром,

                       ‘ или 30.69 В

    M2 = M1

    M3 = M1

    M4 = M1

     

    M1 = M1 / 1000     ‘ обработка тысяч

    N1 = Abs(M1)

     

    M2 = M2 Mod 1000   ‘ обработка сотен

    M2 = M2 / 100

    N2 = Abs(M2)

     

    M3 = M3 Mod 100    ‘ обработка десяток

    M3 = M3 / 10

    N3 = Abs(M3)

     

    M4 = M4 Mod 10     ‘ обработка единиц

    N4 = Abs(M4)

     

    Return

     

    End


  

  Заснял небольшое видео, показывающее работу вольтметра.

 Разрешение измерения вольтметра получилась 0,03 В (большего из 10 битного АЦП на таком диапазоне не выжать), точность не менее 0,05 В. Что весьма не плохо, учитывая что использовался внутренний ИОН и не использовались ВЧ-фильтры на входе преобразователя. Для блока питания самое то.ЗЫ. Если говорить о точности измерения, то в качестве эталонного измерителя напряжения выступал мой Mastech MAS838, поэтому все относительно =) 

Скачать файлы к проекту
Взято с: avrproject.ru


Категория: AVR
Метки:

Написать коментарий

*
= 5 + 4

Добавить изображение

Последние статьи