[Atmega32][Bascom] Zawieszanie programu
[Atmega32][Bascom] Zawieszanie programu
Witam.
Nie mam już pomysłu, może ktoś z was coś podsunie.
Problem leży prawdopodobnie w złym zarządzaniu pamięcią.
Program to miernik energii elektrycznej. Może zamiast kodu przedstawie schemat blokowy.
Cały program znajduje się w pętli, nie używam zadnych gosubów i innych podprogramów. Jest tylko 1 przerwanie co sek i tylko zmiana 1 zmiennej.
1. Program najpierw zapisuje próbki do zmiennych
Dim Utab(200) As Integer
Dim Itab(200) As Integer
Próbek jest po 180 dla napięcia i prądu. Czytane są z 2 zawnętrznych przetworników.
2. Potem wstępne obliczenia i przepisanie danych do zmiennych
( Proces 1 i 2 wykonywany jest ok 15 razy na sek, probki do tablicy zawsze wpisywane są od nowa, znów obliczenia i przepisanie danych do zmiennych)
3. Kolejne obliczenia ale co 1 sek ze zmiennych z punktu 2
4. obsługa przycisków, wyświetlacza.
Przyciski i wyświetlacz mozna pominąć, musze najpierw rozwiązać problem zwieszania.
I teraz ........ niezrozumiałym dla mnie elementem są te tablice i wpisywanie do nich próbek. Zadeklarowanych jest 200 zmiennych (2 bajtowych) dla napięcia i tak samo dla prądu. Wydaje mi się że tak jest prawidłowo. Na 100% nie przekraczana jest ta liczba która w praktyce wynosi 180 próbek. Tymczasem przy takiej deklaracji program wiesza sie po paru minutach poprawnego działania. Przy zadeklarowaniu 400
Dim Utab(400) As Integer
Dim Itab(400) As Integer
program potrafi działać parę godzin.
Max co mogę zadeklarować to 450. Potem kompilator pluje się że brak pamięci.
Mój wniosek to że brakuje ramu, w programie jest ok 25 zmiennych single, sporo operacji matematycznych włącznie z pierwiastkowaniem. Być może program potrzebuje sporo ramu, albo coś bascom partoli. Nie rozumiem co może byc przyczyną dłuższego działania programu przy deklaracji 400.
Zastanawiam się jeszcze nad konfiguracją
$hwstack
$swstack
$framesize
ale nie wiem jak to ugryźć.
Nie mam już pomysłu, może ktoś z was coś podsunie.
Problem leży prawdopodobnie w złym zarządzaniu pamięcią.
Program to miernik energii elektrycznej. Może zamiast kodu przedstawie schemat blokowy.
Cały program znajduje się w pętli, nie używam zadnych gosubów i innych podprogramów. Jest tylko 1 przerwanie co sek i tylko zmiana 1 zmiennej.
1. Program najpierw zapisuje próbki do zmiennych
Dim Utab(200) As Integer
Dim Itab(200) As Integer
Próbek jest po 180 dla napięcia i prądu. Czytane są z 2 zawnętrznych przetworników.
2. Potem wstępne obliczenia i przepisanie danych do zmiennych
( Proces 1 i 2 wykonywany jest ok 15 razy na sek, probki do tablicy zawsze wpisywane są od nowa, znów obliczenia i przepisanie danych do zmiennych)
3. Kolejne obliczenia ale co 1 sek ze zmiennych z punktu 2
4. obsługa przycisków, wyświetlacza.
Przyciski i wyświetlacz mozna pominąć, musze najpierw rozwiązać problem zwieszania.
I teraz ........ niezrozumiałym dla mnie elementem są te tablice i wpisywanie do nich próbek. Zadeklarowanych jest 200 zmiennych (2 bajtowych) dla napięcia i tak samo dla prądu. Wydaje mi się że tak jest prawidłowo. Na 100% nie przekraczana jest ta liczba która w praktyce wynosi 180 próbek. Tymczasem przy takiej deklaracji program wiesza sie po paru minutach poprawnego działania. Przy zadeklarowaniu 400
Dim Utab(400) As Integer
Dim Itab(400) As Integer
program potrafi działać parę godzin.
Max co mogę zadeklarować to 450. Potem kompilator pluje się że brak pamięci.
Mój wniosek to że brakuje ramu, w programie jest ok 25 zmiennych single, sporo operacji matematycznych włącznie z pierwiastkowaniem. Być może program potrzebuje sporo ramu, albo coś bascom partoli. Nie rozumiem co może byc przyczyną dłuższego działania programu przy deklaracji 400.
Zastanawiam się jeszcze nad konfiguracją
$hwstack
$swstack
$framesize
ale nie wiem jak to ugryźć.
Jak w tytule Atmega32
Kod: Zaznacz cały
$regfile = "m32def.dat"
$crystal = 16000000
Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portd.2 , Db5 = Portd.3 , Db6 = Portd.4 , Db7 = Portd.5 , Rs = Portd.0 , E = Portd.1
Cursor Off
Cls
'------------------------- Timer
Config Timer1 = Timer , Prescale = 256
On Timer1 Co1s
Enable Interrupts
Enable Timer1
'------------------------- SPI
Config Pind.7 = Input
Config Pinc.3 = Output ' nie uzywany
Config Pinc.0 = Output ' CS Napiecie
Config Pinc.1 = Output ' CS Prad
Config Spi = Soft , Din = Pind.7 , Dout = Portc.3 , Ss = None , Clock = Portd.6
'------Din-Pd.7 (input) ------ Dout-Pc3 - nie uzywany ------- CS-PC.0 oraz PC.1 (output) ------ clock-Pd.6 (output)
Spiinit
'-------------------------- przyciski , dioda
Config Pinb.0 = 1
Dioda Alias Portb.0
Dioda = 1
Config Pinb.4 = 0
Portb.4 = 1
W_minus Alias Pinb.4
Config Pinb.1 = 0
Portb.1 = 1
W_plus Alias Pinb.1
Config Pinb.3 = 0
Portb.3 = 1
W_ok Alias Pinb.3
Config Pinb.2 = 0
Portb.2 = 1
W_esc Alias Pinb.2
'-------------------------- konfiguracja zmiennych
Dim Adc_u(2) As Byte
Dim Adc_i(2) As Byte
Dim Utab(200) As Integer
Dim Itab(200) As Integer
Dim U_sampl As Integer
Dim I_sampl As Integer
Dim L As Word
Dim Lo As Word
Dim Lb As Word
Dim Ucal As Single
Dim Ical As Single
Dim Cal As Single
Dim Usk_sam As Single
Dim Isk_sam As Single
Dim Usk As Single
Dim Usk_w As Single
Dim Isk As Single
Dim Isk_w As Single
Dim Pcz As Single
Dim Pcz_w As Single
Dim Pb As Single
Dim Pb_w As Single
Dim Ppoz As Single
Dim Ppoz_w As Single
Dim Psam As Single
Dim Pcz_sam As Single
Dim Pb_sam As Single
Dim Usk_kw As Single
Dim Isk_kw As Single
Dim Imax As Single
Dim Imax_w As Single
Dim Usk_s As String * 5
Dim Isk_s As String * 5
Dim Pcz_s As String * 5
Dim Pb_s As String * 5
Dim Ppoz_s As String * 5
Dim Imax_s As String * 5
Dim Zero1 As Bit
Dim Zero2 As Bit
Dim Pomin As Bit
Dim Sw As Bit
Dim So As Bit
Dim Fl As Bit
Dim Flw As Byte
Dim Flw_w As Byte
Dim Wys As Byte
Dim Li_plus As Byte
Dim Li_minus As Byte
'------ Ustawienia
Wys = 2
Set Portc.1
Dim Test As Single
Test = 9.995 ' minimalna ilosc sampli na okres
'***************************************************************
'*************************************************************** Program
'***************************************************************
'------------------------- glowna petla
Do
'************************************************* samplowanie
'------------------------ detekcja przejecia przez zero
Dioda = 0
L = 0
Pomin = 0
Do
Incr L
'-----
Reset Portc.0
Spiin Adc_u(1) , 2
Set Portc.0
'-----
U_sampl = Adc_u(1)
Shift U_sampl , Left , 8
U_sampl = U_sampl + Adc_u(2)
Shift U_sampl , Right , 2
U_sampl = U_sampl And &B0000111111111111
'--------
If U_sampl < 2000 Then
Zero1 = 1
End If
If U_sampl > 2008 And Zero1 = 1 Then
Zero2 = 1
End If
Loop Until Zero2 = 1 Or L = 300
Zero1 = 0
Zero2 = 0
'--------------------- Poczatek petli pomiarow
'--------------------- Kasowanie zmiennych
If L < 300 Then
Pomin = 1
End If
If Pomin = 1 Then
Incr Flw
L = 0
Do
Incr L
Adc_u(1) = 0
Adc_u(2) = 0
Adc_i(1) = 0
Adc_i(2) = 0
U_sampl = 0
I_sampl = 0
'--------------------- Odczyt z przetwornikow
Reset Portc.0
Spiin Adc_u(1) , 2
Set Portc.0
Reset Portc.1
Spiin Adc_i(1) , 2
Set Portc.1
'--------------------- Konwersja
U_sampl = Adc_u(1)
Shift U_sampl , Left , 8
U_sampl = U_sampl + Adc_u(2)
Shift U_sampl , Right , 2
U_sampl = U_sampl And &B0000111111111111
I_sampl = Adc_i(1)
Shift I_sampl , Left , 8
I_sampl = I_sampl + Adc_i(2)
Shift I_sampl , Right , 2
I_sampl = I_sampl And &B0000111111111111
'_______ samplowanie probek
Utab(l) = U_sampl
Itab(l) = I_sampl
'------------------------ detekcja przejecia przez zero
If U_sampl < 2000 And L > 100 Then ' 100 - minimalna ilośc probek
Zero1 = 1
End If
If U_sampl > 2008 And Zero1 = 1 Then
Zero2 = 1
End If
Loop Until Zero2 = 1 Or L = 200
'--------------------- zabezpieczenie detekcji
If L = 200 Then
Pomin = 0
End If
'--------------------- Koniec petli
Zero1 = 0
Zero2 = 0
Dioda = 1
'------------------------ odjęcie ofsetu próbek
Lo = 0
Do
Incr Lo
Utab(lo) = Utab(lo) - 2046
Itab(lo) = Itab(lo) - 2046
Loop Until Lo = L
'***************************** Obliczenia
'----------------------- Obliczanie mocy czynnej
Pcz_sam = 0
Lo = 0
Do
Incr Lo
Psam = Utab(lo) * Itab(lo)
Pcz_sam = Pcz_sam + Psam
Loop Until Lo = L
Pcz_sam = Pcz_sam / L
'----------------------- Obliczanie mocy biernej
Pb_sam = 0
Lo = 0
Lb = L
Lb = Lb / 4
Lb = Lb + 1
Do
Incr Lo
Incr Lb
Psam = Utab(lo) * Itab(lb)
Pb_sam = Pb_sam + Psam
If Lb = L Then
Lb = 0
End If
Loop Until Lo = L
Pb_sam = Pb_sam / L
'----------------------- Przeliczenie probek na wartosci dodatnie
Lo = 0
Do
Incr Lo
If Utab(lo) < 0 Then
Utab(lo) = Utab(lo) * -1
End If
If Itab(lo) < 0 Then
Itab(lo) = Itab(lo) * -1
End If
Loop Until Lo = L
'----------------------- Obliczanie U oraz I skutecznego
Usk_sam = 0
Isk_sam = 0
Lo = 0
Do
Incr Lo
Usk_kw = Utab(lo)
Usk_kw = Usk_kw * Usk_kw
Usk_sam = Usk_sam + Usk_kw
Isk_kw = Itab(lo)
Isk_kw = Isk_kw * Isk_kw
Isk_sam = Isk_sam + Isk_kw
Loop Until Lo = L
Usk_sam = Usk_sam / L
Isk_sam = Isk_sam / L
Usk_sam = Sqr(usk_sam)
Isk_sam = Sqr(isk_sam)
'--------------------------- sumowanie wynikow
Pcz = Pcz + Pcz_sam
Pb = Pb + Pb_sam
Usk = Usk + Usk_sam
Isk = Isk + Isk_sam
End If
'----------- kasowanie zmiennych w przypadku nie przejscia przez zero
If Pomin = 0 Then
Pcz = 0
Pb = 0
Ppoz = 0
Usk = 0
Isk = 0
Decr Flw
End If
'****************************************************
'**************************************************** obliczenia
'****************************************************
If So = 1 Then
'---------------------- kalibracja
Ucal = 0.2599
Ical = 0.01695
Cal = Ucal * Ical
'--------------------- obliczenia
Usk = Usk / Flw
Isk = Isk / Flw
Pcz = Pcz / Flw
Pb = Pb / Flw
Usk = Usk * Ucal
Isk = Isk * Ical
If Imax_w < Isk Then
Imax_w = Isk
End If
Pcz = Pcz * Cal
Ppoz = Usk * Isk
Pb = Pb * Cal
'If Pb < 0 Then
'Pb = Pb * -1
'End If
Usk_w = Usk
Isk_w = Isk
Pcz_w = Pcz
Ppoz_w = Ppoz
Pb_w = Pb
Flw_w = Flw
'If Isk_w < 0.015 Then Isk_w = 0
'-------------------- kasowanie zmiennych
Pcz = 0
Pb = 0
Ppoz = 0
Usk = 0
Isk = 0
So = 0
'Sp = 1
Sw = 1
Flw = 0
End If
'******************************************** obsługa przycisków
'-------------------- przelaczanie wyswietlacza gora dol
If W_minus = 0 Then
Incr Li_minus
Else
If Li_minus >= 1 And Li_minus < 5 Then
Incr Wys
Li_minus = 0
Sw = 1
If Wys = 4 Then
Wys = 3
End If
End If
Li_minus = 0
End If
'-----------
If W_plus = 0 Then
Incr Li_plus
Else
If Li_plus >= 1 And Li_plus < 5 Then
Decr Wys
Li_plus = 0
Sw = 1
If Wys = 0 Then
Wys = 1
End If
End If
Li_plus = 0
End If
'-------------------
'******************************************** wyswietlacz
If Sw = 1 Then
Select Case Wys:
'---------
Case 1
Cls
Locate 1 , 1
Lcd Usk_w
Locate 1 , 12
Lcd " " ; Flw_w ; " "
'---------
Case 2
Usk_s = Fusing(usk_w , "#.&")
Locate 1 , 1
Lcd "Usk= " ; Usk_s ; " V "
Select Case Isk_w
Case 0 To 10
Isk_s = Fusing(isk_w , "#.&&&")
Locate 2 , 1
Lcd "Isk= " ; Isk_s ; " A "
Case Is > 10
Isk_s = Fusing(isk_w , "#.&&")
Locate 2 , 1
Lcd "Isk= " ; Isk_s ; " A "
End Select
'----------
Case 3
Select Case Imax_w
Case -2046 To 10
Imax_s = Fusing(imax_w , "#.&&&")
Locate 1 , 1
Lcd "Isk max= " ; Imax_s ; " A "
Case Is > 10
Imax_s = Fusing(imax_w , "#.&&")
Locate 1 , 1
Lcd "Isk max= " ; Imax_s ; " A "
End Select
Locate 2 , 1
Lcd "Kasowanie > OK"
'----------
'Test = Test + 0.001
'Isk_w = Test
End Select
'---------------- kasowanie zmiennych
Sw = 0
'----------
End If
'----------------------------------------
Loop
End
'************************************************
'************************************************
'********* przerwanie co 1s *****************
'************************************************
'************************************************
Co1s:
Counter1 = Counter1 + 2036
So = 1
Return
Kod: Zaznacz cały
Pcz_sam = 0
Lo = 0
Do
Incr Lo
Psam = Utab(lo) * Itab(lo)
Pcz_sam = Pcz_sam + Psam
Loop Until Lo = L
Jeżeli jest większe od 200, to przekraczasz w tej pętli max dopuszczalny index tablicy. modyfikujesz przypadkowe komórki RAM i program idzie w krzaki.
Dodatkowo L masz zadeklarowane jako WORD mimo że twój max index tablicy to 200, czyli wystarczyłoby ci w zupełności DIM L as BYTE. Zmienna typu Word to ryzyko wyjścia poza obszar adresowania RAMu i kolejny prawdopodobny powód zwiechy.
Ogólnie zapisz sobie warunek w pętli jako stałą np. CONST MAX_tab = 200 a nie używaj zmiennej.
Kod: Zaznacz cały
Const MAX_tab = 200
.... Dimy itd.
Lo = 0
Do
Incr Lo
Utab(lo) = Utab(lo) - 2046
Itab(lo) = Itab(lo) - 2046
Loop Until Lo = MAX_tab
-
keruseykaryu
Właściwie to nie startuje od zera, bo pierwsza instrukcją w pętli jest incr Lo, czyli zwiększ o 1, czyli pierwszy wskazany index tablicy to właśnie 1, czyli prawidłowo.No i niech nie startuje od zera tylko od 1.
Kod: Zaznacz cały
Loop Until Zero2 = 1 Or L = 300
Ogólnie zauważyłem że jednej zmiennej używasz sobie w programie raz jako licznika inny raz jako "stałej" warunku. Jeżeli teraz gdzieś w programie zmienna L przybierze ci wartość większą niż 200, i potem ta sama zmienna określa ci max index w tablicy to program ci się wysypuje. Prawdopodobnie dla tego przy tablicy zadeklarowanej na 400 działa ci dobrze, a na 200 nie. Albo przy detekcji Zera ogranicz sobie L do 200, albo zadeklaruj sobie Tablice 300 elementowe, jeżeli L może max osiągnąć wartość 300.
Dzięki panowie że ktoś się tym o ogóle zainteresował.
Zmienna L dobierana jest automatycznie. Pierwsze to przejście przez zero, pomiar tylko napięcia, wtedy L przekracza nawet waha się między 0 a 300, teraz mam ją na 500. Tutaj nie zbiera danych do tablicy ! Tylko czeka aż pojawi sie zero. Gdy przejdzie przez zero przechodzi program dalej gdzie zbiera próbki przez cały równy okres. W praktyce teraz wynosi 184. Gdyby w pętli zbierania próbek coś dołożył, wydłużyłbym czas pomiędzy zbieraniem próbek i wartość L spada.
Póki co zmieniłem dyrektywy
$hwstack
$swstack
$framesize
Po ich zwiększeniu działa parę godzin na wartościach z tablicy 200. Trzymam kciuki że to to. Jeśli tak to były one standardowo za małe i proc wyłaził poza nie nakładając się na inne zmienne.
Zmienna L dobierana jest automatycznie. Pierwsze to przejście przez zero, pomiar tylko napięcia, wtedy L przekracza nawet waha się między 0 a 300, teraz mam ją na 500. Tutaj nie zbiera danych do tablicy ! Tylko czeka aż pojawi sie zero. Gdy przejdzie przez zero przechodzi program dalej gdzie zbiera próbki przez cały równy okres. W praktyce teraz wynosi 184. Gdyby w pętli zbierania próbek coś dołożył, wydłużyłbym czas pomiędzy zbieraniem próbek i wartość L spada.
Póki co zmieniłem dyrektywy
$hwstack
$swstack
$framesize
Po ich zwiększeniu działa parę godzin na wartościach z tablicy 200. Trzymam kciuki że to to. Jeśli tak to były one standardowo za małe i proc wyłaził poza nie nakładając się na inne zmienne.
-
keruseykaryu