РадиоКот >Схемы >Цифровые устройства >Измерительная техника >

Теги статьи:

Простой миниатюрный встраиваемый цифровой вольтметр для БП (0…19,99В/0…39,99В)

Автор: SSMix
Опубликовано 17.09.2013
Создано при помощи КотоРед.
Участник Конкурса "Поздравь Кота по-человечески 2013!"

 

          В статье описывается простой встраиваемый 4-х разрядный цифровой вольтметр, разработанный для установки в домашний лабораторный БП с выходным напряжением 0…15В, как более дешевая и миниатюрная альтернатива китайским 3-х разрядным поделкам. Вольтметр может быть также использован для контроля напряжения в бортовой сети автомобиля.

          Изменением номиналов резисторов делителя и варианта программы прошивки можно выбрать предел измерения 0…19,99 В или 0…39,99 В. Для универсальности предусмотрены прошивки для установки светодиодных индикаторов с ОА и ОК.

          Вот фото вольтметра в работе:

    Технические характеристики:

Диапазон измерения, В……………...........0…19,99 (0…39,99);

Дискретность измерения, мВ……….......10;

Точность во всём диапазоне, мВ….......±10;

Напряжение питания, В……………...........7…20*;

Потребляемый ток, мА……………............≤40**;

Габаритные размеры, мм…………............43х20х11.

Индикация…………………………..................4-х разрядный 7-сегментный с ОА или ОК.

* - при использовании DA1 78L05A

** - зависит от сопротивлений R4…R11

Схема электрическая вольтметра:

            Входное измеряемое напряжение поступает на делитель R1, R2, R3, R13 с коэффициентом деления 1:8, а с него на вход PC4 АЦП микроконтроллера DD1. Конденсатор C2 – помехоподавляющий.

            Микроконтроллер выбран широко распространённый ATmega8A в малогабаритном корпусе TQFP-32.

            В качестве источника опорного напряжения (ИОН) для АЦП использован внутренний напряжением Vref=2.56В. При этом максимальное измеряемое напряжение на входе делителя составляет 2,56•8=20,48В.

            Если применить входной делитель с коэффициентом деления 1:16, максимальное измеряемое напряжение можно увеличить до  2,56•16=40,96В.

            В программе МК предусмотрены оба варианта делителя. Максимальный предел измерения программно ограничивается величиной 19,99В (39,99В). При превышении предела на индикатор выводится “1 -. - -“ (как в старой доброй КР572ПВ2) или “3 -. - -”.

            При 10-ти разрядном АЦП его диапазон измерения составляет 0…1023, что дает дискретность измерения непосредственно на входе АЦП: 2560мВ/1024=2,5мВ. С учётом входного делителя напряжения получается дискретность измерения 2,5мВ•8=20мВ (для предела 0…20В) или 2,5мВ•16=40мВ (для предела 0…40В). Для получения необходимой дискретности 10 мВ использован приём многократных выборок АЦП с усреднением результата. На официальном сайте Atmel есть интересный pdf-документ под названием “AVR121. Enhancing ADC resolution by oversampling” (Расширение разрешающей способности АЦП, используя передескритезацию).

            На 8-й странице этого документа в таблице 3-1 (правда для Vref=5В) показано, как растёт разрешающая способность 10-разрядного АЦП при увеличении числа выборок. При 4-х выборках с усреднением результата наш АЦП “превращается” в 11-разрядный (0…2047), при 16-ти выборках – в 12-разрядный (0…4095), при 64-х выборках – в 13-разрядный (0…8191) и т.д.

          Общая формула для вычисления необходимого количества выборок для прибавки к разрешению АЦП дополнительных n бит: sf = 2n.

          В данном случае для полного использования переменной накопления результата АЦП типа unsigned int (0…65535) оказалось удобным применить 64 выборки. При этом даже при максимальном коде АЦП 1023 переменная накопления результата никогда не переполнится (1023•64=65472), а разрешающая способность вольтметра для случая (0…40В) улучшится в 8 раз и составит 5 мВ, что вполне подходит.

          Для компенсации разброса сопротивлений резистивного делителя и начального напряжения ИОН служит подстроечный резистор R3.  Подбором сопротивления резистора R13 можно подстроить точность показаний вольтметра более грубо.

         Для варианта (0…19,99)В соотношение сопротивлений верхнего плеча делителя к нижнему должно быть 7:1, а для варианта (0…39,99)В – 15:1, т.е. во втором случае сопротивление резистора R1 нужно будет увеличить до 510кОм, и возможно подобрать R13.

         Светодиодный 4-х разрядный индикатор HL1 KW4-361AGB (с общим анодом) подключен к МК без дополнительных ключевых транзисторов, учитывая небольшой ток потребления. Резисторы R4…R11 определяют яркость свечения индикатора. Можно применить также индикатор с общим катодом, зашив МК соответствующим вариантом hex-файла прошивки. Схема включения при этом остаётся прежней.

         Питание микроконтроллера производится через линейный стабилизатор DA1 78L05A, для которого по DataSheet типовая разность между входом и выходом составляет не менее 1,7 В. Практически минимальное напряжение питания схемы составляет около 7 В. Максимальное – не более 30 В. Если необходимо запитать схему от меньшего напряжения, то следует заменить стабилизатор DA1 на другой тип. Выходное напряжение стабилизатора может находиться в пределах от 3 до 5 В. При питании схемы от большего напряжения, чем 20В, последовательно с цепью питания желательно включить стабилитрон для гашения избыточного напряжения с целью снижения мощности рассеивания на DA1.

         Программа для микроконтроллера написана на языке Си в хорошо зарекомендовавшей себя среде WinAVR-20060125. Вот вкраце рабочий вариант программы для индикатора с ОА и пределом измерения 19.99В.

         Начинается программа традиционно, с подключения библиотек:

 

#include <avr/io.h>            //Подключение системной библиотеки

#include <avr/interrupt.h>   //Подключение библиотеки обработки прерываний

#include <avr/pgmspace.h> //Подключение библиотеки массивов

#include <util/delay.h>       //Подключение библиотеки задержек

 

Определяем константы в flash-памяти микроконтроллера::

//Знакогенератор сегментов светодиодного индикатора с ОА:

static unsigned char __attribute__ ((progmem)) SEGMENTE[] =

{0x03,0xDB,0x85,0x91,0x59,0x31,0x21,0x9B,0x01,0x11,0xFE,0xFF,0xFD};

//0----1----2----3-----4----5----6----7----8----9-(точка)(пусто)(-)

Это байты, которые будут выводиться в порт D микроконтроллера для получения различных символов в разряде индикатора. Сегменты индикатора a, b, c, d, e, f, g, h, соответствуют линиям порта D следующим образом:

a - PD6

b - PD5

c - PD2

d - PD3

e - PD4

f - PD7

g - PD1

h - PD0

            Так оказалось проще разводить печатную плату.

           

            Для коммутации разрядов для порта B также используется табличный массив в flash-памяти:

 

//Таблица динамической коммутации разрядов индикатора

static unsigned char __attribute__ ((progmem)) RAZR[] =

{0b00001000, 0b00000001, 0b00000010, 0b00000100};

//4 разр.      3 разр.     2 разр.      1 разр.

 

           Далее определяем глобальные переменные:

 

volatile unsigned char segcounter = 0;                     //Счётчик разрядов индикатора (0-младший справа, 3-старший слева)

volatile unsigned char mass_ind[]={12, 12, 12, 12};   //Массив выводимых чисел для каждого индикатора (0-младший справа, 3-старший слева), при включении вывод "--.--"

volatile unsigned char p_count=0;                           //Счётчик прерываний (каждые 0,256мс)

 

            Буфер mass_ind[] будет использоваться для хранения индицируемых цифр каждого разряда. Заноситься информация в него будет после каждого суммарного замера АЦП и преобразования результата в формат ХХ.ХХ В. Считывание информации будет производиться в прерывании по переполнению таймера-счётчика 2 (каждые 0,256мс) для  динамической индикации. Первоначально в mass_ind[] заносим данные для вывода на индикатор при включении питания значков “- -. - -".

            В прерывании выставляем лог.1 на аноде текущего разряда в соответствии с состоянием счётчика segcounter, выводим в порт D байт данных из массива mass_ind[] и увеличиваем на 1 переменную segcounter (с проверкой на переполнение и ограничением до 3). Также инкрементируем счетчик прерываний p_count для отсчёта интервалов времени в 0,256мс. Т.о. в каждом прерывании выводится цифра одного из разрядов через каждые 0,256мс. Для 2-го разряда дополнительно добавляется разделительная точка.

 

//Прерывание по переполнению T2 (), динамическая индикация

ISR (TIMER2_OVF_vect)

{ PORTD = 0xFF;                                //Гашение индикатора

  PORTB = (PORTB & 0b11110000) | pgm_read_byte(RAZR+segcounter);//Активация текущего разряда индикатора

  PORTD = pgm_read_byte(SEGMENTE+mass_ind[segcounter]);//Вывод сегментов текущего разряда

  if (segcounter==2)                           //Если 2-й разряд с точкой

  PORTD = PIND & pgm_read_byte(SEGMENTE+10);   //Добавка десятичной точки

  segcounter++;                                //Инкремент разрядов индикатора

  if (segcounter>3) segcounter=0;        //Ограничение счетчика

  p_count++;                                    //Инкремент счётчика прерываний

}

          Никаких сложных вычислений в прерывании специально не делается, чтобы обеспечить минимальное время выполнения. Благодаря этому скорость переключения разрядов индикатора составляет 1/0,256мс=3906,25 Гц, а каждый из четырёх разрядов мигает с частотой 3906,25 Гц/4=976,5625 Гц. Частота довольно высокая, так что никакого мерцания индикатора не заметно.

          Далее следует основная функция программы, начинающаяся с конфигурации портов, таймера-счетчика 2 и АЦП:

 

int main (void)

{ unsigned int value=0;                        //Переменная для накопления результата преобразования АЦП

  unsigned char adc_counter=0;            //Счётчик замеров АЦП

  unsigned int display = 0;                    //Выводимое напряжение ХХХХ В

  DDRD = 0b11111111;

  DDRC = 0b00000000;

  PORTD = 0x00;

  PORTC = 0b11101111;

  DDRB = 0b00001111;

  PORTB = 0b11110000;

//Инициализация таймера-сч.2

  TCCR2 |= (1 << CS20)|(0 << WGM21)|(0 << WGM20);//Предделитель на N=1, прерывания каждые 0,256мс (1000000 Гц / 256 = 3906,25 Гц), Fинд=3906,25 Гц/4 = 976,5625 Гц

  TIMSK |= (1 << TOIE2);               //Разрешение прерывания по переполнению таймера 2

//Инициализация АЦП

  ADMUX = (1 << REFS1)|(1 << REFS0) //Внутренний ИОН 2,56V

          |(0 << ADLAR)                    //Правое выравнивание результата

          |(0 << MUX3)|(1 << MUX2)|(0 << MUX1)|(0 << MUX0);//Вход АЦП - PC4

//

  _delay_ms(50);                            //Задержка времени на 50 мс

  sei();                                         //Глобальное разрешение прерываний

 

            В следующем бесконечном цикле при помощи счетчика  p_count отсчитываем 15 прерываний по 0,256мс, в результате чего получаем интервал 3,84мс и запускаем одиночное преобразование АЦП. Одновременно увеличиваем на 1 счетчик замеров  adc_counter. Результат накапливаем в переменной value.

 

  while(1)

  { if (p_count>=15)                         //Если прошло 15*0,256мс=3.84мс; общее время замеров 64*3.84=245.76мс (4 замера в сек)

    { while (bit_is_set(ADCSRA, ADSC));//Ожидание завершения предыдущего преобразования

      ADCSRA=0b11000011;                 //Пуск АЦП (Кдел=8, f=125 кГц, однократн.)

      while (bit_is_set(ADCSRA, ADSC));//Ожидание завершения преобразования

      value = value + ADC;                  //Чтение и накопление результата преобразования

      adc_counter++;                        //Инкремент счётчика замеров

      p_count=0;

    }

 

После 64 замеров вычисляем напряжение в мВ*10:

 

/* ACD=1024*(U/Кдел)/Vref

   Vref=2.56 В

   Кдел=8

 

   Измеренное напряжение для N замеров:

   U=(ACD/N)*Vref*Кдел/1024

 

   Вычисление мВ:

   mVolt=((value/N)*Vref*Kдел)/1024=((value/N)*2560*8)/1024)=20*value/N=

   =value/3,2 (N=64)

 

   Для отображения 4-х разрядов в формате ХX.ХХ В результат делится на 10 с округлением (прибавляется 5 перед делением)

   mVolt=(value+5)/32  (N=64, Кдел=8)

*/

    if (adc_counter >= 64)   //Если прошло 64 замера АЦП

    { display = (value+5)/32;

 

            При общем количестве замеров 64 получается суммарное время измерения 3,84мс*64=245,76 мс, т.е. примерно 4 измерения в секунду. Чаще делать нет смысла, иначе показания индикатора будут меняться слишком быстро.

            Ну и наконец, заполняем буфер mass_ind[4] для вывода из него информации в прерывании.

 

    //Заполнение массива mass_ind[4] для вывода индикации

      if (display > 1999)                        //Если напряжение больше 19,99В

      { mass_ind[0] = 12;                     //Вывод "-" (справа)

        mass_ind[1] = 12;                     //Вывод "-" в 1-м разряде

        mass_ind[2] = 12;                     //Вывод "-" во 2-м разряде

        mass_ind[3] = 1;                       //Вывод "1" в старший разряд (слева)

      }

      else

      { mass_ind[0] = display % 10;       //Младший разряд (справа)

        mass_ind[1] = (display/10)%10;   //1-й разряд

        mass_ind[2] = (display/100)%10; //2-й разряд

        mass_ind[3] = display/1000;       //Старший разряд (слева)

        if (mass_ind[3]==0) mass_ind[3]=11; //Если в старшем разряде "0" - гашение старшего разряда

      }

      adc_counter = 0;

      value = 0;

    }

  }

}

 

     Скриншот симуляции работы программы в Протеусе:


     Схема вольтметра собрана на плате из одностороннего фольгированного стеклотекстолита размерами 43х20 мм по лазерно-утюжной технологии:

          Перечень элементов:

C1                               = 10,0х20В (Танталовый, корпус B)

 

C2, С4…C6                    = 0,47 (0603)

C3                               = 22,0х6,3В (Танталовый, корпус A)

 

DA1                             = MC78L05A (SOIC-8)

DD1                             = ATmega8A-AU (TQFP-32)  или ATmega8

 

HL1                              = KW4-361AGB (4 сегмента, общий анод)

L1, L2                          = 22uH (0805)

 

R1                               = 240к или 510к (0805)

R2                               = 30к (0805)

R3                               = 1к (Подстроечный SMD CV-035, EVM (3x3мм))

R4, R5, R7…R12              = 270* (0603)

R6                               = 270* (1206)

R13                              = 3,6к* (0805)

          Для подключения программатора на плате предусмотрены соответствующие контактные площадки MOSI, MISO, SCK, RESET, GND, +Vcc:

        После прошивки программы следует запрограммировать следующие фьюзы ("0"-галочки установлены):

        CKSEL3…0=0001 (Внутр.RC-генератор 1 МГц),

        CKOPT=1,

        BODEN=1 (схема BOD выключена),

        SUT10=10 (16 CK, 65 ms, Slowly rising power),

        ("0"-галочки установлены).

        Подключение вольтметра производится тремя проводниками: +Uизмер., +Uпит. и Общий. Если измеряемое напряжение не опускается ниже минимального входного напряжения питания стабилизатора DA1, цепи +Uизмер. и  +Uпит. соединяются вместе.

        В первый момент после включения на индикаторе высветится “- -. - -“, т.к. измерения и обработка результата ещё не проведены. Это корректнее, чем выводить первоначально нулевое напряжение, как сделано во всех встраиваемых вольтметрах. После завершения первой серии замеров на индикатор будет выведено напряжение в вольтах.

        Подключив параллельно измеряемой цепи образцовый цифровой вольтметр, подстроечным резистором R3 необходимо выставить одинаковые с ним показания. Для повышения точности настройки желательно использовать напряжение ближе к верхнему пределу измерения. Регулировка получается довольно плавная. Возможно придётся дополнительно подобрать сопротивление резистора R13 для “попадания” в нужный диапазон подстройки.

        Испытания вольтметра совместно с образцовым мультиметром показали, что  погрешность измерения не превышает единицы младшего разряда (±10 мВ) во всём диапазоне 0…19.99 В.


Файлы:
Файлы проекта


Все вопросы в Форум.