avr timer1 16bit fast PWM

时间:2017-08-29 19:10:15

标签: timer avr pwm

我使用的是Atmega328p-pu。我试图将定时器1用于16位PWM以及使用溢出中断来递增定时器。我的代码如下,我还在make文件中将F_CPU设置为8000000UL。

我希望有一个变量可以计算一段时间,然后重置并继续。到目前为止,我希望它能累计7.5秒。我相信我应该有一个8 MHz的时钟频率,然后快速PWM使用1个预分频器,ICR1在5000 I时,我预计内部频率会发生在1600 Hz。然后我让它计算12000个计数。我希望这需要7.5秒。但是我在57秒左右测量了它。我不确定我错过了什么,也许是寄存器设置中的东西,但我不知道在哪里。谢谢你的帮助,

这是我认为最重要的,

// values for timer1
// WGM      13 12 11 10 is 
// fast PWM  1  1  1  0

TCCR1A |=  (1 << 7); // output on A pin (COM1A1)
TCCR1A |=  (1 << 1); // WGM 11 
TCCR1A &= ~(1 << 0); // WGM 10 

TCCR1B |= (1 << 4); // WGM 13 
TCCR1B |= (1 << 3); // WGM 12 

//for prescaler of 1  set  CS12  CS11  CS10 
                            0     0     1 

TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
TCCR1B |=  (1 << 0); // set prescaler to 1x CS10

TIMSK1 = 0;  // enable output compare A inturrupt
TIMSK1 |= (1 << 0);  // Set the Overflow inturrupt
TCNT1 = 0;            // set the counter to zero on startup
ICR1 =  5000; //Set the top of the counter
OCR1A = 0;  //set the duty cycle  
....
ISR(TIMER1_OVF_vect){
longTimer++;
....
    if (longTimer >= 12000){
    longTimer = 0;

这是整个代码

                                                           /* Light Control */

// ------- Preamble -------- //
#include <avr/io.h>                        /* Defines pins, ports, etc */
#include <avr/interrupt.h>

// Global variables 
volatile uint8_t tick = 0;
volatile uint8_t fastTimer = 0;
volatile uint16_t longTimer = 0;
volatile uint16_t fader = 0;
volatile uint16_t dayBrightness = 0;
volatile uint8_t nightBrightness = 0;
uint8_t Day = 0; 

void init(void) { 

// values for push button inturrupt
  EIMSK = (1 << 0);
  EICRA = (1 << 1) & (1 << 0);

// values for timer1
// WGM      13 12 11 10 is 
// fast PWM  1  1  1  0

  TCCR1A |=  (1 << 7); // output on A pin (COM1A1)
  TCCR1A |=  (1 << 1); // WGM 11 
  TCCR1A &= ~(1 << 0); // WGM 10 

  TCCR1B |= (1 << 4); // WGM 13 
  TCCR1B |= (1 << 3); // WGM 12 

  //for prescaler of 1  set  CS12  CS11  CS10 
                                0     0     1 

  TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
  TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
  TCCR1B |=  (1 << 0); // set prescaler to 1x CS10

  TIMSK1 = 0;  // enable output compare A inturrupt
  TIMSK1 |= (1 << 0);  // Set the Overflow inturrupt
  TCNT1 = 0;          // set the counter to zero on startup
  ICR1 =  5000; //Set the top of the counter
  OCR1A = 0;  //set the duty cycle 

    sei();

// values for IO
  DDRB |= 0b00000011;            /* Data Direction Register B: writing a one to the bit enables output. */
  DDRD  = 0x00;                 /* zero sets all as input */            
  PORTD = 0xff;                 /* set all inputs as pull ups */
}

ISR(INT0_vect){
    //longTimer = 0;
} 

ISR(TIMER1_OVF_vect){
longTimer++;
if(Day){
    fader++;
}
else{
    if(fader > 0){
        fader--;
    }
}
} 

int main(void) {

    init();

// ------ Event loop ------ //
  while (1) {

    if(Day) {
        if (fader >= 5000){
            OCR1A = 5000;
        }
        else {
            OCR1A = fader;
        }
    }
    else {
        OCR1A = fader;
    }


    if (longTimer >= 12000){
        longTimer = 0;
        if(Day){
            fader = 5000;
        }
        else{
            fader = 0;
        }
        tick = 1;
    }

    if (tick == 1){
        Day ^= 1;
        tick = 0;
    }

  }                                                  /* End event loop */
  return 0;                            /* This line is never reached */
}

1 个答案:

答案 0 :(得分:1)

每当我使用内部振荡器时,运行速度更快(8x)或速度慢(8x),我检查CKDIV8位设置。几乎总是这是罪魁祸首。

如果使用外部振荡器或时钟,奇怪的时序通常是在保险丝设置中不切换外部时钟,或者使F_CPU设置与实际频率不同。

此外,有点偏离主题,但这样的代码是多余的:

TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11

默认情况下,这些位为零,因此没有理由清除它们,除非您在学习时只是为了清晰。