logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Jak zapewnić dokładny pomiar czasu reakcji w ATMEGA8 dla dwóch strzelców?

emilax 09 Mar 2008 13:48 6145 9
REKLAMA
  • #1 4889718
    emilax
    Poziom 12  
    Posty: 22
    Ocena: 4
    Witam wszystkich majsterkowiczów :D

    Oto mój jeden z pierwszy programów napisanych na ATMEGE 8. Dotychczas programowanie mikrokontrolerów traktowałem jako zabawę, używając do tego BASCOMA i zestawu Treningowego. Obecnie stoję przed zamiarem budowy pewnego urządzenia ale przed rozpoczęciem prac chciałbym mieć pewność że część programowa będzie ok.
    Sam nie jestem żadnym specjalistą od programowania mam parę napisanych programów w Pascalu, c++ czy Delphi ale raczej wszystkie prace są okupione ogromną ilością godzin spędzonych przy komputerze i wyrwanych włosów oczywiście….

    Ale do rzeczy, urządzenie ma za zadanie zmierzy czas reakcji dwóch strzelców mierzących do celu. Procedura wygląda następująco:

    1 - Urządzenie w stanie gotowości.
    2 – Naciskamy przycisk START. Od naciśnięcie przycisku start następuje losowe załączenie w ciągu 8 sekund lampy bądź sygnalizatora dźwiękowego dającego strzelcom sygnał do oddania strzału. Od momentu uruchomienia sygnalizatora następuje odmierzanie T czasu.
    3 – Zawodnicy oddają strzał aktywując przy tym sensory u celu, które automatycznie określają przedział czasu T1 i T2. (T1w = T1-T oraz T2w = T2-T)
    4 – Procesor wylicza czasy reakcji i wyświetla czas zwycięzcy
    5 – Po naciśnięciu przycisku RESET wszystko wraca do punktu nr 1.

    Program po wgraniu do procesora i emulacji na przyciskach działa aczkolwiek w mojej głowie rodzą się pewne pytania i wątpliwości oto i one:

    1. Używając kwarcu 8MHz i przy wybraniu preskalera 8 przy załadowaniu do licznika TIMER0 wartości 156, przerwanie zostaje wywołane co 0,1 ms. Moje pojęcie wywołania tego przerwania jest następujące - (jeżeli jest mylne prosiłbym o wyprowadzenie z błędu), Zmienna Ti w ciągu 0,1 ms zwiększa swoją wartość TYLKO o jeden.

    Pomiar:				‘ Przerwanie
    
    Timer0 = 156                                                
    If Licz = 1 Then
                		Incr Ti
    End If
    Return


    2. Czy ATMEGA 8 jest na tyle szybka aby dokonać pomiaru takiego czasu rzędu 0,1 ms w istniejącym programie, czy też byłaby potrzebna jakaś wstawka asemblerowa. Czytałem w różnych poprzednich postach że przy precyzyjnych pomiarach czasu najlepszy jest asembler ponieważ można policzy czasy procedur co do jednego cyklu zegara. Nie zamierzam tu wywoływać zażartej polemiki pomiędzy zwolennikami prostych języków programowania a programistami używającymi asemblera, bo wskazania logiki mówią o tym że asembler pod tym względem jest dużo lepszy, niestety nie każdy miał z nim do czynienia i nie każdy go rozumie.
    Jednak wracając do problemu, czy procedury bascom’owe w tym przypadku nie będą spowalniały pomiaru zegara.
    Czy istniałby sens zmiany preskalera na 1, automatycznie zmiany czasu wywołania przerwania a tym samym uprecyzyjnienia pomiaru, czy ma to sens dla tego procesora, czy poradziłby on sobie z takim zliczaniem przy użyciu istniejącego kodu. Czy też musiałbym urzyc czegoś szybszego.

    W przypadku niejasności co do kodu proszę pytać, jestem ciekaw ile popełniłem błędów a co do optymalizacji wiem że każdy ma swoje drogi i rozwiązania. Ja na razie oparłem to na części czysto teoretycznej aczkolwiek praktyka pokazała że program po wgraniu do procesora działa, tylko zastanawia mnie na ile realne jest zliczenie tego czasu. Nie wiem też za bardzo jakie w rzeczywistości mogą by różnice pomiędzy dwoma osobnikami oddającymi strzał, tak że z góry zakładam najmniejszy przedział czasu dostępny w mojej testowej konstrukcji ATMEGA 8 .

    Oto listing programu

    $crystal = 8000000
    
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portd.5 , Db5 = Portd.6 , Db6 = Portd.7 , Db7 = Portd.4 , E = Portd.3 , Rs = Portd.2
    
    Config Portb = &B11000110 : Portb = &B1111001
    Config Portc = &B11111110 : Portc = &B00000001
    Config Portd = &B11111111 : Portd = &B00000000
    
    Config Timer0 = Timer , Prescale = 8 :
    
    Dim A1 As Byte
    Dim A2 As Byte
    Dim Ti As Long
    Dim T1 As Long
    Dim T2 As Long
    Dim Tl As Byte
    Dim T1r As Single
    Dim T2r As Single
    Dim Licz As Bit
    Dim C As Bit
    
    Declare Sub Czysc
    Declare Sub Show
    Declare Sub Losuj
    
    A1 = 0 : A2 = 0 : Licz = 0 : C = 0 : Ti = 0 : T1 = 0 : T2 = 0
    
    Cls
    Lcd " Hey Guys !!!"
    Lowerline : Lcd "  Lets Go !!!" : Cursor Off
    
    
    '---------------------------------main program-----------------------------------------
    
    On Timer0 Pomiar
    
    Do
       If Pinc.0 = 0 Then                                       'Pushbutton RESET
                     Czysc                                     
                     End If
       If Pinb.5 = 0 And C = 0 Then		'Pushbutton START
                               C = 1
                               Losuj
                               Enable Interrupts : Enable Timer0
                               Licz = 1
                               End If
    
    If A1 = 1 And A2 = 1 Then
                            Show
                            End If
    Loop
    End                                                         'Glowna petla programu
    
    '----------------------------------przerwanie------------------------------------------
    Pomiar:
    
    Timer0 = 156                                                '
    
    
    If Pinb.3 = 0 And A1 = 0 Then                               'Uruchamia strzelec nr 1
                            A1 = 1 : T1 = Ti                    'in 0-zwarte do masy
                            End If
    
    If Pinb.4 = 0 And A2 = 0 Then                               'Uruchamia strzelec nr 2
                            A2 = 1 : T2 = Ti
                            End If
    
    If Licz = 1 Then
                Incr Ti
                End If
    Return
    
    '-----------------------procedura pokazania wyniku------------------------------
    Sub Show
    
    Cls
    
    Disable Timer0
    T1r = T1 / 10000
    T2r = T2 / 10000
    
    Lcd "T1=" ; T1r ; " S"
    Lowerline
    Lcd "T2=" ; T2r ; " S"
    
    If T1 > T2 Then                                             'wygrywa nr 2
               Portb.2 = 1
               End If
    If T1 < T2 Then                                             'wygrywa nr 1
               Portb.1 = 1
               End If
    A1 = 0 : A2 = 0
    
    
    Cursor Off
    End Sub
    
    '-----------------------procedura zerowania i kasowania ekranu------------------
    
    Sub Czysc
                   Cls
                   Lcd " Hey Guys !!!"
                   Lowerline : Lcd "  Lets Go !!!" : Cursor Off
                   Portb.1 = 0 : Portb.2 = 0
                   Ti = 0 : T1 = 0 : T2 = 0 : A1 = 0 : A2 = 0 : Licz = 0 : C = 0
                   Portd.0 = 0                                  'Wylaczenie sygnalizatora
    
    
    
    
    End Sub
    
    '-----------------------procedura losowania czasu do startu------------------
    
    Sub Losuj
                   Cls
                   Lcd "....Counting...."
                   Tl = Rnd(8) : Incr Tl
                   Wait Tl
                   Portd.0 = 1              'Sygnalizator, Lampa, syrena - cokolwiek
    
    End Sub
    


    Z góry dziękuję za wszystkie sugestie i porady. Pozdrawiam wszystkich użytkowników portalu.

    :D:D:D
  • REKLAMA
  • #2 4889818
    nsvinc
    Poziom 35  
    Posty: 2870
    Pomógł: 262
    Ocena: 88
    jesli juz chcesz to pisać w jakims jezyku wysokiego poziomu to polecam C...w bascomie masz zero kontroli nad rzeczywistym wykonywaniem komend i czasem ich trwania. Zeby zmierzyc czas z dokladnoscia 0.1s nie potrzebujesz asemblera do tego, wystarczy zastosowac timer...
  • REKLAMA
  • #3 4889993
    asembler
    Poziom 32  
    Posty: 2099
    Pomógł: 123
    Ocena: 11
    No tak asembler ci to mówi:)
    Nawet z wieksza dokładnością 0.000 001s
  • #4 4890033
    nsvinc
    Poziom 35  
    Posty: 2870
    Pomógł: 262
    Ocena: 88
    Ale chyba az tyle to nie potrzeba :D Teoretycznie bascom tez potrafi stworzyc w miare normalny kod o ile sie nie namota warunkami...Twoj kod mozna napisać prościej :) Twój timer buja z prędkością 1MHz, po co, skoro wymagana dokladnosc wynosi 0.1s?
  • REKLAMA
  • #5 4913250
    emilax
    Poziom 12  
    Posty: 22
    Ocena: 4
    Dziękuję za zainteresowanie tematem !!! Chwilowo wystąpił u mnie brak czasu i przystopowanie projektu ale mam nadzieję że w tym tygodniu będzie już lepiej.

    Na początku kilka przemyśleń „do użytkownika nsvinc” odnośnie C+ czy asemblera wiem że jest on dużo dokładniejszy i nie mam co do tego wątpliwości jeżeli chodzi o zagadnienia związane z czasem. Jeszcze raz zaznaczam że nie zamierzam wywoływać dyskusji co jest lepsze (rower czy samochód) ….. Ja na obecny dzień dysponuje tylko umiejętnością pisania w Bascomie i to mi musi wystarczyć.

    Niestety moja wiedza na temat praktycznego zastosowania Bascoma w realizacji mikroprocesorowych projektów nie jest zbyt obszerna, dlatego też nękają mnie pewne pytania wynikające z różnic pomiędzy zastosowaniem symulatora a realnym procesorem.

    Q1. Czy powyższy kod będzie w stanie realnie odmierzyć czas z dokładnością co do 0,1 milisekundy (nie 0,1 sekundy), czy ustawienie preskalera na 8 (timer0 1Mhz) i warunki w pętli przerwania nie opóźnią zbytnio mierzonego czasu lub też go nie zafałszują.

    Q2. Jak się sprawa będzie miała jeżeli ustawię preskaler na 1 (timer0 8Mhz) i zwiększę szybkość wywołania przerwania. Czy to Bedze miało sens ????
    Rozumiem że warunki i pętlę w procedurze przerwania tłumaczone na ilość cykli maszynowych (taktów zegara) opóźniają realne odmierzanie czasu.

    Q3. Jak ewentualnie można uprościć kod samego przerwania ???

    Q4. Jaka jest najmniejsza jednostka czasu możliwa do zmierzenia Atmegą8 przy użyciu Bascoma i na ile taki pomiar jest wiarygodny ??? Nie pytam teraz o procedury pisane w C lub asemblerze.

    Q5. Czy ewentualnie procedura odmierzenia czasu w asemblerze albo innym precyzyjniejszym kompilatorze dla tego przypadku byłaby bardzo skomplikowana ???

    Q6. Czy ktoś byłby w stanie wyliczyć błąd pomiaru na podstawie istniejącego kodu. Ewentualnie zasugerować co zmienić aby ten błąd był jak najmniejszy.

    Dzięki za wszelkie sugestie i pozdrawiam.:idea:
  • REKLAMA
  • #6 4913427
    asembler
    Poziom 32  
    Posty: 2099
    Pomógł: 123
    Ocena: 11
    Mnie sie wydaje ze dokladnosc pomiaru nie zalezy od uzytego jezyka.
    W przypadku 1MHz bedzie to 0.001mS oczywiscie to jest rozdzielczosc (1 mln probek na sek)bo co do dokladnosci to trzba uwzglednic czy ten 1MHZ to rzeczywiscie 1MHz
  • #7 4913509
    nsvinc
    Poziom 35  
    Posty: 2870
    Pomógł: 262
    Ocena: 88
    Co do bascoma...jako ze generuje wolny kod to nie możesz wepchnąć rozbudowanej obsługi licznika w przerwanie, bo pogubisz takty albo wykopyrtniesz procesor bo sie stos przepełni(w przypadku gdybys w obsłudze przerwań nie wyłączał przerwań, a w trakcie trwania jego obsługi wystąpiło następne przerwanie i tak w kółko)
    Musisz wziąć pod uwagę czas reakcji procesora.
    W twoim przypadku NA PEWNO NIE możesz użyc przerwan SYNCHRONICZNYCH...
    1.Musisz zastosować mege64 albo 128, w ktorej pierwsze 4 zewn przerwania są asynchroniczne...
    2.Nie pchaj kodu w suby tu gdzie nie musisz, sub=skok a skok trwa....
    3.PRZERWANIE CO 1uS OD TIMERA W MEGAxx i BASCOM= ZAPOMNIJ...

    Lepsza technika:
    W momencie "start" odpalasz timer, i to nie 8bitowy tylko 16, preskaler na /64, jesli masz kwarc 8mhz, to licznik buja z f=125kHz, więc zwieksza sie co 0.000008s, więc to ci powinno wystarczyć...Przerwanie przepełnienia licznika bedzie wywalać co 0.524288s

    Jak wystąpi przerwanie zewn. z jakiegos INTa, to tylko przechwytujesz zawartość tego timera .

    W samej obsludze przerwania od timera...
    
    timer1_isr:
    incr licznik_przepelnien
    return
    


    Przerwanie INT0, przyklad
    
    ilosc_taktow=timer1
    temp=licznik_przepelnien*65536
    ilosc_taktow=ilosc_taktow+temp
    


    Oczywiscie musisz to rozszerzyć o warunek ktory sprawdza czy oba przerwania juz zostaly wyzwolone, np na flagach jak w twoim przykladzie

    Ale jesli juz posiadasz gotowe zmienne zawierajace ilosc zliczonych taktów od "start" do przerwania, to
    moj_czas=ilosc_taktow*0.000008
    Czas dostaniesz w mikrosekundach :)

    Nie wiem czy dobrze opisałem, moge tylko domniemać bo sie nie bawiłem w mierzenie superkrótkich odstępów czasu :D

    pozdrawiam

    Dodano po 4 [minuty]:

    asembler: dokladnosc NIE zalezy od uzytego języka, ale skutecznosc wykonywania kodu juz tak.
    Napisalem to kierujac sie wyzej wspomnianym powolnym kodem z bascoma w przerwaniu, juz sie pare razy naciołem jak pisalem cos w bascomie, a po przejsciu na C problem prawieże zniknął...
  • #8 4913549
    asembler
    Poziom 32  
    Posty: 2099
    Pomógł: 123
    Ocena: 11
    Po co utrudniac sobie życie jeżeli jest w Atmedze taka nóżka (ICP), która zrobi to sama wszystko i nie pogubi ani jednego taktu procesora.
  • #9 4913607
    nsvinc
    Poziom 35  
    Posty: 2870
    Pomógł: 262
    Ocena: 88
    ano racja, tez chcialem o tym wspomnieć a zapomnialem jak sie ten pin nazywa :D:D a datasheet nie chcial mi sie otworzyc bo komp jest w agonii :D

    Ale autor tematu musi przechwycić DWIE wartośći więc bedzie musiał zastosować dodatkowy uklad logiczny przed tym pinem...Chybaże sprzężyć jakoś pin ICP z INTami....:D
  • #10 4913673
    asembler
    Poziom 32  
    Posty: 2099
    Pomógł: 123
    Ocena: 11
    Jest powiedziane ze wylicza czasy reakcji i wyswietla czas zwyciezcy
    Dla mnie mozna przyjąc ze czas przegranego jest juz z góry wiadomy bo i tak nie ujrzy światła dziennego. Inaczej mówiac mierzymy tylko czas zwycięzscy oraz musimy wskazac kto zwycięzył.

    Dodano po 3 [minuty]:

    Poza tym pierwsze wywolanie przerwania od ICP to pomiar czasu teraz mozna badac dowolnie długo od którego pinu jest to przerwanie bo zakladam ze kazdy zawodnik bedzi emial swoj pin. Rozwijajac temat mozna w ten sposób rozróznic nie tylko dwóch zawodników.

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy realizacji dokładnego pomiaru czasu reakcji dwóch strzelców za pomocą mikrokontrolera ATMEGA8. Autor planuje urządzenie, które po naciśnięciu przycisku START losowo w ciągu 8 sekund uruchamia sygnał świetlny lub dźwiękowy, a następnie mierzy czas reakcji dwóch zawodników. Wskazano, że do precyzyjnego pomiaru czasu (rzędu 0,1 ms) nie jest konieczne użycie asemblera, wystarczy dobrze skonfigurowany timer w języku C lub Bascom, choć Bascom generuje mniej optymalny kod i może mieć ograniczenia w obsłudze przerwań. Zalecane jest użycie 16-bitowego timera z preskalerem, np. przy kwarcu 8 MHz timer może działać z częstotliwością 125 kHz, co pozwala na rozdzielczość pomiaru około 8 µs. Wskazano również na możliwość wykorzystania funkcji ICP (Input Capture Pin) w ATMEGA8, która umożliwia dokładne przechwycenie momentu zdarzenia bez utraty taktów procesora. Problemem pozostaje konieczność pomiaru dwóch niezależnych sygnałów, co może wymagać dodatkowej logiki lub sprzężenia pinów ICP z przerwaniami zewnętrznymi. Dyskusja podkreśla, że dokładność pomiaru zależy bardziej od sprzętu i konfiguracji timerów niż od języka programowania. Wskazano także ograniczenia Bascoma w kontekście obsługi przerwań i konieczność unikania rozbudowanych procedur w przerwaniach, aby nie utracić taktów procesora.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA