Bascom, Atmega8, dziwny problem z przerwaniami

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
Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Bascom, Atmega8, dziwny problem z przerwaniami

Post autor: M@ciej » 03 maja 2012, 8:40

Witam. Chciałem zrobić termometr na DS18B20 i wyświetlaczach multipleksowanych. Multipleksowanie robię w przerwaniach od Timer0, natomiast obsługa DSów jest w pętli głównej. Jak wiadomo, przy obsłudze DSów trzeba odczekać 750ms na konwersję i wtedy zaczynają się hocki-klocki: wyświetlacze wariują a na sam czas oczekiwania wskazują 0.
Nie wiem, czy nie brakuje jakiegoś stosu, gdyż program jest długi (ponad 80% zajętości flash) ze względu na dużą liczbę obliczeń na zmiennych typu Single.

Czy ktoś miał podobną sytuację?

Awatar użytkownika
Ertew
Użytkownik
Posty: 1414
Rejestracja: 03 lip 2005, 10:36
Lokalizacja: Leszno
Kontakt:

Post autor: Ertew » 03 maja 2012, 12:52

Rzuć kod albo streść co on robi, bo tak to wróżenie z fusów.

Generalnie powinieneś na czas komunikacji z DSem wyłączać przerwania żeby nie zakłócały komunikacji. Poza tym od odczytania temperatury z DS do końca konwersji powinieneś pracować na jakimś zestawie zmiennych.
Po uzyskaniu gotowego wyniku przepisz go do oddzielnej zmiennej która jest wyświetlana na wyświetlaczach.
Liczby zmiennoprzecinkowe spróbuj wywalić. Temperaturę pomnóż przez 10 albo 100 i zapisz do liczby całkowitej, przy wyświetlaniu dodasz przecinek w odpowiednim miejscu.

Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Post autor: M@ciej » 04 maja 2012, 9:10

Poniżej podaję fragment programu, który obsługuje wyświetlacze (Nixie) i występuje ten błąd. Pomyślałem sobie, by te 750 ms odliczyć w przerwaniach, ale później wejdzie obsługa klawiatury, gdzie trzeba odczekać 25 ms na eliminację drgań styków i sprawa się jeszcze bardziej komplikuje. Nie wiem, dlaczego WAITMS w pętli głównej zatrzymuje przerwania, pierwszy raz się z czymś takim spotykam. Przecież przerwania powinny iść niezależnie od tego, co w pętli głównej, chyba, ze chcemy je specjalnie zatrzymać, ale tutaj nic takiego nie robię.

Kod: Zaznacz cały

$regfile = "m8def.dat"
$crystal = 2000000

Config Timer0 = Timer , Prescale = 8
On Timer0 Przerwanie
Enable Timer0
Enable Interrupts

Config 1wire = Portc.5

A1 Alias Portb.7
A2 Alias Portd.5
A3 Alias Portd.6
A4 Alias Portd.7
A5 Alias Portb.0

Da Alias Portb.2
Db Alias Portb.3
Dc Alias Portb.4
Dd Alias Portb.5
Dp Alias Portc.0

Dim Tryb As Byte                                            '0-czas, 1 temp1, 2-temp2, 3 swiatlo, 4 cykliczny
Dim Licz As Byte
Dim Liznak As Byte
Dim Symbol As Byte
Dim Liczba1 As Byte
Dim Liczba2 As Byte
Dim Liczba3 As Byte
Dim Liczba4 As Byte
Dim Kropka As Byte

Dim Nukl As Byte                                            'liczba ukladow 1-W                                            'zmienne licznikowe
Dim T As Integer
Dim T1 As Single
Dim Odczyt(2) As Byte
Dim Adres1(17) As Byte
Dim Cyfra(10) As Byte
Cyfra(1) = &B00000000                                       '0
Cyfra(2) = &B00000001                                       '1
Cyfra(3) = &B00000010                                       '2
Cyfra(4) = &B00000011                                       '3
Cyfra(5) = &B00000100                                       '4
Cyfra(6) = &B00000101                                       '5
Cyfra(7) = &B00000110                                       '6
Cyfra(8) = &B00000111                                       '7
Cyfra(9) = &B00001000                                       '8
Cyfra(10) = &B00001001                                      '9

Dim Znak(4) As Byte                                         'zmienna znaku
Znak(1) = &B00000100                                        '-
Znak(2) = &B00001001                                        '+
Znak(3) = &B00000000                                        '~
Znak(4) = &B00000001                                        'nic nie wyświetli
tryb=1

Do

Select Case Tryb
 Case 1:                                                   'tryb 1, wyświetlamy temperaturę z czujnika 1
 '   1wreset
 '   1wwrite &H55                                            'Polecenie Match ROM dla wiecej niz 1 kostek
 '   1wwrite Adres1(1) , 8                                   'adres  kostki
 '   1wwrite &H44                                            'Polecenie konwersji
    Waitms 750                                              'czekanie na konwersje
 '   1wreset
 '   1wwrite &H55                                            'Polecenie Match ROM dla wiecej niz 1 kostek
 '   1wwrite Adres1(1) , 8                                   'adres  kostki
 '   1wwrite &HBE                                            'polecenie odczytu z DS18B20
 '   Odczyt(1) = 1wread(2)                                   '1-LSB, 2-MSB                                'odczytaj dwa pierwsze bajty

   T = &B1111111111001110
  If T.12 = 0 Then                                          'liczby dodatnie
   T1 = T / 2
   Symbol = 2                                               'zaswiec plus
  Else
   T = Not T
   T = T + 1
   T1 = T / 2
   Symbol = 1                                               'zsawiec minus
  End If

    T1 = Abs(t1)

    If T1 < 10 Then
     Liczba1 = T1                                           'mamy 1 liczbe
     T1 = T1 - Liczba1                                      'odejmujemy część całkowitą
     T1 = T1 * 10                                           'mnożymy przez 10
     Liczba2 = T1                                           'mamy 2 liczbę
     T1 = T1 - Liczba2
     T1 = T1 * 10
     Liczba3 = T1
     T1 = T1 - Liczba3                                      'mamy 3 liczbę
     T1 = T1 * 10
     Liczba4 = T1
     Kropka = &B00000010                                    'zaświecamy odpowiednią kropkę
    Else
     T1 = T1 / 10
     Liczba1 = T1                                           'mamy 1 liczbe
     T1 = T1 - Liczba1                                      'odejmujemy część całkowitą
     T1 = T1 * 10                                           'mnożymy przez 10
     Liczba2 = T1                                           'mamy 2 liczbę
     T1 = T1 - Liczba2
     T1 = T1 * 10
     Liczba3 = T1
     T1 = T1 - Liczba3                                      'mamy 3 liczbę
     T1 = T1 * 10
     Liczba4 = T1
     Kropka = &B00000100                                    'zaświecamy odpowiednią kropkę
    End If

  End Select

Loop
End

Przerwanie:
 Load Timer0 , 250
 Incr Licz

  Select Case Licz
  Case 1:
   A1 = 1 : A2 = 0 : A3 = 0 : A4 = 0 : A5 = 0
   Da = Znak(symbol).0
   Db = Znak(symbol).1
   Dc = Znak(symbol).2
   Dd = Znak(symbol).3
  Case 3:
   A1 = 0 : A2 = 1 : A3 = 0 : A4 = 0 : A5 = 0
   Incr Liczba1
   Da = Cyfra(liczba1).0
   Db = Cyfra(liczba1).1
   Dc = Cyfra(liczba1).2
   Dd = Cyfra(liczba1).3
   Dp = Kropka.0
  Case 5:
   A1 = 0 : A2 = 0 : A3 = 1 : A4 = 0 : A5 = 0
   Incr Liczba2
   Da = Cyfra(liczba2).0
   Db = Cyfra(liczba2).1
   Dc = Cyfra(liczba2).2
   Dd = Cyfra(liczba2).3
   Dp = Kropka.1
  Case 7:
   A1 = 0 : A2 = 0 : A3 = 0 : A4 = 1 : A5 = 0
   Incr Liczba3
   Da = Cyfra(liczba3).0
   Db = Cyfra(liczba3).1
   Dc = Cyfra(liczba3).2
   Dd = Cyfra(liczba3).3
   Dp = Kropka.2
  Case 9:
   A1 = 0 : A2 = 0 : A3 = 0 : A4 = 0 : A5 = 1
   Incr Liczba4
   Da = Cyfra(liczba4).0
   Db = Cyfra(liczba4).1
   Dc = Cyfra(liczba4).2
   Dd = Cyfra(liczba4).3
   Dp = Kropka.3
  Case 11:
   Licz = 0

 End Select

Return

Ustal_adresy:

 Nukl = 1wirecount()
 If Nukl = 0 Then
 End If
 Adres1(1) = 1wsearchfirst()                                'komórki 1-8 na adres 1 ukladu
 Adres1(9) = 1wsearchnext()                                 'komórki 9-16 na adres 2 ukladu
Return


Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Post autor: M@ciej » 08 maja 2012, 19:18

Poznęcałem się trochę nad programem i wynika z niego,że podczas wykonywania instrukcji WAITMS w pętli głównej, zatrzymują się przerwania. Patrzałem w necie, czy ktoś miał podobny problem i jakoś nikomu przerwania nie stawały od WAITMS.
Więc albo ja czegoś nie wyłapałem podczas nauki bascoma, może o czymś zapomniałem, albo wersja, którą posiadam ma jakiś feler (1.11.9.8).

Każę wyświetlać na Nixach stałą wartość, np. "1234" i niby wszystko chodzi, obraz jest stabilny. Teraz po naciśnięciu klawisza każę wykonać tylko odczekanie, powiedzmy "Waitms 150". Podczas naciskania klawisza wyświetlacz przygasa, co oznaczałoby, że przerwania nie są wykonywane w tym czasie. Wedle mojej dotychczasowej wiedzy, nawet WAITMS powinien być przerwany w celu wykonania przerwania od Timer0. Mam jeszcze skonfigurowany Timer1, który generuje PWM przetwornicy dla Nixie, ale z tego co pamiętam, PWM działa niezależnie.

Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 08 maja 2012, 21:02

M@ciej pisze:Poznęcałem się trochę nad programem i wynika z niego,że podczas wykonywania instrukcji WAITMS w pętli głównej, zatrzymują się przerwania. Patrzałem w necie, czy ktoś miał podobny problem i jakoś nikomu przerwania nie stawały od WAITMS.
Więc albo ja czegoś nie wyłapałem podczas nauki bascoma, może o czymś zapomniałem, albo wersja, którą posiadam ma jakiś feler (1.11.9.8)
Drobna sugestia patrząc na Twój problem i Twoją historię na forum:
Rozważ wykonanie kroku naprzód i przejście na język C.

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

Post autor: kayron » 08 maja 2012, 21:20

Instrukcja wstrzymuje działanie programu na podaną ilość milisekund. Odmierzany czas jest wartością przybliżoną, więc nie należy stosować tej instrukcji do jego dokładnego odmierzania. Używanie przerwań, może znacznie wydłużyć działanie instrukcji.
Instrukcję przewidziano do generowania opóźnień przy transmisji magistralą I2C. Dla przykładu: układ pamięci szeregowej potrzebuje 10ms by zapisać dane. Instrukcja WAITMS pozwala na łatwe odmierzenie tego czasu.
Więc Waitms nie wyłącza przerwań.
Druga sprawa.
W strasznie skomplikowany i przekombinowany sposób sterujesz wyświetlaczem. Jeżeli sterowanie lampą NXE nie różni się od sterowania, wyświetlaczem LED, to można to zrobić 20x prościej i wydajniej, angazując w to 10x mnie zasobów pamięci tak operacyjnej jak i FLASH.
Szczerze aż sam się dziwie że ten program się kompiluje w BASCOM :o (co sugeruje jakiś czeski błąd), bo nie mogę dojść, co robi i gdzie jest zadeklarowana ta procedura obsługi przerwań.

Kod: Zaznacz cały

Ustal_adresy:

 Nukl = 1wirecount()
 If Nukl = 0 Then
 End If
 Adres1(1) = 1wsearchfirst()                                'komórki 1-8 na adres 1 ukladu
 Adres1(9) = 1wsearchnext()                                 'komórki 9-16 na adres 2 ukladu
Return
Nie potrafię odnaleźć jej deklaracji w postaci On przerwanie Ustal_adresy
ogólnie taka zajefajna sprawą w BASCOM jest to że potrafi czasem skompilować program który nie ma prawa działać, bez żadnych errorów. Sam się kiedyś na tym naciąłem, a rozchodziło sie tylko o to co gdzie i w jakiej kolejności jest napisane w kodzie.

Awatar użytkownika
M@ciej
Użytkownik
Posty: 736
Rejestracja: 13 sie 2005, 21:38
Lokalizacja: Szczecin

Post autor: M@ciej » 09 maja 2012, 17:30

Akurat program obsługi przerwań typu On Timer0 jest dobrze napisany i wskazuje na podprogram "przerwanie". Jednym z błędów, jakie wczoraj spostrzegłem jest regulacja napięcia przetwornicy w pętli głównej. Jak zatrzymamy ją WaitMS, wszystko gaśnie,bo przetwornica staje. Przepisanie obsługi przetwornicy (kilka linijek) do przerwań co prawda już nie gasi wyświetlaczy, ale wszystko się zeruje podczas wykonywania "Waitms" gdyż w głównej nadal tkwi pomiar ADC dzielnika przetwornicy. Spróbuję dziś w ciemno sterować przetwornicą od małych przerwanie bez kontroli napięcia, mam nadzieje, ze nie spalę wszystkiego, gdyż do programowania muszę zdjąć panel z Nixami i przetwora pracuje luzem, no ale od czego są rezystory.

Co do skomplikowania obsługi przerwań, to nie mam zielonego pojęcia, jak to prościej napisać, skoro anodami i katodami (przez 4028) sterują przykładowe piny i nie są pogrupowane w porty. Gdybym tak zrobił, byłoby pewnie prościej (Poprzedni Zegar Nixie tak miał), ale zaprojektowałem płytkę przydzielając porty po kolei. Jeśli Koledzy znają prostszą obsługę przerwań dla wyświetlaczy (nawet LED) z różnymi portami, to wdzięczny byłbym zapoznać się z kodem.

Poddałem się z tą konfiguracją. Przeprojektuję układ tak, by anodami i katodami sterowały oddzielne porty, ale pogrupowane. Np. PD.0 - Anoda1, PD1 - anoda2 itd. i podobnie z katodami, sygnały BCD też kolejno piny każdego portu, resztę wykorzystam na 1-wire i przyciski. Zastanawiam się, czy klawiatury też nie multipleksować w przerwaniach (6 przycisków). Czy tak będzie dobrze? czy można bardziej optymalnie zaprojektować ten układ?

ODPOWIEDZ