📄 int2.asm
字号:
;==============================================================================
; Przerwanie INT2 wywolywane z ADE7759 (probki lub SAG)
; Projekt: Miernik energii i mocy na ADE7759
; optymalizacja na szybkosc
; !!! rejestry nie sa chronione, temp nie jest wykorzystywany
;==============================================================================
;.listmac
; r0, r1, r2 -rejestry operacyjne, r2=0
.def sreg_kopia =r3 ; r3 wykorzystywany jako kopia SREG
.def i_suma0 =r4
.def i_suma1 =r5
.def i_suma2 =r6
.def i_suma3 =r7
.def i_suma4 =r8
.def i_suma5 =r9 ; akumulator kwadratow probek pradu
.def u_suma0 =r10
.def u_suma1 =r11
.def u_suma2 =r12
.def u_suma3 =r13
.def u_suma4 =r14
.def u_suma5 =r15 ; akumulator kwadratow probek napiecia
; r16 =temp, r17 =flagi ; temp nie moze byc wykorzystywany
.def kwd0 =r18
.def kwd1 =r19
.def kwd2 =r20
.def kwd3 =r21 ; kwd3::kwd0 -wynik kwadratu probki
.def kwd4 =r22 ; inne zastosowanie
.def kwd5 =r23 ;
.def prb0 =r24
.def prb1 =r25
.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
;======== M A K R A ===========================================================
; SPI dziala z predkoscia 2MHz (CLK/4 - spitwi.asm)
.macro SPI_BAJT_WYSLIJ
out SPDR, spi_bufor
SBW_1: sbis SPSR, SPIF
rjmp SBW_1 ; czekaj na ustawienie flagi zakonczenia transmisji
in spi_bufor, SPSR ; kasuj powyzsza flage
in spi_bufor, SPDR ; j.w.
.endm ; 4 cykle od zakonczenia transmisji do wyjscia
;--------------------------------------
.macro SPI_BAJT_CZYTAJ ; @0 -rejestr odbiorczy
clr spi_bufor
out SPDR, spi_bufor
SBC_1: sbis SPSR, SPIF
rjmp SBC_1 ; czekaj na ustawienie flagi zakonczenia transmisji
in @0, SPSR ; kasuj powyzsza flage
in @0, SPDR ; odczyt bajtu z rejestru danych SPI
.endm ; 4 cykle od zakonczenia transmisji do wyjscia
;------------------------------------------------------------------------------
.macro KWADRAT16_32: ; (@0:@1)^2 ==> kwd3:kwd2:kwd1:kwd0
; korzysta z r0, r1, r2 oraz r2=0
clr r2 ; r2 zawsze rowny 0
mul @0, @0
movw kwd2, r0 ; kwd3:kwd2 <== r1:r0
mul @1, @1
movw kwd0, r0 ; kwd1:kwd0 <== r1:r0
mul @0, @1
lsl r0
rol r1
rol r2 ; wynik ostatniego mul razy 2
add kwd1, r0
adc kwd2, r1
adc kwd3, r2 ; dodaj podwojony iloczyn
clr r2 ; r2 zawsze rowny 0
.endm ; cykli: 16
;------------------------------------------------------------------------------
.macro SUMA32_48 ; @0:@1:@2:@3:@4:@5 += kwd3:kwd2:kwd1:kwd0
add @5, kwd0
adc @4, kwd1
adc @3, kwd2
adc @2, kwd3
adc @1, r2 ; r2=0
adc @0, r2
.endm ; cykli: 6
;------------------------------------------------------------------------------
.cseg
;======== P R O G R A M =======================================================
INT2_INT: ; rozpoznanie trybu pracy
sbrc flagi, fKAL ; przeskocz, jesli tryb zwykly
rjmp INT2_KAL
;======== Wlasciwa procedura odbioru probek ===================================
INT2_PRB:
sbis ADE_SAG_PIN, ADE_SAG ; testuj linie SAG
jmp BRAK_ZASILANIA
in sreg_kopia, SREG ; zachowaj rejestr SREG
; minimalne opoznienie dla wyslania komendy odczytu probek to 7us (dla takiej konfiguracji int2.asm)
; sumowanie wartosci sredniej napiecia - rejestry prb1 i prb0 nie zmieniaja
; zawartosci po opuszczeniu przerwania (petla glowna czeka na koniec zbierania probek)
clr r2
KWADRAT16_32 prb1, prb0
SUMA32_48 u_suma5, u_suma4, u_suma3, u_suma2, u_suma1, u_suma0
lds kwd0, Ak_mavU
lds kwd1, Ak_mavU+1
lds kwd2, Ak_mavU+2
lds kwd3, Ak_mavU+3 ; akumulator wartosci sredniej
add kwd0, prb0
adc kwd1, prb1
adc kwd2, r2
adc kwd3, r2 ; sumowanie wartosci sredniej
sts Ak_mavU, kwd0
sts Ak_mavU+1, kwd1
sts Ak_mavU+2, kwd2
sts Ak_mavU+3, kwd3 ;20cykli = 2,5us
rcall DELAY_2us
;7,25us opoznienia
; rcall DELAY_3_5us
; ;8us opoznienia
SPI_ADE_ON
ldi spi_bufor, ADE_WAVEFORM_ADR ; komenda odczytu probek
SPI_BAJT_WYSLIJ ; wyslij bajt poprzez SPI
; clr r2
clt
rcall DELAY_3_5us ; min czas miedzy bajtami = 4us
;--1----- ; czytanie pierwszego bajtu
SPI_BAJT_CZYTAJ prb_znak ;4 cykle od zakonczenia transmisji
; sprawdzenie przejscia przez zero napiecia (kanal 2)
mov r0, prb_znak ; prb_znak przechowuje pierwszy odczytany bajt z SPI
ldi spi_bufor, 0b10000000
and r0, spi_bufor ; maska na bit znaku napiecia
brmi I2P_U_MINUS ;8c ; skacze, jesli bit znaku ustawiony (minus)
; probka dodatnia:
lds r1, Hist_zera ; zaladuj licznik histerezy przejscia przez zero
tst r1
breq I2P_U_PLUS ;12c ; jesli Hist_zera=0, to nie jest testowane przejscie przez 0
; testowanie wartosci histerezy
inc r1 ; zwieksz licznik histerezy
lds spi_bufor, Hist_zera_ile ; laduj wartosc oczekiwana histerezy
cp r1, spi_bufor
brlo I2P_HIST_MNIEJ ;17c ; skacz, jesli nie osiagnieto wartosci histerezy
; jest przejscie przez zero
sts Hist_zera, r2 ; wyzeruj licznik histerezy i skasuj bit testowania histerezy
inc okresow ; zwieksz liczbe przejsc przez zero
lds spi_bufor, Okresy_ile ; sprawdzenie czy osiagnieto koniec zliczania
cp okresow, spi_bufor ;23c
brlo I2P_OKRESOW_MNIEJ ; jesli mniej, to pobieraj dalej
rjmp I2P_KONIEC_OKRESOW ; jesli rowne, to zliczonych jest wymagana ilosc okresow
I2P_HIST_MNIEJ:
sts Hist_zera, r1 ; zapisz licznik histerezy
rjmp I2P_11
I2P_U_MINUS:
ldi spi_bufor, 0b10000000 ; ustaw bit rozpoczenia testowania histerezy
sts Hist_zera, spi_bufor ; zapisz
nop
I2P_U_PLUS: nop ;14c
nop
nop
nop
nop
nop
nop
nop
nop
I2P_11: nop ;23c
cpi okresow, 0xFF ; jesli okresow = -1 to nie zbieraj probek
brne I2P_ZLICZAJ
rjmp I2P_NIEZL
I2P_OKRESOW_MNIEJ:
nop ;26c
I2P_ZLICZAJ:
nop
nop
nop
adiw probek0, 1 ; zwieksz licznik probek
;17us...
;--2-----
I2P_BAJT2: SPI_BAJT_CZYTAJ prb1 ; odczyt drugiego bajtu - prad starszy bajt
;4c
mov prb2, prb_znak
lds r1, Hist_przepel_I ; laduj zmienna
lds r0, Hist_przepel_I_ile
; test ilosci probek
lds spi_bufor, Probek_ile
cp probek0, spi_bufor
lds spi_bufor, Probek_ile+1
cpc probek1, spi_bufor ; porownanie liczby zebranych probek z liczba maksymalna
brlo I2P_B3 ; jesli mniej, to zbieraj dalej
set ; jesli rowne, to ustaw flage T
;17c
I2P_B3: lds kwd0, Off_I_dc
lds kwd1, Off_I_dc+1 ; offset DC, czyli symetrii probek
mov r2, kwd1
swap r2 ; dolna polowka r2 to bity znaku offsetu
lds kwd2, Prad_min
lds kwd3, Prad_min+1 ; probka o najmniejszej amplitudzie
lds kwd4, Prad_max
lds kwd5, Prad_max+1 ; probka o najwiekszej amplitudzie
;31c
;25us...
;--3-----
SPI_BAJT_CZYTAJ prb0 ; odczyt trzeciego bajtu - prad mlodszy bajt
lsr prb2
ror prb1
ror prb0
lsr prb2
ror prb1
ror prb0 ; /4
;10c
cp prb0, spi_bufor ; spi_bufor jest zerowany w SPI_BAJT_CZYTAJ
cpc prb1, spi_bufor
brne I2P_I_DOB ; probka nie przepelniona
sbrs prb2, 0 ; bit 16 - jesli H to przepelnienie
rjmp I2P_I_DOB
sbr flagi, 1<<fOVER_I ; ustaw flage przepelnienia probki z ADE7759
I2P_I_DOB: ;14c, 16c
add prb0, kwd0
adc prb1, kwd1 ; kompensacja offsetu
adc prb2, r2
;17c; 19c
; sprawdzenie znaku probki pradu
sbrs prb2, 1 ; sprawdzenie bitu znaku - bit 17 (bo bylo /4)
rjmp I2P_PRAD_PLUS
; probka pradu ujemna
com prb0
com prb1
com prb2 ; tylko odwrocenie bitow
sbrs prb2, 0 ; bit 16 - jesli H to przepelnienie
rjmp I2P_IM_DOB ; jesli L to probka dobra
sbr flagi, 1<<fOVER_I ; ustaw flage przepelnienia probki z ADE7759
ser prb0
ser prb1 ; ustaw probke na maks.
I2P_IM_DOB: ; 25, 27; 27, 29 cykli
; sprawdzenie amplitudy probki ujemnej
cp prb0, kwd2
cpc prb1, kwd3
brlo I2P_PRAD_DAL ; probka mniejsza --> dalej
sts Prad_min, prb0
sts Prad_min+1, prb1 ; probka wieksza --> zapisz
rjmp I2P_PRAD_DAL
I2P_PRAD_PLUS: ;20c; 22c
sbrs prb2, 0 ; bit 16 - jesli H to przepelnienie
rjmp I2P_IP_DOB ; jesli L to probka dobra
sbr flagi, 1<<fOVER_I ; ustaw flage przepelnienia probki z ADE7759
ser prb0
ser prb1 ; ustaw probke na maks.
I2P_IP_DOB: ; 23c, 25c; 25c, 27c
; sprawdzenie amplitudy probki dodatniej
cp prb0, kwd4
cpc prb1, kwd5
brlo I2P_PRAD_DALx ; probka mniejsza --> dalej
sts Prad_max, prb0
sts Prad_max+1, prb1 ; probka wieksza --> zapisz
I2P_PRAD_DALx:
nop
nop
I2P_PRAD_DAL: ;plus: (29, 32), (31, 34), (33, 36)
; minus: (29, 34), (31, 36), (33, 38)
nop
nop
;--4a---- odbior czwartego bajtu
clr spi_bufor
out SPDR, spi_bufor
;33us...
; test przepelnienia probki pradu
sbrc flagi, fOVER_I ; flaga ustawiana wczesniej
rjmp I2P_PRAD_OVER
clr r1 ; zeruj licznik histerezy (wystapila dobra probka)
rjmp I2P_PRAD_OK ; jesli L to probka dobra
I2P_PRAD_OVER: ; testowanie histerezy przepelnienia (kolejnych probek)
inc r1 ; zwieksz licznik histerezy
cp r0, r1 ; sprawdz, czy osiagnieto maks. ilosc
brlo I2P_PRAD_OK ; ...jesli przekroczono, to zostaw flage ustawiona
cbr flagi, 1<<fOVER_I ; ...jesli nie przekroczono histerezy, to kasuj flage
I2P_PRAD_OK:
sts Hist_przepel_I, r1 ; zapisz zmienna
; 7c -ok, 9c -over
KWADRAT16_32 prb1, prb0
;23c, 25c
SUMA32_48 i_suma5, i_suma4, i_suma3, i_suma2, i_suma1, i_suma0
;29c, 31c
lds kwd0, Ak_mavI
lds kwd1, Ak_mavI+1
lds kwd2, Ak_mavI+2
lds kwd3, Ak_mavI+3 ; akumulator wartosci sredniej
add kwd0, prb0
adc kwd1, prb1
adc kwd2, r2
adc kwd3, r2 ; sumowanie wartosci sredniej
;--4b---- ; odczyt czwartego bajtu - starszy bajt U
in spi_bufor, SPSR ; kasuj flage
in prb1, SPDR ; odczyt bajtu z rejestru danych SPI
sts Ak_mavI, kwd0
sts Ak_mavI+1, kwd1
sts Ak_mavI+2, kwd2
sts Ak_mavI+3, kwd3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -