如何使用Pwm Atmega AVR增加亮度或使LED变暗

时间:2018-11-01 22:50:29

标签: c timer interrupt avr

我不知道为什么,但是除了增加亮度之外,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;}

1 个答案:

答案 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。