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

[Atmega8][C]Kilka pytań o multipleksowaniu i nie tylko

Mephistofeles 20 Sty 2009 13:11 1548 2
  • #1 6027009
    Mephistofeles
    Poziom 11  
    Witam. Nowy tu raczej nie jestem, bo przeglądam forum codziennie, ale zarejestrowałem się niedawno, bo wcześniej nie było potrzeby pisania :). No to się przywitałem, a teraz na początek: montuję sobie coś w rodzaju półautomatycznego spudguna, i chciałbym zamontować tam licznik amunicji :D.
    Multipleksowany 2cyfrowy LED, i Atmega8 (może i wystarczy mniejszy uC ale jakoś tak wolę taki). I w związku z tym mam kilka pytań:
    - licznik ma zliczać tylko puszczenie przycisku (bo to semi-auto), więc pomyślałem o przerwaniach. To dobry pomysł? Jeśli tak, to mam ustawić na opadające zbocze (puszczenie przycisku)? Przycisk przeładowania, wciśnięty do czasu wyciągnięcia magazynka mam ustawić na narastające, żeby łapał samo wciśnięcie?
    -drugie pytanie związane z multipleksowaniem, czyli mam w (nieskończonej) pętli przełączać na zmianę segmenty, i zapalać odpowiednie LEDy, tylko czy muszę jakoś ograniczyć częstotliwość multipleksowania? Jeśli tak, to jak?
    -trzecie pytanie: po osiągnięciu zera ma zapalić się czerwona dioda (to umiem oczywiście :D), ale po wciśnięciu spustu pomimo zera chcę, żeby dioda i licznik zaczęły przez chwilę migać (jak pasek tytułu, po otwarciu okna modalnego i kliknięciu w główne). Jak mam to zrobić? Z samym miganiem sobie poradzę, tylko jak ograniczyć częstotliwość, żeby człowiek mógł zobaczyć, dajmy na to 3 mignięcia w ciągu sekundy?
    -i jeszcze jedno: po np. 30 sekundach bezczynności (brak sygnału przerwań) cały układ ma przejść w stan uśpienia (przerwanie wybudzi uC?). Mam po prostu włączyć jakiś timer (jaki?), i liczyć impulsy, a w przerwaniu je zerować?
    -ostatnie: chyba nie potrzebne mi są zewnętrzne rezonatory/generatory?
    Na razie to chyba wszystko. Aha, program będę pisał w C, jeśli to coś zmienia.

    PS. Czerwony czy zielony wyświetlacz lepiej pasuje? :D
  • Pomocny post
    #2 6028922
    kasaidolar
    Poziom 19  
    Pomysl z przerwaniem dobry. Zalezy jak podlaczysz przycisk to na takie zbocze bedziesz ustawial przerwanie. Przewaznie robi sie tak ze przycisk zwiera do masy czyli jak puscisz przycisk to z masy zrobi sie stan wysoki wiec bedzie to zbocze narastające. Z przyciskiem przeladowania - jak wczesniej tlumaczylem ale tu raczej na opadajace (przycisk zwiera do masy).
    Co do multipleksowania to bedziesz musial rzeczywiscie przelaczac pomiedzy dwa wyswietlacze. Czas trzeba ograniczyć zeby każdy z nich przez chwile się swiecil. Jak to zrobic? no dajesz delay ;)
    I zewnetrzny kwarc nie jest Ci potrzebny.

    Dodano po 6 [minuty]:

    aha miganie diody i wyswietlaczy tez zrealizujesz za pomoca delay'a :) czyli tak schematycznie:

    if(licznik_nabojow == 0)
    {
    
    for(i = 0 ; i <3 ; i++)
    {
    wlaczasz diode i wysiwietlacz
    delay 100ms
    wylacz diode i wyswietlacz
    delay 200ms
    }
    }
  • #3 6029547
    Mephistofeles
    Poziom 11  
    O takiej funkcji zapomniałem :D.
    Dzięki. Może jeszcze będę pytał jak będą problemy :P.

    Edit: Czy ten kod jest poprawny? Zakładając, że podłączam wspólne anody/katody do pinu 0 i 1, diodę do 4 pinu (portu D), a poszczególne segmenty do całego portu C...

    // Licznik amunicji
    // Konfiguracja
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/sleep.h>  
    
    //Stałe
    const znak[] = {0x3f, 0x0c, 0x5b, 0x5e, 0x6c, 0x76, 0x77, 0x1c, 0x7f, 0x7e}; // Ustawienia bitów dla poszczególnych znaków 0-9 na port C   
    
    //Zmienne
    volatile unsigned char licznik = 99;
    volatile unsigned char cyfra;
    unsigned short czas = 0;
    
    // Funkcja "czekaj"
    void delayms(unsigned int ds) 
    { 
      unsigned int ii; 
      TCCR0=0x03; 
      TCNT0=0x83; 
      for(ii=0; ii<ds; ii++) 
      { 
        while((TIFR&0x02)!=0x02); 
        TCNT0=0x83; 
        TIFR=(1<<TOV0); 
      } 
    }
    
    //Funkcja migająca
    void Migaj(void)
    {
      PORTC = znak[0]; // Ustaw wyświetlany znak na 0
      unsigned char miganie;
      for(miganie = 0; miganie < 3; ++miganie)
      {
    	PORTD |= _BV(0); // Włącz segment 1
    	PORTD |= _BV(1); // Włącz segment 2
    	PORTD |= _BV(4); // Włącz diodę
    	delayms(100);
    	
    	PORTD &= _BV(0); // Wyłącz segment 1
    	PORTD &= _BV(1); // Wyłącz segment 2
    	PORTD &= _BV(4); // Wyłącz diodę
    	delayms(200);
      }  
    }
    
    
    // Multipleksowanie ~100 Hz
    void Wyswietl(void)
    {
      PORTD |= _BV(0); // Włącz segment   
      cyfra = licznik / 10; // Cyfra dziesiątek
      PORTC = znak[cyfra]; // Wyświetl cyfrę
      delayms(5); // Czekaj ~0.005 sekundy
      PORTD &= _BV(0); // Wyłącz segment 1
      
      PORTD |= _BV(1);; // Włącz segment 2
      cyfra = licznik % 10; // Cyfra jedności
      PORTC = znak[cyfra]; // Wyświetl cyfrę 
      delayms(5); // Czekaj ~0.005 sekundy
      PORTD &= _BV(1); // Wyłącz segment 2
      
      ++czas; // Zwiększ czas bezczynności
    }
    
    
    // Przerwanie spustu
    ISR(INT0_vect) 
    {
      czas = 0; // Zeruj czas bezczynności
      if (licznik > 0)
      {
        if((--licznik) == 0)
    	{
    	  PORTD |= _BV(4); // Włącz diodę
    	}
      } else
      {
    	Migaj();
      }
      delayms(10); // Zabezpieczenie przeciw drganiom styków
    }
    
    // Przerwanie magazynka
    ISR(INT1_vect) 
    {
       czas = 0; // Zeruj czas bezczynności
       licznik = 99; // Zeruj licznik
       PORTD &= _BV(4); // Wyłącz diodę
       delayms(10); // Zabezpieczenie przeciw drganiom styków
    }
    
    
    // Pętla główna
    int main(void)
    {
      set_sleep_mode(SLEEP_MODE_PWR_SAVE); // Ustaw tryb snu
      
      DDRC = 0x7F;  // Wszystkie bity portu C jako wyjścia
      DDRD = 0x03; // Pierwsze dwa bity portu D jako wyjścia, reszta jako wejścia
      
      PORTD = 0x0c; // Jedynka logiczna na bity przerwań INT0 (2) i INT1 (3) portu D
      
      GICR |= _BV(6); // Włącz przerwanie INT0
      GICR |= _BV(7); // Włącz przerwanie INT1
      
      MCUCR |= _BV(0);  // Przerwanie INT0
      MCUCR |= _BV(1); // na zbocze narastające (rozwarcie od masy)
      
      MCUCR &= _BV(2);  // Przerwanie INT1
      MCUCR |= _BV(3); // na zbocze opadające (zwarcie do masy)
      
      //GIMSK = _BV(INT0)|_BV(INT1);    // Przerwanie INT0 i INT1 (nieaktualna nazwa rejestru?)
      //MCUCR = _BV(ISC01)|_BV(ISC11); // Przerwanie INT0 i INT1 na zbocze opadające
    
      sei(); // Obsługa przerwań
    
      for(;;) // Nieskończona pętla
      {
        Wyswietl();
    	if ((++czas) >= 3000) // Jeśli czas bezczynności większy od ~30 sekund
    	{
    	  sleep_mode(); // Śpij
    	}
      }
    }
REKLAMA