AVR Timer1 16位快速PWM [英] avr timer1 16bit fast PWM

查看:148
本文介绍了AVR Timer1 16位快速PWM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

我希望拥有一个变量,该变量在定义的时间内计数,然后重置并继续.到目前为止,我希望它能持续7.5秒.我相信我应该有一个8 MHz的时钟频率,然后使用带有1个预分频器的快速PWM和5000的ICR1,我希望这种干扰会在1600 Hz处发生.然后,我让它计数12000.我预计这将花费7.5秒.但是我已经测量了大约57秒.我不确定我缺少什么,也许是寄存器设置中的某些内容,但是我不确定在哪里.谢谢您的帮助,

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,

这是我认为最重要的,

// 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位设置.几乎总是罪魁祸首.

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.

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

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.

这篇关于AVR Timer1 16位快速PWM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆