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

[ATMEGA32][C]priorytety przerwań (usart+timer)

aniasta 14 Maj 2009 17:25 3103 4
REKLAMA
  • #1 6529846
    aniasta
    Poziom 10  
    Witam. Próbuje uruchomić program testowy, który polega na tym, że po wysłaniu na RS-a liczby 2 dioda zapala się na okres 1 sekundy i na ten sam czas również gaśnie przez okres 30 s. Wysyłanie na port szeregowy wykonuje za pomocą przerwania z USART. Odmierzanie sekund z przerwania Timera w trybie asynchronicznym(RTC). Program nie działa, bo mam problem z priorytetami przerwań. Próbowałam zamienić ISR na Signal, jednak to nie przynosi efektów. Czy dostanę małą podpowiedź jak ustawić priorytety?

    
    #define F_CPU 8000000UL 		//czestotliwosc zegara w Hz
    #define UART_BAUD   9600         //prędkość transmisji
    #define UART_CONST   (F_CPU/(16ul*UART_BAUD)-1)
    unsigned char x=0;
    
    int volatile sekunda=0x00; //zmienna globalna wystepujaca w przerawniu
    volatile unsigned char i=0; //zmienna przy przerwaniu UART
    
    void USART_Transmit( unsigned char data )
    {
       while ( !( UCSRA & (1<<UDRE)) );   /* Czekaj na pusty bufor transmisji */
       UDR = data;                  /* włóż dane do bufora i wyślij je */
    }
    
    unsigned char USART_Receive( void )
    {
       while ( !(UCSRA & (1<<RXC)) );            /* czekaj na dane do wysłania*/
       return UDR;                           /*odbierz i zwróć odebrane dane z bufora */
    }
    
    void USART_Init( unsigned int ubrr )
    {
       UBRRH = (unsigned char)(ubrr>>8);         /* ustaw prędkość transmisji*/
       UBRRL = (unsigned char)ubrr;   
       UCSRB = (1<<RXEN)|(1<<TXEN);      /* zezwól na transmisje i odbiór */   
       UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);   /*  8bitów danych, 2bity stopu */
    
     
    SIGNAL(SIG_UART_RECV) // podprogram przerwania od USART
    {
    i=UDR;
    
    } 
    
    
    ISR(TIMER2_OVF_vect) //podprogram przerwania timer'a
    {  
        sekunda++;
        if (sekunda==30)
    	   { 
        	sekunda=0;                                   
            TIMSK &= ~_BV(TOIE2); //po czasie 30s wylacz przerwania
               }
    	PORTD ^=_BV(7);  //zapala sie dioda i gasnie co 1s 
    }
    
    int main(void)
    {
    DDRD=0xff;    //dioda na  PB7;
    PORTD=0xff;
    
    ASSR |= _BV(AS2);   // TC2 z taktowania zegarem CPU na generator     asynchroniczny
    // preskaler fclk/128 ->dokładnie co 1 s
    TCCR2 = 1<<CS00 | 1<<CS02 |  0<<CS01 ;
    TCNT2 = 0;
    //TIFR   = 0;
    sei();              // włącz obsługę przerwań
    
    USART_Init(UART_CONST);
    
      while(1) 
      {  	UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXC); //wlacz obsluge przerwan USART
    
        	if (i==2)
          {TIMSK |= _BV(TOIE2);    // włącz przerwania z TC2
           	}
     		UCSRB =(1<<UDRIE)|(0<<RXEN)|(0<<TXEN)|(0<<RXC); //przestan nadawac i	   
              
     }         
    } 
    
    
  • REKLAMA
  • Pomocny post
    #2 6529865
    BoskiDialer
    Poziom 34  
    Na jakiej podstawie twierdzisz, że problemem są priorytety przerwań? Przerwania występują na tyle sporadycznie, że nie ma tutaj miejsca na problemy. Jeśli wysyłany jest znak '2', to porównanie (i==2) jest błędne [poprawne było by i=='2'). Dalej jest brak zerowania zmiennej "i" - kod zawiesza się, cały czas załącza przerwanie od timera. Nigdy nie jestem pewien priorytetów operatorów, więc linijkę
    TCCR2 = 1<<CS00 | 1<<CS02 |  0<<CS01 ;
    proponuję zapisać tak:
    TCCR2 = (1<<CS00) | (1<<CS02) | (0<<CS01);
  • REKLAMA
  • #3 6529943
    aniasta
    Poziom 10  
    Poprawiłam program tak jak zasugerowałeś, jednak nadal nic się nie dzieje. Nie wiem co jeszcze może być nie tak, bo w rozłożeniu tego na dwa oddzielne programy wszystko działa.

    Dodano po 1 [godziny] 2 [minuty]:

    Już wiem. Włączenie przerwania od USART powinno być przed while'em.
    
     UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXC); 
    

    Dziękuje za pomoc. Pozdrawiam
  • REKLAMA
  • #4 6530329
    akleiw
    Poziom 12  
    Jeszcze trzy rzeczy w tej pętli while:

    - wyłączenie USARTU następuje bez względu na wartość i - chyba nie w tym miejscu umieściłaś klamrę zamykającą if

    - w jakim celu ustawiasz 1<<UDRIE. W ten sposób blokujesz mikrokontroler - nie ma obsługi tego przerwania, więc nie ma co wyczyścić flagi, a Program Counter w kółko skacze do początku programu.

    - nie ma takiego bitu RXC w UCSRB, jest RXCIE (masz szczęście, że oba są równe 7).
  • #5 6530591
    aniasta
    Poziom 10  
    Z tego można zrezygnować:
    
    UCSRB =(1<<UDRIE)|(0<<RXEN)|(0<<TXEN)|(0<<RXCIE);
    

    Zastąpiłam to po prostu: i=0;
    I nie wiem dlaczego ale ani i==2 ani i=='2' nie działa (dlatego zmieniłam program na i=='E"):P
    Wszystko już jest ok. Thx.Pozdrawiam.
REKLAMA