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

[Atmega8][Bascom] Czas pomiędzy przerwaniami?

johnny99 13 Sie 2011 14:35 3254 18
REKLAMA
  • #1 9821152
    johnny99
    Poziom 17  
    Witam.

    Zbudowałem obrotomierz na Atmega8. Sprzętowo działa poprawnie by sie wydawało. Lecz odczyt obrotów samochodu jest z przedziału 6 - 30 obr/min. Wydaje mi się ze mam bład w samych obliczeniach wyniku.

    Mój obrotomierz działa następująco przy założeniu 1 impuls na obrot (w rzeczywistosci 1,5 imp/obr):
    impuls z cewki podawany jest na przerwanie int1.
    Pierwszy impuls załącza timer1 (16bit?) a drugi go wyłacza.
    Posiadam kwarc 12MHz a prescale timera1 to 256.

    Teraz tak. Jak przekształcić wartość odliczoną przez timier na Obroty na minute?

    Ja to robię tak: Kwarc / prescale (12MHz / 256 = 46875)
    czyli jedno cykniecie timera1 jest co 1 / 46875 = ok 0,000021333 s

    Teraz dla przykładu:
    600 obr / min daje 10 obr / sek co daje 10 impulsów / sek czyli 1 impuls pojawia się co 0,1 sek. Czyli w tym czasie timer1 powinien przyjąć wartość ok 4687 imp.

    Moje pytanie brzmi: czy dobrze rozumiem przekształcanie częstotliwości pracy uC na odmierzany czas przez timer1?

    Z góry dzięki za pomoc.
  • REKLAMA
  • #3 9821325
    johnny99
    Poziom 17  
    timer pracuje w trybie 16 bit.

    to jest fragment obliczania wyniku.

    Temp = Counter1 'odczytaj wartosc timera1
    Zm_pom = Zm_pom + Temp 'dodaj ja do wartosci zmiennej zm_pom
    Temp = 4218750 / Zm_pom 'oblicz predkosc
    Wynik = Temp 'zapiasz wynik do zmiennej wynik

    cos mi sie wydaje ze po prostu moje wyniki przekraczaja zadeklarowana zmienna.
    czy taki zapis jest prawidlowy przy deklaracji zmiennej Temp jako Word?
  • REKLAMA
  • #6 9821356
    johnny99
    Poziom 17  
    Sorry,

    Wiesz ja to sie z tym bawie tylko i program pisze w bascomie metoda prob i bledow.
    Za bardzo sie na tym nie znam tylko sobie przerabiam inne projekty na moje potrzeby. Chodzi mi tylko o to czy dobrze rozumiem te taktowanie procesora.

    no ale jak co to tu masz caly kod:

    
    
    $regfile = "m8def.dat"
    $crystal = 12000000
    
    
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
    Config Int1 = Falling
    Config Timer0 = Timer , Prescale = 256
    Config Timer1 = Timer , Prescale = 256
    
    On Timer1 Zw_licz_czasu                                     'przerwonia obslugi przpelnienia timera1
    On Timer0 Wys_lcd
    On Int1 Pomiar
    
    Dim Wynik As Word                                           'obliczony wynik predkosci RPM
    Dim Temp As Long                                            'zmienna pomocnicza do obliczen
    Dim Zm_pom As Long                                          'zmienna przechowujaca ilosc zliczonych impulsow podczas jednego obrotu
    Dim Zm_pom2 As Long
    Dim Zez_pom As Bit                                          'flaga zezwolenia na pomiar
    Dim Pom_zak As Bit                                          'flaga informujaca o zakonczeniu pomiaru
    Dim Licz_czas As Byte                                       'pomocniczy licznik czasu
    Dim Br_syg As Byte                                          'zmienna licznikowa graku impulsow na wejsciu
    
    
    Disable Int0
    Enable Int1
    Enable Timer1
    
    Counter0 = 0                                                'wartosc poczatkowa timera0
    Start Timer0
    Zm_pom2 = 0
    Wynik = 0
    Set Zez_pom
    Reset Pom_zak
    
    Enable Interrupts
    
    Cls                                                         'powitanie trwajace 5 sekund
    Lcd "Witaj Lukasz"
    Wait 5
    
    Enable Timer0
    
    Do                                                          'petla glowna programu
      If Pom_zak = 1 Then                                       'jezeli pomiar zakonczony to
        Disable Timer1                                          'zablokuj timer1
        Temp = Counter1                                         'odczytaj wartosc timera1
        Zm_pom = Zm_pom + Temp                                  'dodaj ja do wartosci zmiennej zm_pom
        Temp = 4218750 / Zm_pom                                 'oblicz predkosc
        Wynik = Temp                                            'zapiasz wynik do zmiennej wynik
        Reset Pom_zak                                           'zeruj flage zezwolenia na obliczenie predkosci
        Set Zez_pom                                             'ustaw flage zezwalajaca na pomiar
        Zm_pom = 0                                              'wyzeruj zmienne
        Licz_czas = 0
        Enable Timer1
      Else                                                      'w przeciwnym wypadku
        If Wynik > 0 And Br_syg = 65 Then                       'jezeli wynik >0 oraz wartosc br_syg=65 to
          nop
          nop
          nop
          Decr Wynik                                            'zmniejsz zmienna wyniku
        End If
      End If
    Loop
    
    Wys_lcd:
    Incr Zm_pom2
    If Zm_pom2 = 184 Then                                       'obsluga wyswietlacza lcd
    Cls
    Cursor  off
    Lcd "Obr/min: " ; Wynik
    Zm_pom2 = 0
    End If
    
    Return
    
    Zw_licz_czasu:                                              'przerwanie przepelnienia timera1
      Zm_pom = Zm_pom + 65536                                   'dodaj wartosc 65536 (licznik pracuje jako 16-bitowy)
      Incr Licz_czas                                            'zwieksz zmienna licz_czas
      If Licz_czas = 2 Then                                     'jezeli wartosc tej zmiennej osiagnie 2  to
        Stop Timer1                                             'zatrzymaj timer1
        Set Zez_pom                                             'ustaw flage zezwolenia na pomiar
        Br_syg = 65                                             'wyzeruj zmienna br_syg
      End If
    Return
    
    Pomiar:                                                     'obsluga przerwania int1 POMIAR
      If Zez_pom = 1 Then                                       'jezeli flaga zezwolenia pomiaru ustawiona to
        Counter1 = 0                                            'wyzeruj timer1
        Start Timer1                                            'start timer1
        Reset Zez_pom                                           'wyzeruj flage zezwolenia na pomiar
      Else                                                      'w przeciwnym wypadku
        Stop Timer1                                             'zatrzymaj timer1
        Set Pom_zak                                             'ustaw flage pomiar zakonczony
      End If
      Br_syg = 0
    Return
    


    teraz juz zmienilem temp na long i przetestuje
  • REKLAMA
  • #8 9821375
    johnny99
    Poziom 17  
    nie pytalem sie o sprawy od bascoma tylko o to czy rozumiem te timery i to przeksztalcenie.

    bo w innych jezykach to jest tak samo tylko inne komendy i takie tam.

    a to czy mozesz mi napisac czy to dobrze czaje z pierwszego postu?
  • #9 9821387
    dondu
    Moderator na urlopie...
    Żeby przeanalizować czy Twój sposób liczenia jest parwidłowy, muszę wiedzieć jak ustawiasz timer i jak łapiesz czasy, i dlatego muszę przeanalizować Twój kod . Niestety Bascoma nie znam.

    Ale spokojnie, zaraz znajdzie się jakiś Bascomowiec i Ci doradzi.
  • #10 9821393
    johnny99
    Poziom 17  
    no spoko. dzieki i tak za probe pomocy.
  • REKLAMA
  • #11 9821540
    drzasiek
    Specjalista CNC
    Ja też Bascoma nie znam więc Ci wytłumaczę jak ja bym to zrobił, może Ci się przyda.
    Masz zmienną impuls która jest inkrementowana w przerwaniu od zdarzenia zewnętrznego np zboczem opadającym.
    Ustawiasz sobie jeden Timer zgłaszający przerwanie (np od przepełnienia) powiedzmy co 1 ms.
    Deklarujesz zmienną milisekunda którą za każdym razem inkrementujesz w przerwaniu od timera jeśli jest mniejsza od 100 a jeśli jest równa 100 (czyli licznik naliczył 1 sekundę) to wtedy przepisujesz do jakiejś globalnej zmiennej wartość zmiennej impuls(czyli ile było impulsów w ciągu sekundy) oraz ustawiasz jakąś flagę, że masz nowy pomiar a następnie zerujesz zmienne milisekunda oraz impuls.
    A w pętli głównej programu masz sprawdzanie czy flaga jest ustawiona, jeśli jest to wtedy obliczasz sobie co chcesz i zerujesz flagę.

    W tym przykładzie odświeżanie wyniku będzie co 1 sekundę, można analogicznie zrobić szybciej lub wolniej.
  • #12 9821548
    johnny99
    Poziom 17  
    ja to zrobilem ze licze czas miedzy impulsami i dzialalo. teraz mi sie cos zjaralo i juz nie dziala haha jak poskladam to z powrotem do kupy to napisze czy jest dobrze. po prostu mialem zla zmienna i wychdzilem ponad jej zakres
  • Pomocny post
    #13 9822718
    Konto nie istnieje
    Poziom 1  
  • #14 9823264
    johnny99
    Poziom 17  
    to znaczy chcialem to zrobic wlasnie w taki sposob zeby liczyc czas miedzy przerwaniami. o tym drugim sposobie tez czytalem ale wybralem ten i na nim sie skupilem.

    na to nie wpadlem ze nie trzeba zatrzymywac timera non stop i go uruchamiac. tylko zerowac. byloby mniej kodu no ale wlasnie w taki sposob czlowiek sie uczy.

    przez te wszsytkie przeksztalcenia przeszedlem bez problemu tylko wynik mi zle pokazywalo gdyz przekroczylem zakres zmiennej temp typu word. Po zmianie jej na long wszystko smigalo bardzo dobrze dopoki (tak jak pisalem w poprzednim poscie) nie zjaral mi sie regulator napiecia atmega i wyswietlacz lcd. hahaha.

    Wyswietlacz jeszcze mam jeden atmegi tez pare sie znajdzie tylko ten nieszczesny regulator chyba mi brakuje. wiec na pare dni projekt utknie az zdobede regulatory nowe.

    a takie pytanie z innej beczki. regulator tak mi sie zjaral ze podawal za duze napiecie na wyjsciu rzedu 9V. Czy mozna jakos poprowadzic te zasilanie do lcd przez jakas diode (zenner 4,7V) zeby zabezpieczyc przed takimi przypadkami? Wyswietlacze sa nieco drogie. u mnie rzedu 10 euro. Wiec czy jest jakis sposob zabezpieczenia tego ukladu?
  • #15 9823385
    gaskoin
    Poziom 38  
    emarcus napisał:

    Zechcesz liczyc RPM więc na sygnał z INT1 odczytujesz zawartość timera1 i go natychmiast zerujesz. (tak zwyczajnie, - 'w biegu'). W tym momencie nie jest ważny ten pierwszy odczyt że nie jest poprawny, wszystki następne już będą rzeczywistymi wynikami wskazań Timera1 pomiędzy impulsami.
    Znając 'step' i zawartść timera1 obliczymy czas pomiędzy dwoma kolejnymi impulsami na INT1.


    A co jak ktoś jedzie baaaaardzo wolno, albo stanie na chwile na światłach/na lody ? Potem jak ruszy to mu licznik wskaże losową wartość (bo się zdąży przekręcić ze sto razy). Lepiej chyba uruchomić timer w CTC i programowo naliczać czas pomiędzy impulsami niż liczyć na to, że nasz timer jednak się nie przekręci.
  • #16 9823409
    johnny99
    Poziom 17  
    jesli ktos jedzie baaardzo wolno to i tak silnik pracuje. ja licze obroty silnika a nie kola. prescaler timera jest tak ustawiony zeby sie nie przepelnial na najnizszych obrotach. wiec nadal liczy i pokazuje poprawne wyniki.

    a jak staniesz na lody to wylaczasz silnik. chyba a jak nie to pracuje na najnizszych obrotach. tylko jak wylaczysz silnik to wtedy moze zajsc taka sytuacja ze nie zakonczy pomiaru. lecz w takim przypadku jak timer sie przepelni pare razy to wynik jest obnizany stopniowo do zera. w rzeczywistosci od razu pokaze 0 na wyswietlaczu co jest prawidlowe.

    Dodano po 1 [minuty]:

    a sorry ja sie odnioslem do mojego sposobu. wiesz jeszcze za bardzo nie kontaktuje po wczorajszej imprezie hahha
  • #17 9823416
    gaskoin
    Poziom 38  
    johnny99 napisał:
    jesli ktos jedzie baaardzo wolno to i tak silnik pracuje. ja licze obroty silnika a nie kola


    UPS :P to zdecydowanie zmienia postać rzeczy :)
  • #18 9827615
    Konto nie istnieje
    Poziom 1  
  • #19 12184006
    johnny99
    Poziom 17  
    Obrotomierz działa już kilka miesięcy bez zarzutu.
REKLAMA