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

[Atmega8][C] - Eliminacja drgań zestyków - po raz kolejny

demeus 13 Maj 2009 19:12 3434 8
  • #1 6526169
    demeus
    Poziom 18  
    Witam
    Bawię sie ostatnio taka ciekawa funkcją do eliminacji zestyków i niestety nie potrafię jej zmusić do działania.
    #include <avr/pgmspace.h>
    #include <avr/io.h>				// dostęp do rejestrów
    #include <avr/interrupt.h>		// funkcje sei(), cli()
    #include <avr/signal.h>			// definicje SIGNAL, INTERRUPT
    #include "HD44780.h"
    #include "delay.h"
    
    #define T0_INIT				256-250
    #define podswietlenie_on	1
    #define podswietlenie_off	0
    
    uint16_t tmp_tab[14]={0};		// Tablica pomocnicza
    uint16_t tmp=0; 				// Zmienna pomocnicza
    uint8_t	liczt0=0;				// Licznik wejsc do przerwania, klawisz badany gdy liczt0=0
    char 	flaga_wlacz=0;			// Flaga sygnalizujaca stan urzadzenia
    
    volatile uint8_t	podswietlenie_lcd=1;		// Zmienna ustawiająca podświetlenie LCD
    volatile uint8_t 	liczydelko=0;
    volatile uint16_t 	licznik=0;
    volatile uint16_t	licznik1=0;
    
    void Inicjalizacja_mcu (void)
    {
    	asm("sei");
    	LCD_Initalize();					// inicjalizacja wyświetlacza
    
    	TCNT0 = T0_INIT; 					// wartość początkowa T/C0
    	TCCR0 = _BV(CS00)|_BV(CS01);		// preskaler ck/64
    	TIMSK = _BV(TOIE0);
    	
    	DDRD &= 0xEF; 						//DDRD,PD4 jako wejście (przycisk A)
    	PORTD |= 0x10;						//PORTD,PD4 z wew. podciąganiem (przycisk A)
    }
    
    char RawKeyPressed(void)
    {
     if (bit_is_clear (PIND,PD4))
      {
      return FALSE;
      }
     else
      return TRUE;
    }
    
    char DebounceSwitch()
    { 
    static uint16_t State = 0; // Current debounce status 
    State=(State<<1) | !RawKeyPressed() | 0xe000; 
    licznik=State;
    if(State==0xf000)
     {
      return TRUE; 
      ++licznik1;
     }
      else
     {
      return FALSE; 
     }
    }
    
    SIGNAL (SIG_OVERFLOW0)
    {
     TCNT0 = T0_INIT; // wartość początkowa T/C0 przerwanie co 1ms
     if (++liczydelko==5)  
      {
       DebounceSwitch();
       liczydelko=0;
      }
    }
    
    int main(void)
    {	
    	Inicjalizacja_mcu();
    	while(1)
    	{	
    	 LCD_GoTo(0,0);
    	 tmp=licznik;
    	 itoa (tmp, tmp_tab, 2);
    	 LCD_WriteText(tmp_tab);
    	 LCD_GoTo(0,1);
    	 tmp=licznik1;
    	 itoa (tmp, tmp_tab, 10);
    	 LCD_WriteText(tmp_tab);
    	}
    }


    Niby wszystko działa poprawnie, ale nigdy nie wykonuje sie porównanie:
    if(State==0xf000), funkcja DebounceSwitch() nigdy nie zwraca, ani TRUE, ani FALSE. Czy ktoś może się orientuje gdzie popłeniam błąd.

    Zmienne licznik i licznik1 są to tylko zmienne kontrolne/debugujące by sprawdzić przebieg działania tej funkcji.

    Jeśli ktoś sobie życzy lub nie rozumie z chęcią wytłumaczę jak działa funkcja DebounceSwitch() (no przynajmniej tak jak ją rozumiem).

    Z góry dziękuję za każdą uwagę i sugestię.

    --
    pozdawiam
    demeus
  • Pomocny post
    #2 6527558
    Dr.Vee
    VIP Zasłużony dla elektroda
      return TRUE;
      ++licznik1; 
    No ja też się zastanawiam dlaczego zmienna licznik1 nigdy nie zmienia wartości ;)

    Włącz flagę -Wunreachable-code, to kompilator sam Cię ostrzeże.

    Pozdrawiam,
    Dr.Vee
  • #3 6527797
    demeus
    Poziom 18  
    Jedyny warning który coś sugerował to:
    Cytat:

    klawiatura_test.c:46: warning: function declaration isn't a prototype


    Poprawione w następujący sposób:
    char DebounceSwitch(void) 
    { 
    static uint16_t State = 0; // Current debounce status 
    State=(State<<1) | !RawKeyPressed() | 0xe000; 
    licznik=State; 
    if(State==0xf000) 
     { 
      ++licznik1;
      return TRUE; 
     } 
      else 
     { 
      return FALSE;
     } 
    }


    W każdym razie warning usunąłem zmieniając deklarację funkcji
    z
    char DebounceSwitch()
    na
    char DebounceSwitch(void)

    Dodanie flagi:
    -Wunreachable-code
    w sumie nic nie zmieniło, ale ostatecznie załapałem swój błąd ;)

    Flagę dodałem w makefile w następujący sposób:
    LDFLAGS += -lm -Wunreachable-code



    --
    pozdrawiam
    demeus
  • #5 6528449
    Nagus
    Poziom 27  
    Strasznie przekombinowałeś.

    Do obsługi klawiszy nie powinno używać się przerwań. To nie jest operacja wymagająca natychmiastowej reakcji.

    Jesteś pewien, że zmienna State nie jest zerowana przy każdym wejściu do funkcji?

    W wyznaczaniu State operacja 'OR 0xE000' jest zbędna, oczywiście wówczas późniejszy warunek byłby: "State == 0x1000".

    I na koniec, taki kod też działa (KEY_1 to numer pinu):
    if (PIND & _BV(KEY_1))
    		keys_pressed &= ~_BV(KEY_1);
    	else {
    		if (!(keys_pressed & _BV(KEY_1))) {
    			_delay_us(20);
    			if (!(PIND & _BV(KEY_1))) {
    				keys_pressed |= _BV(KEY_1);
    				//------ akcja ------
    				JakasAkcja();
    			}
    		}
    	}
    
  • #6 6528914
    demeus
    Poziom 18  
    Nagus napisał:
    Strasznie przekombinowałeś.

    Do obsługi klawiszy nie powinno używać się przerwań. To nie jest operacja wymagająca natychmiastowej reakcji.

    Jesteś pewien, że zmienna State nie jest zerowana przy każdym wejściu do funkcji?

    W wyznaczaniu State operacja 'OR 0xE000' jest zbędna, oczywiście wówczas późniejszy warunek byłby: "State == 0x1000".


    Moim zdaniem nie przekombinowałem, ponieważ ta funkcja, którą podałem działa wyśmienicie. Klawiatura jest skanowana przez timer co 5ms i ładnie reaguje na zbocze narastające/odpuszczenie klawisza (w moim przypadku). Zmienna state jest deklarowana i zerowana przy pierwszym wykonaniu funkcji.

    Prześledź sobie krok po kroku jak działa funkcja.

    Wydaje mi się, że do obsługi klawiszy nie powinno się używać delayms, gdyż w układach "skopensowanych" czasowo gdzie jest obsługa różnych protokołów, czujników taki _delay_ to spora strata czasu.

    P.S. Ja nie używam przerwań do obsługi klawiatry. W przerwaniu jest tylko sprawdzane naciśnięcie klawisza i dalsza obsługa następuje w innych funkcjach programu poza przerwaniem.

    Funkcję tę zaczerpnąłem z tego dokumentu:
    Załączniki:
  • #7 6529250
    akleiw
    Poziom 12  
    Pomimo kilku błędów w kodzie powinno to jakoś działać - przynajmniej u mnie ruszyło (zamiast LCD mam wyświetlacz 7-LED)
    Moje trzy pomysły: 1-bardzo prawdopodobne 2-średnio 3-najmniej

    1. W jaki sposób masz zdefiniowane TRUE i FALSE? Ja musiałem to podmienić odpowiednio na 1 i 0. Jest kilka powodów dla których lepiej nie używać w C takich definicji.

    2. Zakładam że przycisk masz wpięty pomiędzy PD4 a masę i chcesz rejestrować moment wciśnięcia (a nie puszczenia) przycisku. W takim wypadku wywal funkcję RawKeyPressed() a w funkcji DebounceSwitch() zamień
    State=(State<<1) | !RawKeyPressed() | 0xe000;
    na
    State=(State<<1) | bit_is_set(PIND,PD4) | 0xe000;


    3. Dopisz #include <stdlib.h> (zawiera funkcję itoa) i zmień typ tmp_tab[] z uint16_t na char

    Zostały jeszcze jakieś drobiazgi, ale i tak powinno działać (zakładam że komunikacja z lcd jest ok).
  • #8 6529268
    BoskiDialer
    Poziom 34  
    akleiw: Twój pomysł z zastosowaniem bit_is_set jest chybiony:
    // sfr_defs.h:234
    #define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))

    To makro jest dobre, jeśli wartości używa się jako wartości logicznej, co jednak nie oznacza, że przyjmuje wartości 0 i 1. Pod tym względem negacja logiczna "!" sprawuje się o wiele lepiej. Jednak czemu nikt nie pisze o prostym if'ie?
  • #9 6530125
    demeus
    Poziom 18  
    akleiw napisał:
    Pomimo kilku błędów w kodzie powinno to jakoś działać - przynajmniej u mnie ruszyło (zamiast LCD mam wyświetlacz 7-LED)
    Moje trzy pomysły: 1-bardzo prawdopodobne 2-średnio 3-najmniej

    1. W jaki sposób masz zdefiniowane TRUE i FALSE? Ja musiałem to podmienić odpowiednio na 1 i 0. Jest kilka powodów dla których lepiej nie używać w C takich definicji.

    2. Zakładam że przycisk masz wpięty pomiędzy PD4 a masę i chcesz rejestrować moment wciśnięcia (a nie puszczenia) przycisku. W takim wypadku wywal funkcję RawKeyPressed() a w funkcji DebounceSwitch() zamień
    State=(State<<1) | !RawKeyPressed() | 0xe000;
    na
    State=(State<<1) | bit_is_set(PIND,PD4) | 0xe000;


    3. Dopisz #include <stdlib.h> (zawiera funkcję itoa) i zmień typ tmp_tab[] z uint16_t na char
    .


    Ad.1 TURE I FALSE nie trzeba definiować z natury TRUE=1 a FALSE=0
    Ad.2 Tak przycisk PD4 jest wpięty pomiedzy masę i pin procesora, ta funkcja rejestruje moment puszczenia przycsku
    Ad.3 Funkcja itoa działa bez <stdlib.h>, tmp_tab jest tak zdefiniowane bo obsługuje jeszcze inne rzeczy to co tutaj przedstawiłem to tylko wycinek programu do testowania obsługi klawiatury.

    Poza tym cały program działa niesamowicie sprawnie i super eliminuje drgania zestyków.

    --
    pozdrawiam
    demeus
REKLAMA