2017-04-15 4 views
0

Ich bin neu in AVR C Programmierung, ich teste eine einfache PWM mit 16-Bit-Timer auf Atmega328p Counter/Timer, die als Dimmer zu einer LED fungieren soll.16-Bit-Timer PWM LED-Dimmer

Mein Code:

#define F_CPU 16000000UL 

void initTimer(); 

int x = 1; 
int n = 1000; 

int main(void) 
{ 

    initTimer(); 

    DDRB |= (1 << PB1)| (1 << PB2); 

    while(1) 
    { 
     x++; 

     if(x > 65) { 
      x = 1; 
     } 
    } 
} 

void initTimer() { 

    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); 
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); 
    // used for TOP, makes for 50 Hz PWM 
    ICR1 = 40000; 
    OCR1A = n * x; 

} 

ISR(TIMER1_OVF_vect) 
{ 
    OCR1A = n * x; 
} 

Problem ist, dass es nicht die Abdunkelungseffekt nicht angezeigt, die Helligkeit der LED konstant bleibt, wie, was auch immer Wert I für OCR1A (PB1) Ausgangsstift zunächst seine suppose um den Wert zu ändern, während der Interrupt passiert, aber es tut dies einfach nicht, das soll ein einfacher Test sein, was mache ich falsch?

Update:

Als Beratung aktiviere ich die Interrupts die TIMSK1 Register und SEI(), aber immer noch das gleiche Problem der LED-Helligkeit bleibt konstant, was auch immer der ursprüngliche Wert von OCR1A verwenden, die in der angegeben wurde initTimer().

int main(void) 
{ 
    initTimer(); 
    DDRB |= (1 << PB1)| (1 << PB2); 

    while(1) 
    { 
     x++; 
     if(x > 65) { 
      x = 1; 
     } 
    } 
} 

void initTimer() { 

    ICR1 = 40000; 
    OCR1A = n * x; 
    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); 
    TIMSK1 |= (1 << ICIE1); 
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); 
    sei(); 
} 

ISR (TIMER1_COMPA_vect) 
{ 
    OCR1A = n * x; 
} 

Obwohl ich einen alternativen Ansatz versucht, und das gibt mir die Verdunkelung beeinflussen:

int main(void) 
{ 

    initTimer(); 

    DDRB |= (1 << PB1)| (1 << PB2); 

    while(1) 
    { 
     _delay_ms(20); 
     OCR1A = n * 4; 
     _delay_ms(20); 
     OCR1A = n * 8; 
     _delay_ms(20); 
     OCR1A = n * 15; 
     _delay_ms(20); 
     OCR1A = n * 25; 
     _delay_ms(20); 
     OCR1A = n * 1; 

    } 
} 

void initTimer() { 

    ICR1 = 40000; 
    OCR1A = n * x; 
    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); 
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); 

} 

So scheint es, das Problem mit dem Interrupts, da PWM Arbeiten beeinflussen, aber es ist einfach nicht mit den Interrupt-Handler arbeiten .

Antwort

1

Das erste, was bei mir herausspringt, ist x und n sollte flüchtig sein. Sie sollten den Interrupt auch im TIMSK0-Register aktivieren. Aktivieren Sie auch Interrupts durch den Aufruf von sei.

Wenn ich Sie wäre, würde ich mit etwas gutem Beispielcode beginnen. Die Seite, die ich erwähnte, hat ein Beispiel, das alle 4ms einen Interrupt auslöst. Nimm diesen Code und schalte die LED ein und aus.

Ein weiteres Problem ist die Änderung von x ohne Rücksicht darauf, ob der isr aufgerufen wurde oder nicht. In der Praxis erhalten Sie jedes Mal ein zufälliges x im isr. Dieser Code ist einfach genug, um in einem einfachen Muster stecken zu bleiben. Verschieben Sie stattdessen die Einstellung von x auf Ihr Isr.

Hier ist eine gute Einführung zu Avr-Timer: https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328

Verwandte Themen