avr timer1 16 位快速 PWM

avr timer1 16bit fast PWM

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

我希望有一个变量可以在定义的时间内进行计数,然后重置并继续。到目前为止,我预计它会持续 7.5 秒。我相信我应该有一个 8 MHz 的时钟频率,然后使用带有 1 预分频器的快速 PWM 和 5000 的 ICR1,我希望中断发生在 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 */
}

每当我使用内部振荡器并且事情 运行 快 (8x) 或慢 (8x) 时,我都会检查 CKDIV8 位设置。几乎总是那是罪魁祸首。

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

另外,有点跑题了,但是这样的代码是多余的:

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

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