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ę?
Bascom, Atmega8, dziwny problem z przerwaniami
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.
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.
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
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.
.
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.
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.
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.
Drobna sugestia patrząc na Twój problem i Twoją historię na forum: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.
Rozważ wykonanie kroku naprzód i przejście na język C.
Więc Waitms nie wyłącza przerwań.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.
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
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
Returnogó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.
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?
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?