Prueba esto, lo siento, no lo comenté mucho. No tengo ninguna forma de probarlo, pero debería funcionar. Si tiene algún problema o pregunta, hágamelo saber.
Es fácil hacerlo con bucle principal y retrasos. Pero, como dije, estoy
tratando de hacer esto solo con interrupciones.
La interrupción cambia y establece la salida, y el bucle principal se encarga de cambiar de incremento a decremento y viceversa; y cambia los leds con los que trabaja. Puede mover todo esto al ISR con algunos cambios, sin embargo, normalmente desea que su ISR contenga el menor código posible.
Cómo funciona:
Inicialmente, establece un valor aleatorio para cada led, rgbVals[0]
es rojo, rgbVals[1]
es verde, rgbVals[2]
es azul. Luego, cada 1000 ticks (timer0 interupt) incrementa o disminuye 2 leds, dependiendo del valor almacenado en rgbInc[]
para cada led, 1 es rojo, 2 es verde y 3 es azul. Los bucles principales comprueban si un led está en su máximo o mínimo, luego cambia el valor de incremento de ese led rgbInc[]
a 1 o -1, por lo que comenzará a ir en la otra dirección. Y cambia el par de led que están cambiando, ptrCurrent
y ptrNext
. Un problema con esto es que tendrá el mismo patrón, al establecer un valor aleatorio de 0 1 o 2 en 'ptrCurrent' y 'ptrNext' (siempre que no sean iguales al mismo valor) lo haría mejor.
#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
}
}
el punto entero de la lámpara del estado de ánimo es su aleatoriedad
Con solo unas pocas modificaciones menores, puedes hacerlo más aleatorio. Al igual que alterar aleatoriamente los valores de incremento / decremento ( rgbInc
, actualmente solo cambia de 1 a -1) y cambiar aleatoriamente los 2 colores de led con los que trabaja ( ptrCurrent
y ptrNext
(pero asegúrese de que no funcionen) igual el mismo valor.)
Aquí hay una publicación que da algunas otras ideas: Corriendo a través del espectro RGB
Aquí hay un ejemplo de código de y sitio de Arduino :
También quiero señalar que en su código ISR original, debe configurar los valores de OCRxx en la instrucción if para que cada interrupción no solo esté restableciendo los mismos valores. Así:
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;
}
}
Y si el código fuera para producción, me desharía de los red green blue
chars ya que solo puedes tener OCR0A = rand() / (RAND_MAX / 0xff + 1);
, y la memoria en estos dispositivos pequeños es preciosa.