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

[C] [avr] Debouncig zmiany w programie

janbernat 20 Wrz 2010 20:10 2572 16
REKLAMA
  • #1 8532131
    janbernat
    Poziom 38  
    Zrobiłem taki programik:
    
    #define MASKA_ODCZYT		0b00001111
    #define MASKA_WYJSCIE		0b11110000
    //----------------------------------
    
    	if(flaga_przycisku>=4)	//Ten fragment wykonuje się co16ms x4 z Timer0
    		{	
    		
    			uint8_t	stan_przyciskow;
    			stan_przyciskow=debounce();
    			
    			if(stan_przyciskow==1)
    				{
    				PORTB=(0x3|MASKA_WYJSCIE);//wyjście tylko na port0-3
    				LCD_GoTo(22,1);
    				LCD_WriteText("lewo ");
    				
    				}
    			if(stan_przyciskow==2)
    				{
    				PORTB=(0xc|MASKA_WYJSCIE);
    				LCD_GoTo(22,1);
    				LCD_WriteText("prawo");
    				
    				}
    		flaga_przycisku=0;
    		}	
    

    Wykorzystując program Freddiego Chopina:
    
    unsigned int debounce(void)// funkcja Freddiego Chopina
    {
    	static unsigned int last = 0;
    	unsigned int port;
    	unsigned int wynik;
       
    	port = PINC&MASKA_ODCZYT; //odczyt tylko z młodszych pinów
        wynik=port&(~last);
        last=port;
       
       return wynik;
    } 
    

    Wszystko ślicznie działa.
    Ale męczy mnie pomysł- czy da się to zrobić jednym przyciskiem?
    Pierwsze przyciśnięcie- w lewo.
    Drugie- w prawo.
    Albo kolejno- każde przyciśnięcie w lewo aż do czterech- a potem w lewo od 4 do 1.
  • REKLAMA
  • #2 8532378
    gaskoin
    Poziom 38  
    Chodzi Ci o coś takiego ?

    
    unsigned char funkcje_przycisku;
    
          
    if(pinprzycisku & (1 << pin)){
                funkcje_przycisku = abs(funkcje_przycisku - 1);    //zakladajac tylko stan prawo/lewo, latwo jednak to rozszerzyc
    }
    


    Po przyciśnięciu przycisku, zmieniasz funkcję jaka ma się wykonywać i tyle.
  • #3 8534057
    janbernat
    Poziom 38  
    To niezupełnie tak.
    Tu jest opis:
    https://www.elektroda.pl/rtvforum/topic1092816.html#5513807#5513807
    Chodzi o to że gdy nacisnę i po 32-64ms puszczę przycisk to ładnie się przełącza.
    Ale dopóki nie nacisnę innego przycisku to ten poprzednio wciśnięty nie reaguje na następne wciśnięcia.
    To jest pewnie zapamiętane w static last.
    I nie wiem jak wykombinować żeby to wykasować nie demolując całej funkcji debounce().
    A dyskusja jest tu:
    https://www.elektroda.pl/rtvforum/topic1092816.html#5513807#5513807
  • #4 8534156
    szelus
    Poziom 34  
    Może coś w tym guście:
    
        uint8_t keys;
        static uint8_t old_keys = 0xff; // valid keys from previous keypress 
        static uint8_t scan_keys = 0xff; // last keyboard scan state
        static uint8_t debounce_cnt = 0;
    
    /*...*/
            //read keys
            keys = KBD_INP_PORT & KBD_INP_MASK;
            
            if (keys ^ scan_keys)
            {
                // key state change from previous scan
                // start debounce delay
                scan_keys = keys;
                debounce_cnt = DEBOUNCE_DELAY_CNT;
            }
            else if (keys ^ old_keys)
            {
                // key state same as in previous scan and diffrent
                // than last keypress - check if debouncing has finished
                if (debounce_cnt == 0)
                {
                    // valid keypress now detected
                    KeyDecoder(keys, old_keys);
                    old_keys = keys;
                }
                else
                {
                    --debounce_cnt;
                }
            }
    
    


    To wołane np. w obsłudze przerwania. Tam gdzie wołane jest KeyDecoder() masz wykryte zarówno naciśnięcie klawisza, jak i puszczenie. Puszczenie oczywiście możesz ignorować - następne naciśnięcie zostanie i tak wykryte.
    Kłopot przy wołaniu tego z obsługi przerwania jest z przekazaniem informacji do głównego programu w przypadku, gdy nie jesteś w stanie zagwarantować że odbiorca odbierze tę informację przed nadejściem następnego przerwania.
    U mnie akurat to się nie woła z przerwania tylko z obsługi programowego timera.
  • REKLAMA
  • #5 8534170
    Konto nie istnieje
    Konto nie istnieje  
  • #6 8534312
    szelus
    Poziom 34  
    To prawda, kod Freddiego jest prostszy, ale ma swoje ograniczenia - debounce() tylko filtruje stan, wobec tego wykrywanie kolejnych naciśnięć i puszczeń musi się odbywać wyżej. Kod powyżej raczej nie zadziała dobrze. Moim zdaniem potrzeba to jakoś tak:
    
    {
        static int action = 0;
        static int pressed = 0;
    
        if (debounce() == 1)
        {
            if (pressed == 0)
            {
               pressed = 1;
               switch(action)
               {
                   case 0:     // Lewo
                             instrukcje;
                             .....
                             break;
                   case 1:    /// Prawo
                             instrukcje
    ...................................................
                   default:
                             break;
               }
               action++;
               action %= ILOSC;
            }
        }
        else
        {
            pressed = 0;
        }
    }
    
  • #7 8534349
    Konto nie istnieje
    Konto nie istnieje  
  • REKLAMA
  • #8 8534469
    szelus
    Poziom 34  
    OK, mój błąd. Analizowałem, ale faktycznie przeoczyłem najbardziej sprytną sztuczkę. ;) Kod precyzyjnie wykrywa zbocze narastające. Jak nie jest wołany zbyt często. ;)
  • #9 8534500
    janbernat
    Poziom 38  
    Kod Freddiego Chopina jest bardzo fajny i potrafi zrobić debouncing od razu na całym porcie lub po zamaskowaniu na części portu.
    I można wprowadzić opóźnienie z przerwania w sporym zakresie- mi chodziło od 16 do 160ms.
    No i sprawdzanie jest po puszczeniu przycisku.
    I faktycznie po sprawdzeniu że przycisk był wciśnięty można zrobić jedną lub kilka czynności w if-ach lub switchu.
    No ale dopóki nie wciśnie się innego przycisku to próba powtórnego wykonania tych samych czynności się nie powiedzie.
    Można oczywiście wykorzystać drugi przycisk jako NOP i wtedy znowu ten pierwszy zareaguje.
    Ale może da się to zrobić jakoś inaczej- dodać coś do funkcji Freddiego?
  • REKLAMA
  • #10 8534538
    szelus
    Poziom 34  
    Coś nie tak. Masz przyciski aktywne zerem, czy jedynką?
    Może ja ciągle źle rozumiem kod Freddiego, ale wydaje mi się, że on jest przystosowany do przycisków aktywnych jedynką.
    Ale nawet jak masz aktywne zerem, to jedynka na wyjściu będzie pojawiać się po każdym puszczeniu przycisku. Ponowna jedynka.
  • #12 8534816
    szelus
    Poziom 34  
    OK, czyli nie do końca zrozumiałem intencje (nie wczytywałem się przedtem w post Freddiego, tylko w kod ;) ). Dla mnie to jakieś ergonomicznie ciężkie jest, że przycisk staje się aktywny w momencie puszczenia. Ale to już jak chcesz...

    Kod Freddiego jest na tyle sprytny, że da się przystosować do dowolnej koncepcji.

    Ale tak jak masz, to debounce() zwraca jedynkę raz, przy każdym puszczeniu przycisku. Nie rozumiem, dlaczego Ci nie działa. Możesz zamieścić swój kod w wersji dla jednego przycisku?
  • #13 8534863
    sulfur
    Poziom 24  
    Ale chwileczkę bo albo mam problemy z czytaniem ze zrozumieniem albo czegoś nie wiem. W temacie podanym przez janbernat jest deklaracja, że autor używa ściągania do masy. Kolega janbernat podciąga do VCC. Z tego co widzę, kody są identyczne. Wniosek: coś poszło nie tak.
  • #15 8535003
    Konto nie istnieje
    Konto nie istnieje  
  • Pomocny post
    #16 8535007
    sulfur
    Poziom 24  
    Faktycznie subtelna. Gratuluję spostrzegawczości.

    Pytanie pomocnicze do janbernat. Po czy kolega stwierdza, że przycisk nie reaguje na kolejne naciśnięcia ?
    Podpowiedź: nie można tego stwierdzić na podstawie zamieszczonego kodu.

    Moim zdaniem załączony kod pozwala stwierdzić, że nie ma możliwości, aby program nie reagował na kolejne naciśnięcia tego samego klawisza.
  • #17 8535505
    janbernat
    Poziom 38  
    Cytat z FCh:
    "po drugie, widze, ze u ciebie przycisk wcisniety to 0, puszczony to 1 (tak jest?) - w takim wypadku zmien funkcje na:

    wynik=port&(~last);

    aby wykrywala puszczenie, a nie nacisniecie przycisku."
    No i tak zrobiłem.
    Po czym stwierdzam że nie reaguje- w rzeczywistym układzie.
    Wszystko co ma się wykonać po naciśnięciu przycisku się wykonuje.
    Zaraz- coś mi to dało do myślenia.
    Przecież wykonuje się to samo- więc jak mam zauważyć że coś się zmieniło!!!
    Muszę coś wymyślić- jakis toggle.

    Dodano po 1 [godziny] 26 [minuty]:

    Oczywiście że ślicznie działa:
    
    		if(flaga_przycisku>=4)	//Ten fragment wykonuje się co16ms x4 z Timer0
    		{	
    			static uint8_t toggle=1;
    			uint8_t	stan_przyciskow;
    			stan_przyciskow=debounce();
    			
    			if(stan_przyciskow==1)
    			{
    				if(toggle)
    				{
    				PORTB=(0x1|MASKA_WYJSCIE);//wyjście tylko na port0-3
    				LCD_GoTo(22,1);
    				LCD_WriteText("lewo ");
    				toggle=0;
    				}
    				else
    				{
    				PORTB=(0xC|MASKA_WYJSCIE);
    				toggle=1;
    				}
    			}
    
    			if(stan_przyciskow==2)
    			{
    				if(toggle)
    				{
    				PORTB=(0x2|MASKA_WYJSCIE);
    				LCD_GoTo(22,1);
    				LCD_WriteText("prawo");
    				toggle=0;
    				}
    				else
    				{
    				PORTB=(0xC|MASKA_WYJSCIE);
    				toggle=1;
    				}
    			}
    		flaga_przycisku=0;
    		}	
    

    Tak się skupiłem na uczeniu sie C że aż na zwykłe myślenie rozumu mi zabrakło.
REKLAMA