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

[AVR][C] Przerwania dwóch timerów, a zmiana sygnału PWM

ky3orr 22 Sie 2011 01:09 2457 5
REKLAMA
  • #1 9849352
    ky3orr
    Poziom 11  
    Witam wszystkich!

    Aktualnie bawię się trybami PWM atmegi32.
    Na timerze0 robię phase correct pwm, zaś na timerze2 zegar systemowy.

    PWM jest software'owy i ustawianie poziomu logicznego znajduje się w przerwaniu od OCR0.

    Czas systemowy to po prostu inkrementowana zmienna globalna w przerwaniu od OCR2, gdzie licznik pracuje w trybie CTC.

    Mój problem polega na tym, że nie bardzo potrafię rozszyfrowac dla czego gdy pominę inicjalizację system_clock_init() PWM działa OK, zaś gdy zainicjalizuję licznik od czasu systemowego, częstotliwość PWM maleje i poziom jasności LED'a się zmienia (rozjaśnia się).

    dzięki za podpowiedzi.

    kod poniżej:

    
    #define F_CPU 10000000UL 
    #define LED PC2 //pin where LED is connected
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    volatile uint8_t system_clock; //global system clock
    
    void phase_correct_pwm_init(void)
    {
    	TCNT0 = 1;				//workaround after errata (so TCNT is not 0xFF or 0x00 causing interrupt losing problem)
    	TCCR0 |= ((1<<CS00) || (1<<CS01));	//clock=F_CLK/64 (tick=6.4us)
    	TCCR0 |= (1<<WGM00);	//timer0 phase correct PWM mode
    	SFIOR |= (1<<PSR10);	//prescaler reset
    	TIMSK |= (1<<OCIE0);	//timer0 compare match int. enable
    	OCR0 = 4;				//initial PWM
    }
    
    ISR(TIMER0_COMP_vect)
    {
    	static uint8_t ocr_counter;
    	
    	if(ocr_counter) {
    		PORTC &= ~(1<<LED);	//reset LED on 2nd OCR
    		ocr_counter = 0; //reset counter
    	} else {
    		PORTC |= (1<<LED); //set LED on 1st OCR
    		ocr_counter++; //set counter
    	}
    }
    
    void system_clock_init(void)
    {
    	TCNT2 = 1;				//workaround after errata (so TCNT is not 0xFF or 0x00 causing interrupt losing problem)
    	TCCR2 |= (1<<CS21);		//prescaler = 8 (tick=0.8us)
    	TCCR2 |= (1<<WGM21);	//timer2 CTC mode
    	SFIOR |= (1<<PSR2);		//prescaler reset
    	TIMSK |= (1<<OCIE2);	//timer2 OCR interrupt enable
    	OCR2 = 249;				//OCR interrupt every 0.8us*250=200us
    }
    
    ISR(TIMER2_COMP_vect, ISR_NOBLOCK) //interrupt every 200us
    {
    	system_clock++;
    }
    
    int main(void)
    {
    	DDRC |= (1<<LED); //led pin output direction
    	
    	system_clock_init();
    	phase_correct_pwm_init();
    	sei();
    	
        while(1)
        {
    
        }
    }
  • REKLAMA
  • REKLAMA
  • #3 9850022
    Andrzej__S
    Poziom 28  
    Jaki jest powód użycia operatora logicznego || w instrukcji TCCR0 |= ((1<<CS00) || (1<<CS01));? Moim zdaniem powinno być bitowe OR, czyli pojedynczy znak |, ponieważ w ten sposób raczej nie uzyskasz oczekiwanego preskalera.

    Korzystając ze sprzętowego PWM lepiej jest używać dedykowanego pinu OC0(PB3). Eliminuje to konieczność obsługi przerwania (TIMER0_COMP_vect) i "ręcznej" zmiany stanu pinu. Chyba, że z jakichś ważnych powodów musisz użyć konkretnego pinu lub nie możesz użyć PB3.

    Poza tym w trybie "phase correct" licznik liczy w górę poźniej w dół, a przerwanie output compare pojawia się w każdym kierunku zliczania. Przy zastosowanym przez Ciebie sposobie sterowania PWM może zaistnieć sytuacja (szczególnie przy niskim preskalerze i małej wartości OCR0), że podczas inicjalizacji timera "zgubisz" jedno przerwanie i wtedy sygnał na pinie będzie zanegowany. Stosując dedykowany pin unikniesz takiej sytuacji.
  • REKLAMA
  • #4 9851944
    ky3orr
    Poziom 11  
    LordBlick ISR_NOBLOCK powoduje, że obsługa przerwania nie blokuje globalnie przerwań na czas jego wykonania.
    Obsługa czasu systemowego, zwłaszcza ze względu na jegj prostą konstrukcję nie blokuje przerwań na wypadek zejścia się z przerwaniem od PWM'a.

    Andrzej__S masz rację. Pomyłka jak sie patrzy :)
    Z mojego kodu wynika, że w TCCR0 ustawiam "1" czyli tylko CS00, a zatem preskaler=1.

    Sprawdzę w układzie i podeślę obserwacje.

    Co do wyjścia sprzętowego to mnie nie urządza, gsyż zabieram się za sterowanie silnikiem bezszczotkowym i potrzebuje trzech wyjść PWM.

    pozdrawiam
  • REKLAMA
  • #5 9852249
    LordBlick
    VIP Zasłużony dla elektroda
    ky3orr napisał:
    LordBlick ISR_NOBLOCK powoduje, że obsługa przerwania nie blokuje globalnie przerwań na czas jego wykonania.
    W niesprzyjających okolicznościach stos się rozjedzie...
    ky3orr napisał:
    Co do wyjścia sprzętowego to mnie nie urządza, gsyż zabieram się za sterowanie silnikiem bezszczotkowym i potrzebuje trzech wyjść PWM.
    ->ATtiny167/87; ATtiny461/861; AT90PWM...
  • #6 9852706
    ky3orr
    Poziom 11  
    poprawka błędu związana z użyciem OR'a "||" zamiast logicznej sumy "|" naprawiła błąd.
    wszystko działa jak należy.

    dzięki za pomoc

    pozdrawiam
REKLAMA