It is rare to have that kind of failure. You might expect to see a little more noise on a pin, or have that pin completely non-functional. But to have it "somewhat work, but not in a useful way" is rare. I would suspect there are design issues that are causing the problems, and have something to do with a difference between the 164A and 164P. Since jitter is high, I would look at power related things. Are all the power/gnd pins connected? Are are the I/O pins either driven or pulled high or low? Etc.
But there still remains the possibility that the parts are bad. It's rare, but not unheard of. The only real way to tell is to get some more parts, from a different supplier, and try them. If they work, then you need to investigate further and see if you killed them in handling/soldering or if they really did come from Digikey bad.
Give this a shot, sorry I didn't comment it much. I don't have any way to test it, but it should work. If you have any issues or questions let me know.
It's easy to make it with main loop and delays. But, as I said, I'm
trying to do this just with interrupts.
The interrupt changes and sets the output, and the main loop takes care of switching from increment to decrement and vice versa; and changes the leds it is working with. You can move this all to the ISR with a few changes however you normally want your ISR's to contain as little code as possible.
How it works:
Initially it sets a random value to each led, rgbVals[0]
is red, rgbVals[1]
is green, rgbVals[2]
is blue. Then every 1000 ticks (timer0 interupt) it increments or decrements 2 leds, depending on the value stored in rgbInc[]
for each led, 1 is Red, 2 is Green, and 3 is blue. The main loops checks if a led is at it's max or min, then switches that led's increment value rgbInc[]
to 1 or -1, so it will start going the other direction. And it switches the pair of led's that are changing, ptrCurrent
and ptrNext
. One problem with this is that it will have the same pattern, setting a random value of 0 1 or 2 to 'ptrCurrent' and 'ptrNext' (as long as they don't equal the same value) would make it better.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
volatile uint16_t tick = 0;
volatile uint8_t rgbVals[3]; // rgbVals[0] is red; rgbVals[1] is green; rgbVals[2] is blue
volatile uint8_t ptrCurrent = 0; // current led
volatile uint8_t ptrNext = 1; // next led
int8_t rgbInc[3]; // will hold the increment/decrement value for each led
int main(void)
{
// init timers as fast PWM
TCCR0A = (1 << WGM00) | (1 << WGM01);
TCCR1A = (1 << WGM10) | (1 << WGM12);
// set prescaler to 1
TCCR0B |= (1 << CS00);
TCCR1B |= (1 << CS00);
// set ports to output
DDRB |= (1 << PB2);
DDRB |= (1 << PB3);
DDRB |= (1 << PB4);
// set outputs to PWM
TCCR0A |= (1 << COM0A1);
TCCR1A |= (1 << COM1A1);
TCCR1A |= (1 << COM1B1);
// overflow interrupt setup
TIMSK |= (1 << TOIE0);
sei();
rgbVals[0] = rand() / (RAND_MAX / 0xff + 1);
rgbVals[1] = rand() / (RAND_MAX / 0xff + 1);
rgbVals[2] = rand() / (RAND_MAX / 0xff + 1);
// Power led to rand values
OCR0A = rgbVals[0];
OCR1A = rgbVals[1];
OCR1B = rgbVals[2];
rgbInc[0] = 1; // You can play with these values to make it change faster
rgbInc[1] = 1;
rgbInc[2] = 1;
while(1)
{
for(uint8_t i =0; i<3; i++)
{
if(rgbVals[i] == 0 || rgbVals[i] == 255)
{
rgbInc[i] *= -1;
ptrCurrent = ptrNext;
ptrNext++;
if(ptrNext == 3) // roll over, since we only have 3 led colors, 0 1 and 2
ptrNext =0;
}
}
}
return 1; // never executed
}
ISR(TIMER0_OVF_vect)
{
tick++;
if(tick == 1000)
{
rgbVals[ptrCurrent] += rgbInc[ptrCurrent];
rgbVals[ptrNext] += rgbInc[ptrNext];
OCR0A = rgbVals[0]; // set PB2 to Red's value
OCR1A = rgbVals[1]; // set PB3 to Green's value
OCR1B = rgbVals[2]; // set PB4 to Blue's value
tick = 0; // reset tick
}
}
the whole point of mood lamp is its randomness
With just a few minor modifications you can make it more random. Like randomly altering the increment/decrement values (rgbInc
, currently only changes from 1 to -1,) and randomly changing the 2 led colors it is working with (ptrCurrent
and ptrNext
(but make sure they don't equal the same value.)
Here is a post that gives some other ideas: Running through RGB spectrum
Here is an code example from and Arduino site:
Also I want to point out that in your original ISR code you should set the OCRxx values in the if statement so that every interrupt it is not just re-setting the same values. Like this:
ISR(TIMER0_OVF_vect)
{
elapsed_cycles++;
if (elapsed_cycles == 10000)
{
red = rand() / (RAND_MAX / 0xff + 1);
green = rand() / (RAND_MAX / 0xff + 1);
blue = rand() / (RAND_MAX / 0xff + 1);
OCR0A = red;
OCR1A = green;
OCR1B = blue;
elapsed_cycles = 0;
}
}
And if you code was for production, I would get rid of the red green blue
chars since you can just have OCR0A = rand() / (RAND_MAX / 0xff + 1);
, and memory on these small devices is precious.
Best Answer
CKDIV8
must be 1 (unprogrammed), andCKSEL
must be %1111. The rest of the fuse bits are application-dependent and you must read the datasheet in order to determine what they should be.