"ATMEGA 16" While loop is not working while using timer in fast PWM mode and interrupts

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello , i wrote this code to fade a LED  using PWM by recalculating he dutycycle in the timer overflow interrupt beside blinking a LED in the while loop , but the code in while loop is not working just the interrupt code is running

 

Here is the code :

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#define F_CPU 4000000

volatile double dutyCycle = 0;
int factor=1;

int main(void)
{
    
    DDRB = (1 << PB3);
    DDRD = (1 << PD7);

    TCCR0 =  (1 << WGM01) | (1 << WGM00) | (1 << COM01) ;
    TIMSK = (1 << TOIE0);

    //OCR0 = (dutyCycle * 100)/255;
    sei();
    TCCR0 |= (1 << CS01) ;
    
    while(1)
    {
    
        PORTD ^= (1 << PD7);
        _delay_ms(100);
        //PORTD &= ~(1 << PD7);
        
        
    
    }
    
}    

ISR(TIMER0_OVF_vect)
{
_delay_ms(20);
dutyCycle += 10;

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

OCR0 = (dutyCycle * 100)/255;
}

 

 

 

but when i undeclare the sei() function the code in the while loop runs  , it seems that ISR is overwriting the whileloop or something  , so anyone can help because iam really confused.

This topic has a solution.
Last Edited: Wed. Nov 2, 2016 - 01:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why the heck do you put a 20ms wait in an ISR?? Every time the ISR is hit your 100ms delay is incremented by the time it takes for the ISR to complete, even WITHOUT the 20ms delay the 100ms will be longer.

 

So the 100ms could be several minutes long, who knows.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How ling does it take for timer0 to overflow? Less than 20ms? Why have a delay in the isr???
Also F_CPU should be defined before the include for delay.h

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Atgeek,

welcome @ avrfreaks.

 

You are using a 20ms delay in the interrupt.

This probably means that the interrupt flag is set again before the interrupt exits and it is triggered again after 1 cpu cycle in you for loop.

 

It is also unusal to use floating point for integer calculations.

Note that if there is no floating point var's in your code the floating point lib does not have to be included and your hex file wil be a kb or so smaller.

 

I assume you want to scale your duty cycle between 0 and 100% ?

uint8_t dutyCycle;
OCR0 = (dutyCycle * 256)/100;

Then the code above will work a bit better :)

 

You also probably don't want to change the dutyCycle in the interrupt. So move:

dutyCycle += 10;

to the while (1) loop.

 

It's also good practice to do as little as practical in an interrupt routine. In this case it means moving most (Euhhmmm All?) your interrupt code to a separate function.

volatile uint16_t dutyCycle;        // "uint16_t" is portable, see C99 standard.

void setDuty( uint8_t duty)        // 8-bit, probably faster function call.
{
    uint16_t timerVal = duty;       // Promote to 16 bit.

    timerval = (timerVal *255)/100; // Scale: 100% -> 255
    if( timerVal > 255){
        timerVal = 255;
    }
    cli();                          // Writing to dutyCycle must be atomic.
    dutyCycle = timerVal; 

    // Or write to OCR0 directly:
    // OCR0 = timerVal;
    sei();
}

ISR( TIMER0_OVF_Vect){
    OCR0 = dutyCyle;
}

Notes: Some people prefer to use the ATOMIC_...{} macro's instead of sei() / cli().

The main reason is you want to restore the previous interrupt state at the end, not just enable them (Design decision).

if OCR0 is an 8 bit register you can omit the cli() / sei().

 

Edit:

Damn, js & Kartman beat me to it.

Did it take me more than 20 minutes to type this post?

 

 

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

Last Edited: Wed. Nov 2, 2016 - 06:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

An example of why punctuation is so important...

Damn, js & Kartman beat me to it.

 

Ross McKenzie, Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is _delay_ms() reentrant?

 

Indeed, with the delays, quite an "interesting" way to structure an app.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks that was the problem

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a lot Paulvdh

 

the problem was in the 20ms delay in the interrupt , also thanks for your clean code my code was really messed up :)