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

[Attiny2313][C] - problem ze zmienną timera

koralgolek 16 Lut 2011 19:44 2169 12
  • #1 9161059
    koralgolek
    Poziom 11  
    Napisałem prosty program do fazowej regulacji napięcia za pomocą triaka przy uzyciu pilota (rc5).

    
    #define F_CPU 8000000L
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    #include "rc5.h"
    
    
    volatile int16_t czas=65379;
    
    SIGNAL (SIG_OVERFLOW1)
    {
    
    sei();
    PORTB |= 1<<PB0; // ON
    
     _delay_us(9);
    
    PORTB &= ~(1<<PB0); // OFF 
    
    }
    
    SIGNAL (SIG_INTERRUPT1){ 
    sei();
    
    TCNT1 = czas;
    	
    }
    
    
      int main (void)
      {
    
      
     
    DDRB |= 1<<PB0;
    PORTB &= ~(1<<PB0); // oFF	
         
    MCUCR |= (1<<ISC11);  // na jaki edge reagowac
    GIMSK |= (1<<INT1);  // odpal zew. przerwanie
    
    TCCR1B |= (1 << CS02); //time run with prescaler 256
    TIMSK |= (1 << TOIE1); // odpal przerwanie licznika
    
    
    
         
         rc5_init (RC5_ALL);
      
          sei();
    
          while (1)
          {
                   if (rc5.flip >= 0)
              {
               switch (rc5.code)
               {
    		   	    case 0x20:  
    					czas+= 5;
    					
    					TCNT1 = czas;
    					rc5.flip = -1; 
                         break; 
    			    case 0x21:  
    					czas -= 5;
    					
    					TCNT1 = czas;
    					rc5.flip = -1; // 
                         break;                      
    		   
    		   }
    		   }
              
            rc5.flip = -1;    
              } 
            
              
              
              
    }


    Program działa tak że w wyniku zewnętrznego przerwaniana INT1 , timer1 jest ładowany wartościa odpowiedniego opóźnienia, z którym ma byc odpalony triak.

    Wartośc 'czas' jest zwiekszana lub zmniejszana w zalezności od wcisniętego przycisku na pilocie.

    Problem polega na tym że zmienna 'czas' zaktualizuje się jedynie wtedy jeżeli odrazu po dokonaniu na niej zmiany załaduję ją do timer'a (mam na mysli linijkę z TCNT1 = czas;) Bez tej linijki zmienna czas pozostaje bez zmian tak jak została zadeklarowana na początku programu. Dlaczego tak się dzieje?
  • #2 9162427
    dondu
    Moderator na urlopie...
    Spróbuj wyłączyć optymalizację kodu przez kompilator oraz sprawdź jaki faktycznie powstaje kod asemblera.

    Jakiego środowiska używasz?

    Podaruję Ci 20pkt, bo widzę żeś biedny 0.34pkt :)
    Kolegów także zachęcam, bo widać, że się stara no i C używa :D
  • #3 9162502
    koralgolek
    Poziom 11  
    Mniej wiecej doszedłem o co chodzi. Używam avr-gcc na linuxa. Najwidoczniej jeżeli cos jest w nieskończonej pętli i nie ma powiązania z żadną zewnętrzną funkcją to zmienna nie jest akutalizaowana. Problem rozwiązałem tak że kody zczytywane z pilota sa rozpoznawane jeszcze na poziomie timer0'a ktory słuzy do dekodowania rc5. Procedura przerwania timera zawsze się kiedyś kończy w przeciwieństwie do while (1) {} więc zmienna jest tym razem aktualizowana. Dziękuję za punkty ;)
  • #4 9162564
    Konto nie istnieje
    Poziom 1  
  • #5 9162567
    koralgolek
    Poziom 11  
    Hmm? Zmienna 'czas' została użyta w nieskńczonej pętli w main() oraz w procedurze przerwania SIGNAL (SIG_INTERRUPT1).
  • #6 9162570
    dondu
    Moderator na urlopie...
    koralgolek napisał:
    Hmm? Zmienna 'czas' została użyta w nieskńczonej pętli w main() oraz w procedurze przerwania SIGNAL (SIG_INTERRUPT1).

    No właśnie dla tego wycofałem mój pierwszy post, bo nie zauważyłem, że w przerwaniu jest używana: https://www.elektroda.pl/rtvforum/topic1916069.html
  • #7 9163591
    Konto nie istnieje
    Konto nie istnieje  
  • #8 9164791
    koralgolek
    Poziom 11  
    100% pewności nie ma bo na zewnątrz układu tego nie widać. Przerwanie to jest generowane przez timer wiec sądze że zawsze kiedyś sie tam przekręci. Wartość timer'a (wg kodu w C - nie wiem jak to wygląda w asm) jest zmieniana jedynie w main przez zmienną 'czas'.

    Moje twierdzenie się sprawdza jak np po 'czas -= 5' dam 'main();' co powduje ponowne uruchomienie funkcji - wtedy zmienna się aktualizuje. Najwidoczniej zmiennych nie mozna "więzić" w pętlach. Póki z niej nie wyjdziemy nie mozemy uzyć jej wartości w innych funkcjach.
  • #9 9164962
    janbernat
    Poziom 38  
    Tak się zastanawiam co kompilator z tym robi:
    volatile int16_t czas=65379;
    Bo piszą w AVRLibc że int16_t może mieć maksymalną wartość 32767.
  • #10 9165073
    szelus
    Poziom 34  
    Kompilator zapewne wpisze (16 bitów) jak jest (dając ostrzeżenie) i wyjdzie mu wartość ujemna. Ale tajmerowi to nie robi.

    Do autora:
    SIG_INTERRUPT1 to zewnętrzne przerwanie nr 1 (stara składnia zresztą). Jeżeli nie podajesz sygnału na pin INT1, to się nie wywołuje.
    Po licho też wołasz sei() na poczatku obsługi przerwania? Wiesz, co robisz? Bo nie widzę uzasadnienia, a może co najwyżej namieszać.
  • #11 9165111
    koralgolek
    Poziom 11  
    SIG_INTERRUPT1 jest wyzwalany przez opadające zbocze z transoptora zasilanego z prostownika którym wykrywam przejście przez zero. Miałem problem z pilotem bo mniej wiecej co 2 wcisnięcie przycisku układ reagował. Domyślalem się (błędnie) że podczas dekodowania rc5 dochodzi do przerwania z SIG_INTERRUPT1 co psuje odczyt z pilota (zaburzenie czasu)

    Sei(); na poczatku przerwania miało odblokować inne przerwania w czasie trwania obecengo. Taki rodzaj priorytetu. Gdzieś wyczytałem że na czas trwania danego przerwania bit 7 w rejestrze SREG jest zerowany co oznacza zablokowanie przerwań.


    Uczę się programować Attiny'ego od kilku tygodni - jaka powinna być poprawna składnia?

    Podczas kompilowania powyższego kodu nie mam żadnych warning'ów.

    Kompiluje tak:

    avr-gcc -mmcu=attiny2313 -Os -Wall main.c -o wyjscie.out -lm biblioteki.o
  • #12 9165241
    szelus
    Poziom 34  
    Zacznę od końca - jeżeli nie ma ostrzeżenia, to byłby to błąd gcc (znaczy, brak ostrzeżenia).

    Nowa składnia obsługi przerwań: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

    Priorytety przerwań - teoretycznie, ponieważ w przerwaniu od timera masz delay(), to sei() mogłoby mieć uzasadnienie. Ale jeżeli warunki są takie, że następne przerwanie od INT1 następuje zanim skończy się obsługa tego od timera, to znaczy, że przeciągałbyś impuls sterujący na poczatek następnego okresu sieci i triak nie będzie się wyłączał. Czyli tak, czy owak, bez sensu. Jest granica minimalnego kąta otwarcia triaka wyznaczona czasem trwania impulsu wyzwalajacego.
    sei() w drugim przerwaniu nie ma żadnego uzasadnienia.

    Poza tym, twoje wnioski o działaniu programu sa raczej nieuzasadnione. Zmienna czas jest volatile, wiec modyfikacja następuje od razu i jest natyczmiast widoczna w obsłudze przerwań. Raczej podejrzewałbym błąd w obsłudze RC5. Właściwie, w jaki sposób to obsługujesz - w (innych) przerwaniach? Jak jest zadeklarowana zmienna rc5? volatile?
  • #13 9166256
    koralgolek
    Poziom 11  
    Jak wspomniałem wcznieśniej problem rozwiązałem troche inaczej i już wszystko jest w porządku a nawet lepiej. Układ reaguje za każdym razem poprawnie i nie ma denerwujaćego migania żarówki podczas jej ściemniania i pojaśniania.

    Dekodowanie rc5 wziąłem stąd: http://www.gjlay.de/pub/c-code/rc5.html
REKLAMA