20.09.2018 г.
Главная
Проекты
Статьи
Начинающим
Архив новостей
Ссылки
Контакты
Поиск
Файлы
Форум
Карта сайта
Авторизация





Забыли пароль?
Ещё не зарегистрированы? Регистрация
Поддержи наш сайт!
Через WebMoney

 R785211844650
 Z210696637574
 E368177590409

Простые устройстваОтличные товары по превосходным ценамОтличные товары по превосходным ценам
Форум ARV Research
Добро пожаловать, Гость
Пожалуйста Вход или Регистрация.
Забыли пароль?
Измерение действующего значения напряжения (RMS) (1 просматривает)
_GEN_GOTOBOTTOM Ответить

TOPIC: Измерение действующего значения напряжения (RMS)

#8875
vadeg (Пользователь)
Новичок
Постов: 7
graphgraph
Измерение действующего значения напряжения (RMS) 12.10.2017 00:19 Репутация: 0  
Вопрос по статье Измерение действующего значения напряжения
Роман Викторович, как это у вас так получилось, что последняя цифра не дрыгается +/-3В? Я понимаю, статью вы писали, чтобы мы работали мозгами, но я сдаюсь. Сколько видел реализаций этого алгоритма на разных индикаторах - везде последняя цифра дрыгалась. Попробовал сделать усреднение 64-х замеров, но без толку. Код не мой, но я его изучил и сейчас работаю с ним, т.к. там только вольтметр и ничего лишнего. Вроде все правильно, но видимо что-то я не учитываю.
Code:

 #include <mega8.h> #include <delay.h> // Alphanumeric LCD Module functions #asm .equ __lcd_port=0x12 ;PORTD #endasm #include <lcd.h> #include <stdio.h> #include <math.h>                           // // #define F_OSC 8000000UL #define F_LINE 50 // 50 Герц измеряем #define N_IZM 200 // 200 выборок за период #define F_MEASURE  F_LINE * N_IZM // устанавливаем частоту на 1 таймер без пределителя 50*200 Hrz #define TMR1_CALCULATE 65535 - (F_OSC/F_MEASURE) #define ADC_VREF_TYPE 0x40 #define U_OPORN 5000 // напряжение опоры в милливольтах #define  KF 131 // volatile struct {     unsigned char cCounter;     unsigned int iArr[N_IZM];     unsigned int iRez;     char cReady; }sMeasure; unsigned long lRez; unsigned char lcd_buffer[16]; unsigned int  Urms=0; // void fn_SetMeas(void); unsigned int read_adc(unsigned char adc_input); unsigned int fn_Calculate(void); //----------------------------------------------- interrupt [TIM1_OVFvoid timer1_ovf_isr(void) {     TCNT1+=TMR1_CALCULATE;     if(sMeasure.cReady)     {         sMeasure.iArr[sMeasure.cCounter]= read_adc(0);         sMeasure.cCounter++;         if(sMeasure.cCounter >= N_IZM){sMeasure.cReady=0;}     } } //----------------------------------------------- void main(void) {     // Declare your local variables here     // Input/Output Ports initialization     // Port B initialization     // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In     // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T     PORTB=0x00;     DDRB=0x00;     // Port C initialization     // Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In     // State6=T State5=T State4=T State3=T State2=T State1=T State0=T     PORTC=0x00;     DDRC=0x00;     // Port D initialization     // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In     // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T     PORTD=0x00;     DDRD=0x00;     // Timer/Counter 0 initialization     // Clock source: System Clock     // Clock value: Timer 0 Stopped     TCCR0=0x00;     TCNT0=0x00;     // Timer/Counter 1 initialization     // Clock source: System Clock     // Clock value: 8000,000 kHz     // Mode: Normal top=FFFFh     // OC1A output: Discon.     // OC1B output: Discon.     // Noise Canceler: Off     // Input Capture on Falling Edge     // Timer1 Overflow Interrupt: On     // Input Capture Interrupt: Off     // Compare A Match Interrupt: Off     // Compare B Match Interrupt: Off     TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);     TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);     TCNT1=TMR1_CALCULATE;     ICR1H=0x00;     ICR1L=0x00;     OCR1AH=0x00;     OCR1AL=0x00;     OCR1BH=0x00;     OCR1BL=0x00;     // Timer/Counter 2 initialization     // Clock source: System Clock     // Clock value: Timer2 Stopped     // Mode: Normal top=FFh     // OC2 output: Disconnected     ASSR=0x00;     TCCR2=0x00;     TCNT2=0x00;     OCR2=0x00;     // External Interrupt(s) initialization     // INT0: Off     // INT1: Off     MCUCR=0x00;     // Timer(s)/Counter(s) Interrupt(s) initialization     TIMSK=0x04;     // Analog Comparator initialization     // Analog Comparator: Off     // Analog Comparator Input Capture by Timer/Counter 1: Off     ACSR=0x80;     SFIOR=0x00;     // ADC initialization     // ADC Clock frequency: 1000,000 kHz     // ADC Voltage Reference: AVCC pin     ADMUX=ADC_VREF_TYPE 0xff;     ADCSRA=0x83;     // LCD module initialization     lcd_init(16);     // Global enable interrupts #asm("sei")     fn_SetMeas();     while (1)     {                 if(!sMeasure.cReady)         {             sMeasure.iRezfn_Calculate();             lRez=(unsigned long)sMeasure.iRez U_OPORN;             lRez*=KF;             lRez+=512// снижаем ошибку целочисленного деления             lRez/=1024// делим в последнюю очередь             lRez+=500;// снижаем ошибку целочисленного деления             Urms=(unsigned int)(lRez/1000); // переводим в вольты               lcd_gotoxy(0,0);                sprintf(lcd_buffer," Urms=%03d",Urms);    //             lcd_puts(lcd_buffer);                    //             delay_ms(50);             fn_SetMeas();         };     }; } /* Во время прихода положительной полуволны запускается АЦП, Который успевает за время прохождения  этой полуволны сделать порядка 100 выборок, которые обрабатываются по формуле: Urms= sqrt(1/T* S[u(t)*u(t)]dt, где: sqrt - корень квадратный, S - интеграл за период времени от 0 до Т. Для дискретного способа взятия интеграла формула упроститься до вида Urms=K*sqrt(1/N*sum(Uadc*Uadc)), Где: К - поправочный коэффициент, Uadc - значение на выходе АЦП, N - число выборок за время  прохождения полуволны синусоиды. */ void fn_SetMeas(void) {     sMeasure.cCounter=0;     sMeasure.cReady=1; } //------------------------------------------------ // Read the AD conversion result unsigned int read_adc(unsigned char adc_input) {     ADMUX=adc_input | (ADC_VREF_TYPE 0xff);     // Delay needed for the stabilization of the ADC input voltage     delay_us(10);     // Start the AD conversion     ADCSRA|=0x40;     // Wait for the AD conversion to complete     while ((ADCSRA 0x10)==0);     ADCSRA|=0x10;     return ADCW; } //------------------------------------------------ unsigned int fn_Calculate(void) {     unsigned long lRez=0;     unsigned long lKv;     unsigned char i;     for(i=0;i<N_IZM;i++)     {         lKv=(unsigned long)sMeasure.iArr[i]*(unsigned long)sMeasure.iArr[i];         lRez+=lKv;     }     lRez/=N_IZM;     return lsqrt(lRez); } //------------------------------------------------

  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
#8876
ARV (Администратор)
Администратор
Постов: 2384
graph
В ответ на: Измерение действующего значения напряжения (RMS) 16.10.2017 20:29 Репутация: 175  
Так в статье протеус - там все будет идеально. В реале же мой алгоритм так же дрыгался бы, как и у всех.
Что я могу предложить для уменьшения этих скачков... фильтруйте показания. Не просто усредняйте, а фильтруйте. Разница между средним и выходом фильтра в том, что среднее обновляет показания 1 раз за N выборок, а фильтр выдает N результатов. Самое простое - "скользящее среднее", я обычно им всегда пользуюсь.
Code:

 #define AVE_DEPTH   32 int filtr_average(int sample){    static int buf[AVE_DEPTH];    static int pos=0;    buf[pos++] = sample;    if(pos >= AVE_DEPTHpos 0;    long int sum 0;    for(int i=0AVE_DEPTHi++)       sum += buf[i];    return sum AVE_DEPTH;   }

Чем больше AVE_DEPTH, тем сильнее фильтрация. Разумно подбирать это значение из ряда степеней двойки, т.е. 4, 8, 16 и т.д., тогда деление будет наиболее быстрым. Тип данных int взят для примера, можно другие, разумеется.

На вход этой функции подаете семпл - на выходе то, что надо выводить на дисплей. Для RMS значения под фильтром следует понимать вычисленное очередное значение RMS.

Содержимое поста отредактировано: ARV, в: 16.10.2017 20:29
Не стыдно не знать, стыдно не учиться
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
_GEN_GOTOTOP Ответить
© Copyright 2007 Best of Joomla, Работает на FireBoardполучить последние сообщения прямо на Ваш рабочий стол