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

Liczenie zmian stanów na porcie - obsługa przycisków

Mihó 30 Kwi 2009 09:02 1452 5
REKLAMA
  • #1 6473596
    Mihó
    Poziom 27  
    Chciałem napisać program, który zlicza wystąpienia stanu niskiego na portach wejściowych (impulsy do 1kHz). Ten, który napisałem jakby liczył czas, w którym miałem wciśnięty przycisk. Podejmowałem już próby napisania programu, gdzie wykorzystując funkcję delay (i zabezpieczenie przed drganiami styków)

    Jak poniżej:


    #include <avr/io.h> 
    #include <avr/interrupt.h> 
    #include <stdlib.h>
    #include "lcd.h"
    #include <avr/delay.h>
    
    int kolo1=0;
    int kolo2=0;
    int kolo3=0;
    int kolo4=0;
    unsigned char buf[10];
    
    
    void vel1(void)
    { 
      kolo1++; 
      _delay_us(90);   
     while(bit_is_clear(PINC, PC0))	;
      _delay_us(150);	
     while(!bit_is_clear(PINC, PC0)); 
    }
    
    void vel2(void)
    { 
      kolo2++; 
      _delay_us(90);   
     while(bit_is_clear(PINC, PC1))	;
      _delay_us(150);	
     while(!bit_is_clear(PINC, PC1)); 
    }
    
    void vel3(void)
    { 
      kolo3++; 
      _delay_us(90);   
     while(bit_is_clear(PINC, PC6))	;
      _delay_us(150);	
     while(!bit_is_clear(PINC, PC6)); 
    }
    
    void vel4(void)
    {
     
      kolo4++; 
      _delay_us(90);   
     while(bit_is_clear(PINC, PC7))	;
      _delay_us(150);	
     while(!bit_is_clear(PINC, PC7));
    }
    
    int main(void)    //Program główny 
    { 
    
    	// konfiuguracja portow
    	DDRB = 0b10000011;
    	PORTB = 0b01111111;
    	DDRC = 0b11111111;
    	PORTC = 0b11111111;
    	DDRD = 0b11111111;
    	PORTD = 0b11111111;
    	
    	TCCR1A = 0x00;
    	TCCR1B = 0b00001101;
    	OCR1A =  0xD8;
    	TIMSK = _BV(TOIE1)|_BV(OCIE1A); 
    	lcd_init(LCD_DISP_ON);
             
    while (1) 
    { 
    
    if(bit_is_clear(PINC, PC0)) vel1();
    if(bit_is_clear(PINC, PC1)) vel2();
    if(bit_is_clear(PINC, PC6)) vel3();
    if(bit_is_clear(PINC, PC7)) vel4();
    
    
    
    if(1){
    	
    	itoa(kolo1,buf,10); // zmiana int na char	
    	lcd_gotoxy(0,0);
    	lcd_puts(buf);
    	itoa(kolo2,buf,10);
    	lcd_gotoxy(5,0);
    	lcd_puts(buf);
    	itoa(kolo3,buf,10);
    	lcd_gotoxy(0,1);
    	lcd_puts(buf);
    	itoa(kolo4,buf,10);
    	lcd_gotoxy(5,1);
    	lcd_puts(buf);
    }} }


    Działanie jest takie - mam 4 klawisze, ale nie mogę dojść do sytuacji, by niezależnie od siebie inkrementowały wartości. Najpierw należy przytrzymać tego, który chcę by zwiększał wartość, następnie kliknąć tego, który działał do tej pory. A chcę niezależnej inkrementacji. Jak tego dokonać ?
  • REKLAMA
  • Pomocny post
    #2 6476691
    Dr.Vee
    VIP Zasłużony dla elektroda
    Zrób coś w tym stylu:
    #include <avr/io.h>
    #include <util/delay.h>
    
    static uint8_t kolo[4];
    static const uint8_t maski[4] =
        {_BV(0), _BV(1), _BV(6), _BV(7)};
    static const uint8_t wszystkie_maski =
        _BV(0) | _BV(1) | _BV(6) | _BV(7);
    
    
    int main(void) {
        uint8_t poprzedni_stan = PINC & wszystkie_maski;
    
        for (;;) {
            uint8_t nowy_stan = PINC & wszystkie_maski;
            uint8_t opadajace_zbocza = poprzedni_stan & ~nowy_stan;
    
            if (opadajace_zbocza) {
                int i;
                for (i = 0; i < sizeof(maski); ++i) {
                    if (opadajace_zbocza & maski[i])
                        kolo[i]++;
                }
    
                /* tutaj aktualizuj wyświetlanie wyników */
            }
    
            poprzedni_stan = nowy_stan;
    
            _delay_us(150);
        }
    }

    Jeśli wejścia to przyciski, to najlepiej byłoby zrobić z poprzedni_stan tablicę, zwiększyć opóźnienie i zaimplementować coś a la rejestr przesuwny, ale od biedy tak też możesz zostawić.

    Pozdrawiam,
    Dr.Vee
  • REKLAMA
  • #3 6477140
    marenc
    Poziom 24  
    Kondensator ceramiczny 100n na przyciski, a implementację programu bym rozwiązał tak...

    Jeden przycisk aktywuje inkrementację, więc sprawdzasz tylko jego stan - jeżeli wciśnięty, to sprawdzasz, który z pozostałych jest też wciśnięty(jeżeli za dużo to opuszczasz) - na jego podstawie inkrementujesz co tam chcesz i dajesz opóźnienie, aby za szybko się nie inkrementowało ;)

    Nie ma sensu sprawdzanie całego portu, bo przy przyciskach opóźnienia o kilka mikrosekund nie mają znaczenia - reakcja człowieka jest wolniejsza.
  • REKLAMA
  • #4 6509740
    Mihó
    Poziom 27  
    Dr. Vee, dziękuję. Niestety Twój program działa o tyle gorzej, że nawet zbliżenie dłoni do płytki powoduje przyrost zmiennych przez cały czas, gdy piny są na 0

    Myślę, że problem udałoby się rozwiązać, gdyby po linijce
    dodać instrukcję, która powoduje, że przechodzimy do kolejnego elementu tablicy ?
  • REKLAMA
  • #5 6510432
    Dr.Vee
    VIP Zasłużony dla elektroda
    Zdecyduj się, co ma być podłączone do wejść. Jeśli logika, to użyj mojego programu i wywal delay_us(). Jeśli przyciski, to najpierw musisz przeprowadzić eliminację wpływu drgań styków, sprzętowo lub programowo. Programowo odczytujesz stany przycisków co kilka ms i sprawdzasz - jeśli najstarszy wynik jest różny od wszystkich późniejszych, to wykryłeś zbocze. Oczywiście nowe wyniki nadpisują te starsze (bufor cykliczny).

    Pozdrawiam,
    Dr.Vee
  • #6 6510545
    Mihó
    Poziom 27  
    Logika. Problemem może być to, że częstotliwość zmian będzie w zakresie od ~20Hz do ~900Hz. Stąd długość jednego impulsu wyniesie od ~1ms do ~50ms. Jak mogę uzyskać gwarancję, że ten najkrótszy impuls będzie policzony dokładnie tak samo długo jak ten o długości 50ms ?
REKLAMA