Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[Attiny2313][Bascom] Prędkościomierz, poprawność kodu.

leop 19 Dec 2010 01:50 2414 8
  • #1
    leop
    Level 13  
    Witam, jako, że w szkole nie mam programowania nowych uc postanowiłem się tego sam nauczyć.
    Zainspirował mnie projekt prędkościomierza, więc wybrałem go. Jest to mój pierwszy program i dlatego też chcę zapytać czy ma on szanse na poprawne działanie.
    Sygnał z czujnika to sygnał z hallotronu, który odbiera sygnał co 1/6 obwodu koła (czyli 0.25m). Reszta przedstawia program. (Jeśli chodzi o ubogie komentarze, to myśle, że program jest na tyle "prosty", że jest przejrzysty i tak.
    Code:
    $crystal = 1000000
    
    $regfile = "2313def.dat"

    Config Lcd = 16 * 1
    Config Lcdpin = Pin , Db4 = Portb.2 , Db5 = Portb.3 , Db6 = Portb.4 , Db7 = Portb.5 , E = Portb.6 , Rs = Portb.7




    Config Portb = &B10111111                                   'Pin Pb.1 jako wejście, reszta jako wyjścia
    Config Pind.6 = Input                                       ' wyprowadzenie PD6 jako wejście (przełacznik wyświetlania)
    Portb.0 = 0                                                 'Pin wyjścia sygnału do innego układu
    Dim Wynik As Long
    Dim A As Byte                                               'do przesuwania wyświetlacza

    Config Timer0 = Timer , Prescale = 1024
    Config Timer1 = Timer , Prescale = 8

    Cls
    Initlcd
    Lcd "Predkosciomierz"
    Wait 1
    For A = 0 To 15
    Shiftlcd Left
    Next
    Lcd "V= km/h"


    Part1:
    Do
    Timer0 = 0                                                  'wartość początkowa T0=0
    Timer1 = 0                                                  'wartość początkowa T1=0
    If Portb.1 = 1 Then                                         'czekamy na początek sygnału z czujnika
     If Portb.1 = 0 Then                                        'zaczynamy zliczać gdy stracimy sygnał z czujnika
     Start Timer1
     Start Timer0
     End If
      If Timer0 = 250 Then                                      'zbyt długi czas pomiaru
       Stop Timer1
       Stop Timer0
       Cls
       Lcd "V=0 km/h"
       Goto Part1
       End If
        Part2:
        If Portb.1 = 0 Then                                     'zapętlam program do czasu aż pojawi się sygnał z czujnika
        Goto Part2
        Else
        Stop Timer0                                             'Kończymy zliczanie
        Stop Timer1
        Timer0 = 0
        Wynik = Timer1
        Wynik = 0.25 / Wynik                                    'wynik w m/s
        End If
         If Portd.6 = 0 Then
         Wynik = Wynik * 3.6                                    'wynik w km/h
         Cls
         Lcd "V=Wynik km/h"
         Else
         Cls
         Lcd "V=Wynik m/s"
         End If
          If Wynik > 90 Then
           Set Portb.0
           Cls
           Lcd "Zwolnij!"
           Waitms 400
           Reset Portb.0
           Cls
           Lcd "V=Wynik"
           End If
    Else
    Goto Part1
    End If
    Loop
    End                                                         'end program
  • #2
    Ilmarinen
    Level 14  
    Przejrzałem program i kilka rzeczy od razu sie rzuca w oczy
    1. brak procedur obsługi przerwań od przepełnienia Timer0 i timer1
    Po skonfigurowaniu powinneś określić do jakiej procedury program ma wskoczyć po odliczeniu przez timer np 10ms Powinno być zaraz po konfiguracji timera
    Code:

    On Timer0 etykietka

    A na końcu programu
    Code:

    etykietka:
        ...
       instrukcjie
       .....
    return

    2 rzecz to wypełnienie początkowe timera podajemy w procedurze jego obsługi

    3 . Brak wyraźnie zaznaczonej głównej pętli programu Do Loop i jakieś dziwne etykietki part1 part 2

    Co do podejścia ciężko rozkapować jak chcesz mierzyć ta prędkość tutaj widzę 2 drogi liczymy ilość impulsów w określonym czasie lub liczymy czas w jakim zarejestrowano np 100 impulsów myślę że bliżej było w twoim wypadku do drugiego sposobu. Ostatnio robiłem podobny projekt pomiar prędkości zrealizowałem według 1 sposobu w procedurze obsługi przerwanie zewnętrznego INT0 zliczałem ilość wystąpień impulsów a w Timerze co 10 ms przeliczałem ten wynik na ilość imp na 10ms i zerowałem licznik
  • #3
    M. S.
    Level 34  
    Ilmarinen wrote:
    Przejrzałem program i kilka rzeczy od razu sie rzuca w oczy
    1. brak procedur obsługi przerwań od przepełnienia Timer0 i timer1


    Ale kolega nie używa przerwania od timerów.

    Program mi się nie podoba pomimo, że działać może. Kolego, dla swojego dobra zapomnij o instrukcji GOTO. Napisz program tak aby jej nie było. Wyskakiwanie z pętli do loop przez Goto Part1 jest co najmniej nieeleganckie. Lepiej uczyń to za pomocą Exit Do (jeśli koniecznie musisz).

    Piszesz, że czekasz na sygnał za pomocą:

    Code:
    If Portb.1 = 1 Then                                         'czekamy na początek sygnału z czujnika
    
     If Portb.1 = 0 Then                                        'zaczynamy zliczać gdy stracimy sygnał z czujnika


    To nie jest oczekiwanie, bo program leci sobie dalej.

    Oczekiwanie można np. zrobić tak:

    Code:
    If Portb.1 = 1 Then                                          
    
    Do: Loop Until Portb.1 = 0
    End If


    ... a są jeszcze inne sposoby.

    Co do wychwytywania impulsu z zewnątrz to najlepiej byłoby użyć przerwania zewnętrznego INT.

    P.S. Potraktuj moje uwagi jako luźne spostrzeżenia naprowadzające bardziej na "dobrą praktykę"
  • #4
    Ilmarinen
    Level 14  
    fakt przerwania od Timerów nie sa używane ale myśle że zliczanie odpowiedniego czasu lepiej zrobić w obsłudze przerwań niż w głównej pętli programu
  • #5
    leop
    Level 13  
    Dziękuje Wam za napisanie swoich spostrzeżeń bo z pewnością okażą się mi pomocne. Jest to mój pierwszy program, nikt mnie tego nie uczył, a robiłem go metodą prób i błędów, więc spodziewałem się, że jego budowa i estetyka mogą pozostawić wiele do życzenia.
    Problem czekania na sygnał nie wiedziałem jak rozwiązać więc namieszałem trochę z warunkami i wyjaśnię niejasności:
    Quote:
    Piszesz, że czekasz na sygnał za pomocą:

    Kod:
    If Portb.1 = 1 Then 'czekamy na początek sygnału z czujnika
    If Portb.1 = 0 Then 'zaczynamy zliczać gdy stracimy sygnał z czujnika


    To nie jest oczekiwanie, bo program leci sobie dalej.

    Owszem jest czekanie, bo ja wiem, że warunek:
    Code:
    If Portb.1 = 1 Then                                         'czekamy na początek sygnału z czujnika

    ma swoją drugą część z ELSE na końcu programu:
    Code:
    Else
    
    Goto Part1


    2.
    Quote:
    Oczekiwanie można np. zrobić tak:

    Kod:
    If Portb.1 = 1 Then
    Do: Loop Until Portb.1 = 0
    End If


    ... a są jeszcze inne sposoby.

    Jakie są te inne sposoby? Wolę teraz dowiedzieć się więcej na przyszłość.

    3.
    Quote:
    2 rzecz to wypełnienie początkowe timera podajemy w procedurze jego obsługi

    Nie chcę być upierdliwy, ale na tyle co ja znam Bascom to wolałbym łopatologicznie mieć wytłumaczone Wasze propozycje.

    Z góry dziękuje.

    PS. Program ma działać tak, że wykrywa dodani impuls z hallotronu, licznik zaczyna zliczać gdy impuls z czujnika osiągnie stan niski i liczy do czasu pojawienia się kolejnej jedynki.
    Zapoznam się ze wszystkimi uwagami i w ciągu tygodnia postaram się napisać na nowo cały program.
  • #6
    emarcus
    Level 38  
    leop wrote:

    Sygnał z czujnika to sygnał z hallotronu, który odbiera sygnał co 1/6 obwodu koła (czyli 0.25m). Reszta przedstawia program.



    Jeżeli faktycznie masz hallotron a nie kontaktron (Reed SW) to masz z niego 'czysty' cyfrowy sygnał, który możesz podać bezpośrednio na wejście z dowolnym interruptem (INT0 lub (INT1).
    Wystarczy odpowiednio skonfigurować Timer0 lub Timer1 aby liczyc czas pomiędzy kolejnymi impulsami (interruptami). Będzie to czas przebycia drogi 0.5 m (w/g twoich danych)/.
    Reszte sobie policzysz.
    Pozostały timer możesz użyć do naliczania dowolnych przedziałów czasowych, w których będziesz odświerzał display wyników na LCD.
    Tak na marginesie;
    Konfigurując piny LCD staraj sie (na ile to możliwe) aby Data D.4 do D.7 należały do tego samego portu. Unikaj 'zajmowania' dla LCD pinów o sczególnie ważnej drugiej alternatywnej funkcji np; INT0 albo INT1 czy też weścia sygnału dla liczników T0/T1; mogą one być przydatne w dalszej części programu.

    Timer liczący czas pomiędzy impulsami nie musi być zatrzymywany (!); wystarczy go w odpowiednim momencie wyzerować lub wpisać dowolną/stosowną wartość jeżeli tego wymaga procedura liczenia czasu.
    Odnośnie "GOTO" już wyżej ktoś to odpowiednio zreferował...

    e marcus
  • #7
    leop
    Level 13  
    Witam ponownie,
    Mam nadzieję, że tym razem mój program wygląda nieco lepiej. A oto kod:
    Code:
    $crystal = 4000000
    
    $regfile = "2313def.dat"

    Config Lcd = 16 * 1
    Config Lcdpin = Pin , Db4 = Portb.2 , Db5 = Portb.3 , Db6 = Portb.4 , Db7 = Portb.5 , E = Portb.6 , Rs = Portb.7

    Dim P As Bit                                                'Bit aktywnego pomiaru
    Dim Pz As Bit                                               'Bit zakonczenia pomiaru
    Dim A As Byte                                               'Zmienna do przesuwania tekstu na lcd
    Dim Wynikms As Single                                       'Zmienna dla wyniku w m/s
    Dim Wynik As Single                                         'Zmienna dla wyniku w km/h
    Dim Wms As Byte                                             'Ograniczam liczbe do miejsca po przecinku (w m/s)
    Dim W As Byte                                               'Ograniczam liczbe do miejsca po przecinku (w km/s)
    On Int1 Zliczanie                                           'Dla przrwania OVV1 skocz do podprogramu Przepelnienie
    On Ovf1 Przepelnienie                                       'Dla przerwania INT0 skocz do podprogramu Zliczanie
    Enable Ovf1                                                 'Włączam przerwanie od przepełnienia T1

    Config Timer1 = Timer , Prescale = 64                       'Konfiguruję T1 (16bit), czas jaki wyniesie zliczenie 65000 wynosi 0.832s

    Initlcd
    Cls
    Lcd "Prędkosciomierz"                                         'Intro na wyświetlaczu
    Wait 1
    For A = 0 To 8
    Shiftlcd Left
    Next
    Cls
    Lcd "Ruszaj!"

    ''''''''''''''Program główny''''''''''''''

    Do
    Timer1 = 0                                                  'Zeruję T1
    Reset P                                                     'Ustawiam bit pomiaru = 0
    Set Pz                                                      'Ustawiam bit zakonczenia pomiaru na 1 by wprowadzić program do pętli
    Enable Int1                                                 'Włączam przerwanie INT1


    Do
    Loop Until Pz = 0                                           'Przejdź dalej gdy bit zakonczenia pomiaru = 0
    Wynikms = 0.25 / Wynikms                                    'Wartość prędkości w m/s
    Wynik = Wynikms * 3.6                                       'Wartość prędkości w km/h
    Wms = Wynikms
    W = Wynik
       If Wynik > 90 Then
         Cls
         Lcd "Zwolnij!"
         Set Portd.6
         Waitms 400                                             'Część dotycząca wyświetlania.
         Reset Portd.6
       End If
           If Portb.0 = 1 Then
             Cls
             Lcd Wms ; "m/s"
             Waitms 400
           Else
             Cls
             Lcd W ; "km/h"
             Waitms 400
           End If
    Enable Int1                                                 'Włączam przerwanie z wejścia Int1
    Loop
    End                                                         'end program




    ''''''''''''''Podprogramy''''''''''''''


    Zliczanie:
    Toggle P                                                    'zmień wartość bitu  pomiaru na przeciwny                                                    'wyzeruj bit zakonczenia pomiaru
      If P = 1 Then
        Start Timer1
      Else
        Stop Timer1
        Disable Int1                                            'wyłaczam by nienastąpiło przypadkowe wznowienie liczenia zanim skończy się procedura programu
        Wynikms = Timer1 * 0.0000128                                     
        Reset Pz
      End If
    Return
                                                              '
    Przepelnienie:
    Disable Int1                                                'wyłączam przerwanie by
    Stop Timer1
    Wynikms = 0
    Reset Pz
    Reset P
    Return
    'Program wykorzystuje INT1 jako przerwanie które zatrzymuje bądź startuje licznik
    'za pomocą If-Then-Else.
  • #8
    emarcus
    Level 38  
    leop wrote:
    Witam ponownie,
    Mam nadzieję, że tym razem mój program wygląda nieco lepiej. A oto kod:


    Bez urazy ale to nie jest poprawna droga do programowania µC.
    Popatrz na gotowy przykład z tej strony:
    http://www.edn.com/contents/images/51205di.pdf

    Podpowiem ci więcej; skonfiguruj Timer1 z prescalerem 1024.
    W przerwaniu od INT1 lub INT0 (bez znaczenia) "łapiesz" aktualny stan Timera1 do jakiejś zmiennej np: 'time_counts' lub cokolwiek nazwiesz i zerujesz Timer1. To wszystko.
    Praktycznie jest to jedyna zmienna w całym procesie, reszta to są stałe wartości.
    Prędkość objektu/pojazdu obliczysz ze wzoru:

    speed = 2*pi*R*3600*clk/time_count*1000*x
    gdzie:
    R= promień koła,
    time-counts = ilośc cykli zliczonych przez Timer1 pomiędzy kolejnymi przerwaniami,
    x= prescaler,
    clk = taktowanie processora.
    W Do .... Loop znajdzie się rachunek obliczenika prędkości (wyjątkowo prosty),
    oraz obsługa wyniku na LCD.

    e marcus
  • #9
    leop
    Level 13  
    e marcus,
    Jak najbardziej rozumiem to co napisałeś, ale teraz to chciałbym wiedzieć czy mój kod ma rację bytu, czy zadziała. Fakt, jest dużo zmiennych, ale usuwając dodatkowe "funkcje" czyli m/s i km/h, czy też ekran powitalny programu zostaje mało. Co jest złego w tym kodzie?