在 atmega328p 的 TIMER1 中使用 ISR 创建 10 秒延迟

问题描述

我正在尝试在 atmega328p 中使用 TIMER1(16 位)创建 10 秒延迟,我不知道是否已创建延迟,因为它需要的持续时间超过 10 秒和预期输出(即创建 pwm 波)未获得。这里我创建了一个 1 秒的延迟并循环了 10 次,TIMER0 用于创建 pwm 波。

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "interrupt.h"
#define SET_BIT(PORT,BIT) PORT |= (1<<BIT)
#define CLR_BIT(PORT,BIT) PORT &= ~(1<<BIT)

struct {
  volatile unsigned int BIT: 1;
}
FLAG_TIMER;

void timer_configuration()  //16 bit timer
{
  TCCR1A = 0x00; // normal mode of operation
  TCNT1 = 0xC2F8;
  TCCR1B |= ((1 << CS10) | (1 << CS12));
  TCCR1B &= ~(1 << CS11); //101
  sei(); // Global interrupt
}
void timer_on()
{
    TimsK1 |= (1 << TOIE1);
}
void pwm_configuration()    //TIMER0 - 8 bit
{
    TCCR0A |= ((1<<WGM00) | (1<<WGM01));    //setting it to fast PWM mode
    TCCR0A |= (1<<COM0A1);
    TCCR0A &= ~(1<<COM0A0);
    TCNT0 = 0x00;
    TCCR0B |= ((1<<CS00) | (1<<CS02)); //Prescaler setting 1024
    TCCR0B &= ~(1<<CS01);
    sei();
}


ISR(TIMER1_OVF_vect) 
{
  static unsigned int counter;
  counter++;
    if(counter >= 10)
    {
        
        FLAG_TIMER.BIT=1;
        counter = 0;
        TCNT1 = 0xC2F8;
        TimsK &= ~(1<< TOIE1);
    }
    else
    {
        FLAG_TIMER.BIT=0;
    }
  }
int main(void)
{
SET_BIT(DDRD,PD6); //CRO
timer_configuration();
pwm_configuration();
while(1)
{
timer_on();

    if(FLAG_TIMER.BIT == 1)
    {
        OCR0A = 128; //50% dutycycle
    }
}

解决方法

您在初始化时将计数器设置为 49912 并在它溢出时增加您的计数,但它随后将从 0 开始,因此如果 15624 个计数 = 1 秒,那么您的计数器将在 15624 + 9 x 216 计数或大约 38.75 秒。

在 ISR 中移动 TCNT1 = 0xC2F8; 行:

ISR(TIMER1_OVF_vect) 
{
  static unsigned int counter;

  TCNT1 = 0xC2F8;

  counter++;
  if(counter >= 10)
  {
    FLAG_TIMER.BIT=1;
    counter = 0;
    TIMSK &= ~(1<< TOIE1);
  }
  else
  {
    FLAG_TIMER.BIT=0;
  }
}

我不熟悉 ATmega,但我不相信这是使用计时器的合适方式。通常,您会向上计数到一个比较值并自动重置为零,或者从自动重新加载值向下计数到零并让硬件重新加载计数器。