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

[Attiny2313][Bascom]Różne czasy reakcji na wciskanie przycisku.

oski_pl 27 Mar 2011 19:09 2985 24
REKLAMA
  • #1 9330051
    oski_pl
    Poziom 10  
    Część Witajcie! Jestem Oskar, dopiero zaczynam przygodę z mikrokontrolerami.

    Otóż, dostałem niedawno swoją pierwszą Attiny2313. Napisałem również do niej program i pojawił się problem z przyciskami. Mianowicie gdy chcę aby przycisk zadziałał muszę jednego razu dłużej przytrzymać drugiego krócej. Zrobiłem sobie dodatkowo diodę informującą mnie kiedy mogę puścić przycisk. Zamysł mojego programu jest bardzo prosty, chodzi o to, że po wciśnięciu pierwszego przycisku zmieni się czas migania diody. Po wciśnięciu drugiego przycisku zmieni się migająca dioda (diod jest 3 plus informująca i dwa przyciski (swithe)).
    Wszytko działa poprawnie tylko denerwuje mnie czas reagowania przycisków. Raz wolniej raz szybciej. Próbowałem na 10 sposobów wyeliminować drgania styków, ale doszedłem do wniosku, że to nie ich wina (jeśli się mylę proszę o poprawę i pomoc w ich eliminacji). Dodam że pracuje na płytce stykowej, a przyciski mam podłączone przez rezystor 1Kohm do masy.

    Ogólnie chciałbym, jeżeli to jest możliwe aby przyciski działały od razy po wciśnięciu, nawet bardzo krótkim.

    Atmega pracuje również na wewnętrznym kwarcu 1Mhz. Tu pojawia się moje drugie, pewnie banalne i głupie pytanie, jak zmienić częstotliwość pracy (programowo oczywiście, bez kwarców zewnętrznych) gdyż bardzo mało o tym wiem.


    Zamieszczam program:
    
    
    
      
    $regfile = "attiny2313.dat"                                 'najpierw określamy typ proca 
    $crystal = 1000000                          'definiujemy z jakim taktowaniem będzie pracował 
    
    
    Config Portd = &B11111111                                  
           Portd = &B11111111                                    
    Config Portb = &B0000000                                    
           Portb = &B1111111                                    
    
     Dim Zmienna As Byte 
     Zmienna = 0 
     Dim Czas As Integer 
     Czas = 2500 
    
    
     Do 
    
    
       If Pinb.1 = 0 Then                                       'jeżeli przycisk wciśnięty 
       Waitms 100 
       Portd.5 = 0                                              'zapal diode informującą 
       Bitwait Pinb.1 , Set                                     'czekaj aż przycisk zostanie zwolniony 
       Czas = Czas - 500                                        'ujmij z czasu migania diody 500 ms 
       Portd.5 = 1                                              'zgaś diode informującą 
       End If 
    
       If Czas < 500 Then                                       'jeżeli czas mniejszy niż 500ms to czas = 2500ms 
       Czas = 2500 
       End If 
    
       If Pinb.0 = 0 Then                                       'jeśeli przycisk 1 wciśnięty 
       Waitms 100 
       Portd.5 = 0                                              'zapal diode informującą 
       Bitwait Pinb.0 , Set                                      'czekaj aż przycisk zostanie zwolniony 
       Zmienna = Zmienna + 1                                    'dodaj do zmiennej 1 
       Portd.5 = 1                                              'zgaś diode informującą 
       End If 
    
       If Zmienna > 2 Then                                      'jeżeli zmienna większa od 2 to zmienna = 0 
       Zmienna = 0 
       End If 
    
    
       If Zmienna = 0 Then                                      'jeżeli zmienna = 0 
       Portd.1 = 1                                              'zgaś diode 1 
       Portd.2 = 1                                              'zgaś diode 2 
       Waitms Czas                                              'czekaj zmienną "czas" 
       Toggle Portd.0                                           'zmień wyprowadzenie diody 0 
       End If 
    
    
       If Zmienna = 1 Then                                      'jeżeli zmienna = 1 
       Portd.0 = 1                                              'zgaś diode 0 
       Portd.2 = 1                                              'zgaś diode 2 
       Waitms Czas                                              'czekaj zmienną "czas" 
       Toggle Portd.1                                           'zmień wyprowadzenie diody 1 
       End If 
    
    
       If Zmienna = 2 Then                                      'jeżeli zmienna = 2                               ' 
       Portd.0 = 1                                              'zgaś diode 0 
       Portd.1 = 1                                              'zgaś diode 1 
       Waitms Czas                                              'czekaj zmienną "czas" 
       Toggle Portd.2                                           'zmień wyprowadzenie diody 2 
       End If 
    
    Loop 
    End          
    
    


    Bardzo proszę o pomoc.

    Ps. Zakładam w tym dziale, z powodu trudności określenia odpowiedniego, w razie czego proszę o przeniesienie do odpowiedniego działu.
  • REKLAMA
  • #2 9330083
    tadzik85
    Poziom 38  
    Jeden z podstawowych kłopotów początkujących programistów uP. Stosowanie długich oczekiwań typu wait a później zdziwienie że program chodzi za wolno. Przecież wykorzystujesz duże opóźnienia. I stan przycisku jest sprawdzany tylko po jego odczekaniu. I to daje efekt wspomniany przez ciebie. poczytaj o timerach
  • #3 9330117
    oski_pl
    Poziom 10  
    Niestety po zmianie polecenia waitms ze 100 na 15 nic się nie zmienia. Wiąż przycisk działa raz po pół sekundy a raz po 3 sekundach.
  • #5 9330172
    oski_pl
    Poziom 10  
    Tak, zmieniłem program i wyeliminowałem miganie diody, wszystko teraz działa jak należy, lecz kosztem programu.
    Tutaj nasuwa mi się kolejne pytanie, w jaki sposób można wyeliminować takie działania nie uszkadzając działania programu. Przepraszam, że takie banalne pytania, bo pewnie trzeba to zrobić za pomocą zwiększenia taktowania procka, ale nie znalazłem sensownego artykułu o tym więc proszę o pomoc w ustawieniu taktowania procesora.
  • #6 9330190
    tadzik85
    Poziom 38  
    To nie kwestia taktowania.

    A sposobu w jaki piszesz program. Instrukcji typu wait należy unikać. Przecież procesor w czasie tych twoich ponad 2secund nic nie robi tylko czeka. A to marnotrawstwo. Jak już powiedziałem zapoznaj się z licznikami timerami.
  • #7 9330275
    Overclocker
    Poziom 13  
    jeżeli nie zależy ci na szybkości działania programu, możesz spokojnie użyć funkcji Debounce (w helpie znajdziesz dokładny opis), jeżeli chcesz wyeliminować opóźnienia najlepiej w momencie wykrycia naciśnięcia przycisku wystartować licznik(lub użyć do tego już działającego licznika, aby nie tracić cennych timerków :)), tak, żeby ten zliczył ~25ms ustawiając jednocześnie jakąś flagę odczekiwania, która zostanie skasowana, gdy licznik skończy liczyć. Po tym ponownie sprawdzasz stan pinu, i jeżeli stan się utrzymał, to wykonujesz jakiś tam blok obsługi przycisku.

    I jeszcze coś, dawno nie pisałem w bascomie, ale zawsze konfigurowałem porty w ten sposób: Config Portx = Input/output lub piny Config Portx.x = Input/output.
    przyciski można na stałe podłączyć do masy z jednej strony, a od strony procesora ustawić wew. podciągnięcie do +
  • #8 9330298
    oski_pl
    Poziom 10  
    Mogę prosić o przykład takiego wykorzystania timera aby sterował miganiem diody? Z tego co zrozumiałem jest to możliwe, ale mimo tego, że dość dużo czytam/tałem o timerach nie wiem jak to wykorzystać, a przykład pomoże mi to zrozumieć.
  • REKLAMA
  • Pomocny post
    #9 9330408
    Overclocker
    Poziom 13  
    Jak już pisałem, dawno nic nie robiłem w bascomie, ale poniżej daję ogólny zarys opóźnienia dla przycisku przy użyciu licznika

    Config Timer0 = Timer , Prescale = 1024
    Enable Interrupts
    On Timer0 , Czas
    Dim Flaga As Bit
    
    Main:
    Do
    If Pinx.x = 0 and Flaga = 0 Then
           Load Timer0 , 25                                     '0,0256s.  dla 1MHz
           Enable Timer0
    End If
    If Flaga = 1 Then
          Reset Flaga
          If Pinx.x = 0 Then
    
             '
             'obsluga przycisku
             '
          End If
    End If
    loop
    
    
    Czas:
    Disable Timer0
    Set Flaga
    Return
  • REKLAMA
  • Pomocny post
    #10 9330416
    tadzik85
    Poziom 38  
    sam bascom posiada nie mało przykładowych programów przetestuj je
  • #11 9330427
    oski_pl
    Poziom 10  
    Wielkie dzięki za wszelką pomoc. Teraz postaram się to ogarnąć ;)
  • #12 9330477
    Overclocker
    Poziom 13  
    I jeżeli korzystasz z wyboru różnych funkcji obsługujących dla różnych wartości korzystaj z "select case" jest bardziej przejrzyście, i to co się powtarza np to opóźnienie dajesz po wykonaniu całego selecta.
  • Pomocny post
    #13 9335919
    SylwekK
    Poziom 32  
    Poczytaj np. tu to może Ci się nieco rozjaśni ;)
    A kilka postów wcześniej cytowanego linka jest podobne rozwiązanie z zastosowaniem timerów.
    Połącz oba i będziesz miał złoty środek...
    Pozdrawiam.
  • REKLAMA
  • #14 9342176
    oski_pl
    Poziom 10  
    W końcu udało mi się pojąć ten program i mniej więcej przerwania, ale nastało kolejne pytanie z mojej strony. W jaki sposób mogę obliczyć wartość timera, żeby mógł odliczyć np 0,5 sek lub 2 sek. Chodzi mi na razie o Timer0 8 bitów. W jaki sposób mogę też liczyć przepełnienia?
  • #15 9342289
    SylwekK
    Poziom 32  
    Zapoznaj się obowiązkowo z konfiguracją timerów!
    Jeśli Ci potrzeba większych przedziałów niż pozwala na to standardowa konfiguracja timerów użyj dodatkowej zmiennej licznikowej w tym przerwaniu, która zwielokrotni wynik...
  • #16 9342872
    oski_pl
    Poziom 10  
    Napisałem swój pierwszy program z przerwaniami i w zasadzie działa tak jak oczekuje. Jego zamysł jest podobny do pierwszego programu (początek tematu) z tym że nie steruje szybkością migania diody. Problem polega na tym, że (co nie powinno być dziwne) zmienić diodę mogę tylko wtedy gdy się ona pali. Gdy wcisnę przycisk gdy jest zgaszona program się zawiesza. Chce się dowiedzieć czy jest możliwe zniwelowanie tego, że obojętnie kiedy wcisnę to zadziała.

    
    
    
    $regfile = "attiny2313.dat"                                 'najpierw określamy typ proca
    $crystal = 1000000                          'definiujemy z jakim taktowaniem będzie pracował
    
    
    Config Portd = &B11111111                                   ' ustawienie całego Portu B jako wyjscia
           Portd = &B11111111                                   ' stan spoczynkowy wszystkich wyjsć ustawiony na 1
    Config Portb = &B0000000                                    ' ustawienie bitów PD0 i PD1 jako wejscia reszta Portu D jako wyjscia
           Portb = &B1111111
    
    
    
    Config Timer0 = Timer , Prescale = 1024
    Enable Interrupts
    On Timer0 , Czas
    Timer0 = 0
    
    Dim Sa As Byte
    sa = 0
    Dim Zmienna As Byte
    Zmienna = 0
    Dim Flaga As Bit
    Reset Flaga
    
    
    Do
    
    
      While Zmienna < 2
       If Flaga = 0 Then
       Enable Timer0
       End If
      Wend
    
       If Pinb.0 = 0 Then
       Bitwait Pinb.0 , Set
       Sa = Sa + 1
       End If
    
    
       If Sa > 2 Then
       Sa = 0
       End If
    
       If Zmienna = 2 And Sa = 0 Then
       Zmienna = 0
       Reset Flaga
       Toggle Portd.0
       Set Portd.1
       Set Portd.2
       End If
    
       If Zmienna = 2 And Sa = 1 Then
       Zmienna = 0
       Reset Flaga
       Toggle Portd.1
       Set Portd.0
       Set Portd.2
       End If
    
       If Zmienna = 2 And Sa = 2 Then
       Zmienna = 0
       Reset Flaga
       Toggle Portd.2
       Set Portd.1
       Set Portd.0
       End If
    
    
    Loop
    End
    
    
    Czas:
    Disable Timer0
    Timer0 = 0
    Zmienna = Zmienna + 1
    Reset Flaga
    Return
    
    
  • #17 9343964
    SylwekK
    Poziom 32  
    Szczerze mówiąc trochę zamotałeś ten program. Przede wszystkim używaj więcej komentarzy (przynajmniej do czego wykorzystujesz zmienne) - to bardzo się przydaje zwłaszcza kiedy rzucasz progsa na forum.
    Na początek wypisz może w punktach dokładnie co ma robić program czyli akcja (przycisk) i reakcja. Czytelny zapis i określenie funkcji wg, których ma pracować program to pół sukcesu do jego prawidłowego napisania. Uwierz to bardzo pomaga.

    P.S. Nie wiem jak u Was ale u mnie coś dziwnego dzieje się w Bascom z instrukcją ładowania Timer0=x. Odkąd zacząłem stosować Counter0=x (w zasdzie 255-x) problemy znikły...
  • #18 9343981
    Overclocker
    Poziom 13  
    zapominasz ładować konkretną wartość do licznika przed jego uruchomieniem. obliczasz ją (w podstawowym trybie) mniej więcej tak:
    obliczasz czas jednego cyklu 1/fclk np dla 1Mhz 1us
    bierzesz teraz czas, jaki chcesz odliczyć, i dzielisz go przez czas jednego taktu, dostaniesz wtedy ilość potrzebną do zliczenia.np
    0,020s/0,000 001 = 20000
    jak wiesz licznik ma tylko 8 bitów, więc można teraz zrealizować to na 2 sposoby:
    inkrementujesz zmienną w każdym przerwaniu, a gdy wyrówna się ona z liczbą, którą obliczysz ustawi flagę, wyjdzie z przerwania, i wykona daną obsługę. można powiedzieć, że to taki programowy prescaler :) np.

    0,000 001s *255= 0,000255s max czas, jaki może zliczyć licznik przy prescalerze 1
    0,02s/0,000255s= 78,4 więc daje to ok 78 takich inkrementacji.
    2 sposób, to użycie prescalera, czyli inaczej podzielenie częstotliwości taktowania procesora przez ustawioną liczbę np
    20 000 / 1024 =~95
    wychodzi ci liczba cykli którą ma zliczyć licznik przed przepełnieniem teraz należy ją tylko odpowiednio wpisać (licznik zlicza zawsze go góry, aż do FFh)
    ale o tym już sobie gdzieś znajdziesz :)

    ja używałem przeważnie polecenia np LOAD TIMER1, 123 (odrazu wykonuje odejmowanie, czyli wpisuje 255-123)
    ze znakiem = nie zawsze mi działało z tego co pamiętam, ogólnie to w bascomie troszkę trzeba się nakombinować, żeby zrobić, coś, co działa bez problemów :)
  • #19 9344285
    oski_pl
    Poziom 10  
    Podaje program z komentarzem.
    
    
    $regfile = "attiny2313.dat"                                 'najpierw określamy typ proca
    $crystal = 1000000                          'definiujemy z jakim taktowaniem będzie pracował
    
    
    Config Portd = &B11111111                                   ' ustawienie całego Portu B jako wyjscia
           Portd = &B11111111                                   ' stan spoczynkowy wszystkich wyjsć ustawiony na 1
    Config Portb = &B0000000                                    ' ustawienie bitów PD0 i PD1 jako wejscia reszta Portu D jako wyjscia
           Portb = &B1111111
    
    
    
    Config Timer0 = Timer , Prescale = 1024
    Enable Interrupts
    On Timer0 , Czas
    Timer0 = 0
    
    
    Dim Sa As Byte                                              'sa - zmienna, która zmienia migającą diode
    Sa = 0
    Dim Zmienna As Byte                                         'zmienna - zmienna pozwalająca zliczać przepełnienia licznika (dla pół sek 2 przepełnienia)
    Zmienna = 0
    Dim Flaga As Bit                                            'flaga - określa czy licznik ma zacząć zliczać
    Reset Flaga
    
    
    Do
    
    
       If Pinb.0 = 0 Then                                       'jeżeli Przycisk Wciśnięty Dodaj Do "sa" 1
       Waitms 50
       Bitwait Pinb.0 , Set
       Sa = Sa + 1
       End If
    
      While Zmienna < 2                                         'jeżeli zmienna mniejsza od 2, start timer0
       If Flaga = 0 Then
       Enable Timer0
       Else
       Disable Timer0
       End If
      Wend
    
       If Sa > 2 Then                                           'jeżeli "sa" większe od 2 to "sa" równa 0
       Sa = 0
       End If
    
       If Zmienna = 2 And Sa = 0 Then                           'jeżeli zmienna = 2 i sa = 0
       Zmienna = 0
       Reset Flaga
       Toggle Portd.0                                           'zmień wyprowadzenie diody 0
       Set Portd.1                                              'zgaś diode 1 i 2
       Set Portd.2
       End If
    
       If Zmienna = 2 And Sa = 1 Then                           'analogicznie do pierwszego
       Zmienna = 0
       Reset Flaga
       Toggle Portd.1
       Set Portd.0
       Set Portd.2
       End If
    
       If Zmienna = 2 And Sa = 2 Then                           'analogisznie do pierszego
       Zmienna = 0
       Reset Flaga
       Toggle Portd.2
       Set Portd.1
       Set Portd.0
       End If
    
    
    Loop
    End
    
    
    Czas:                                                       'po przepełnieniu timera0 program wskakuje tutaj
    Disable Timer0                                              'wyłącz timer0
    Timer0 = 0                                                  'timer0 = 0
    Zmienna = Zmienna + 1                                       'dodaj do zmiennej 1
    Reset Flaga
    
    Return
    


    W programie chodzi o to, by timer odmierzał 0,5 sek i zmieniał wyprowadzenie diody (dioda zaczyna migać).
    Taktowanie = 1000000 Mhz
    i takt na 0.000001 sek
    prescaler - 1024 więc około 976 (nie musi być dokładnie, dlatego zaokrąglę do 1000)
    i takt na 0.001 sek
    na 0,5 sek potrzeba 500 takich taktów
    licznik przepełnia się po 255 więc potrzeba dwóch przepełnień
    program zlicza przepełnienia do dwóch i zmienia wyprowadzenie diody.
    Chodzi mi o to, że nie mogę w każdym momencie zmienić diody. Czasami program się zawiesza i dioda przestaje migać.
    Jeśli jest jakiś prostszy sposób napisania tego programu to bardzo proszę o rady ewentualnie o pomoc w naprawie błędy z przyciskiem.

    Ps. Nie ładowałem do licznika wartości bo potrzebuje dwóch pełnych przeładowań.
  • #20 9344398
    SylwekK
    Poziom 32  
    Załaduj ten programik (zmień tylko procek i port dla własnych potrzeb) i zobacz jak to działa. To o wiele czytelniejszy i łatwiejszy sposób odliczania potrzebnych czasów niż zabawa we włączanie i wyłączanie timerów. Możesz zrobić nawet kilka różnych "odliczaczy" i to nie tylko 8-o ale i 16 (lub więcej) bitowych, a do tego coś się jeszcze innego w przerwaniu może wykonywać.

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Poza tym używanie Bitwait blokuje wykonywanie programu i prawdę mówiąc nie analizowałem szczegółowo Twojego kodu ale wnioskuje, że coś się gubi po drodze z tymi przepełnieniami i flagami...
    Pozdrawiam
  • #21 9345121
    oski_pl
    Poziom 10  
    Dzięki za program, działa bardzo dobrze, trochę go zmodyfikowałem dla swoich potrzeb, ale idąc Twoim tokiem myślenia chce zrezygnować z bitwait. Niestety drgania styków nie dają mi spokoju, a bardzo bym chciał wyeliminować je programowo. Proszę o pomoc z tym problemem.


    Próbowałem wykorzystać też debounce ale słabo mi to wychodzi ;/
  • Pomocny post
    #22 9345158
    SylwekK
    Poziom 32  
    Po prostu podwójne badanie wciśniętego key...

    Chyba najbardziej znane rozwiązanie (nie koniecznie najlepsze!):

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Co istotne - wciśnięcie klawisza w takim rozwiązaniu spowolni główną pętlę o 25ms (podobnie zresztą jak Debounce) więc mając to co teraz napisałem i w poprzednim moim poście pozbądź się Waitms (o ile nie przeszkadza Ci to spowolnienie pętli) - to będzie taki trening ;) W końcu na czymś musisz się uczyć...
  • #23 9345193
    oski_pl
    Poziom 10  
    Znałem ten sposób, co prawda w połączeniu z bitwait, ale i tak niestety nie działa poprawnie. Dłuższe przytrzymanie keya powoduje podwójną zmianę diody.
    Bitwait rozwiązuje sprawę i o dziwo program działa bardzo dobrze.
    Będę się starał znaleźć coś na rozwiązanie tego problemu nie korzystając z bitwait.
    Dzięki za wszelką pomoc!!
  • Pomocny post
    #24 9345216
    Konto nie istnieje
    Poziom 1  
  • #25 9350776
    oski_pl
    Poziom 10  
    Dzięki za wszelaką pomoc :)
    Napisałem już program według moich oczekiwań i sprawdza się bardzo dobrze.

    Pozdrawiam!
REKLAMA