Zerknij w podglądzie, jaki jest odstęp między impulsami Energy_All_Duration. Jeżeli włączysz grzałkę (np. czajnik), to ta wartość powinna być z grubsza stała. Zapewne zobaczysz, że raz masz np. 450ms innym razem 530ms itd.
Przy dużych mocach/częstych impulsach (np. 2kW) pojawia się problem nieregularnego wykonania programu odpowiedzialnego za zliczanie energii. Sterownik obciążony zadaniami raz zajrzy do Twojego programu z opóźnieniem np. 30ms i już masz gotową różnicę w zmiennej Energy_All_Consum. W tym samym czasie wskazanie licznika będzie narastać prawidłowo, bo sterownik nie gubi impulsów tylko nieregularnie wykonuje obliczenia. Przy rzadkich impulsach różnica wskazań w Energy_All_Consum będzie niezauważalna.
W bloku IF dodaj jeszcze Energy_All_Meter := Energy_All_Meter + 0.001; żeby mieć wskazanie liczydła z licznika.
Rozwiązaniem jest wyliczenie zmiennej Energy_All_Consum raz na kilka impulsów i będzie jak należy. Idealnie w zależności od aktualnego poboru energii.
Miałem podobny problem z falownikiem, który bardzo szybko zmieniał wskazania produkcji i chciałem to uśrednić. Poniżej fragment kodu, który nakreśli Ci ogólną koncepcję.
IF ((PV_FroniusLicznik_Total-PV_FroniusLicznik_Total_prev) >= PV_FroniusCounterStep) THEN
PV_FroniusCounterChange := DWORD_TO_INT(PV_FroniusLicznik_Total-PV_FroniusLicznik_Total_prev);
PV_FroniusLicznik_CurrentAvg := REAL_TO_INT(3600000.0/PV_FroniusLicznik_Total_prev_duration * PV_FroniusCounterChange);
PV_FroniusLicznik_Total_prev := PV_FroniusLicznik_Total;
PV_FroniusLicznik_Total_prev_time := TIME();
(* spowolnienie usredniania jezli produkcja jest wysoka, a impulsy zbyt czeste *)
CASE (DWORD_TO_INT(PV_FroniusLicznik_CurrentAvg)) OF
0..800:
PV_FroniusCounterStep := 1;
801..1400:
PV_FroniusCounterStep := 2;
1401..2000:
PV_FroniusCounterStep := 3;
2001..3000:
PV_FroniusCounterStep := 4;
ELSE
PV_FroniusCounterStep := 5;
END_CASE;
END_IF;
W Twoim przypadku byłoby jakoś tak:
Energy_All_Trigger(CLK:=xIN_Licznik_Energii_All);
IF Energy_All_Trigger.Q THEN
Energy_All_Meter := Energy_All_Meter + 0.001;
END_IF;
IF (Energy_All_Meter - Energy_All_Meter_prev >= Energy_All_Meter_step / 1000) THEN
(*
Energy_All_Meter_prev := Energy_All_Meter;
tutaj wszystkie obliczenia
*)
CASE (DWORD_TO_INT(Energy_All_ConsumAvg)) OF
0..800:
Energy_All_Meter_step := 1;
801..1400:
Energy_All_Meter_step := 2;
1401..2000:
Energy_All_Meter_step := 3;
2001..3000:
Energy_All_Meter_step := 4;
ELSE
Energy_All_Meter_step := 5;
END_CASE;
END_IF;
Zwróć uwagę na typy zmiennych, ja trzymam liczniki w zmiennych REAL. Ponadto zmienna Energy_All_Meter powinna być w bloku VAR RETAIN PERSISTENT, żeby wskazania nie przepadały przy restartach.