当在ATmega328上以64的时钟预分频器运行时,我的一个定时器在执行的特定时间由于未知原因而加速。
我在ATmega328上使用了两个定时器来生成TLC5940所需的时钟(请参见下面的原因;这与问题无关紧要)。TIMER0
使用快速PWM开启生成时钟信号OC0B
,其设置如下:
TCCR0A = 0
|(0<<COM0A1) // Bits 7:6 – COM0A1:0: Compare Match Output A Mode
|(0<<COM0A0) //
|(1<<COM0B1) // Bits 5:4 – COM0B1:0: Compare Match Output B Mode
|(0<<COM0B0)
|(1<<WGM01) // Bits 1:0 – WGM01:0: Waveform Generation Mode
|(1<<WGM00)
;
TCCR0B = 0
|(0<<FOC0A) // Force Output Compare A
|(0<<FOC0B) // Force Output Compare B
|(1<<WGM02) // Bit 3 – WGM02: Waveform Generation Mode
|(0<<CS02) // Bits 2:0 – CS02:0: Clock Select
|(1<<CS01)
|(0<<CS00) // 010 = clock/8
;
OCR0A = 8;
OCR0B = 4;
TIMSK0 = 0;
TIMER2
旋转数据线以每256 TIMER0
个周期产生一个消隐脉冲,其设置如下:
ASSR = 0;
TCCR2A = 0
|(0<<COM2A1) // Bits 7:6 – COM0A1:0: Compare Match Output A Mode
|(0<<COM2A0) //
|(0<<COM2B1) // Bits 5:4 – COM0B1:0: Compare Match Output B Mode
|(0<<COM2B0)
|(0<<WGM21) // Bits 1:0 – WGM01:0: Waveform Generation Mode
|(0<<WGM20)
;
TCCR2B = 0
|(0<<FOC2A) // Force Output Compare A
|(0<<FOC2B) // Force Output Compare B
|(0<<WGM22) // Bit 3 – WGM02: Waveform Generation Mode
|(1<<CS22) // Bits 2:0 – CS02:0: Clock Select
|(0<<CS21)
|(0<<CS20) // 100 = 64
;
OCR2A = 255;
OCR2B = 255;
TIMSK2 = 0
|(1<<TOIE2); // Timer/Counter0 Overflow Interrupt Enable
TIMER2
在溢出时(每256个周期)调用ISR。ISR手动生成消隐脉冲,并在必要时生成锁存脉冲:
volatile uint8_t fLatch;
ISR(TIMER2_OVF_vect) {
if (fLatch) {
fLatch = 0;
TLC5940_XLAT_PORT |= (1<<TLC5940_XLAT_BIT); // XLAT -> high
for (int i=0;i<10;i++)
nop();
TLC5940_XLAT_PORT &= ~(1<<TLC5940_XLAT_BIT); // XLAT -> high
}
// Blank
TLC5940_BLANK_PORT |= (1<<TLC5940_BLANK_BIT);
for (int i=0;i<10;i++)
nop();
TLC5940_BLANK_PORT &= ~(1<<TLC5940_BLANK_BIT);
}
nop()
上面代码中的延迟只是为了使脉冲在逻辑分析仪迹线上更明显。main()
函数中的循环如下所示:发送一些串行数据,等待ISR处理锁存,然后再次执行:
for (;;) {
if (!fLatch) {
sendSerial();
fLatch = 1;
_delay_ms(1);
}
nop();
}
sendSerial()
进行一些SPI发送(为简洁起见,在pastebin上编写代码)。我的问题是,sendSerial()
完成后,在等待fLatch
将其设置为低(已处理)时,时钟计时器会加速。这是逻辑分析仪的迹线(我将相同信号继续使图形变小的区域切掉了):
在左侧,通道0和1显示正在发送的SPI数据的尾端。同样在左侧的通道4上,您可以看到消隐脉冲。在通道2上,时钟脉冲如预期那样跳动。在图像的间隙附近,将在例程内部fLatch
设置。然后很快就以大约4倍的速度加速。最后,执行了消隐脉冲和锁存脉冲(通道3和4,位于图像的三分之一处),现在时钟脉冲恢复了其正常频率,串行数据变为再次发送。我尝试取出中的行,但获得了相同的结果。这是怎么回事?我应该注意,ATmega是由20Mhz晶体时钟驱动的,然后使用以下代码将速度降低64倍:1
main()
TIMER0
delay_ms(1);
main()
CLKPR = 1<<CLKPCE;
CLKPR = (0<<CLKPS3)|(1<<CLKPS2)|(1<<CLKPS1)|(0<<CLKPS0);
这是为了什么:我正在尝试控制TLC5940 LED驱动器:这些芯片需要外部时钟以及在时钟周期结束时进行复位。
sendSerial()
我的代码是通过SPI发送数据的:它不触摸TCCR
(定时器控制)寄存器。