📄 int2.asm
字号:
;51c, 53c
mov prb2, prb_znak
swap prb2
lds r1, Hist_przepel_U ; laduj zmienna
lds r0, Hist_przepel_U_ile
;57c
lds kwd0, Off_U_dc
lds kwd1, Off_U_dc+1 ; offset DC, czyli symetrii probek
mov r2, kwd1
swap r2 ; dolna polowka r2 to bity znaku offsetu
;63c
nop
;--5a---- odbior piatego bajtu
clr spi_bufor
out SPDR, spi_bufor
lds kwd2, Napiecie_min
lds kwd3, Napiecie_min+1 ; probka o najmniejszej amplitudzie
lds kwd4, Napiecie_max
lds kwd5, Napiecie_max+1 ; probka o najwiekszej amplitudzie
;8c
;42us...
;--5b---- odczyt piatego bajtu
SBC_5: sbis SPSR, SPIF
rjmp SBC_5 ; czekaj na ustawienie flagi zakonczenia transmisji
in spi_bufor, SPSR ; kasuj flage
in prb0, SPDR ; odczyt bajtu z rejestru danych SPI
clr spi_bufor
SPI_ADE_OFF
lsr prb2
ror prb1
ror prb0
lsr prb2
ror prb1
ror prb0 ; /4
;11c
cp prb0, spi_bufor ; spi_bufor jest zerowany w SPI_BAJT_CZYTAJ
cpc prb1, spi_bufor
brne I2P_U_DOB ; probka nie przepelniona
sbrs prb2, 0 ; bit 16 - jesli H to przepelnienie
rjmp I2P_U_DOB
sbr flagi, 1<<fOVER_U ; ustaw flage przepelnienia probki z ADE7759
I2P_U_DOB: ;15c, 17c
add prb0, kwd0
adc prb1, kwd1 ; kompensacja offsetu
adc prb2, r2
;18c; 20c
; sprawdzenie znaku probki napiecia
sbrs prb2, 1 ; sprawdzenie bitu znaku - bit 17 (bo bylo /4)
rjmp I2P_NAP_PLUS
; probka napiecia ujemna
com prb0
com prb1
com prb2 ; tylko odwrocenie bitow
sbrs prb2, 0 ; bit 16 - jesli H to przepelnienie
rjmp I2P_UM_DOB ; jesli L to probka dobra
sbr flagi, 1<<fOVER_U ; ustaw flage przepelnienia probki z ADE7759
ser prb0
ser prb1 ; ustaw probke na maks.
I2P_UM_DOB: ; 26, 28; 28, 30 cykli
; sprawdzenie amplitudy probki ujemnej
cp prb0, kwd2
cpc prb1, kwd3
brlo I2P_NAP_DAL ; probka mniejsza --> dalej
sts Napiecie_min, prb0
sts Napiecie_min+1, prb1 ; probka wieksza --> zapisz
rjmp I2P_NAP_DAL
I2P_NAP_PLUS: ;21c; 23c
sbrs prb2, 0 ; bit 16 - jesli H to przepelnienie
rjmp I2P_UP_DOB ; jesli L to probka dobra
sbr flagi, 1<<fOVER_U ; ustaw flage przepelnienia probki z ADE7759
ser prb0
ser prb1 ; ustaw probke na maks.
I2P_UP_DOB: ; 24c, 26c; 26c, 28c
; sprawdzenie amplitudy probki dodatniej
cp prb0, kwd4
cpc prb1, kwd5
brlo I2P_NAP_DAL ; probka mniejsza --> dalej
sts Napiecie_max, prb0
sts Napiecie_max+1, prb1 ; probka wieksza --> zapisz
I2P_NAP_DAL: ;plus: (28, 31), (30, 33), (32, 35)
; minus: (30, 35), (32, 37), (34, 39)
; test przepelnienia probki
sbrc flagi, fOVER_U ; flaga ustawiana wczesniej
rjmp I2P_NAP_OVER
clr r1 ; zeruj licznik histerezy (wystapila dobra probka)
rjmp I2P_NAP_OK ; jesli L to probka dobra
I2P_NAP_OVER: ; testowanie histerezy przepelnienia (kolejnych probek)
inc r1 ; zwieksz licznik histerezy
cp r0, r1 ; sprawdz, czy osiagnieto maks. ilosc
brlo I2P_NAP_OK ; ...jesli przekroczono, to zostaw flage ustawiona
cbr flagi, 1<<fOVER_U ; ...jesli nie przekroczono histerezy, to kasuj flage
I2P_NAP_OK:
sts Hist_przepel_U, r1 ; zapisz zmienna
; 7c -ok, 9c -over
; plus_ok: 35-42, plus_ov: 37-44
; minus_ok: 37-46, minus_ov: 39-48
;50us...
; KWADRAT16_32 prb1, prb0
; SUMA32_48 u_suma5, u_suma4, u_suma3, u_suma2, u_suma1, u_suma0
; ;57c - 70c
;zmiana! lds kwd0, Ak_mavU
; na lds kwd1, Ak_mavU+1
; poczatek 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
;77c - 90c
;--------
brts I2P_KONIEC_PROBEK ; jesli T=1 zebrano wymagana ilosc probek (nie okresow)
out SREG, sreg_kopia
reti ;84c - 97c
;ok. 56us min.
;ok. 3,5us wiecej dla maks.
; + czas na poczatku przerwania!
;--------------------------------------
I2P_NIEZL: ; niezbieranie probek, gdy okresow = -1
SPI_ADE_OFF
lds prb0, Prb_0xff
lds prb1, Prb_0xff+1
adiw prb0, 1
sts Prb_0xff, prb0
sts Prb_0xff+1, prb1
lds r0, Prb_na_okr_x2 ; r1:r0 zawiera ilosc probek na okres *2
lds r1, Prb_na_okr_x2+1
cp prb0, r0
cpc prb1, r1
brlo I2PN_D
clr okresow
; jesli zliczono przerwan (od probek) dwa razy wiecej niz
; okres sieci (1/50Hz) i nie stwierdzono okresowosci, to
; pewnie przylozono napiecie "nieprzemmienne"
; wiec zacznij zbierac probki
I2PN_D: clr prb0
clr prb1
out SREG, sreg_kopia
reti
;------------------------------------------------------------------------------
I2P_KONIEC_OKRESOW: ; koniec zliczania ze wzgledu na ilosc okresow napiecia
;26c
SPI_ADE_OFF
;--------------------------------------
I2P_KONIEC_PROBEK: ; koniec zliczania ze wzgledu na ilosc probek
push temp
push r0
rcall ZBIERANIE_PROBEK_WYLACZ
pop r0
pop temp
cbr flagi, 1<<fINT2 ; kasuj flage informacji o stanie przerwania INT2
out SREG, sreg_kopia
ret ; RET aby po wyjsciu z przerwania nie wskoczylo znowu do niego
; poniewaz moze byc ustawiona flaga INT2 w GIFR
;==============================================================================
;===== Procedura odbioru probek ===============================================
;===== dla pradu stalego (gdy nie ma przebiegow okresowych) ===================
;==============================================================================
INT2_KAL: ; potrzebne do kalibracji
; linia SAG musi byc wylaczona (rejestr MODE)
; poniewaz gdy nie ma okresowosci napiecia w CH2 to zglaszane jest przerwanie
; na linii IRQ nawet jesli rejestr IRQEN=0
; a takze ilosc probek na okres =140 (7kHz)
push spi_bufor
in spi_bufor, SREG ; zachowaj rejestr SREG
push spi_bufor
rcall DELAY_3_5us
rcall DELAY_3_5us
SPI_ADE_ON
ldi spi_bufor, ADE_RSTSTATUS_ADR ; komenda odczytu interrupt status
SPI_BAJT_WYSLIJ ; wyslij bajt poprzez SPI
rcall DELAY_3_5us ; min czas miedzy bajtami = 4us
SPI_BAJT_CZYTAJ spi_bufor
SPI_ADE_OFF
sbrc spi_bufor, I_WSMP ; przeskocz, jesli bit WSMP wyzerowany
rcall INT2_PRB ; WSMP=1 --> przerwanie w celu odbioru probki
cli
pop spi_bufor
out SREG, spi_bufor
pop spi_bufor
reti
;==============================================================================
; DELAY_2us
; petla = 4 takty
; stala = 12 takty (lacznie z wywolaniem procedury - RCALL)
; czas [us] = (D40us * 4 + 12) / F_zegara [MHz]
; D40us = (czas * F_zegara - 12) / 4
;==============================================================================
.equ D2us =1 ; 2us dla F_zegara =8MHz
DELAY_2us: ; 3c (rcall)
nop ; 1c (wyrownanie)
push r16 ; 2c
ldi r16, D2us ; 1c
D2us_1: dec r16 ; 1c
tst r16 ; 1c
brne D2us_1 ; 2c
pop r16 ; 2c
ret ; 4c
;------------------------------------------------------------------------------
.equ D3_5us =4 ; 3,5us dla F_zegara =8MHz
DELAY_3_5us: ; 3c
nop ; 1c
push r16 ; 2c
ldi r16, D3_5us ; 1c
D35us_1: dec r16 ; 1c
tst r16 ; 1c
brne D35us_1 ; 2c
pop r16 ; 2c
ret ; 4c
.exit
;==============================================================================
Probka napiecia lub pradu jest 20-bitowa (w uzupelnieniu do dwoch):
- bit 19 to znak
- maks wartosc probki to +262143 oraz -262143 => +(2^18-1) oraz -(2^18-1)
probki przepelnione - zatrzasniecie na +262144 oraz -262144 czyli: +-(2^18)
- czyli bit 18 sygnalizuje przepelnienie, ale TYLKO na dodatniej probce
- probka przesylana przez SPI jest 24-bitowa: najstarsze 4 bity to powielony bit znaku (bit 19)
wyjatek stanowi przeslanie jednoczesne probki pradu i napiecia - wtedy sa one 20-bitowe
- format przesylania probki pradu i napiecia:
________ ________ ____________________________ ____________________________
| 4-bity | 4-bity | 16-bitow pradu | 16-bitow napiecia |
| nap. | pradu | | |
| b 19:16| b 19:16| bity 15:0 | bity 15:0 |
(b39)-------- -------- ---------------------------- ----------------------------(b0)
SPI: | 1st bajt czytany| 2nd B czyt. | 3rd B czyt. | 4rd B czyt. | 5rd B czyt. |
;------------------------------------------------------------------------------
Obrobka pradu i napiecia - pelna rozdzielczosc:
*** czesc w przerwaniu ***
1. odbior 1st bajtu - znaki probki pradu i napiecia
1a. testowanie przejscia przez zero (napiecia) oraz histerezy przejscia
1b. jesli brak okresowosci przez dwa okresy sieci 50Hz (czyli w ciagu 40ms) to od tego momentu
zbierana jest wymagana ilosc probek (okresow_ile+1) * probek_na_okres
2. odbior 2nd bajtu
3. po pobraniu 3rd bajtu - laczenie probki (3B)
3a. dzielenie probki przez 4
3b. test przepelnienia probki z ADE7759
3c. kompensacja offsetu za pomoca 11-bitowej liczby w kodzie U2 (max. +-230mA i +-4,6V)
3d. detekcja znaku probki - jesli ujemna, to negacja
3e. test przepelnienia probki po korekcji -oddzielnie dla probki dodatniej i ujemnej
3f. sprawdzanie wartosci probki -amplituda (j.w.)
3g. testowanie przepelnienia probki (flaga fOVER) oraz histerezy przepelnienia (bit 18)
3h. kwadrat probki (2B)^2 => (4B)
3i. akumulacja probek^2 przez zadana ilosc okresow (lub konkretna ilosc probek)
(4B) => (6B)
3j. akumulacja probki (nie kwadratu) j.w. - (2B) => (4B) (wartosc srednia)
4. analogicznie jak 2.
5. analogicznie jak 3.
*** czesc poza przerwaniem ***
6. dzielenie akumulatora przez ilosc probek (6B) / (2B) => (4B)
7. pierwiastek kwadratowy wyniku sqrt(4B) => (2B)
(rozdzielczosci: 3,28LSB na 1mA, 16,5LSB na 0,1V)
8. kompensacja offsetu zera (odjecie)
*** dla pradu: ***
9. mnozenie przez wsp_I (2B) * (2B) => (4B)
10. odrzut dwoch najmlodszych bajtow (4B) / (2B) => (2B)
dwa starsze bajty zawieraja wartosc pradu w [mA] (maks 20000 mA)
*** dla napiecia: ***
9. mnozenie przez wsp_LPF1 (2B) * (2B) => (4B)
10. wynik razy 2 (rol) => (5B)
11. odrzut dwoch najmlodszych bajtow (5B) / (2B) => (3B)
12. mnozenie przez wsp_U (3B) * (2B) => (5B) a wlasciwie (4B)
13. odrzut dwoch najmlodszych bajtow (4B) / (2B) => (2B)
dwa starsze bajty zawieraja wartosc napiecia w [0,1V] (maks 3960 0,1V)
;--------------------------------------
Uwaga! Wartosc probki napiecia jest zalezna od czestotliwosci, Wsp_LPF1 kompensuje ta odchylke
;==============================================================================
Maksymalny czas obslugi przerwania to 70us dla 280 probek na okres (WAVSEL =14kHz)
- dla SCK =2MHz (fosc/4) czas transmisji bajtu to 4us
czas przerwania INT2_PRB (bez dodatkowego opoznienia na poczatku):
- minimalny: 58,5us
- maksymalny: 61,5us
W zwiazku z przeniesieniem kwadratu i akumulacji wartosci sredniej napiecia na poczatek
tam gdzie ma byc dodatkowe opoznienie, zaoszczedza sie na czasie trwania przerwania.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -