Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

ATMEGA8 - jak poczekać na wciśnięcie przycisku w C?

bestmlody 02 Cze 2009 14:56 5502 18
  • #1 02 Cze 2009 14:56
    bestmlody
    Poziom 14  

    Chciałbym napisać program w C dla ATMEGA8. Będzie to mój pierwszy program, myślałem że będzie bardzo prosty a tu już problemy.
    Chodzi mi o to żeby przy wciskaniu jednego przycisku, kolejno po sobie zapalały się diody, za pierwszym wciśnięciem jedna, za drugim dwie, itd.
    Ale funkcja której użyłem - while(PINC & 0x01) {} - nie czeka za wciśnięciem przycisku. Wszystko jest w nieskończonej pętli, więc jak wcisnę przycisk to akurat trafie na 3 diody, później na 1. Co zrobić aby czekał?

    0 18
  • #2 02 Cze 2009 15:06
    kuuczoo
    Poziom 26  

    Witam
    Pokaż cały program i schemacik, bez tego ciężko coś stwierdzić...

    0
  • #3 02 Cze 2009 15:06
    voytaschec
    Poziom 24  

    Jest coś takiego jak drgania zestyków. Przy każdym wciśnięciu przycisku (im tańszy tym gorzej :)) następuje drganie blaszek styku, które procesor rozpoznaje jako wielokrotne naciskanie switch'a. W zależności od przycisku może to trwać nawet kilka - kilkadziesiąt milisekund. Jeśli to jest Twój pierwszy program to najprościej zaraz po wykryciu wciśnięcia przycisku zrób sobie opóźnienie np. na 80ms i dopiero później kontynuuj pracę programu (zapalanie diod). Ewentualnie najpierw zapal diody a później zrób opóźnienie. Oczywiście są lepsze rozwiązania tego problemu, ale na pierwszy raz i w tak prostym programie takie coś wystarczy.

    0
  • #4 02 Cze 2009 19:38
    bestmlody
    Poziom 14  

    wiem wiem o tych drganiach bo uczę się z chyba najbardziej znanego kursu internetowego:
    kurs programowania
    więc niektóre fragmenty można po prostu skopiować.
    Tak jak piszesz opóźnienia są 80ms, więc raczej drgania styków można wykluczyć.
    Niestety nie ma sekwencji jaką chciałem uzyskać, diody zapalają się i gasną "losowo".
    Już pokazuje mój kod:

    Code:

    #define F_CPU 1000000L
    #include <avr/io.h>
    #include <util/delay.h>

    int main(void)
    {
      /* Wszystkie linie portu D będą wyjściami */
      DDRD  = 0xff;
      PORTD = 0xff;
      /* Linia PC0 będzie wejściem z podciągnięciem do VCC */
      DDRC  = 0x00;
      PORTC = 0x01;
         
       
      while(1)
      {
        /* Jeśli przycisk wciśnięty pierwszy raz zapali sie jedna dioda*/
        if(!(PINC & 0x01))
          {
               PORTD = 0x0e;     
               _delay_ms(80);     
               while(!(PINC & 0x01)) {}     
               _delay_ms(80);
          }

       
       /* Jeśli przycisk wciśnięty drugi raz zapalą się 2 diody*/
       if(!(PINC & 0x01))
          {
               PORTD = 0x0c;     
               _delay_ms(80);     
               while(!(PINC & 0x01)) {}     
               _delay_ms(80);
          }
          
       
       /* Jeśli przycisk wciśnięty trzeci raz zgasna wszystkie*/
       if(!(PINC & 0x01))
          {
               PORTD = 0x0F;     
               _delay_ms(80);     
               while(!(PINC & 0x01)) {}     
               _delay_ms(80);
          }
          
      }
    }

    0
  • #5 02 Cze 2009 20:03
    Mat_91
    Poziom 25  

    Kolego:) Nie wiem czy dobrze Cię zrozumiałem ale to co chyba chcesz zrobić masz przedstawione na w/w stronie w listingu 2,5:

    Code:

        /* Jeśli pierwszy przycisk wciśnięty */
        if(!(PINC & 0x01))
        {
         /* Zwiększenie stanu licznika o 1 */
          PORTD +=1;
          /* opóżnienie aż drgania na stykach ustaną */
           _delay_ms(80);
          /* oczekiwanie na zwolnienie przycisku */
          while(!(PINC & 0x01)) {}
          /* opóżnienie aż drgania na stykach ustaną */
           _delay_ms(80);
    }

    0
  • #6 02 Cze 2009 20:35
    dawid512
    Poziom 32  

    Proponuję skorzystać ze switch.

    0
  • #7 02 Cze 2009 20:42
    kuuczoo
    Poziom 26  

    dawid512 - mylisz się. sprawdza ten pin który powinien i w dodatku sprawdza go prawidłowo - w nawiasie jest wykrzyknik czyli negacja...

    0
  • #8 02 Cze 2009 23:00
    voytaschec
    Poziom 24  

    Twój program działa dobrze (tzn. tak jak jest napisany ;)).
    A działa w ten sposób:
    Są trzy porównania (if), które są sprawdzane sekwencyjnie jedno po drugiem. Gdy warunek nie jest spełniony program przechodzi do sprawdzania kolejnego (który nawiasem mówiąc jest taki sam). Jeśli w którymś momencie naciśniesz przycisk to program wykona ten warunek przy którym akurat akyualnie się znajduje. Można powiedzieć, że zrobiłeś całkiem zgrabny generator liczb pseudolosowych ;)

    Jeśli chciałbyś przerabiać swój program to powinien wyglądać mniej więcej tak (jedna z wielu możliwości):

    Code:

    int main(void)
    {
    /* Wszystkie linie portu D będą wyjściami */
    DDRD = 0xff;
    PORTD = 0xff;
    /* Linia PC0 będzie wejściem z podciągnięciem do VCC */
    DDRC = 0x00;
    PORTC = 0x01;


    while(1)
    {
    /* Jeśli przycisk wciśnięty pierwszy raz zapali sie jedna dioda*/
    while(PINC & 0x01);
     
    PORTD = 0x0e;
    _delay_ms(80);
    while(!(PINC & 0x01)) {}
    _delay_ms(80);
     


    /* Jeśli przycisk wciśnięty drugi raz zapalą się 2 diody*/
    while(PINC & 0x01);
     
    PORTD = 0x0c;
    _delay_ms(80);
    while(!(PINC & 0x01)) {}
    _delay_ms(80);
     


    /* Jeśli przycisk wciśnięty trzeci raz zgasna wszystkie*/
    while(PINC & 0x01);
     
    PORTD = 0x0F;
    _delay_ms(80);
    while(!(PINC & 0x01)) {}
    _delay_ms(80);
     

    }
    }

    0
  • #9 03 Cze 2009 00:07
    bestmlody
    Poziom 14  

    Widze, że kolega voytaschec doskonale mnie rozumie :)
    Ja rozumiem kod i wiem, że wciskając przycisk "łapie" różne miejsca w kodzie. Stąd właśnie pytanie - jak poczekać...
    Chyba próbowałem z while, ale jutro to sprawdzę jeszcze raz i napisze, czy zadziałało.

    0
  • #10 03 Cze 2009 00:10
    rpal
    Poziom 27  

    Przy okazji wtrącę że na drania styków najcześciej polecana jest zwłoka kilku ms. Gdy tymczasem pomnocny moze być kondensator dołączony równolegle do styku o pojemności kilkuset nF.

    0
  • #11 03 Cze 2009 12:54
    frykow
    Poziom 10  

    Należy dodać drugi warunek, który sprawdza czy przycisk został puszczony (a więc wcześniej należy również zapamiętać, że został wciśnięty). Gdy zostanie puszczony - zwiększać wartość licznika zliczającego kolejne wciśnięcia.

    0
  • #12 03 Cze 2009 13:58
    bestmlody
    Poziom 14  

    Niestety nadal pełna losowość. Program od razu wchodzi w pierwszą pętlę while i zaświeca pierwszą diode. Później też żadnej sekwencji.
    Pamiętam, że w C była funkcja getchar, której właśnie używałem w celu przytrzymania programu. Może i dla uC można jej jakoś użyć?

    0
  • #13 03 Cze 2009 16:15
    kuuczoo
    Poziom 26  

    Nie pamiętam dokładnie składni a nie chce wprowadzać w błąd więc napisze schematem:

    Code:

    licznik=0
    zgas_diody
    pętla nieskończona
    {
      czekam na przycisk ( while (!(pinc&0x01)) )
      {
        czekam na puszczenie przycisku ( while (pinc &0x01) {} )
        {
          zwiększam licznik
          if (licznik>2) licznik=0;
          if licznik==0 zgas_diody
          if licznik==1 zapal_1_diode
          if licznik==2 zapal_2_diody
          wait_ms(200) (dla pewności)
        }
      }
    }

    zakładamy że masz układ przeciwko drganiom styków (kondensator)

    Kod, pseudokod, itp, należy umieszczać w znacznikach [code]
    [zumek]

    0
  • #14 03 Cze 2009 20:08
    bestmlody
    Poziom 14  

    pomysł mi się podoba, kod jest jakiś taki czytelny :)
    no więc program teraz wygląda tak:

    Code:

    int licznik=0;
     
      while(1)
      {
       
       // Jeśli przycisk wciśnięty
           while(!(PINC & 0x01))
          {
               _delay_ms(50);     
               while(PINC & 0x01) {}     
               _delay_ms(50);
          }
          
       licznik++;   
       
       if (licznik>2)  { licznik=0; PORTD=0x0f; } // zeruje licznik i gasi diody
       if (licznik==1) PORTD=0x0e; //zapal pierwszą diodę
       if (licznik==2) PORTD=0x0d; //zapal drugą diodę
       
        _delay_ms(1000);
       
      }


    Nie wiem czy to wina mojej elektroniki, ale program teraz wykonuje się sam. Gdyby nie to opóźnienie na końcu to nie byłoby tego widać, ale że jest sekundowe opóźnienie to zapala się jedna, druga, gasną. Po prostu problem nadal jest w tym że ta część odpowiedzialna za przycisk, nie czeka.


    Dodano po 1 [godziny] 33 [minuty]:

    no chyba rozgryzłem temat :) narazie działa bardzo ładnie
    dla wszystkich którzy kiedyś mieliby podobny problem podaje pełny, działający kod:
    Code:
    #define F_CPU 1000000L
    
    #include <avr/io.h>
    #include <util/delay.h>

    int main(void)
    {
      /* Wszystkie linie portu D będą wyjściami */
      DDRD  = 0xff;
      PORTD = 0xff;
      /* Linia PC0 będzie wejściem z podciągnięciem do VCC */
      DDRC  = 0x00;
      PORTC = 0x01;
         
      int licznik=0;
     
      while(1)
      {
       
       // Jeśli przycisk wciśnięty
           while(!(PINC & 0x01))
          {
               if (licznik>2)  { licznik=0; PORTD=0x0f; } // zeruje licznik i gasi diody
             if (licznik==1) PORTD=0x0e; //zapal pierwszą diodę
             if (licznik==2) PORTD=0x0d; //zapal drugą diodę
             
             _delay_ms(80);     
               while(!(PINC & 0x01)) {} // puszczenie przycisku
               _delay_ms(80);
             licznik++;
          }
          
          
       _delay_ms(30);
       
      }
    }


    Nie myślałem, że tak duże znaczenie mogą mieć opóźnienia. W zależności (jak to już ktoś tu napisał) od jakości należy dobrać je doświadczalnie.
    Wrzucenie sprawdzania licznika w pętle sprawdzającą przycisk powoduje zapalenie diody od razu po wciśnięciu, natomiast poza pętlą lub na końcu powoduje działanie na zboczu opadającym.

    Mam nadzieje, że jutro pomożecie mi znów :) bo będe próbował zrobić coś takiego - sekwencja jak ta, ale jeśli wciśnięcia następują po sobie. A jeśli ustaną np. na 5 sek to następne wciśnięcie diody zgasi.

    Dodałem znaczniki [code] - proszę ich używać.
    [zumek]

    0
  • #15 04 Cze 2009 08:26
    642877
    Użytkownik usunął konto  
  • #16 04 Cze 2009 09:18
    kuuczoo
    Poziom 26  

    bestmlody - z koncepcją którą ci podałem wszystko byłoby ok, gdybyś nie wyrzucił warunków ( if licznik.....) poza drugą pętlę while (tą po pętli nieskończonej). To dlatego program wykonywał się sam. Ja też co prawda popełniłem błąd, gdyż w drugim while (tym pustym ) warunek powinien wyglądać jak ten pierwszy (powinien blokować program dopóki przycisk nie jest puszczony) i rzeczywiście będzie to działać na drugim zboczu.

    0
  • #17 16 Lip 2009 02:58
    ŻakSziRak
    Poziom 9  

    Panowie, skoro już jest taki temat to ja jeszcze dorzucę jedno pytanie, bo wydawało mi się, że już wiem o co chodzi, a po przekopaniu elektrody zaczynam wątpić. Przycisk podłączony jest do Atmegi tak:

    ATMEGA8 - jak poczekać na wciśnięcie przycisku w C?

    czyli ten odpowiedni pin ustawiony na wejście i podciągnięty do logicznej jedynki. Jeśli przycisk jest wciśnięty, to zostaje ten pin ustawiony na logiczne "zero". I teraz po jego zwolnieniu na pinie znów jest logiczna jedynka..? Wydawało mi się, że jeśli pin jest zwierany z masą poprzez wciśnięcie przycisku , to stan niski na pinie pozostaje po jego zwolnieniu i trzeba samemu programowo podciągnąć ten pin znów do jedynki. Widzę jednak że chyba źle myślałem. Możecie mnie wyprowadzić z błędu ?

    0
  • #18 16 Lip 2009 07:19
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Dobrze myślisz, że źle myślałeś [;

    Podciąganie samo się nie wyłącza bo niby jak i niby dlaczego?

    4\/3!!

    0
  • #19 19 Lip 2009 21:03
    ŻakSziRak
    Poziom 9  

    ok, dzięki za rozwianie wątpliwości ;)

    0