📄 obliczenia.asm
字号:
;==============================================================================
; Liczenie wartosci RMS z zebranych probek pradu i napiecia
; Obliczanie mocy, wpolczynnika mocy i czestotliwosci
; Projekt: Miernik energii i mocy na ADE7759
;==============================================================================
;.listmac
; r0, r1, r2 -rejestry operacyjne, r2=0
; akumulator kwadratow probek pradu
;.def i_suma5:0 =r9::r4
; akumulator kwadratow probek napiecia
;.def u_suma5:0 =r15::r10
;.def n5:0 =r15::r10 deklaracja w PIERW_48
; r16 =temp, r17 =flagi
;.def kwd5::0 =r23::r18 ; deklaracja w int2.asm
;.def en6::en0 =r24::r18 ; w int0.asm
;.def prb2 =r26 ;
;.def prb_znak =r27 ; rejestr X
;.def spi_bufor =r28
;.def okresow =r29 ; rejestr Y
;.def probek0 =r30
;.def probek1 =r31 ; rejestr Z
.cseg
;------------------------------------------------------------------------------
OBLW_I: clr n1
sub p0, n0
sbc p1, n1 ; kompensacja offsetu
brcc OBI_1
clr p0
clr p1 ; wystapila pozyczka czyli przekrecenie rejestrow
OBI_1: lds n0, Wsp_I
lds n1, Wsp_I+1 ; zaladuj Wsp_I
rcall MUL_16_16 ; kwd3::0 = p1:p0 x Wsp_I
ret ; r21::r18 = r25::r24 x r11:r10
;--------------------------------------
OBLW_U: clr n1
lsl n0
rol n1 ; *2 aby zwiekszyc zakres korekcji
sub p0, n0
sbc p1, n1
brcc OBU_1
clr p0
clr p1 ; wystapila pozyczka czyli przekrecenie rejestrow
OBU_1: lds n0, Wsp_LPF1
lds n1, Wsp_LPF1+1 ; zaladuj Wspolczynnik
rcall MUL_16_16 ; kwd3::0 = p1:p0 x Wsp_LPF1
; r21::r18 = r25::r24 x r11:r10
clr kwd4
lsl kwd0
rol kwd1
rol kwd2
rol kwd3
rol kwd4 ; razy 2
movw p0, kwd2
mov p2, kwd4 ; kopia trzech starszych bajtow do mnoznika
lds n0, Wsp_U
lds n1, Wsp_U+1 ; zaladuj Wsp_U
rcall MUL_24_16 ; kwd4:0 = p2::p0 x Wsp_U
ret ; r22::r18 = r26::r24 x r11:r10
;--------------------------------------
MAV_LDUI: ld n0, y+
ld n1, y+
ld n2, y+
ld n3, y+
clr n4
clr n5
rcall DIV_48_16
movw p0, n0
ret
;--------------------------------------
AMP_LDI: ld p0, y+
ld p1, y+
sbrc temp, f4KAL_ZI ; przeskocz jesli wyzerowany bit kalibracji zera
sts Off_Ia_z, p0 ; zapisz wartosc probki jako offset zera
lds n0, Off_Ia_z ; offset zera ampl
rcall OBLW_I
st z+, kwd2
st z+, kwd3
ret
AMP_LDU: ld p0, y+
ld p1, y+
sbrs temp, f4KAL_ZU ; przeskocz jesli ustawiony bit kalibracji zera
rjmp AU_N
lsr p0
sts Off_Ua_z, p0 ; zapisz wartosc probki jako offset zera
AU_N: lds n0, Off_Ua_z ; offset zera ampl
rcall OBLW_U
st z+, kwd2
st z+, kwd3
ret
;==============================================================================
OBLICZENIA:
;==============================================================================
;RMS_U: ; procedura liczenia RMS napiecia
; MUSI byc liczone przed RMS_I
lds temp, Flagi4
rcall DIV_48_16 ; dzielenie r15::r10 przez r30:r31
; czyli u_suma = u_suma / probek
rcall PIERW_32 ; pierwiastek z r13::r10 => r25:r24
sbrs temp, f4KAL_ZU ; przeskocz jesli ustawiony bit kalibracji zera
rjmp RU_N
lsr p0
sts Off_Ur_z, p0 ; zapisz wartosc probki jako offset zera
RU_N: lds n0, Off_Ur_z ; offset zera rms
rcall OBLW_U
sts Napiecie_rms, kwd2
sts Napiecie_rms+1, kwd3 ; zapis napiecia do RAM (dwa starsze bajty)
;------------------------------------------------------------------------------
;RMS_I: ; procedura liczenia RMS pradu
movw u_suma0, i_suma0
movw u_suma2, i_suma2 ; przesuniecie akumulatora pradu do akumul. napiecia
movw u_suma4, i_suma4 ; dzieki temu mnozenie operuje na tych samych rejestrach
rcall DIV_48_16 ; dzielenie r15::r10 przez r30:r31
; czyli u_suma = u_suma / probek
rcall PIERW_32 ; pierwiastek z r13::r10 => r25:r24
sbrc temp, f4KAL_ZI ; przeskocz jesli wyzerowany bit kalibracji zera
sts Off_Ir_z, p0 ; zapisz wartosc probki jako offset zera
lds n0, Off_Ir_z ; offset zera rms
rcall OBLW_I
sts Prad_rms, kwd2
sts Prad_rms+1, kwd3 ; zapis pradu do RAM (dwa starsze bajty)
;------------------------------------------------------------------------------
;MAV_I: ; liczenie wartosci sredniej I
ldi yl, low(Ak_mavI)
ldi yh, high(Ak_mavI)
rcall MAV_LDUI
sbrc temp, f4KAL_ZI ; przeskocz jesli wyzerowany bit kalibracji zera
sts Off_Im_z, p0 ; zapisz wartosc probki jako offset zera
lds n0, Off_Im_z ; offset zera mav
rcall OBLW_I
sts Prad_mav, kwd2
sts Prad_mav+1, kwd3 ; zapis pradu do RAM (dwa starsze bajty)
;MAV_U: ; liczenie wartosci sredniej U
rcall MAV_LDUI
sbrs temp, f4KAL_ZU ; przeskocz jesli ustawiony bit kalibracji zera
rjmp MU_N
lsr p0
sts Off_Um_z, p0 ; zapisz wartosc probki jako offset zera
MU_N: lds n0, Off_Um_z ; offset zera mav
rcall OBLW_U
sts Napiecie_mav, kwd2
sts Napiecie_mav+1, kwd3 ; zapis napiecia do RAM (dwa starsze bajty)
;AMPL_IM: ; amplituda ujemna I
ldi zl, low(Prad_am)
ldi zh, high(Prad_am)
rcall AMP_LDI
;AMPL_IP: ; amplituda dodatnia I
rcall AMP_LDI
;AMPL_UM: ; amplituda ujemna U
rcall AMP_LDU
;AMPL_UP: ; amplituda dodatnia U
rcall AMP_LDU
;==============================================================================
;MOCE: ; moc S
lds n0, Prad_rms
lds n1, Prad_rms+1
lds mn0, Napiecie_rms
lds mn1, Napiecie_rms+1
rcall MUL_16_16 ; mnozenie napiecia i pradu
movw n0, kwd0
movw n2, kwd2 ; przeniesienie wyniku
movw i_suma0, kwd0
movw i_suma2, kwd2 ; kopia wyniku dla innego mnozenia
ldi mn0, low(16777)
ldi mn1, high(16777) ; 16777 / 2^24 ~= 1/1000
rcall MUL_32_16
; kwd4:kwd3 zawiera moc S w [0,1VA]
lds kwd0, Moc_P
lds kwd1, Moc_P+1
cp kwd3, kwd0
cpc kwd4, kwd1 ; porownanie mocy S i P
brsh MS_SW ; skocz, jesli S >= P
; S mniejsze od P - niedokladnosc liczenia
mov kwd3, kwd0
mov kwd4, kwd1 ; moc S = P (bo S nie moze byc mniejsza od P)
MS_SW: sts Moc_S, kwd3
sts Moc_S+1, kwd4 ; zapis mocy do RAM
; obliczanie energii pozornej sekundowej
movw n0, i_suma0
movw n2, i_suma2 ; odzyskanie wyniku mnozenia rms_i * rms_u
ldi mn0, low(30542)
ldi mn1, high(30542) ; * 30542 / 2^16 ==> energia sekundowa do akumulacji
rcall MUL_32_16
; kwd5:kwd2 -energia sekundowa
lds kwd0, Flagi2
sbrs kwd0, f2EN_S ; jesli EN_S=1 to zapisz energie sek. pozorna
rjmp MS_DAL
sts Energia_sek, kwd2
sts Energia_sek+1, kwd3
sts Energia_sek+2, kwd4
sts Energia_sek+3, kwd5
MS_DAL:
;------------------------------------------------------------------------------
;OBL_PF: ; wspolczynnik mocy
lds kwd3, Moc_S
lds kwd4, Moc_S+1 ; moc S
lds kwd0, Moc_P
lds kwd1, Moc_P+1 ; moc P
ldi mn0, 200
cp kwd3, kwd0
cpc kwd4, kwd1 ; porownanie mocy S i P
breq PF_1 ; S = P => PF = 1
MUL16x8 kwd1, kwd0, mn0 ; mnozenie P przez 200
movw n0, wyn0
mov n2, wyn2
clr n3
clr n4
clr n5
mov y0, kwd3
mov y1, kwd4 ; dzielnik (S)
rcall DIV_48_16 ; dzielenie P*200 przez S
; n0 zawiera wynik: 0 < PF <= 200
lsr n0 ; /2
adc n0, n5 ; dodaj carry bit (zaokraglenie)
sts Pf_mocy, n0
rjmp MOCE_Q
PF_1: lsr mn0 ; /2
sts Pf_mocy, mn0 ; PF = 100
;------------------------------------------------------------------------------
MOCE_Q: ; i od razu moc Q
mov p0, kwd3
mov p1, kwd4
rcall KWADRAT_16 ; kwadrat S
movw n0, kwd0
movw n2, kwd2
lds p0, Moc_P
lds p1, Moc_P+1
rcall KWADRAT_16 ; kwadrat P
sub n0, kwd0
sbc n1, kwd1
sbc n2, kwd2
sbc n3, kwd3 ; roznica: S^2 - P^2
rcall PIERW_32 ; pierwiastek roznicy
sts Moc_Q, p0
sts Moc_Q+1, p1 ; zapis mocy do RAM
;------------------------------------------------------------------------------
;OBL_F:
;CZESTOTLIWOSC: ; czestotliwosc (DLUGO trwa: 1,5 okresu napiecia)
; lub maks. 44ms
in temp, TIFR
sbr temp, (1<<ICF1) | (1<<TOV1) ; czyszczenie flagi
out TIFR, temp
; [0] ; czekanie na zbocze opadajace
rcall CZST_X
clr r2
cli
out TCNT1H, r2 ; czyszczenie licznika
out TCNT1L, r2
ldi temp, (1<<ICES1) | (1<<CS11) ; zbocze narastajace na ICP...
rcall CZST_OUT
sei
; [1] ; czekanie na zbocze narastajace - START okresu
rcall CZST_X
cli
in r0, ICR1L
in r1, ICR1H ; czytaj zawartosc ICR
ldi temp, 1<<CS11 ; zbocze opadajace na ICP...
rcall CZST_OUT
sei
; [2] ; czekanie na zbocze opadajace - polowa okresu
rcall CZST_X
cli
in r2, ICR1L
in r3, ICR1H ; czytaj zawartosc ICR
ldi temp, (1<<ICES1) | (1<<CS11) ; zbocze narastajace na ICP...
rcall CZST_OUT
sei
; [3] ; czekanie na zbocze narastajace - KONIEC okresu
rcall CZST_X
cli
in r4, ICR1L
in r5, ICR1H ; czytaj zawartosc ICR
ldi temp, 1<<CS11 ; zbocze opadajace na ICP...
out TCCR1B, temp
sei
sub r2, r0 ; [2] - [1]
sbc r3, r1 ; czas trwania polokresu dodatniego
sub r4, r0 ; [3] - [1]
sbc r5, r1 ; czas trwania okresu
; liczenie wsp. wypelnienia
ldi mn0, 200
clr mn1
movw n0, r2
rcall MUL_16_16 ; mnozenie r3:r2 przez 200
movw n0, kwd0
movw n2, kwd2
clr n4
clr n5
movw y0, r4 ; dzielnik
rcall DIV_48_16
lsr n0 ; /2
adc n0, n5 ; dodaj carry bit (zaokraglenie)
sts Wypeln, n0 ; wynik: 0 < Wypeln < 100
; liczenie F
clr n0
ser temp
mov n3, temp ; bity znaku
lds n1, Wsp_F
lds n2, Wsp_F+1 ; Wspolczynnik korekcji F *256
sbrs n2, 7 ; przeskocz jesli liczba ujemna
clr n3 ; bity znaku =0
lsl n1
rol n2 ; *2
lsl n1
rol n2 ; *2
lsl n1
rol n2 ; *2
lsl n1
rol n2 ; *2
lsl n1
rol n2 ; *2
mov n4, n3
mov n5, n3 ; powiel bity znaku
ldi kwd0, low(STALA_DLA_F)
ldi kwd1, byte2(STALA_DLA_F)
ldi kwd2, byte3(STALA_DLA_F)
ldi kwd3, byte4(STALA_DLA_F)
clr kwd4
clr kwd5
add n0, kwd0
adc n1, kwd1
adc n2, kwd2
adc n3, kwd3
adc n4, kwd4
adc n5, kwd5
rcall DIV_48_16
sts Czestosc, n0
sts Czestosc+1, n1
; obliczanie wsp_LPF1
movw n2, n0 ; * 2^16
clr n0
clr n1
lsr n3
ror n2
ror n1
clr n4
clr n5
ldi y0, low(15600)
ldi y1, high(15600)
rcall DIV_48_16
movw p0, n0
rcall KWADRAT_16
ori kwd3, 0x40 ; + 2^30
movw n0, kwd0
movw n2, kwd2
rcall PIERW_32
sts Wsp_LPF1, p0
sts Wsp_LPF1+1, p1
ret
;--------------------------------------
;--------------------------------------
CZST_OUT: out TCCR1B, temp
in temp, TIFR
sbr temp, 1<<ICF1 ; czyszczenie flagi
out TIFR, temp
ret
;--------------------------------------
CZST_X: in temp, TIFR
sbrc temp, TOV1 ; przeskocz jesli TOV1=0 (timer nieprzepelniony)
rjmp CZST_OV
sbrs temp, ICF1 ; przeskocz jesli flaga ustawiona
rjmp CZST_X
ret
CZST_OV: ; przepelnienie timera - brak okresowosci napiecia lub < 23Hz
clr temp
sts Czestosc, temp
sts Czestosc+1, temp ; Czestosc=0
sts Wypeln, temp ; Wypeln=0
ldi temp, low(32768)
sts Wsp_LPF1, temp
ldi temp, high(32768)
sts Wsp_LPF1+1, temp ; minimalny wsp_LPF1
in zh, SPH
in zl, SPL ; adres stosu do rejestru Z
adiw zl, 2 ; zwieksz wskaznik stosu o slowo
out SPL, zl
out SPH, zh
ret ; powrot z "OBLICZENIA"
.exit
;==============================================================================
Moc S oblicza sie ze wzoru:
S [0,1VA] = U * I * 16777 / 2^24
(4B) * (2B) => (6B) w praktyce (5B) / (3B) => (2B)
Moc Q oblicza sie ze wzoru:
Q [0,1var] = pierw( S^2 - P^2 )
pierw ((4B) - (4B)) => (2B)
Takie obliczenie Q wprowadza jednak duzy blad i dlatego energia bierna nie moze byc akumulowana
Wspolczynnik mocy liczy sie tak:
PF [1..100] = P * 100 / S
((2B) * (1B)) / (2B) => (1B)
a) jesli P=S to PF=100
b) wynik PF uzupelnic zerami z przodu do trzech miejsc wstawiajac przecinek po pierwszej cyfrze
wtedy rozdzielczosc PF wynosi 0,01
Czestotliwosc:
Zakladajac ze taktowanie procesora jest znane i dokladnie rowne 8MHz oraz ustawiajac preskaler
dla T1 na CLK/8, to ilosc zliczen w liczniku T1 przez czas 1/F (F -czestotliwosc napiecia)
jest rowna:
ICP = (CLK/8)/F = 1000000/F => F [Hz] = 1000000/ICP
lub dokladniej:
F [0,01Hz] = (100000000 +(Wsp_F*32*256)) / ICP
(2B) = (4B) / (2B)
Minimalna czestotliwosc to 1,5 * (CLK/8) / 65535 = 23Hz
ICP to wartosc rejestru ICP timera T1 pracujacego w trybie Input Capture.
Dodatkowo Wsp_F (od 0xFE01 do 0x1FF kod U2) daje mozliwosc korekcji F o +-2,1Hz (1LSB =0,0041Hz)
Liczenie Wsp_LPF1:
Wsp_LPF1 = sqrt(2^30 + ((2^15 * F)/15600)^2)
;--------------------------------------
Kompensacja offsetu:
Wartosc offsetu jest odejmowana od probki przed przemnozeniem przez wspolczynniki.
Offsety zera sa jednobajtowe, wiec:
Dla pradu maksymalna wartosc kompensacji to 77mA
Dla napi阠ia -- || -- 3V
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -