avr timer1 16bit fast PWM

南楼画角 提交于 2021-02-10 23:13:09

问题


I am using an Atmega328p-pu. I am trying to use the timer 1 for both a 16 bit PWM as well as using the overflow inturrupt to increment a timer. My code is below, I also set the F_CPU to 8000000UL in the make file.

I would like the to have a variable that counts up for a defined amount of time and then resets and continues. so far I would expect it to count up for 7.5 seconds. I believe I should have a clock frequency of 8 MHz, then with fast PWM with a 1 prescaler and ICR1 at 5000 I would expect the inturrupt to happen at 1600 Hz. Then I let it count up for 12000 counts. I would expect this to take 7.5 seconds. but I've measured it at around 57 seconds. I'm not sure what I'm missing, maybe something in the setting of the registers, but I'm not sure where. thanks for your help,

here is what I think is most important,

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

and here is the entire code

                                                           /* 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:


Whenever I'm using the internal oscillator and things are running either way (8x) faster, or way (8x) slower, I check the CKDIV8 bit setting. Almost always that's the culprit.

If using an external oscillator or clock, weird timings are often from not switching the the external clock in the fuse settings, or from having F_CPU set differently from actual frequency.

Also, off-topic a bit, but code such as this is redundant:

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

Those bits are zeroes by default so no reason to clear them unless it's just for clarity as you're learning.



来源:https://stackoverflow.com/questions/45946688/avr-timer1-16bit-fast-pwm

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!