2017-04-15 2 views
0

Je suis novice en programmation AVR C, je teste un PWM simple utilisant un minuteur 16 bits sur des compteurs/temporisateurs Atmega328p qui est censé agir comme un gradateur sur une DEL.Minuterie DEL dimmateur 16 bits

Mon 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; 
} 

Le problème est qu'il ne présente pas l'effet de variation, la luminosité de la LED reste constante à toute valeur que je mis à la broche de sortie OCR1A (PB1) d'abord, son suppose pour changer la valeur que l'interruption se produire mais c'est juste ne pas faire cela, c'est supposé être simple test qu'est-ce que je fais mal?

Mise à jour:

Comme conseil que j'activer les interruptions à l'aide du registre de TIMSK1 et SEI(), mais toujours la même question la luminosité LED reste constante à quelle que soit la valeur d'origine de OCR1A qui a été spécifié dans la 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; 
} 

Bien que j'ai essayé une autre approche et qui me donne la gradation effet:

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); 

} 

Il semble que le problème est avec les interruptions depuis PWM affectent les œuvres, mais son juste ne fonctionne pas avec le gestionnaire d'interruption .

Répondre

1

La première chose qui me saute aux yeux est x et n devrait être volatile. Vous devez également activer l'interruption dans le registre TIMSK0. Activez également les interruptions en appelant sei.

Si j'étais vous, je commencerais avec un bon exemple de code. La page que j'ai mentionnée a un exemple qui déclenche une interruption toutes les 4ms. Prenez ce code et allumer et éteindre le voyant.

Un autre problème est que vous modifiez x sans tenir compte de l'appel ou non de l'ISR. Donc, en effet, vous obtiendrez un x aléatoire à chaque fois dans l'isr. Ce code est assez simple, il pourrait être coincé dans un modèle simple. Au lieu de cela, déplacez le paramètre de x sur votre isr.

Voici une bonne introduction aux contrôleurs avr: https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328