Tiny13 and PWM

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

Hi, I would have thought I'd could work something like this out myself by now, but I just can't get it working. I have an LED connect to PB0 and a pot to PB2 on a Tiny13. I want to vary the intensity of the LED depending on the ADC value from the pot. I have taken some code from the butterfly book and tried to modify it for the Tiny13 with no luck. This is my code:-

#include 
#include 
#include 

#define LED 0

int Get_Pot(void);
void milliSecInit(unsigned char);
void setOCR0A(unsigned char);
void Init_Tiny(void);


ISR(SIG_OVERFLOW0)
{
        // toggle relay pin
        if(PORTB &= 1) cbi(PORTB, LED);
        else sbi(PORTB, LED);
}

void milliSecInit(unsigned char count)
{
        // timer 0 compare interrupt
        TIMSK0 = (1<<OCIE0A);

        // set the compare value
        setOCR0A(count);

        // set PWM phase correct mode, CLK/8 prescaler
        TCCR0A = (0<<WGM01)|(1<<WGM00);
        TCCR0B = (0<<FOC0A)|(1<<CS01);
}

void setOCR0A(unsigned char count)
{
        // set the compare value
        OCR0A = count;
}

int Get_Pot(void)
{
        char i;
        int ADCr = 0;
        int pot = 0;

        sbi(ADCSRA, ADEN); // enable the ADC

        // do a dummy reading first
        ADCSRA |= (1<<ADSC);

        // wait for conversion done flag
        while(ADCSRA & (1 << ADSC));

        // do conversion 8 times for accuracy
        for(i=0;i<8;i++)
        {
                ADCSRA |= (1<<ADSC);

                // wait for conversion done flag
                while(ADCSRA & (1 << ADSC));

                // get result
                pot = ADCH;

                // accumulate results for averaging later
                ADCr += pot;
        }

        ADCr = ADCr >> 3; // average 8 samples

        pot = ADCr;

        cbi(ADCSRA, ADEN); // disable the ADC

    return pot;
}

void Init_Tiny(void)
{
        // set PORTB 0 for output
        DDRB = (1<<DDB0);

        PORTB = (1<<0); // turn led off

        // set PB2 as ADC and set result as left adjusted
        ADMUX = (1<<ADLAR) | (1<<MUX0);

        // set ADC prescaler to 64
        ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
}

int main (void)
{
        int pot_value = 0;

        Init_Tiny();

        while(1) {
                // read pot value
                pot_value = Get_Pot();

                // set timer overflow to reflect pot value
                milliSecInit(pot_value);
        }

}

Any ideas?

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

I realised that initialising the PWM continually in the main loop is obviously not the thing to do, so I am just getting the ADC reading and initialising the PWM once before the main loop and it is still not working. I mustn't be setting the PWM up properly.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
if(PORTB &= 1)

This is not right. You're actually writing to the PORTB register. You should be reading the PINB register. Something like this:

if(PINB & 1)
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mrono wrote:

if(PORTB &= 1)

This is not right. You're actually writing to the PORTB register. You should be reading the PINB register. Something like this:

if(PINB & 1)


Thanks for that, after reading the tutorial on timers I changed it to
PORTB ^= (1 << 0);

which toggles the LED nicely. But I still can't get the PWM working.

I am not even bothering to read the ADC at the moment. I am just trying to get the PWM to toggle the LED by setting OCR0A = 127; for a 50% cycle. But I get nothing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR(SIG_OVERFLOW0)
...
  // timer 0 compare interrupt
  TIMSK0 = (1<<OCIE0A); 

Well, there's a problem for a start, you need to use
ISR(SIG_OUTPUT_COMPARE0A) instead of the overflow interrupt.

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

You must configure the COM0A1,COM0A0 bits in TCCR0A to something other than 0,0 to have PWM output.
/Lars

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

Thanks BrianS and Lars, that got it working. :D

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

Quote:
Well, there's a problem for a start, you need to use
ISR(SIG_OUTPUT_COMPARE0A) instead of the overflow interrupt.

Well, really you don't need any interrupts at all. Once you have the timer set up for PWM, all you need to do is set OCR0A to the value you want. Your main loop can be just:

while (1) 
{
    OCR0A = Get_Pot();
}

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:

Well, really you don't need any interrupts at all. Once you have the timer set up for PWM, all you need to do is set OCR0A to the value you want. Your main loop can be just:

while (1) 
{
    OCR0A = Get_Pot();
}


Even simpler, thanks.