⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 obliczenia.asm

📁 实现对ADE7759电能芯片的读写和校准,AVR单片机源码与电路图,单相电能表读写程序和初始化程序
💻 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 + -