Главная » Arduino » Измерение напряжения и частоты переменного тока: Arduino в роли надежного помощника

Измерение напряжения и частоты переменного тока: Arduino в роли надежного помощника

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

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

Благодаря этому проекту вы сможете не только расширить свои знания в области электротехники, но и развить навыки работы с платой Arduino, что может быть полезным в будущей карьере или ваших личных проектах. Погрузитесь в мир технического творчества и докажите, что вы способны создать нечто по-настоящему уникальное и полезное!

Этот проект обладает преимуществами, которые делают его непревзойденным в сравнении с предварительно откалиброванным промышленным цифровым мультиметром Fluke 289. Он не только обеспечивает высокую точность и стабильность, но и предлагает полную изоляцию сети электропитания от аппаратной схемы Arduino с помощью трансформатора напряжения. Это особенно важно в условиях, когда требуется работа с высокими напряжениями. Благодаря этой схеме, мы можем измерять фазное переменного напряжение до 500 В с расчетом среднеквадратичного значения.

Измерение напряжения и частоты переменного тока с помощью Arduino

Принципиальная схема проекта показана ниже:

Измерение напряжения и частоты переменного тока с помощью Arduino

Описание работы схемы

На измерительные клеммы может быть подано напряжение до 500 Вольт. Это означает, что можно измерять фазное напряжение в домашней сети (230 Вольт) и синфазное напряжение (400 Вольт).

Измеряемое напряжение поступает на трансформатор DL-PT202D (T1) через 4 токоограничивающих резистора по 75 кОм (R6, R7 и R11, R12). Для достижения наилучших результатов допуск резисторов должен быть не более 1%, номинальное напряжение не менее 200В, а номинальная мощность не менее 0,25Вт.

Трансформатор датчика напряжения, используемый в данном проекте, представляет собой трансформатор с коэффициентом трансформации 1000:1000, преобразующий переменный ток на первичной обмотке в равный ему ток на вторичной обмотке. Максимальный рабочий ток, который может быть подан на первичную обмотку, составляет 2 мА RMS.

Существует множество альтернативных вариантов трансформатора DL-PT202D. Например, ZMPT112 или ZMPT101B. Все они должны иметь такое же номинальное напряжение и коэффициент трансформации, как у DL-PT202D: 2 мА на входе и 2 мА на выходе.

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

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

Коэффициент трансформации с учетом резисторов R6, R7 и R11, R12 и R10, составляет:

100/300к = 1/3000

Это означает, что среднеквадратичное напряжение 400 В будет уменьшено до 0,13333 В = 133,33 мВ среднеквадратичного значения.

Напряжение на резисторе R10 усиливается с помощью дифференциального усилителя OPA2191 фирмы Texas Instruments с коэффициентом усиления 3. Таким образом, коэффициент усиления до этого момента составляет:

100 x 3 / 3000 = 1/1000

Значит при входном напряжении 400 В RMS на выходе операционного усилителя OPA2191 U4A будет 400 мВ RMS.

Микросхема OPA2191 содержит два независимых операционных усилителя в одном корпусе, которые обозначены на принципиальной схеме U4A и U4B. Для питания этой микросхемы необходим биполярный источник питания ±5 В, поскольку мы имеем дело с сигналом переменного тока.

Для получения отрицательного напряжения -5 В применен инвертор напряжения с подкачкой заряда TPS60403 60 мА от Texas Instruments. Устройство TPS60403 автоматически генерирует -5 В из источника питания +5 В. Положительное напряжение 5 В для OPA2191 и TPS60403 поступает с платы Arduino MEGA.

Второй операционный усилитель OPA2191 (U4B) добавляет к входному сигналу напряжение смещения 1,024 В, поэтому сигнал переменного тока колеблется на уровне 1,024 В вместо 0 В.

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

Следующая микросхема OPA2191 используется для построения двух схем повторителя напряжения: одна для упомянутого ранее сигнала напряжения (U5A), а другая для напряжения смещения по постоянному току (U5B).

Опорное напряжение АЦП

Для получения стабильного и точного напряжения 2,048 В использована сверхмалошумящная высокоточная ИС опорного напряжения ADR4520 производства Analog Devices. Данная микросхема в дальнейшем используется в качестве положительного опорного напряжения для модуля АЦП Arduino и напряжения смещения для сигнала переменного напряжения.

Выход ADR4520 напрямую подключен к выводу AREF Arduino и к неинвертирующему выводу ОУ «U5B» через фильтр нижних частот. Подключенный к нему ОУ U5B образует схему повторителя напряжения с выходным напряжением, равным входному напряжению 2,048 В, и используется в качестве напряжения смещения по постоянному току для сигнала переменного напряжения, а также при его переходе через ноль.

Обнаружение пересечения нуля

Для обнаружения пересечения нуля применена сдвоенная высокоскоростная ИС компаратора напряжения TLV3502 производства Texas Instruments. Сигнал переменного тока (со смещением по постоянному току) подается на инвертирующий вход, а напряжение смещения по постоянному току — на неинвертирующий вход компаратора. Здесь постоянное смещение делится на 2 с помощью простой схемы делителя напряжения, состоящей из резисторов R17 и R18. Допуск R17 и R18 не должен превышать 1%.

При такой конфигурации компаратор сравнивает входное напряжение переменного тока с напряжением 1,024 В. Если входное напряжение выше 1,024 В, то на выходе компаратора низкий уровень (0 В), а если входное напряжение ниже 1,024 В, то на выходе компаратора высокий уровень (5 В). Выход компаратора напрямую подключен к цифровому выводу 2 Arduino.

Обратите внимание, что для выхода компаратора не требуется подтягивающий резистор, так как он работает по принципу push-pull.

Когда на схему подано переменное напряжение, компаратор выдает серию импульсов, как описано выше. Arduino может вычислить время между импульсами и, следовательно, период сигнала (P). При известном периоде мы можем рассчитать частоту сигнала по формуле:

F = 1/P

Измерение напряжения и частоты переменного тока — программная часть

Ниже приведен код программы, который был протестирован на плате Arduino MEGA.

#include <LiquidCrystal.h>   // подключаем библиотеку Arduino LCD

// Подключения модуля ЖК-дисплея (RS, RW, E, D4, D5, D6, D7)
LiquidCrystal lcd(3, 4, 5, 6, 7, 8, 9);

#define CPU_CLK  16  // задаем тактовую частоту процессора в МГц
#define Voltage_Correction  1.0116   // задаем коэффициент коррекции напряжения

// объявление переменной
const uint8_t n = 64;            // количество выборок за цикл
volatile int16_t Samples[2*n];   // массив сохранения образцов сигнала напряжения

volatile uint16_t SampleSum;
volatile uint32_t period = 0;
volatile bool ZC_Event = 0;

uint8_t m1 = 0,         // используется для задания массива записи (массива сбора и сохранения образцов)
        m2 = 0;         // используется для задания массива чтения
volatile uint8_t m;     // используется для сохранения образцов в массиве Samples[]

void setup() {
  
  Serial.begin(9600);
  Serial.println( "Starting..." );
  lcd.begin(16, 2);       // Задаем количество столбцов и строк ЖК-дисплея

  // очистить массив
  for (uint8_t i = 0; i < 2*n; i++)
    Samples[i] = 0;
  SampleSum = 0;

  // Timer1 конфигурация
  TCCR1A = 0;
  TCCR1B = 0x09;   // режим CTC, установить прескалер таймера на CPU_CLK/1 (тактовая частота таймера = 16 МГц)
  // конфигурация выходных регистров сравнения с частотой строк по умолчанию 50 Гц, где:
  // 5000 = 20000 us (период цикла 50 Гц) * CPU_CLK (МГц) / (n * TIMER1_PRESCALER) = 20000*16/(64*1)
  // Дополнительно: для 60 Гц используется значение 4167
  OCR1A  = 5000;   
  OCR1B  = 5000;   //  

  // Конфигурация модуля АЦП
  ADMUX  = 0x00;  // устанавливаем +ive reference ADC на внешний AREF
                   // используем правильно настроенное представление результатов АЦП
                   // выбираем аналоговый канал 0
  ADCSRA = 0xFF;  // включаем модуль АЦП
                   // включаем автоматический триггер АЦП
                   // включаем прерывание АЦП и очищаем бит флага (ADIF)
                   // устанавливаем прескалер АЦП на 128 --> ADC CLK = 125 кГц
  ADCSRB = 0x05;  // установите источник запуска АЦП на Таймер/Счетчик1. Сравнить совпадение B.

  // Timer3 конфигурация
  TCCR3A = 0;
  TCCR3B = 0x02;   // установить прескалер таймера на CPU_CLK/8 (тактовая частота таймера = 16/8 = 2 МГц)
  TIFR3  = 0x01;   // сброс флага прерывания по переполнению таймера
  TIMSK3 = 0x01;   // включить прерывание по переполнению таймера

  pinMode(2, INPUT_PULLUP);
  attachInterrupt( digitalPinToInterrupt(2), get_cycle_period, FALLING );
  
}

// внешнее прерывание ISR (подключено к контакту 2 Arduino)
void get_cycle_period() {
  period  += TCNT3;
  TCNT3    = 0;    // сбросить Таймер3
  ZC_Event = HIGH;
}

// TIMER3 переполнение ISR
ISR (TIMER3_OVF_vect) {
  period  += 40000;       // период цикла 20 мс
  ZC_Event = HIGH;
}

// ADC ISR
ISR (ADC_vect) {
  uint16_t an = ADCL | (uint16_t)ADCH << 8;
  Samples[m1 + m] = an;
  SampleSum += an;
  m++;
  TIFR1 = (1 << OCF1B);  // очистить флаг OCB1B (флаг соответствия выхода таймера 1B)
}


void loop() {

    static uint8_t cycle = 0;
    static uint32_t Voltage_RMS = 0;

    while (m < n) ;           // ждем завершения 1 цикла
    TCCR1B &= ~(1 << CS10);   // стоп Timer1
    m = 0;
    //переключение между чтением и записью массивов
    if (m1 > 0) {
      m1 = 0;
      m2 = 64;
    }
    else {
      m1 = 64;
      m2 = 0;
    }

    uint16_t Average = SampleSum / n;  // средний расчет. n — количество выборок на цикл
    SampleSum = 0;
    while ( ZC_Event == LOW ) ;   // ждем события пересечения нуля
    TCNT1   =  OCR1A - 1;
    TCCR1B |= (1 << CS10);       // запускаем Таймер1 без предварительного масштабирования (CLKin = CPU_CLK = 16 МГц)
    ZC_Event = 0;

    // рассчитываем среднеквадратичное напряжение последнего цикла
    uint32_t ch_voltage = 0;
    for ( uint8_t i = 0; i < n; i++ ) {
      Samples[m2 + i] -= Average ;
      Samples[m2 + i] = Samples[m2 + i] * Voltage_Correction ;
      uint16_t j = abs( Samples[m2 + i] ) ;
      ch_voltage += (uint32_t)j * j ;
    }

    ch_voltage = ch_voltage / n;
    ch_voltage = sqrt(ch_voltage) * 100;  // 100, чтобы получить более точное значение
                                           // (2 значащие цифры после запятой)

    // рассчитываем реальное среднеквадратичное напряжение, подаваемое на аналоговый канал MCU (умноженное на 100)
// 2 = 2048/1024, где 2048 — АЦП +ive VREF = 2048 мВ, а 1024 — максимальное цифровое значение 10-битного АЦП (приблизительно)
     // Обратите внимание, что это напряжение всегда измеряется в миллиВольтах, умноженных на 100, это тоже напряжение
     // ниже меры (x100)
    ch_voltage *= 2;
    uint16_t RMS = ch_voltage;
    if (RMS > 5000)   // если среднеквадратичное напряжение цикла > 50,00 В
      Voltage_RMS += RMS;

    cycle++;

    if (cycle >= 25) {
      uint32_t acc_pr, freq;
      acc_pr = period;
      period = 0;
  
      // рассчитываем средний период цикла в нсек.
      //   2 = CPU_CLK(MHz)/TIMER3_PRESCALER = 16/8
      uint16_t cycle_pr = acc_pr / (cycle * 2);

      // обновляем регистры OCR в соответствии с новым средним периодом цикла. 16=CPU_CLK(MHz)/TIMER1_PRESCALER = 16/1
      //  n — количество выборок за один цикл
      OCR1A = ( (uint32_t)cycle_pr * 16 ) / n;
      OCR1B = OCR1A;

      // вычисляем частоту
       // 1000000, чтобы перейти от нсек к сек, и 100, чтобы получить 2 значащие цифры после запятой
      freq = (1000000 * 100) / cycle_pr;

      // печатаем значения напряжения на ЖК-дисплее и последовательном мониторе
      char display_buffer[12];
      Voltage_RMS /= cycle;    
      sprintf( display_buffer, "V = %03u.%01u V",  (uint16_t)(Voltage_RMS/100), (uint8_t)( (Voltage_RMS % 100) / 10) );
      lcd.setCursor(0, 0);    // перемещаем курсор в столбец 0, строку 0 [позиция (0, 0)]
      lcd.print(display_buffer);
      Serial.println(display_buffer);

      // печатаем значения частоты на ЖК-дисплее и последовательном мониторе
      sprintf( display_buffer, "F = %02u.%02u Hz",  (uint8_t)(freq/100), (uint8_t)(freq % 100) );
      lcd.setCursor(0, 1);    //перемещаем курсор в столбец 0, строку 1 [позиция (0, 1)]
      lcd.print(display_buffer);
      Serial.println(display_buffer);

      Serial.println();
      Voltage_RMS = 0;
      cycle = 0;

    }

}

 

Данный скетч Arduino обеспечивает вычисление среднего и среднеквадратичного значения сигналов переменного тока, причем среднее значение используется только для вычисления среднеквадратичного значения. Устройство отображает на ЖК-дисплее и последовательном мониторе только среднеквадратичное значение приложенного напряжения.

Просто среднее значение (среднее или смещение по постоянному току) в дискретном времени — это сумма всех выборочных значений, деленная на количество выборок:

формула количества выборок

Среднеквадратичное значение в дискретном времени можно рассчитать с помощью следующего уравнения:

формула среднеквадратичное значение в дискретном времени

Микроконтроллер Arduino UNO и аналогичные платы (ATmega328P) имеют 10-разрядный модуль АЦП с положительным опорным напряжением 2,048 В. При этом 0 В в цифровом виде представляется как 0, а 2,048 В — как 1023.

Замечания по коду

Поскольку у нас имеется 10-разрядный АЦП, работающий в диапазоне [0 — 2,048 В], микроконтроллер делает 64 выборки за 1 цикл и сохраняет данные выборки в массиве с именем Samples.

Модуль АЦП с включенной опцией автоматического запуска настроен на срабатывание от источника сравнения B Timer1, что позволяет автоматически запускать аналого-цифровое преобразование по времени.

Для сигнала частотой 50 Гц период составляет 20 мс. Микроконтроллер снимает одну выборку каждые 20000/64 = 312,5 мкс. В программе использовано сравнение B Timer1, чтобы запускать преобразование АЦП каждые 312,5 мкс, и после завершения преобразования данные сохраняются в переменной массива Samples. Элемент массива увеличивается при каждом новом чтении до заполнения всех элементов и завершения цикла.

Если частота немного изменилась, Arduino может измерить новую частоту и скорректировать время выборки в соответствии с новой частотой. Здесь таймер Timer3 используется для измерения ширины импульса с использованием внешнего прерывания, подключенного к цифровому выводу 2 Arduino.

Микроконтроллер Arduino MEGA ATmega2560 работает на частоте 16 МГц (может достигать 16 MIPS). Для запуска аналого-цифрового преобразования каждые 312,5 мс Timer1 настроен на работу на частоте 16 МГц (прескалер = 1), это означает, что Timer1 сделает 5000 тиков за время 312,5 мс (16 x 312,5 = 5000), что является запрограммированным значением регистров OCR1A и OCR1B для частоты сети по умолчанию 50 Гц. Это значение не является фиксированным и постоянно изменяется в зависимости от частоты входного переменного напряжения.






Добавить комментарий