我猜测,我的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引脚置为高/低,有时不在“死胡同”!这是毛刺上的VIDEO。请注意,绿色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
{
}
它是关闭还是我仍然是蓝色的?
答案 0 :(得分:1)
是的,溢出中断可能随时发生(尽管它经常发生)。那么引脚可以改变中断。在这种情况下,它们中的每一个仅触摸单个8位易失性变量(分别为tot_overflow
和pInt
),而这些变量又由主循环进行轮询。除非主循环有其他工作要做,这可能需要超过一个完整的定时器周期(在这种情况下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开始。
答案 1 :(得分:0)
@YannVernier感谢您向我推进正确的方向,或者给我完整的方法! ;-)我想我终于把它钉了起来,还有朋友的额外帮助! 这是最后的CODE 我没有先得到我必须删除TIMSK启用ande sei()加上ISR例程,以及之后意外放置的else语句:
if ( ((TIFR & (1 << TOV1)) && ((pulse & 0xff))) < 0x80)
{
pulse += 0x100; // Overflow had not been counted
}