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

ATmega8 + C + wyswietlacz LED

bestmlody 17 Paź 2009 20:06 1902 5
  • #1 7140911
    bestmlody
    Poziom 14  
    Problem jest następujący. Dziś zacząłem się uczyć obsługiwać wyświetlacze LED. Przeczytałem tutorial na wkrętaku, zaimplementowałem u mnie i jak zwykle coś nie tak...
    #define F_CPU 1000000L
    #include <avr/io.h>
    #include <util/delay.h>
    #include <wyswietlacze.h>
    #include <avr/interrupt.h>
    
    unsigned char jednosci; 
    unsigned char dziesiatki;
    unsigned char setki;
    
    unsigned char aktywna_cyfra=0;     // zmienna pokazuje który wyswietlacz jest aktywny
    
    ISR(TIMER1_COMPA_vect)
    {
        switch (aktywna_cyfra)
        {
            case 0:
                PORTB |=  (1 << 0); //ustawia bit 0 portu B - włącza wyświetlacz nr 0
    			PORTB &= ~(1 << 1); //zeruje bit 1 portu B - wyłącza wyświetlacz nr 1
                PORTB &= ~(1 << 2); //zeruje bit 2 portu B - wyłącza wyświetlacz nr 2
    			
                PORTD = cyfra(setki);
                aktywna_cyfra++;
            break;
    
            case 1:
                PORTB &= ~(1 << 0); //zeruje bit 0 portu B - wyłącza wyświetlacz nr 0
    			PORTB |=  (1 << 1); //ustawia bit 1 portu B - włącza wyświetlacz nr 1
                PORTB &= ~(1 << 2); //zeruje bit 2 portu B - wyłącza wyświetlacz nr 2
                
    			PORTD = cyfra(dziesiatki);
                aktywna_cyfra++;
            break;
    		
    		case 2:
                PORTB &= ~(1 << 0); //zeruje bit 0 portu B - wyłącza wyświetlacz nr 0
    			PORTB &= ~(1 << 1); //zeruje bit 1 portu B - wyłącza wyświetlacz nr 1
                PORTB |=  (1 << 2); //ustawia bit 2 portu B - włącza wyświetlacz nr 2
    			
    			PORTD = cyfra(jednosci);
                aktywna_cyfra=0;
            break;
        }
    
      }
    
    
    // ----- funkcja główna ------------------------------------------------------------
    int main(void)
    {
    // Wszystkie linie portu D będą wyjściami dla segmentów wyświetlacza
      DDRD  = 0xff;
     
      DDRB  = 0x07; // 3 pierwsze bity to wyjścia dla kluczy wyświetlaczy, PB3 to wejście dla switcha programowania
      PORTB = 0x08;
          
      unsigned int wartosc=124;   // wyswietlana wartosc
      
    TCCR1B |= (1 << WGM12); // Ustawia timer1 w tryb CTC
    OCR1A = 5208; // Ustawia wartość pożądaną na 3Hz dla preskalera 64
    TCCR1B |= ((1 << CS10) | (1 << CS11));  // Ustawia timer z preskalerem Fcpu/64
    TIMSK |= (1 << OCIE1A); // Zezwolenie na przerwania dla CTC
    sei(); // Zezwolenie globalne na przerwania
    
      //----------------------------------------------------------------------------
     
      while(1)
      {
      setki=wartosc/100;	
      dziesiatki = (wartosc/10) % 10; 
      jednosci = wartosc % 10;
      
      if (wartosc == 999) {wartosc = 0;} else {wartosc++;} 
      
      _delay_ms(500);
      }
    }


    Specjalnie spowolniłem wszystko, żeby widzieć co się dzieje. Wyświetlacze zapalają się po koleji, ale zawsze wyświetlają wartość 0.
    Zauważyłem, że jeśli przeniosę kod
    setki=wartosc/100;	
    dziesiatki = (wartosc/10) % 10; 
    jednosci = wartosc % 10;

    przed pętle while to wyświetli wartość 124. Jak jest on w środku to tylko 000.
  • #2 7140991
    tmf
    VIP Zasłużony dla elektroda
    Zadeklaruj setki, dziesiatki, jednosci ze slowem volatile. Przypuszczam, ze bez tego kompilator robi jakies optymalizacje w petli - wywala caly twoj kod, bo przeciez on efektywnie z punktu widzenia kompilatora nic nie robi. Inna sprawa, ze wyliczanie poszczegolnych cyfr musi byc operacja atomowa, bo co jesli nastapi przerwanie pomiedzy kolejnymi przypisaniami? Co prawda na krotko, ale wyswietlacz bedzie wyswietlal nieprawidlowa liczbe.
  • #3 7141087
    bestmlody
    Poziom 14  
    Dzięki. Działa :)
    Co oznacza to słowo volatile? Jakoś zmienia zmienną? ale kiedy tego używać?
  • #4 7141137
    tmf
    VIP Zasłużony dla elektroda
    Znaczy to, zeby kompilator nie probowal byc za madry. Uzywac tego ogolnie nalezy jesli dzielisz zmienna pomiedzy petle glowna programu i procedure obslugi przerwania.
    Zauwaz, ze np. w twoim przypadku w main w petli przypisujesz wartosci do zmiennych setki, dziesiatki, jednosci, co z punktu widzenia kompilatora, ktory nie wie, ze wykorzystujesz je w przerwaniach wyglada jakby one byly nieuzywane i optymalizator wywala caly ten kod. Dzieki volatile kompilator wie, ze mu sie tylko tak wydaje, a zmienna moze byc wykorzystywana w np. przerwaniu, co zapobiega takiemu dzialaniu optymalizatora.
  • #5 7142119
    Freddie Chopin
    Specjalista - Mikrokontrolery
    bestmlody napisał:
    Co oznacza to słowo volatile?

    Oznacza conajmniej dwie rzeczy:
    1. Oznacza, że nie szukałeś na forum na którym pytasz - po co, lepiej palnąć od razu nowy temat. Kwestia tego modyfikatora w tym tygodniu (jak zresztą w każdym...) była poruszana już kilka razy. I co z tego? Nic. Dalej każdy adept myśli, że "takiego problemu jak ja mam to na pewno jeszcze nie było".
    2. Oznacza też, że nie wiesz co to google, bo zapytanie go o 'volatile' daje 20M wyników, z czego pierwszy jest dobry, więc nawet nie trzeba rozmyślać i wybierać.

    Dobrze że tmf jest nowy, pare tygodni i już nie będzie mu się chciało po raz setny odpowiadać na pytanie "czemu kompilator wywala moje zmienne używane w przerwaniu". Szkoda że pewnie do tego czasu pojawi się kolejna osoba, która odpowie na to pytanie 10x, a potem następna i nastepna...

    4\/3!!
  • #6 7145529
    bestmlody
    Poziom 14  
    Tak ale tmf wyjaśnił mi to po polsku, bo w opisach języka C++... trzeba by to dopiero na polski przełożyć.
    p.s. Freddie nie jesteś nowy a chce Ci się pisać nie na temat więcej znaków niż tmf na temat....
REKLAMA