0
\$\begingroup\$

A am new to AVR programming. I have an Attiny85 and an LED hooked up to pin 5 on the chip (PB0). My goal is to get the LED to fade on, then turn off and repeat. When I give power to the chip the LED lights up very little. It is a very faint glow. It stays the same brightness for several seconds then lights up to its full brightness. Below is my code.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

double dutyCycle = 0;

int main() {

    DDRB = (1 << PORTB0); // Set PB0 as output

    TCCR0A = (1 << COM0A1) | (1 << WGM00) | (1 << WGM01); // Clear OC0A on compare, WGMxx selscts fast mode
    TIMSK = (1 << TOIE0);

    OCR0A = (dutyCycle / 100.0) * 255.0;

    sei();

    TCCR0B = (1 << CS00); // Set prescalar and start timer

    while (1) {
        _delay_ms(100);
        dutyCycle = dutyCycle + 15;

        if (dutyCycle > 100) {
            dutyCycle = 0;
        }
    }

    return 0;
}

ISR(TIMER0_OVF_vect) {
    OCR0A = (dutyCycle / 100.0) * 255.0;
}

I tried changing the type of the dutyCycle variable to an uint8_t but the results were the same. I removed the '.0' from some and all of the math calculations but again the results were the same.

\$\endgroup\$
  • \$\begingroup\$ My C/C++ experience is nowhere near that of the others here on the stack so maybe I'm wrong, but I would personally start with typecasting the result of the calculation to uint_8. Or rather I would probably drop the floating point doubles all together and make it unsigned integer math. Just define your dutycycle range (uint_8) 0..255 instead of (double) 0..100. \$\endgroup\$ – jippie Jan 9 '16 at 7:50
  • \$\begingroup\$ Also have a look at this similar proof of concept program of mine, although written for an ATtiny13 it should be pretty much comparable. You'll notice some timer register bits set differently, check the datasheets for differences. git.linformatronics.nl/gitweb/… \$\endgroup\$ – jippie Jan 9 '16 at 8:01
  • \$\begingroup\$ I changed up some of the types but nothing seemed to work. \$\endgroup\$ – user3131261 Jan 9 '16 at 21:35
2
\$\begingroup\$

No need to assign OCR0A on every overlow, only reassign it when it changes. This code removes the ISR so is shorter and simpler (and works)...

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

double dutyCycle = 50;

int main() {

    DDRB = (1 << PORTB0); // Set PB0 as output

    TCCR0A = (1 << COM0A1) | (1 << WGM00) | (1 << WGM01); // Clear OC0A on compare, WGMxx selscts fast mode

    TCCR0B = (1 << CS00); // Set prescalar and start timer

    while (1) {

        OCR0A = (dutyCycle / 100.0) * 255.0;

        _delay_ms(100);
        dutyCycle = dutyCycle + 15;

        if (dutyCycle > 100) {
            dutyCycle = 0;
        }


    }

    return 0;
}

If you ever really need to use an ISR (unlike in this case), there are complications. For example, you are writing to the variable dutyCycle in the main loop, and reading from it in the ISR. This means the variable must be volatile. You also probably want to do avoid doing any floating point inside an ISR, so better to compute the final value in the main thread and then pass only the new byte to the ISR so it can do its job and return as quickly as possible.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.