我不知道为什么,但是除了增加亮度之外,LED脉冲还缩短了每个脉冲之间的时间间隔。这是从教程中复制的代码,在他的视频中效果很好,但对我来说,即使在模拟器中也没有。怎么会这样?
使用AVR 328p。
#define F_CPU 20000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
double dutyCycle = 0;
int main(void)
{
DDRD = (1 << PORTD6);
TCCR0A = (1 << COM0A1) | (1 << WGM00) | (1 << WGM01);
TIMSK0 = (1 << TOIE0);
OCR0A = (dutyCycle/100.0)*255.0;
sei();
TCCR0B = (1 << CS00) | (1 << CS02);
while(1)
{
_delay_ms(100);
dutyCycle += 10;
if(dutyCycle > 100){
dutyCycle = 0;
}
}
}
ISR(TIMER0_OVF_vect){ OCR0A = (dutyCycle/100.0)*255;}
答案 0 :(得分:0)
1)如果在主代码和中断中同时使用了某个变量,则必须将其标记为volatile
。然后,对其的每次读取或写入都将被编译为相应存储单元的读取/写入。否则,编译器可以进行优化,从而最大程度地减少内存访问。因此,在中断中看不到写入主程序内部的变量。
2)为什么使用double
?除非非常有必要,否则不要使用浮点数。 AVR不支持浮点运算的硬件,因此每个浮点运算将表示为多个运算。在您的示例中,使用从0到255的整数变量不会停止任何事情。即使您要使用0-100范围变量,也可以使用整数算术重新计算它。
3)注意更新超过1个字节长的变量。 AVR是8位架构。这意味着,要更新内存中超过8位宽的变量,需要执行一系列的多次操作。 double
长8个字节,需要太多此类操作。该中断可能在该系列的中间时刻触发,这意味着在ISR内部获取的变量的值将仅部分更新,从而导致不可预测的结果。在cli()
-sei()
的主代码中,所有在ISR中使用且宽度超过1个字节的变量的更新。
3)避免在ISR中进行困难的计算。根据经验:任何ISR都应尽快完成,所有密集的计算都应放在ISR之外。
4)在此示例中,您完全不需要ISR!您可以在主代码中编写OCR0A。