【问题标题】:AVR timer overflow interrupt not workingAVR 定时器溢出中断不工作
【发布时间】:2017-04-03 16:30:29
【问题描述】:

你好堆栈溢出的好人。我的问题是一个看似永远不会执行的中断服务程序(ISR)!以下是关于我的设置的一些信息: 我正在闪烁 avr attiny85。到目前为止,我只用一个 main.c 和两个模块:timer 和 hardwareInit 建立了一个项目的基本框架。在定时器模块中,我有一个 timer0_init 函数,用于将 timer0 设置为 CTC 模式,使其每 1 ms 溢出一次。这是函数:

void timer0_init( void )
{
    cli();
    TCCR0B |= 3;    //clock select is divided by 64.
    TCCR0A |= 2;    //sets mode to CTC
    OCR0A = 0x7C;   //sets TOP to 124 so the timer will overflow every 1 ms.    
    TIMSK |= 2;     //Enable overflow interrupt
    sei();          //enable global interrupts
}

通过设置计时器,我添加了一个 ISR 以在每次计数器溢出时递增滴答声,这样我就可以跟踪已经过去了多少时间,等等。

ISR(TIMER0_OVF_vect)
{
    cli();
    //ticks ++;
    PORTB |= ( 1 << PORTB0 );   
    sei();
}

如您所见,我注释掉了 ticks++,因为它不起作用,并用 PORTB |= ( 1 &lt;&lt; PORTB0 ); 替换它,它只是打开一个 LED,所以如果中断被执行,我会通过 LED 的证明来知道正在上。
不幸的是,我无法打开它,也看不到我错过了什么。 (为了证明我 1. 将 LED 设置在正确的引脚上,并且 2. 在正确的寄存器中操作正确的位,我将这条语句 PORTB |= ( 1 &lt;&lt; PORTB0 ); 放入我的无限循环并确认 LED 亮起)

为了进一步解释,这里是我的 main.c:

/*================================= main.c =================================*/

#define F_CPU   8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "timer.h"
#include "hardwareInit.h"


int main(){

    //Initialize hardware HERE  
    DDRB |= ( 1 << PORTB0 );    //set this pin as an output for an LED

    SetClockPrescale(1);    //internal clock divided by 1 = 8 MHz, from hardwareInit

    timer0_init();          //set up timer0 for 1 ms overflow


    while(1)
    {
        /* if( getTicks() > 0 )
        {
            PORTB |= ( 1 << PORTB0 );
            _delay_ms(1000);
            PORTB &= ~( 1 << PORTB0 );
            _delay_ms(1000);
        } */

    }
    return 0;
}

所以,你在无限循环中看到的是我首先尝试的,但是在那之后没有用,我尝试了一些更简单的方法,只是有一个空循环(注释掉以前的东西),并等待中断得到触发将打开 LED。

您能提供的任何帮助将不胜感激。我很困惑为什么这不起作用。

【问题讨论】:

  • 尝试将TIMSK |= 2; 更改为TIMSK |= (1&lt;&lt;4);TIMER0_OVF_vect 更改为TIM0_COMPB_vect。但不能保证。
  • 或者,保持定时器初始化不变,只需尝试将向量更改为TIM0_OVF_vect

标签: c embedded interrupt avr attiny


【解决方案1】:

正如@andar 正确指出的那样,您使用了错误的 ISR。在 CTC“比较时清除定时器”模式下,定时器永远不会溢出,因为它会在比较匹配时被清除。

所以你也启用了错误的定时器中断。 TIMSK 寄存器的位 1 使能 timer0 上的定时器溢出中断。不会因为前面的原因触发。取自datasheet

当您使用OCR0A 设置比较值时,您必须启用Bit 4 – OCIE0A:定时器/计数器0 输出比较匹配A 中断启用

回到 ISR,您需要 ISR(TIMER1_COMPA_vect)ISR(TIMER1_COMPB_vect),具体取决于您在 TIMSK 中设置的位。请注意,比较值也应写入匹配的寄存器,OCR0AOCR0B


请注意,您可以在代码中使用位名称,就像寄存器名称一样,我认为这会使代码更加透明。

您的代码应更改如下以启用相应的中断:

void timer0_init( void )
{
    cli();          
    TCCR0B |= (1<<CS01) | (1<<CS00);   //clock select is divided by 64.
    TCCR0A |= (1<<WGM01);              //sets mode to CTC
    OCR0A = 0x7C;                      //sets TOP to 124 so the timer will overflow every 1 ms.    
    TIMSK |= (1<<OCIE0A);              //Output Compare Match A Interrupt Enable
    sei();                             //enable global interrupts
}

ISR:

ISR(TIMER0_COMPA_vect)
{
    cli();
    //ticks ++;
    PORTB |= ( 1 << PORTB0 );   
    sei();
}

【讨论】:

  • 太棒了!我错过了 CTC 模式的要点。当我将OCR0A设置为124时,我以为既然TOP改为124,定时器就会溢出。我现在很清楚只有当计时器达到“真实”顶部时才会溢出,在这种情况下是 255。关于你说的其他事情是错误的,让我澄清一下。您说“您还启用了错误计时器的错误中断”,但我真的没有。我将 TIMSK 寄存器与值 2 进行或运算,二进制为 00000010,有效地将 TOIE0 位设置为 1。以下行是等效的: TIMSK |= 2; TIMSK |= (1
  • 答案的后半部分也是如此,您列出了几个更正。 “寄存器的第 3 位与时钟分频无关。”我没有设置第 3 位,而是将整个寄存器与值 3 或 00000011 进行或运算以设置其前 2 位(CS00 和 CS01)以获得 64 的时钟分频。校正 2 也是如此。我知道这是我的由于懒惰并将我的符号与一个值进行 ORing 和 ORing 与位名称移位了一点,这是错误的。对困惑感到抱歉。这有意义吗?
  • 如果您修改答案以更正该问题,我将投票赞成并接受您的答案。感谢您的帮助!
  • @chen 是的,是的,你是对的。我不知道为什么我认为你在位移这些值。可能因为我一直用bitshift,我会改正的
  • 是的,我现在更改了我的代码以在任何地方使用位移方法,它更具可读性。我还更改为输出比较中断而不是溢出,它工作得很好!所以谢谢!也感谢您对答案的修改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-25
  • 1970-01-01
相关资源
最近更新 更多