I am doing 24 plug port power strip with 3 input plugs (each input plug controls one group of 8 receptacles of 24 plugs)
Basically I am doing power strip with 50Hz/120V input and I have 24 receptcles (each group is 8), like that 3 groups of eight receptacles in each strip, I am reading currents back from 24 receptacle relays, also I am reading 3 voltages, one from each group of eight receptacles. I am using 5 GPIO pins to select one of the receptacle (24 currents + 3 volatges + few for temperature), basically I have to read 24 currents, 3 voltage. 24 Instaneous currents, 3 Instaneous voltages, then I have to VI (voltage * current), also I have to calculate average voltage and current: total readings are:
Three Vrms from Three groups
8 * 3 = 24 rms currents + 3 boards + 1 total
28 Powers
28 VA (V rms * I rms)
28 PF (P / VA)
I have to do 840 samples per second to measure Instantaneous current and Instantaneous voltage. using them I have to calculate RMS Current and RMS voltage, then actual power (instantaneous current * instantaneous voltage), apparent power (RMS Current * RMS voltage), then Power factor ( actual power / apparent power).
I am using 5 GPIO pins (AN0 - AN4) select one at a time and AN7 to read the value. Please throw some ideas about real-time sampling (how can I do exactly real-time 840 samples per second).
Thanks.
TV.
The constant interval between the samples can be arranged by interrupt of free-running PIT.
The simplest implementation of the ISR takes set of the samples and messages the set to the upper level.
The following sequence of samples in the set provides pseudo-simultaneous sampling of U and I for calculation of power factor:
U0 I0 I1 ... I7 I7 I6 ... I0 U0
U1 I8 I9 ... I15 I15 I14 ... I8 U1
U2 I16 I17 ... I23 I23 I22 ... I16 U2
The average value of the two samples of the channel is related to the same time.
These averages are used to calculate instantaneous U*I and the further power factor.
Either first or second half of each line is used for calculation of Irms and Urms.
Quantity of such a sets must represent integer number of ~50 Hz mains voltage.
In case of CPU time between the samples needs to be used, PIT ISR needs only to trigger the first sample in the set. ADC ISR needs to read the ready sample from the ADC and to trigger the next sample. By read of the last sample in the set, the ADC ISR needs to message the set to the task of the upper level.
Thanks yevgenit.
If I set PIT ISR for 1ms (1000 samples per second, 1 / 1000 = 1 ms), in PIT ISRE I have a BOOL flag measure_instantaneous_sample = TRUE, in my main task which reads Ui (Inst volt) and Ii (Inst current), I have to check for that flag measure_instantaneous_sample == TRUE, then collect One instantaneous sample (U0, I0, I1.....I7), then set flag to FALSE and wait till PIT ISR triggers again to measure next sample. also once collect half of total samples which is 500 (1000 / 2 = 500) then calculate RMS current and RMS voltage (accumulation of squares of Inst currents and inst voltages, then average / 500 to get RMS) and then calculate powers and power factor. once calculated reset this count to zero again measure when this counter reached 500 again. earlier flag to take samples and this counter to calculate powers.
Now I have to see whether I can use one PIT for 1ms and just set the flag in PIT ISR, sothing doing except set the flag in ISR. the task resets this flag back and buffer those inst currents and voltages.
I'd recommend the following design. It is relatively sophisticated, but it provides more available CPU time.
Two buffers of 54 samples each are need: while the calculation task processes the granted buffer, the other buffer is fill with the samples in the background.
The complete set of samples in the just filled buffer is as the following:
U0 I0 I1 ... I7 I7 I6 ... I0 U0
U1 I8 I9 ... I15 I15 I14 ... I8 U1
U2 I16 I17 ... I23 I23 I22 ... I16 U2
Assuming constant time interval between samples in the set, the average value of the two samples of the channel is related to the same time.
PIT ISR triggers the ADC for first sample in the set. Then, PIT ISR returns.
ADC ISR reads first sample from ADC to the buffer. Then, ADC ISR triggers the ADC for the second sample. Then, PIT ISR returns.
Next ADC ISR reads second sample from ADC to the buffer. Then, ADC ISR triggers the ADC for third sample. Then, PIT ISR returns.
...
When ADC ISR reads and fills the last sample (54-th) of the set, it updates number of the just filled (and granted) buffer. Then, ADC ISR releases the semapfore, which locks the calculation task.
Such a way, the sampling is suspended until next PIT interrupt.
Unlocked calculation task must process the granted buffer before the next buffer is granted. After processing of the granted buffer, the calculation task again pends on the semaphore.
I'd recommend, that, the calculation task use the fixed quantity of ~50 Hz periods of the mains voltage, instead of the exact 0.5 seconds. Start of each ~50 Hz period of the mains voltage can be detected by zero crossing of one of the well filtered ~50 Hz voltages. Such the arrangement keeps the accuracy of the measurement for the actual mains frequency below 50 Hz. Moreover, natural automatic tuning to 60 Hz is implemented.
To further save CPU time I'd recommend to assign both the task stacks and the buffers in the SRAM.
Actually when I see above Three lines, I feel like I am sampling twice, I wanted to sample only once for every plug (measure PF twice in a second). I divided the above table into Half, I have to take minum 780 samples per second (60 * 7th harmonic is 420, double is 840), I wanted to go for 1000 samples per second, that is 1ms interval, I need to measure twice a second means for every 500 ms, then calculate powers.
U0 I0 I1 ... I7
U1 I8 I9 ... I15
U2 I16 I17 ... I23
This is my prog, I want to use GPT for 1ms interval, after 500ms, I need to measure PF for every 500ms. here buffers numbered from 1 to 24, also accumulators 1 to 24, buffers gets reqritten for every instantaneous, where accumulator gets overwrittem for every 500ms, i.e., after calculated all powers. GPT ISR sets flag (timer_isr_take_samling_flag), oncetask reads ADC readings, resets flag back after every instant. for power calculations I have local counter cheacks whether it is equal to 500 or not.
(I divided below prog into Two postings because of size)
(continuation from previous page)
if (measure_power_factor == 500) {
rms_volt1 = sqrt( (volt1_accu / (SAMPLE/2) ));
rms_curr1 = sqrt( curr1_accu / (SAMPLES/2) );
rms_curr2 = sqrt( curr2_accu / (SAMPLES/2) );
rms_curr3 = sqrt( curr3_accu / (SAMPLES/2) );
rms_curr4 = sqrt( curr4_accu / (SAMPLES/2) );
rms_curr5 = sqrt( curr5_accu / (SAMPLES/2) );
rms_curr6 = sqrt( curr6_accu / (SAMPLES/2) );
rms_curr7 = sqrt( curr7_accu / (SAMPLES/2) );
rms_curr8 = sqrt( curr8_accu / (SAMPLES/2) );
appa_pow1 = rms_curr1 * rms_volt1;
appa_pow2 = rms_curr2 * rms_volt1;
appa_pow3 = rms_curr3 * rms_volt1;
appa_pow4 = rms_curr4 * rms_volt1;
appa_pow5 = rms_curr5 * rms_volt1;
appa_pow6 = rms_curr6 * rms_volt1;
appa_pow7 = rms_curr7 * rms_volt1;
appa_pow8 = rms_curr8 * rms_volt1;
rms_volt2 = sqrt( (volt2_accu / (SAMPLE/2) ));
rms_curr9 = sqrt( curr9_accu / (SAMPLES/2) );
rms_curr10 = sqrt( curr10_accu / (SAMPLES/2) );
rms_curr11 = sqrt( curr11_accu / (SAMPLES/2) );
rms_curr12 = sqrt( curr12_accu / (SAMPLES/2) );
rms_curr13 = sqrt( curr13_accu / (SAMPLES/2) );
rms_curr14 = sqrt( curr14_accu / (SAMPLES/2) );
rms_curr15 = sqrt( curr15_accu / (SAMPLES/2) );
rms_curr16 = sqrt( curr16_accu / (SAMPLES/2) );
appa_pow9 = rms_curr9 * rms_volt2;
appa_pow10 = rms_curr10 * rms_volt2;
appa_pow11 = rms_curr11 * rms_volt2;
appa_pow12 = rms_curr12 * rms_volt2;
appa_pow13 = rms_curr13 * rms_volt2;
appa_pow14 = rms_curr14 * rms_volt2;
appa_pow15 = rms_curr15 * rms_volt2;
appa_pow16 = rms_curr16 * rms_volt2;
rms_volt3 = sqrt( (volt3_accu / (SAMPLE/2) ));
rms_curr17 = sqrt( curr17_accu / (SAMPLES/2) );
rms_curr18 = sqrt( curr18_accu / (SAMPLES/2) );
rms_curr19 = sqrt( curr19_accu / (SAMPLES/2) );
rms_curr20 = sqrt( curr20_accu / (SAMPLES/2) );
rms_curr21 = sqrt( curr21_accu / (SAMPLES/2) );
rms_curr22 = sqrt( curr22_accu / (SAMPLES/2) );
rms_curr23 = sqrt( curr23_accu / (SAMPLES/2) );
rms_curr24 = sqrt( curr24_accu / (SAMPLES/2) );
appa_pow17 = rms_curr17 * rms_volt3;
appa_pow18 = rms_curr18 * rms_volt3;
appa_pow19 = rms_curr19 * rms_volt3;
appa_pow20 = rms_curr10 * rms_volt2;
appa_pow21 = rms_curr11 * rms_volt2;
appa_pow22 = rms_curr12 * rms_volt2;
appa_pow23 = rms_curr13 * rms_volt2;
appa_pow24 = rms_curr14 * rms_volt2;
power_fact1 = power1_accu / appa_pow1;
power_fact2 = power2_accu / appa_pow2;
power_fact3 = power3_accu / appa_pow3;
power_fact4 = power4_accu / appa_pow4;
power_fact5 = power5_accu / appa_pow5;
power_fact6 = power6_accu / appa_pow6;
power_fact7 = power7_accu / appa_pow7;
power_fact8 = power8_accu / appa_pow8;
power_fact9 = power9_accu / appa_pow9;
power_fact10= power10_accu / appa_pow10;
power_fact11 = power11_accu / appa_pow11;
power_fact12 = power12_accu / appa_pow12;
power_fact13 = power13_accu / appa_pow13;
power_fact14 = power14_accu / appa_pow14;
power_fact15 = power15_accu / appa_pow15;
power_fact16 = power16_accu / appa_pow16;
power_fact17 = power17_accu / appa_pow17;
power_fact18 = power18_accu / appa_pow18;
power_fact19 = power19_accu / appa_pow19;
power_fact20 = power20_accu / appa_pow20;
power_fact21 = power21_accu / appa_pow21;
power_fact22 = power22_accu / appa_pow22;
power_fact23 = power23_accu / appa_pow23;
power_fact24 = power24_accu / appa_pow24;
/* set to zero, since 50 samples are equal to Half-Second */
measure_power_factor = 0;
/* reset all accumulatos */
curr_18_AT = 0;
curr_9_16_AT = 0;
curr_17_24_AT = 0;
pow_18_AT = 0;
pow_9_16_AT = 0;
pow_17_24_AT = 0;
} /* if (measure_power_factor == 50) */
} /* main_task */