HSV color changing led driven by AVR tiny45
Jun0
In my last post I focused on delivering an integer only based algorithm to make a HSV to RGB conversion. I wanted to to drive a mood lamp with an AVR tiny13 which as only a 1K byte program memory. I ended gaving up on this idea because, I was not having good results.
I decided to get a new chip, with more program memory. The chosen one was the tiny45 with 4K bytes of program memory.
I got back in time and started again with the floating point version of the algorithm. And voila! It is working. It has a few glitches which increase with a small interval between color changing.
At this point, the code is very simple and it is like this (assumes a 2Mhz clock on the tiny45):
-
-
#include <avr/io.h>
-
#include <avr/interrupt.h>
-
#include <avr/pgmspace.h>
-
#include <avr/eeprom.h>
-
#include <avr/wdt.h>
-
#include <util/delay.h>
-
#include <math.h>
-
-
#define R_PIN PB0
-
#define G_PIN PB1
-
#define B_PIN PB2
-
-
static float h=0,s=0.8,v=0.5,r=0,g=0,b=0;
-
static int ri,gi,bi;
-
-
void HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
-
{
-
int i;
-
float f, p, q, t;
-
-
if( s == 0 ) {
-
*r = *g = *b = v; // achromatic (grey)
-
return;
-
}
-
-
h /= 60; // sector 0 to 5
-
i = floor( h );
-
f = h – i; // factorial part of h
-
p = v * ( 1 – s );
-
q = v * ( 1 – s * f );
-
t = v * ( 1 – s * ( 1 – f ) );
-
-
switch( i )
-
{
-
case 0:
-
*r = v;
-
*g = t;
-
*b = p;
-
break;
-
case 1:
-
*r = q;
-
*g = v;
-
*b = p;
-
break;
-
case 2:
-
*r = p;
-
*g = v;
-
*b = t;
-
break;
-
case 3:
-
*r = p;
-
*g = q;
-
*b = v;
-
break;
-
case 4:
-
*r = t;
-
*g = p;
-
*b = v;
-
break;
-
default:
-
*r = v;
-
*g = p;
-
*b = q;
-
break;
-
}
-
}
-
-
ISR(TIM0_COMPA_vect)
-
{
-
static unsigned char count = 0;
-
-
if (count == 0)
-
PORTB = _BV(R_PIN) | _BV(G_PIN) | _BV(B_PIN);
-
-
if (count==ri)
-
PORTB^=_BV(R_PIN);
-
-
if (count==gi)
-
PORTB^=_BV(G_PIN);
-
-
if (count==bi)
-
PORTB^=_BV(B_PIN);
-
-
count++;
-
}
-
-
int main()
-
{
-
// Enable PORTB as output
-
DDRB=0xff;
-
-
// Enable global interrupts
-
sei();
-
-
// Setting timer in CTC mode
-
TCCR0A = _BV(WGM01);
-
-
// Setting no prescaler
-
TCCR0B = _BV(CS00);
-
-
// Enabling compa
-
TIMSK = _BV(OCIE0A);
-
-
// Setting compare to make a frequency of 60*256 Hz
-
OCR0A = 0×82;
-
-
while(1)
-
{
-
if (h==360)
-
h=0;
-
-
h++;
-
-
HSVtoRGB(&r,&g,&b,h,s,v);
-
-
ri = r*255.;
-
gi = g*255.;
-
bi = b*255.;
-
-
_delay_ms(100);
-
}
-
-
return 0;
-
}
-
-
How to setup PWM on a AVR (Part II)
Jun0
In my last post I have described a little bit of what PWM is and which are the abstract steps are necessary to be executed. Now let’s go to the code. This code assumes a Tiny 13 AVR with an internal oscilator of 9.6 MHz divided by 8 (fuses configuration).
-
int main()
-
{
-
// Enable PORTB as output
-
DDRB=0xff;
-
-
// Enable global interrupts
-
sei();
-
-
// Enabling Timer 0 Fast PWM mode
-
TCCR0A = _BV(WGM01) | _BV(WGM00) | _BV(COM0A1);
-
-
// Setting Prescaler to none
-
TCCR0B = _BV(CS00);
-
-
// Setting the duty cycle to 50%
-
OCR0A = 0x7f;
-
-
while(1);
-
}
And that’s it. This code enables a PWM with a 50% duty cycle and controls a led connected to PB0 pin. If you need to give to led full intensity, then OCR1A must be set to 0xff, if you want the less intensity possible you need to set OCR1A to 0×00.
How to setup PWM on a AVR (Part I)
Jun0
I have been trying to make the setup of a PWM with an AVR. My wish is to build my own mood lamp. I divided my problem into smaller problems which the most basic is the generation of a PWM signal to control the brightness of the led.
PWM stands for Pulse Width Modulation and it consists in generating a square wave with a variable duty cycle. Imagine a perfect square wave, that half of the cycle is up and another half is down. That wave as a duty cycle of 50%.
If you power a lamp with this signal and give the up value 5 volts, at 50 Hz, it means that it will receive a 2.5 voltage 50 times per second, because 2.5 its the mean value along the time.
If you change the duty cycle you can obtain a full on, or a full of. This is simple explanation and lot can be found about PWM googling a little bit.
To make an AVR generate a PWM signal you just need to do the following:
- Setup a timer to a PWM mode.
- Enable global interrupts
- Enable port as output
My next post will be about more pratical and it will focus on how to implement led intensity change on a Tiny13 AVR using PWM.