1

我猜,我的CODE中的溢出中断(用于将 8 位定时器的分辨率从 16µs/步提高到 1µs/步)有一些问题。当程序在我的主循环中的 if 语句中时,似乎溢出中断触发,从而搞砸了!

    if(pInt == 1)           //PCNINT-if-statment
    {           
        pulse16 = (tot_overflow << 8) | TCNT1;          //adds tot_overflow and TCNT1 to be able to set if-statements in PCINT-while-loop with µs 

        if(PINB & (1 << PINB3))         //if PB3 is HIGH
        {
            TCNT1 = 0;      //resets Timer/Counter1
            tot_overflow = 0;       //resets tot_overflow variable   
        }

        else        
        { 
            if (pulse16 >1555)          //when stick 1 travels from 1555 µs towards 2006 µs  
            {
                PORTB &= ~(1 << relayPin);        //relay pole switch, + & - on motor 
                PORTB |= (1 << greenLED);        //LED green indicates forward motion
                PORTB &= ~(1 << redLED);        //turn off red LED
            }

                else if (pulse16 <1490)         //when stick 1 travels from 1490 ms towards 920 µs  
                {
                    PORTB |= (1 << relayPin);        //relay pole switch, - & + on motor 
                    PORTB &= ~(1 << greenLED);        //turn off green LED
                    PORTB |= (1 << redLED);         //LED red indicates backward motion
                }   

            else        //if µs is 1490> or <1555 - dead-span to prevent gliteches on relay when stick is in centre position 
            { 

            }   

        }

        pInt = 0;       //resets pInt to exit PCNINT-if-statment   
    }

pInt是一个“标志变量”,表示 PCINT 已被触发每次触发溢出中断时,tot_overflow 变量都会递增

我使用 ATtiny85 作为 RC 开关,当来自接收器的 µs 高于 1555 时,它应该在 PB2 引脚上变为低电平,当 µs 低于 1490 时变为高电平。
会发生以下情况:当检查 µs 是否高于 1555 或低于 1490并且使用溢出中断它有时会在 1490-1555 的“死区”中将 PB2 引脚高/低,而不应该在“死区”之外,有时会在“死区”之外!这是关于故障的视频。请注意,在我的代码中,绿色 LED 是redLED,黄色 LED 是greenLED 。

我对此很陌生,我不确定为什么会这样,我不明白为什么代码不起作用。我已经查看了 CTC 功能,但我看不出它会有所帮助,因为我仍然必须使用定时器溢出中断来获得我想要的 1µs/步的分辨率。


编辑

我尝试了几种变体(@yann-vernier 的建议),但仍然无法正常工作,这是最接近工作代码的方法:

while(1)        //leave and/or put your own code here
{
    static uint8_t tot_overflow;        //variable to count the number of Timer/Counter1 overflows  

    if (TIFR & (1 << TOV1) )
    {
        TIFR |= (1 << TOV1);        // clear timer-overflow-flag
        tot_overflow ++;
    }

    if(GIFR & (1 << PCIF) )         //PCINT-flag idicates PCINT
    {
        uint16_t pulse;         //variable to make a 16 bit integer from tot_overflow and TCNT1  

//          PORTB |= (1 << debugPin);       //pin is HIGH on when interrupt is intialized

        pulse = (tot_overflow << 8) | TCNT1;            //adds tot_overflow and TCNT1 to be able to set if-statements in PCINT-while-loop with µs 

这部分我没有开始工作:

        if ( ((TIFR & (1 << TOV1)) && ((pulse & 0xff))) < 0x80)
        {
            pulse += 0x100;   // Overflow had not been counted
        }

我不确定我明白上面发生了什么,我唯一知道的是我可能做错了!当我评论上述部分时,它的工作方式与 mu 旧代码相同!

        else
        {
            if(PINB & (1 << PINB3))         //if PB3 is HIGH
            {
                TCNT1 = 0;      //resets Timer/Counter1
                tot_overflow = 0;       //resets tot_overflow variable   
            }

            else        
            {       
                if (pulse > 1555)           //when stick 1 travels from 1555 µs towards 2006 µs  
                {
                PORTB &= ~(1 << relayPin);        //relay pole switch, + & - on motor 
                    PORTB |= (1 << greenLED);        //LED green indicates forward motion
                    PORTB &= ~(1 << redLED);        //turn off red LED
                }

                    else if (pulse < 1490)          //when stick 1 travels from 1490 ms towards 920 µs  
                    {
                        PORTB |= (1 << relayPin);        //relay pole switch, - & + on motor 
                        PORTB &= ~(1 << greenLED);        //turn off green LED
                        PORTB |= (1 << redLED);         //LED red indicates backward motion
                    }   

                else        //if µs is 1490> or <1555 - dead-span to prevent gliteches on relay when stick is in centre position 
                { 
//                  PORTB |= (1 << greenLED);           //for debug to indicate dead-span   
//                  PORTB |= (1 << redLED);         //for debug to indicate dead-span   
                }   

            }

        }

        GIFR |= (1 << PCIF);    //clear PCINT-flag  
    }

    else
    {

    }

}

}

ISR(TIMER1_OVF_vect)            //when Counter/Timer1 overflows  
{

}

ISR(PCINT0_vect)        //when pin-level changes on PB3
{ 

}

它是接近还是我仍然在蓝色?

4

2 回答 2

1

是的,溢出中断可能随时发生(尽管它确实经常发生)。引脚更改中断也可以。在这种情况下,它们中的每一个都只触及一个 8 位 volatile 变量(tot_overflowpInt分别),而这些变量又由您的主循环轮询。除非主循环有其他工作要做,这些工作可能需要比一个完整的计时器周期更长的时间(在这种情况下为 256*8=2048 个周期),否则这种结构并不能真正帮助您。

因此,您可以在主循环中检查 GIFR 位 PCIF(而不是 pInt)和 TIFR 位 TOV1,而不是启用中断,这将使您更容易理解行为。重置它们是一种特殊情况,将 1 写入该位并且仅写入该位。这将为您节省引脚更改中断的时间,因为主循环检查可能会更频繁地发生,并且不需要跳转到中断服务程序的延迟。

但是,它不会解决您的问题。您正在尝试测量脉冲宽度,在稍大的 AVR 上,可以使用定时器输入捕捉功能轻松完成。ATtiny85 中的计时器没有此功能。在这样做的 AVR 上,输入捕捉和定时器溢出中断的排列方式使得输入捕捉中断可以安全地读取软件驱动的溢出计数器。

当你得到一个定时器溢出时,你增加 tot_overflow,当你检测到一个引脚变化时,你读取 TCNT1 来组合这些值。这两个计数器虽然一个为另一个提供数据,但不会同时读取。您的阈值为 0x5d2 和 0x613。如果在读取 tot_overflow 之后但在读取 TCNT1 之前发生翻转,那么您很可能一次得到一个像 0x501 这样的时间,它应该是 0x601。同样,如果您停止 tot_overflow 更新。如果您在 tot_overflow 之前读取 TCNT1,您可能会在应该读取 0x5fe 时得到 0x6fe。简单地说,没有安全的秩序——但有关系。我们需要知道的是在读取计数器值时溢出计数值是否是最新的。

static uint8_t ovf;
if (TIFR & 1<<TOV1) {
   TIFR = 1<<TOV1;   // Clear overflow flag
   ovf++;
}
if (GIFR & 1<<PCIF) {
   GIFR = 1<<PCIF;   // clear pin change flag
   uint16_t timestamp = ovf<<8 | TCNT1;
   if (TIFR&1<<TOV1 && (timestamp&0xff)<0x80)
       timestamp += 0x100;   // Overflow had not been counted
   // Do what we like with the timestamp here
}

关键是我们已经加载了定时器值之后检查溢出。如果溢出发生在我们读取值之前,那么读取的值一定是低的;否则我们想要旧的计数。此特定示例实际上依赖于未在中断中处理的溢出,但您可以通过将块包含在中断屏蔽中来使用相同的方法。我们需要 TOV1 和 ovf 的两个读取匹配,并在 TCNT1 之后读取 TOV1。我们不希望有一个中断过程,从而清除 TOV1,这样我们就无法推断 ovf 和 TCNT1 的顺序。请注意,使用引脚更改中断来执行此逻辑会自动授予我们这一点,因为中断处理程序在中断禁用的情况下运行。

您的脉冲宽度不会比响应引脚变化的延迟方差更高的精度,并且在您显示的代码中,定时器复位(它也应该复位预分频器,GTCCR 中的 PSR1 位)。这通常意味着您确实想在中断处理程序本身中读取计时器。我们还可以观察到,您可以选择一个计时器步速,使您的阈值适合 8 位值;例如,当 timer1 以 8MHz/64 运行时,您的阈值将是 186 和 194,偏移量为 16-24µs。甚至可以做一些技巧,比如在溢出时精确设置一个阈值,因为计时器不必从 0 开始。

于 2015-05-29T12:44:58.107 回答
0

@YannVernier 感谢您将我推向正确的方向,或为我提供正确的方法!;-) 我想我终于搞定了,在一位朋友的帮助下,我得到了一点额外的帮助! 这是我没有首先得到
的最终代码,我必须删除 TIMSK enable ande sei() 以及 ISR 例程,以及意外放在后面的 else 语句:

    if ( ((TIFR & (1 << TOV1)) && ((pulse & 0xff))) < 0x80)
    {
        pulse += 0x100;   // Overflow had not been counted
    }
于 2015-05-30T20:37:59.060 回答