вольтмер 220V

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

в 9 строке поменяйте условие if на цикл while(см выше)

while(cntr<=100);//ждем 100 измерений

таймер включится, отработает, а в основной программе будет на цикле ожидать 100 измерений

DimaP.
Offline
Зарегистрирован: 21.04.2013

Вообщем в итоге получается что напряжение плавает от 229 до 231 при фактическом напряжении 230 вольт!!! 

наверное это хорошая точность :))

DimaP.
Offline
Зарегистрирован: 21.04.2013

И еще знаете что интересно в 12 строке мы вычисляем реальную величину умножая вычисленное значение квадратно корня на коэффициент который по моим расчетам получился 0.010 хотя в реальности его пришлось изменить на 0.0795!!! почему до сих пор не понятно!!

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

чо 1% точности измерения неплохо в принципе, у стабилизаторов напряжения  2-8%, так что нормально

у китайских стабилизаторов также скачет показания в пределах 1-3 вольт

для проверки на латр посадите и по всему диапазону прогоните

DimaP.
Offline
Зарегистрирован: 21.04.2013

Пргонял по всему диапазону от 0 вольт, до 250 в принципе точность приемлемая!!! все осталось аппаратную часть подогнать навесить LCD и DS 1307 подкоректировать код и прибор будет готов!!!

P.S всем очень благодарен!!!!

Snubist
Offline
Зарегистрирован: 18.02.2013

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

DimaP.
Offline
Зарегистрирован: 21.04.2013

я выложу но немного в сокращенном варианте!!! 

и немного позже!!!

DimaP.
Offline
Зарегистрирован: 21.04.2013

Возник вопрос почему когда я добавил в обработчик прерывания вот этот код 

	//****************обработчик прерывания********************
	
ISR(TIMER2_COMPA_vect) 
	
{  
           
  if (cntr<=99)     
 {
   /*для фазы A */
  Uism_A = analogRead(ADC1); // считываем значения с аналогового порта 1
  Uism_A -= Ucor; // убираем подьем синусоиды на 2 вольт
  Uism_A *= Uism_A;// возводим значение в квадрат
  Usumm_A += Uism_A; // склдываем квадраты измерений
  /* для фазы B */
  Uism_B = analogRead(ADC2); // считываем значения с аналогового порта 2
  Uism_B -= Ucor; // убираем подьем синусоиды на 2 вольт
  Uism_B *= Uism_B;// возводим значение в квадрат
  Usumm_B += Uism_B; // склдываем квадраты измерений 
 /* для фазы С */  
  Uism_C = analogRead(ADC3); // считываем значения с аналогового порта 3
  Uism_C -= Ucor; // убираем подьем синусоиды на 2 вольт
  Uism_C *= Uism_C;// возводим значение в квадрат
  Usumm_C += Uism_C; // склдываем квадраты измерений  
  
  cntr++; // увеличиваем счетчик на 1 с каждым тактом!
                }
          else  
          {
                   TIMSK2 = 0b00000000; // останавливаем таймер
          }
      }           

 

точность измерения упала в разы???

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

что то где то не успевает щитать, вы в обработчик столько всего напихали

 я бы вам посоветовал все эти мат. операции в основном теле делать, когда выводите значения напряжения

DimaP.
Offline
Зарегистрирован: 21.04.2013

Вот я подправил функцию и переписал немного код, ((( к сожалению ситуация не поменялась!

Фаза А читается с точностью 0.7% фазы В и С с точностьб 1.5% хотя я читаю входы напрямую(((


/* переменные работающие в обработчике прерывания */
volatile int Umass_A [100]; //масив переменных для хранения мгновенных напряжений фазы А

volatile int Umass_B [100]; //масив переменных для хранения мгновенных напряжений фазы B

volatile int Umass_C [100]; //масив переменных для хранения мгновенных напряжений фазы C

long Uism_A = 0; // переменная для хранения измеренного напряжения и квадрата фазы А
long Usumm_A = 0; // переменная для хранения сумм квадратов фазы А 
long Uism_B = 0; // ------В-----
long Usumm_B = 0;//------В------
long Uism_C = 0; // -------С-----
long Usumm_C = 0;// --------С------
volatile int cntr = 0; // счетчик в обработчике прерывания

/* подключаем аналоговые входы */
int ADC0 = 0; // аналоговый вход 0 для переменной Ucor!
#define ADC1    1  // вход измерения фазы А
#define ADC2    2  // вход измерения фазы B
#define ADC3    3  // вход измерения фазы С
int Ucor = 0; // переменная будет хранить напряжение корректировки!!!

/*переменные для расчета реальных величин!!*/
int real_U_A = 0; //переменная расчета рельной величины для фазы А
float sqrtUsum_A = 0.0; //переменная расчете квадратного корня для фазы A
int real_U_B = 0; //переменная расчета рельной величины для фазы В
float sqrtUsum_B = 0.0; //переменная расчете квадратного корня для фазы В
int real_U_C = 0; //переменная расчета рельной величины для фазы С
float sqrtUsum_C = 0.0; //переменная расчете квадратного корня для фазы С

/* переменные массивов*/

unsigned long timeOut = 0;// переменная для хранения времени!!!
unsigned long time = 0;





void setup()  
{ 
    TIMSK2 = 0b00000000;         // запрещение прерывания по совпадению таймера/счетчика Т2  
    TCCR2A = 0b00000100;       // режим работы СТС
    TCCR2B = 0b00000011;     // предделитель на 32
    ASSR &= ~(1<<AS2);    // Выбор источника синхронизации таймера(от системного генератора
                                         
    OCR2A = 100;           // срабатывание таймера 16000000/32/100=5000 раз в секунду 100 раз за секунду
    
    ADMUX = 0b0100000;
    ADCSRA = 0b10000111;
                    
     Serial.begin(9600);
    
}


void loop() 
{    
  
  if(millis() - timeOut >250)// ждем 0,25 секунды и...
 
  {
    Ucor = analogRead (ADC0); // сохраняем напряжение коррекции
    
    TCNT2 = 0x00; // перезарежаем таймер
    /* обнуляем суммы напряжений*/ 
    Usumm_A = 0; 
    Usumm_B = 0;
    Usumm_C = 0;
    
    TIMSK2 |= (1<<OCIE2A); // разрешаем прерывание по совпадению
    timeOut = millis();
  }
  
    
  
  
  
  /* расчет реальных величин*/
   if (cntr==100)
  {
  /* Uism_A -= Ucor; 
  Uism_A *= Uism_A;// возводим значение в квадрат
  Usumm_A += Uism_A;   */
   
 
     
 /* Uism_C -= Ucor; // убираем подьем синусоиды на 2 вольт
  Uism_C *= Uism_C;// возводим значение в квадрат
  Usumm_C += Uism_C; // склдываем квадраты измерений  */
  
  
  
  for ( int i =0; i<99; i++)
  {  
    Uism_A =  Umass_A [i];
    Uism_A -= Ucor;// убираем подьем синусоиды на 2 вольт
    Uism_A *= Uism_A;// возводим значение в квадрат
    Usumm_A += Uism_A;// склдываем квадраты измерений
    
    Uism_B =  Umass_B [i];
    Uism_B -= Ucor; // убираем подьем синусоиды на 2 вольт
    Uism_B *= Uism_B;// возводим значение в квадрат
    Usumm_B += Uism_B; // склдываем квадраты измерений
    
    Uism_C =  Umass_C [i];
    Uism_C -= Ucor; // убираем подьем синусоиды на 2 вольт
    Uism_C *= Uism_C;// возводим значение в квадрат
    Usumm_C += Uism_C; // склдываем квадраты измерений
  }
   
  
   
    sqrtUsum_A = sqrt(Usumm_A); //вычисляем квадратный корень из суммы квадратов
    real_U_A = 0.104 * sqrtUsum_A; //вычисляем реальное напряжение для фазы А
    /*для фазы В */
    sqrtUsum_B = sqrt(Usumm_B); //вычисляем квадратный корень из суммы квадратов
    real_U_B = 0.104 * sqrtUsum_B; //вычисляем реальное напряжение для фазы В
    /*для фазы С */
    sqrtUsum_C = sqrt(Usumm_C); //вычисляем квадратный корень из суммы квадратов
    real_U_C = 0.104 * sqrtUsum_C; //вычисляем реальное напряжение для фазы С
 
    cntr = 0;
  }
	



 
    if(millis()-time >50){
    // печатаем вторую строку
    Serial.print("A=");
    Serial.print(real_U_A);
    Serial.print("   ");
    Serial.print("B=");
    Serial.print(real_U_B);
    Serial.print("  ");
    Serial.println(cntr);
    
     time = millis();
    }
  
}
/*функция для чтения данных с АЦП*/	
word read_adc(byte adc_input)
{
         ADMUX=adc_input | (ADMUX & 0xF0);
//задержка для стабилизации входного напряжения
         delayMicroseconds(10);
//начинаем преобразование (ADSC = 1)
         ADCSRA |= (1<<ADSC);
         while((ADCSRA & 0x10)==0); //ждем, пока АЦП закончит преобразование (ADIF = 0)
        ADCSRA|=0x10;//устанавливаем ADIF
        return ADCW;//ADCW - содержит ADCH и ADCL как нам нужно
}





	//****************обработчик прерывания********************
	
ISR(TIMER2_COMPA_vect) 
	
{  
           
  if (cntr<=99)     
 {
   cntr++; // увеличиваем счетчик на 1 с каждым тактом!
   /*для фазы A */
  Umass_A [cntr] = read_adc(ADC1); // считываем значения с аналогового порта 1 и сохранием в массив
  
  /* для фазы B */
  Umass_B [cntr] = read_adc(ADC2); // считываем значения с аналогового порта 2 и сохранием в массив
  
 /* для фазы С */  
  Umass_C [cntr] = read_adc(ADC3); // считываем значения с аналогового порта 3 и сохранием в массив
  
  
  
                }
          else  
          {
                   TIMSK2 = 0b00000000; // останавливаем таймер
          }
      }           

 

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

м/б при интегрировании для фаз Б и С время немного уходит и получается неточные результаты...

попробуйте поэксперементировать: в ISR считывайте первой, например, фазу В... Если она будет точно считаться, а остальные с ошибкой, то тогда точно чо нить со временем

DimaP.
Offline
Зарегистрирован: 21.04.2013

Да именно так и происходит если меняещь в ISR  последовательность считывания точость вырастает именно на той фазе которая читается первая! Это немного расстраивает!

А как вы думаете если взять ADC_vect и последовательно считывать фазы !  тоесть сначала фазу А -набил массив перешел к фазе B ну и так далее !! Как бы это програмно реализовать, прерывание по таймеру все равно же нужно чтобы сделать 100 измерений за период!!

Snubist
Offline
Зарегистрирован: 18.02.2013

А если типа такого? 

ISR(TIMER2_COMPA_vect) 
	
{  
  // put your main code here, to run repeatedly: 
boolean A=false, B=false, C=false;           
  if (cntr<=99 && !A)     
 {
   cntr++; // увеличиваем счетчик на 1 с каждым тактом!
   /*для фазы A */
  Umass_A [cntr] = read_adc(ADC1); // считываем значения с аналогового порта 1 и сохранием в массив
 }
cntr=0;
A=!A;
  if (cntr<=99 && !B)     
 { 
  /* для фазы B */
  Umass_B [cntr] = read_adc(ADC2); // считываем значения с аналогового порта 2 и сохранием в массив
 }
cntr=0;
B=!B;
  if (cntr<=99 && !B)     
 { 
/* для фазы С */  
  Umass_C [cntr] = read_adc(ADC3); // считываем значения с аналогового порта 3 и сохранием в массив
 }
C=!C;
   if (A && B && C)  
          {
                   TIMSK2 = 0b00000000; // останавливаем таймер
          } 
}

 

Только переменную cntr надо нормально обрисовать.

Michal
Michal аватар
Offline
Зарегистрирован: 26.04.2013

можно с loop передовать в ISR номер канала для считывания. В ISR будет считываться только заданный канал

DimaP.
Offline
Зарегистрирован: 21.04.2013

Решил я снова взяться за это гиблое дело,  набросал вот тут примерно как можно последовательно считывать каналы АЦП, подскажите может есть у кого более практичный метод?

/* переменные работающие в обработчике прерывания */
volatile int Umass_A [100]; //масив переменных для хранения мгновенных напряжений фазы А

volatile int Umass_B [100]; //масив переменных для хранения мгновенных напряжений фазы B

int Usumm_A=0;

volatile int counter = 0; // счетчик в обработчике прерывания

volatile int counter_A = 0; // счетчик в обработчике прерывания

volatile int counter_B = 0; // счетчик в обработчике прерывания

int ADC0 = 0; // аналоговый вход 0 для переменной Ucor!

#define ADC1    1  
#define ADC2    2

int flag = 0;



unsigned long timeOut = 0;// переменная для хранения времени!!!


void setup()
{
    TIMSK2 = 0b00000000;         // запрещение прерывания по совпадению таймера/счетчика Т2  
    TCCR2A = 0b00000100;       // режим работы СТС
    TCCR2B = 0b00000011;     // предделитель на 32
    ASSR &= ~(1<<AS2);    // Выбор источника синхронизации таймера(от системного генератора
                                         
    OCR2A = 100;           // срабатывание таймера 16000000/32/100=5000 раз в секунду 100 раз за секунду
    
    ADMUX = (0<<REFS1)|(1<<REFS0)|(0<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
    ADCSRA = 0b10000111;
                    
     Serial.begin(9600);
    
}
void loop()
{
  switch(counter)
  {
    case 0:
    flag = 1;
    break;
    case 100:
    flag = 2;
    break;
    case 200:
    flag = 3;
    break;
   }
   
   if(millis()-timeOut > 300)
     {
       timeOut = millis();
       TCNT2 = 0x00; // перезарежаем
       TIMSK2 |= (1<<OCIE2A);
       
      }
   
   
   if(counter == 300)
   {
    
     
     for(int i = 0; i<99; i++)
     {
       // выводим массивы и считаем математику
    
     
     counter =0;
     counter_A = 0;
     counter_B= 0;
     }
     
  
    
  
   
}

word read_adc(byte adc_input)
{
         ADMUX = adc_input | (ADMUX & 0xF0);
//задержка для стабилизации входного напряжения
         delayMicroseconds(10);
//начинаем преобразование (ADSC = 1)
         ADCSRA |= (1<<ADSC);
         while((ADCSRA & 0x10)==0); //ждем, пока АЦП закончит преобразование (ADIF = 0)
        ADCSRA|=0x10;//устанавливаем ADIF
        return ADCW;//ADCW - содержит ADCH и ADCL как нам нужно
}




	//****************обработчик прерывания********************
	
ISR(TIMER2_COMPA_vect) 
	
{  
 counter++; // увеличиваем счетчик на 1 с каждым тактом!          
  if (flag == 1)     
 {
   counter_A++;
  
  Umass_A[counter_A] = read_adc(ADC1);
   
 }
 if(flag == 2)
 {
   counter_B++;
   Umass_B[counter_B]=read_adc(ADC2);
   
 
 }
 
  
  
 
         if(counter == 300) 
          {
                   TIMSK2 = 0b00000000; // останавливаем таймер
          }
 }           

 

вот такое чудо родилось в моем мозге(

BIG_k
Offline
Зарегистрирован: 21.09.2013

Вроде ТАКОЙ большой и уважаемый форум, а FAQ или результата под такую типовую задачу для РФ - НЕТ ((

 Не мог ли бы поделиться актуальной информацией по данному вопросу ?

 

Bagunda
Offline
Зарегистрирован: 04.04.2012

BIG_k пишет:

результата под такую типовую задачу для - НЕТ ((

Вот +1. Не понятен конечный результат

Keeper-Volok
Keeper-Volok аватар
Offline
Зарегистрирован: 10.06.2016

BIG_k пишет:
FAQ или результата под такую типовую задачу для РФ - НЕТ ((

Ну так в английском форуме есть )

BIG_k пишет:
актуальной информацией по данному вопросу ?

Актуально - использовать специальные шилды от LC Technology с трансформатором ZMPT101B и ОУ (~200 ք на али)
Выход с ОУ возвращает пропорциональную синусоиду, относительно опорного напряжения (подстраивающегося многооборотным резистором)

Или использовать специальные интегрирующие АЦП по SPI, типа ADE7758.
Но к ним требуется нормальная обвязка, желательно прецизионного качества.

ra9ane
Offline
Зарегистрирован: 01.11.2016

Здравствуйте, прочитал ветку форума, у меня то же есть желание что то придумать с 3 фазами, но задумка не много другая переключать аналоговые входы и выводить с интервалом 3 секунды каждую из фаз, но в программировании не силен, понахватал чужого кода и слепил вольтметр с выводом на ТМ1637, как переключать входы не знаю,

/*Подключаем библиотеку*/
#include "TM1637.h"
/*Определяем пины подключения*/
#define CLK 3
#define DIO 2
TM1637 tm1637(CLK, DIO);
/* переменные работающие в обработчике прерывания */
volatile int Umass_A[101]; //масив переменных для хранения мгновенных напряжений фазы А
int Ucor = 0;
long Uism_A = 0; // переменная для хранения измеренного напряжения и квадрата фазы А
long Usumm_A = 0; // переменная для хранения сумм квадратов фазы А 
volatile byte counter = 0; // счетчик в обработчике прерывания
int ADC0 = 0; // аналоговый вход 0 для переменной Ucor!
int ADC1 = 1;
#define ADC1    1  
volatile byte flag = 0;
/* переменные для усреднения напряжений*/
float sqrtUsum_A = 0;
int real_U_A = 0;
float coff = 0.138;
unsigned long timeOut = 0;// переменная для хранения времени!!!

void setup()  {   
      /*Инициализация дисплея*/
  tm1637.init();
  tm1637.set(BRIGHT_TYPICAL);  
    TIMSK2 = 0b00000000;         // запрещение прерывания по совпадению таймера/счетчика Т2  
    TCCR2A = 0b00000010;       // режим работы СТС
    TCCR2B = 0b00000011;     // предделитель на 32
    ASSR &= ~(1<<AS2);    // Выбор источника синхронизации таймера(от системного генератора
    OCR2A = 98;                                     
               // срабатывание таймера 16000000/32/100=5000 раз в секунду 100 раз за секунду   
    ADMUX = (0<<REFS1)|(1<<REFS0)|(0<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
    ADCSRA = 0b10000111;
    Serial.begin(9600);   
}

void loop()
{  
   if(millis()-timeOut > 400)
     {
       timeOut = millis();     
         metod();      
      }   
   if(flag == 3)
   {
     for ( int i = 1; i<101; i++)
     {  
       Uism_A =  Umass_A [i];
       Uism_A -= Ucor;// убираем подьем синусоиды на 2 вольт     
       Uism_A *= Uism_A;
       Usumm_A += Uism_A;      
      }
      sqrtUsum_A = sqrt(Usumm_A); //вычисляем квадратный корень из суммы квадратов
      real_U_A = coff * sqrtUsum_A; //вычисляем реальное напряжение для фазы А    
       Usumm_A = 0;
       counter = 0;
       flag = 0;    
       Serial.println(real_U_A);
  /*Вывод чисел массива на дисплей*/
  int digitV = real_U_A/1000;      // После деления на 1000 остаётся разряд тысяч.
  int digitoneV = real_U_A/100%10;   // После деления на 100 остаётся разряд сотен. 
  int digittwoV = real_U_A/10%10; // Выделяем разряд. десятков.
  int digitfriV = real_U_A%10;     // Выделяем разряд единиц.
     //Выводим массив на дисплей
  tm1637.display(0, digitV);
  tm1637.display(1, digitoneV); 
  tm1637.display(2, digittwoV);
  tm1637.display(3, digitfriV);
  delay(1000);       
   }
}
   
void metod()
{
   Ucor = analogRead(ADC0);   
   TIMSK2 |= (1<<OCIE2A); // разрешаем прерывание
   while(flag<3);
   TIMSK2 = 0b00000000; // останавливаем таймер     
}
word read_adc(byte adc_input)
{
         ADMUX = adc_input | (ADMUX & 0xF0);//задержка для стабилизации входного напряжения  
//начинаем преобразование (ADSC = 1)
         ADCSRA |= (1<<ADSC);
         while((ADCSRA & 0x10)==0); //ждем, пока АЦП закончит преобразование (ADIF = 0)
        ADCSRA|=0x10;//устанавливаем ADIF
        return ADCW;//ADCW - содержит ADCH и ADCL как нам нужно
}  
  //****************обработчик прерывания********************
ISR(TIMER2_COMPA_vect)  
{  
  counter++;
  if((counter<= 100)&&flag == 0)
  {
    Umass_A[counter] = read_adc(ADC1);  
    if(counter == 100)
    {
      flag = 3;
      counter = 1;
    }
  }
} 

планирую подключит как на рисунке фаза А-А0,А1; В-А2,А3; С-А4,А5. Буду благодарен если поможете.snimok_10.png

Buldakov
Offline
Зарегистрирован: 17.01.2016

Ну сразу первый вопрос? А операционники от чего питаются? +/- 5в или +/- 15в. R48 и R49 должны быть желательно одного номинала. Конденсатор С6 можно выкинуть. Все резисторы желательно с допуском лучше 1%. А что такое W3? Непонятно ни вам , ни многим. Ну и вывод 13 и 12 ставим диодики на плюс /минус источник питания ОУ. Аналогично D7 D8. А то отвалится W3 и С8 и на выв 13 ОУ будет 220в. Она может и не пережить.

Ну а код примерно такой:

analogReference(DEFAULT);                 //Задаем работу АЦП от +5в                                    //
ADCSRA |= ((1 << ADPS2)|(1 << ADPS1));    //Биты ADPS2 и ADPS1 =1 коэффициент деления АЦП 64            //
ADCSRA &= ~ (1 << ADPS0);                 //Биты ADPS0 =0                                               //


//---Настройка таймера 1--------------------------------------------------------------------------------//
TCCR1A  = 0;TCCR1B = 0;TCNT1  = 0;                                                                      //
TCCR1B  = (1<<WGM12);                     // Режим CTC (сброс по совпадению)                            //
TCCR1B |= (1<<CS10);                      // Тактирование от CLK.                                       //
OCR1A=3199;                               // Отсчитать 3 200 тактов до прерывания F= 5000 гц.           //
TIMSK1 |= (1 << OCIE1A);                  // Разрешить прерывание по совпадению                         //


//---Начало прерывания по таймеру 1---------------------------------------------------------------------//
ISR (TIMER1_COMPA_vect){                                                                                //
ovf_tic_timer_1_int=ovf_tic_timer_1_int+1;//считать количество переполнений таймера 1                   //
temp_analog_in=analogRead(0);                                                                           //

 

ra9ane
Offline
Зарегистрирован: 01.11.2016

Спасибо за ответ и советы по улучшению схемы входных операционников, посмотрел код и не увидел как будут переключаться аналоговые входа А0-А1, А2-А3, А4-А5. Идея как раз чтобы измерять каждую из фаз по отдельности и выводить на индикатор в первом разряде фазу А,В,С, а далее напряжение на каждой фазе.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Идея простая. Самое большое время при использовании АЦП это время преобразования. Это время задается битами Биты ADPS2 и ADPS1. обычно время преобразования достаточно долгое. Если опрашиваем каждые 5000 раз в секунду то время должно быть 200 мкс. Поскольку каналов 6 (2 канала на 3 фазы)  то в итоге время измерения не более 30 мкс. Но при этом контроллер не будет больше ничего делать. необходимо сюда прибавить время усреднения данных (для ускорения усреднение делать только для целых чисел напряжения а не для уровней считывания с АЦП)

Поэтому вижу только способ реализации:

1. Определяем переход каждой фазы через нулевое напряжение и это делаем не реализуя контроллер, а обычные детали. Например определили, когда фаза А переходит через ноль. При этом не должно производиться никаких вычислений типа усреднения или вывода на экран. По этому сигналу считываем в буфер 100 значений отсчетов одного периода сетевого напряжения. На этом фазу А заканчиваем. Повторяем после этого все это для фаз В и С. Далее мы получили 3 буфера со значением со входов АЦП. Преобразуем значение напряжение на АЦП в мгновенное напряжение. Далее это напряжение приводим к целому числу. Находим определенный интеграл для этих целых чисел. (усреднение). Выводим значение среднего напряжения на экран или делаем еще что то. После того, как это закончится определяем переход фазы через ноль и повторяем все заново.

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

3. Использовать рэле напряжения уже готовое.

http://electricalschool.info/relay/1691-kak-rabotajut-ustrojjstva-avtoma...

 

nik182
Offline
Зарегистрирован: 04.05.2015

Какой интересно альтернативный взгляд на вольтметр. Пиковым детектором измерить можно только синусоидальное напряжение, чего в наших сетях нет никогда. Поэтому только RMS , что бы обеспечить более менее приемлемую точность. Для RMS необходимо иметь точки через равные промежутки времени и при этом скорость АЦП совершенно не играет роли. Можно обойтись analogRead и снимать точки сразу для трех каналов. Расчёт RMS самая долгая процедура. МК лучше взять помощнее - stm32f4xx или esp32. Именно здесь хорошо виден принцип - выбор MK под задачу, а не сделать на том, что есть.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Поскольку ставилась задача отключать нагрузку при превышении напряжения то пиковый детектор в данном случае подойдет. Раньше, когда не было импульсных блоков питания форма сигнала была почти синус. Теперь она в основном срезает верхушки синуса. Вероятнее всего автор будет использовать для какой нибудь зашиты. Допустим амплитуда напряжения составит 310в , а RMS в зависимости от формы сигнала составит 210 или 230в. Зачем в данном случае измерять RMS если конденсатор сетевого фильтра все равно зарядится до 310в? А это уже пиковое значение. А пиковый детектор в простейшем случае это диодный мостик , кондненсатор и резисторный делитель.

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

nik182
Offline
Зарегистрирован: 04.05.2015

Пиковый детектор в реле напряжения это тоже плохо. Он будет срабатывать на каждый чих. Отключать нагрузку нужно если превышение напряжения остаётся несколько (от 5 до 10 в зависимости от нагрузки) периодов сети. Если есть МК, который может и RMS и количество периодов посчитать, зачем дополнительные МС, да ещё дорогие?

Buldakov
Offline
Зарегистрирован: 17.01.2016

Так это и очень хорошо, что на каждый чих. Возьмем к примеру - 1 случай - RMS = 220в а пиковое напряжение 300в. - 2 случай RMS= 220в а пиковое напряжение 400в. Во втором случае у вас все сгорит, хотя RMS и в первом и втором случае одинаково.

А по поводу специальных микросхем. это на все воля автора. Может у него их целая куча? А самое простое сделать вариант из 1 поста. Только там автор мерил переменку, а надо постоянку. Поставить , например 3 нестабилизированных блока питания (например от модема) для гальванической развязки. и мерить напряжение на трех выходах.

nik182
Offline
Зарегистрирован: 04.05.2015

Buldakov пишет:

Так это и очень хорошо, что на каждый чих. Возьмем к примеру - 1 случай - RMS = 220в а пиковое напряжение 300в. - 2 случай RMS= 220в а пиковое напряжение 400в. Во втором случае у вас все сгорит, хотя RMS и в первом и втором случае одинаково. ...

Может быть мы про разный RMS говорим? RMS рассчитывается для каждого периода сети. Даже лампа накаливания спокойно переносит несколько периодов сети с превышением напряжения процентов на 40 - 50. То что описали вы называется импульсное превышение, например от молнии попавшей в линию. От такого не спасёт ни RMS ни пиковый детектор. На защиту от импульсных напряжений ставят варисторы, снабберы и прочие элементы схемотехники. 

Buldakov
Offline
Зарегистрирован: 17.01.2016

Я пишу тут про то, что если мы имеем электрическую сеть - то для нее есть прямая зависимость между RMS и амплитудой напряжения. Если растет амплитуда то и растет RMS. И вот это и нужно использовать. Если хотим срабатывание в диапазоне 10% - то и к погрешности RMS надо подходить с такой же точностью. Тот же самый контроллер вместо сложного и точного измерения RMS может просто измерить амплитуду, а потом это преобразовать в RMS. Поскольку точность в 1-2% тут не важна.

Тут же не ставится задача измерить RMS с точностью 0.1%. Для этого есть другие средства.

nik182
Offline
Зарегистрирован: 04.05.2015

Извините, но какое у Вас образование? Ваши ответы не соответствуют ни ПУЭ ни здравому смыслу. Ну никак нельзя пересчитать амплитуду в RMS и обратно для не синусоидального напряжения. Тем более что все специализированные на измерения МК из серии msp430 измеряют переменные ток и напряжение только через RMS. Вы предлагаете упрощения процесса измерений которые отрицательно влияют на точность. Если Вас устраивает - пожалуйста. Но не надо других учить плохому.    

ra9ane
Offline
Зарегистрирован: 01.11.2016

У меня задумка не много другая переключать аналоговые входы и выводить с интервалом 3 секунды каждую из фаз, но в программировании я не силен. Реально это воплотить или не стоит репу морщить.

nik182
Offline
Зарегистрирован: 04.05.2015

Не надо фазы переключать через секунды. Нужно подсоединить три фазы к трём аналоговым входам и почти одновременно, последовательно с задержкой на переключение входов, несколько десятков микросекунд считывать значение напряжений трёх фаз. И выводить их на дисплей одновременно. А можно ещё рассчитать разность напряжений и предупреждать о перекосе фаз.

ra9ane
Offline
Зарегистрирован: 01.11.2016

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ra9ane пишет:

 но вычисления проводить в одном цикле с выводом на индикатор, рассчитало фазу А вывело на индикатор, далее фазу В вывело на индикатор, далее фазу С вывело на индикатор.

Ну так именно это и есть ошибка проектирования, о чем nik182 совершенно справедливо заметил.

ra9ane
Offline
Зарегистрирован: 01.11.2016

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

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ra9ane пишет:

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

Сергей, проще надо, переключатель и вольтметр переменного тока )))

slider
Offline
Зарегистрирован: 17.06.2014

Ого на сколько тему растянули.

Что строите , для чего точный 3х фазный вольтметр ?

Черкну тогда свой опыт.

на входах по диоду, резистивному делителю из четырёх последовательно 0805 типоразмеров резисторов + резистор, конденсатор.

Сначала попробовал так: 
1.вариант :  чтобы быстро измерить 3 фазы , и пулять данные по юарту (гальвано-развязка ADUM1201ARZ) каждые 0.5сек как в мультиметре. и выводить на свой  OLED дисп : 
т.к. напряжение  меняется по синусу относительно медленно =20мс ,  то АЦП измерял поочередно по 3м каналам, задержка, снова по 3м каналам, задержка,... , в итоге за 20мс  атмега328 успевала промерить сразу 3 фазы, по очень много раз. данные заносились в 3 массива. Применял ускорение analogRead() . Для стабильноcти показаний , промерял не 20мс, а 200мс 

 

.........
#define A0_Read (AnRead(B01000000))
#define A1_Read (AnRead(B01000001))
#define A2_Read (AnRead(B01000010))
.............

 void loop() 
{
........
     valueinL1 =  A0_Read; 
     valueinL2 =  A1_Read; 
     valueinL3 =  A2_Read; 
...............
}

// из либы CyberLib  , ускорение аналогового опроса . // но что то  выдает шум
uint16_t AnRead(uint8_t An_pin)
{
  ADMUX=An_pin;   
  delayMicroseconds(10);	  
  ADCSRA=B11000110;	//B11000111-125kHz B11000110-250kHz 
  while (ADCSRA & (1 << ADSC)) {};
  An_pin = ADCL;
  uint16_t An = ADCH; 
  return (An<<8) + An_pin;
}

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

2й вариант: без массивов, искал попадающее максимальное амплитудное значение (было около 300-310в) , фильтр ( те значения которые чаще попадались , им присваивался больший вес, и они имели более доверение)  . Амплитудное значение делил на 1.41 и получал действующее 220в . 
Проблема возникла при кривом синусе. Это если взять бесперебойник с кривым синусом, то этот вольтметр покажет 180-190в, как и дешёвый китайский мультиметр.  Т.е. днём когда офисы компы работают, синус с обрезанными верхушками . А вечером уже другие показания. Выход - домножить результаты на чуть чуть , чтобы угождало и дню и вечеру. 

3й вариант, окончательный : библиотек EmonLib.h, она не только считает TrueRMS тока, но и напряжение. 
заменил стаб 5в на MIC5202 т.к. у него  1% точность и вывозит 16в (т.е. питать можно через дешёвые гальвано-развязывающие DC-DC 12в-12в т.к. 12в-9в дороже) , в отличии от внутреннего  ИОН 10% 1.0-1.2в ( при серийной сборке не вариант 10% ) .
Резисторы в делителе применили 0.1% . 

В будущем надо попробовать внешний, какой нибудь дешевый ширпотребный ИОН из REF1912,048. ,  REF192. 2,50. ,   REF193. 3,00. REF194. 4,50.,   REF195. 5,00.,   REF196. 3,30. ,   REF198. 4,096  

// есть ещё ADR02ARZ с точностью 0.1% , температура -40 +125 . Стабы MCP1754S и им подобные с точностью 0.4% уже и не нужны. М.б. важнее уже малошумящие стабы, или уделить внимание правильной развязке у AREF и AVCC .