[Atmega32][Bascom] Zawieszanie programu

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
niezly
-
Posty: 4
Rejestracja: 29 lis 2011, 13:24
Lokalizacja: Net

[Atmega32][Bascom] Zawieszanie programu

Post autor: niezly » 29 lis 2011, 13:35

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źć.

Awatar użytkownika
Pikczu
Użytkownik
Posty: 754
Rejestracja: 18 lip 2005, 18:33
Lokalizacja: Dublin
Kontakt:

Post autor: Pikczu » 29 lis 2011, 14:03

Najlepiej wklej kod nie napisałeś jaki procek jak wersja bascoma i jak szybko go pędzisz.
Więc ciężko tak wywróżyć co jest nie tak.

niezly
-
Posty: 4
Rejestracja: 29 lis 2011, 13:24
Lokalizacja: Net

Post autor: niezly » 29 lis 2011, 14:27

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

Awatar użytkownika
kayron
Użytkownik
Posty: 2088
Rejestracja: 21 wrz 2008, 12:53
Lokalizacja: Poland
Kontakt:

Post autor: kayron » 29 lis 2011, 18:40

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 
A ile wynosi L które jest warunkiem w pętli ?
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
 
wtedy masz pewność że nie wyskoczysz poza obszar zdefiniowany dla tablicy.

keruseykaryu

Post autor: keruseykaryu » 29 lis 2011, 18:44

A ile wynosi L które jest warunkiem w pętli ?
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.
No i niech nie startuje od zera tylko od 1.

Awatar użytkownika
kayron
Użytkownik
Posty: 2088
Rejestracja: 21 wrz 2008, 12:53
Lokalizacja: Poland
Kontakt:

Post autor: kayron » 29 lis 2011, 18:48

No i niech nie startuje od zera tylko od 1.
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.

Kod: Zaznacz cały

Loop Until Zero2 = 1 Or L = 300 
A dla czego w tym fragmencie L masz równe 300 skoro indexów tablicy masz 200 :?:
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.

niezly_kr
-
Posty: 6
Rejestracja: 29 lis 2011, 21:32
Lokalizacja: Net

Post autor: niezly_kr » 29 lis 2011, 21:42

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.

keruseykaryu

Post autor: keruseykaryu » 30 lis 2011, 6:42

niezly_kr pisze:Póki co zmieniłem dyrektywy
$hwstack
$swstack
$framesize
Po ich zwiększeniu działa parę godzin na wartościach z tablicy 200.
Odsunąłęś tym tylko widmo crash-u. Ale ten jest dalej nieunikniony.
I zainteresuj się "wiecznie głodnym psem", by zresetował procka jak coś się majtnie.

niezly
-
Posty: 4
Rejestracja: 29 lis 2011, 13:24
Lokalizacja: Net

Post autor: niezly » 30 lis 2011, 7:54

Dzięki :) Bardzo pocieszające stwierdzenie z rana .....
Działa ponad 6h idelanie. Może po prostu brakowało mu pamięci stosu i nadpisywał mi zmienne ? To było by wyjaśnienie dłuższego działania na zadeklarowanej tablicy 400. Nadpisywał zmienne z tablicy których nie używał program.

Awatar użytkownika
Pikczu
Użytkownik
Posty: 754
Rejestracja: 18 lip 2005, 18:33
Lokalizacja: Dublin
Kontakt:

Post autor: Pikczu » 30 lis 2011, 9:45

Wydaje mi się ze sensownym rozwiązaniem było by użycie przerwania do wykrywania tego przejścia przez zero.

niezly
-
Posty: 4
Rejestracja: 29 lis 2011, 13:24
Lokalizacja: Net

Post autor: niezly » 01 gru 2011, 7:49

18 godzin działał idealnie i od czasu zwiększenia tych parametrów stosu itp wszelkie problemy zniknęły.
Pozdrawiam.

ODPOWIEDZ