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 - jak poczekać na wciśnięcie przycisku w C?

bestmlody 02 Cze 2009 14:56 6738 18
REKLAMA
  • #1 6606956
    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ł?
  • REKLAMA
  • #2 6606994
    kuuczoo
    Poziom 26  
    Witam
    Pokaż cały program i schemacik, bez tego ciężko coś stwierdzić...
  • REKLAMA
  • #3 6606996
    Konto nie istnieje
    Poziom 1  
  • #4 6608034
    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:
    
    #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);
    		}
    		
      }
    }
    
  • #5 6608147
    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:
    
        /* 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);
    }
    
    
  • #6 6608298
    dawid512
    Poziom 32  
    Proponuję skorzystać ze switch.
  • REKLAMA
  • #7 6608347
    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...
  • #8 6609115
    Konto nie istnieje
    Poziom 1  
  • #9 6609333
    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.
  • #10 6609346
    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.
  • #11 6610382
    Konto nie istnieje
    Poziom 1  
  • #12 6610555
    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ć?
  • #13 6611035
    kuuczoo
    Poziom 26  
    Nie pamiętam dokładnie składni a nie chce wprowadzać w błąd więc napisze schematem:
    
    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]
  • REKLAMA
  • #14 6611495
    bestmlody
    Poziom 14  
    pomysł mi się podoba, kod jest jakiś taki czytelny :)
    no więc program teraz wygląda tak:
    
    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:
    #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]
  • #15 6613647
    Konto nie istnieje
    Konto nie istnieje  
  • #16 6613775
    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.
  • #17 6784258
    ŻakSziRak
    Poziom 11  
    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 ?
  • #19 6798663
    ŻakSziRak
    Poziom 11  
    ok, dzięki za rozwianie wątpliwości ;)
REKLAMA