简体   繁体   中英

How to increase brightness or dim the LED using pwm atmega avr

I dont know why but instead of increasing brightness, LED pulses, the period between each pulse is getting shorter. This is copied code from tutorial, in his video it worked fine but for me it didnt, even in simulator. How can that happen?

Using 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) If some variable is used simultaneously in the main code and in an interrupt, then it has to be marked as volatile . Then every read or write to it will be compiled as reading/writing of the corresponding memory cell. Otherwise, the compiler can optimize, minimizing memory access. So, writing to the variable inside the main program will not be visible in the interrupt.

2) Why are you using double ? Do not use floating point unless it strongly necessary. AVR has no hardware support for the floating-point arithmetic, so each floating-point operation will be represented as multiple operations. In your example, nothing stops from use integer variable which changes from 0 to 255. Even if you want to use 0-100 range variable, you can recalculate it using integer arithmetics.

3) Be aware updating variables which are more than 1 byte long. AVR is an 8-bit architecture. That means, updating of variables in memory more than 8-bit wide, requires a series of multiple operations. double which is 8 bytes long, requires too much of such operations. The interrupt may fire in any moment in the middle of that series, that means, the value of the variable, obtained inside the ISR will be updated only partially, causing unpredictable results. In the main code eclose in cli() - sei() any update of variables which are used inside the ISR and more than 1 byte wide.

3) Avoid hard calculations in the ISR. As a rule of thumb: any ISR should complete as soon as possible, all intense calculations should be placed outside the ISR.

4) In this example, you need no ISR at all! You can write OCR0A just inside the main code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM